Merge branch 'update_smoltcp' into 'master'

Migrating to smoltcp 0.10 and add support for multiple interfaces

See merge request redox-os/netstack!39
This commit is contained in:
Jeremy Soller
2023-09-08 01:58:46 +00:00
18 changed files with 1922 additions and 649 deletions
Generated
+436 -96
View File
@@ -2,11 +2,35 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "arg_parser"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0375ebcca85b3e88db7378e82fa"
[[package]]
name = "atomic-polyfill"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28"
dependencies = [
"critical-section",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -19,6 +43,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "byteorder"
version = "0.5.3"
@@ -31,6 +61,15 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
@@ -43,6 +82,33 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"time",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "critical-section"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
@@ -62,6 +128,38 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "defmt"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98"
dependencies = [
"bitflags",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e"
dependencies = [
"defmt-parser",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]]
name = "defmt-parser"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0"
dependencies = [
"thiserror",
]
[[package]]
name = "dns-parser"
version = "0.7.1"
@@ -73,25 +171,49 @@ dependencies = [
]
[[package]]
name = "extra"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#cf213969493db8667052a591e32a1e26d43c4234"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"bitflags",
"fuchsia-zircon-sys",
"byteorder 1.4.3",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
name = "heapless"
version = "0.7.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743"
dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version",
"spin",
"stable_deref_trait",
]
[[package]]
name = "iana-time-zone"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "idna"
@@ -105,30 +227,14 @@ dependencies = [
]
[[package]]
name = "iovec"
version = "0.1.4"
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"libc",
"wasm-bindgen",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "lazycell"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
[[package]]
name = "libc"
version = "0.2.147"
@@ -136,12 +242,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "log"
version = "0.3.9"
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"log 0.4.20",
"autocfg",
"scopeguard",
]
[[package]]
@@ -152,9 +259,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "managed"
version = "0.7.2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
[[package]]
name = "matches"
@@ -162,36 +269,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "mio"
version = "0.6.14"
source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901"
dependencies = [
"fuchsia-zircon",
"fuchsia-zircon-sys",
"iovec",
"kernel32-sys",
"lazycell",
"libc",
"log 0.4.20",
"miow",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
name = "miow"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
dependencies = [
"kernel32-sys",
"net2",
"winapi 0.2.8",
"ws2_32-sys",
]
[[package]]
name = "net2"
version = "0.2.37"
@@ -199,24 +276,22 @@ source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=master#db0
dependencies = [
"cfg-if 0.1.10",
"libc",
"winapi 0.3.9",
"winapi",
]
[[package]]
name = "netutils"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#105ed1ea43413a91152b289fbe76e7efc996e933"
source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#fc11b9bb3c1f5eefccb93ae670e4ec8b3d6fad4f"
dependencies = [
"arg_parser",
"extra",
"libc",
"mio",
"net2",
"ntpclient",
"pbr",
"redox-daemon",
"redox_event",
"redox_syscall 0.2.16",
"redox_syscall 0.3.5",
"redox_termios",
"termion",
"url",
@@ -231,12 +306,27 @@ dependencies = [
"time",
]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "pbr"
version = "1.1.1"
@@ -245,7 +335,7 @@ checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514"
dependencies = [
"crossbeam-channel",
"libc",
"winapi 0.3.9",
"winapi",
]
[[package]]
@@ -254,12 +344,54 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox-daemon"
version = "0.1.1"
@@ -270,6 +402,18 @@ dependencies = [
"redox_syscall 0.3.5",
]
[[package]]
name = "redox-log"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557"
dependencies = [
"chrono",
"log",
"smallvec",
"termion",
]
[[package]]
name = "redox_event"
version = "0.1.0"
@@ -284,9 +428,10 @@ version = "0.1.0"
dependencies = [
"byteorder 1.4.3",
"dns-parser",
"log 0.3.9",
"log",
"netutils",
"redox-daemon",
"redox-log",
"redox_event",
"redox_syscall 0.3.5",
"smoltcp",
@@ -320,23 +465,83 @@ dependencies = [
]
[[package]]
name = "slab"
version = "0.4.9"
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"autocfg",
"semver",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "smoltcp"
version = "0.5.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d2e3a36ac8fea7b94e666dfa3871063d6e0a5c9d5d4fec9a1a6b7b6760f0229"
dependencies = [
"bitflags",
"byteorder 1.4.3",
"cfg-if 1.0.0",
"defmt",
"heapless",
"log",
"managed",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termion"
version = "1.5.6"
@@ -349,6 +554,26 @@ dependencies = [
"redox_termios",
]
[[package]]
name = "thiserror"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]]
name = "time"
version = "0.1.45"
@@ -357,7 +582,7 @@ checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi",
"winapi 0.3.9",
"winapi",
]
[[package]]
@@ -381,6 +606,12 @@ version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
@@ -401,6 +632,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
@@ -408,10 +645,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.2.8"
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.29",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.29",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "winapi"
@@ -423,12 +708,6 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
@@ -442,11 +721,72 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"winapi 0.2.8",
"winapi-build",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[patch.unused]]
name = "mio"
version = "0.6.14"
source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901"
+7 -4
View File
@@ -20,22 +20,25 @@ netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" }
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" }
redox-daemon = "0.1.1"
redox_syscall = "0.3"
redox-log = "0.1"
byteorder = { version = "1.0", default-features = false }
dns-parser = "0.7.1"
[dependencies.log]
version = "0.3"
version = "0.4"
default-features = false
features = ["release_max_level_warn"]
[dependencies.smoltcp]
path = "smoltcp"
version = "0.10.0"
default-features = false
features = [
"std",
"ethernet",
"medium-ethernet", "medium-ip",
"proto-ipv4",
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp"
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp",
"iface-max-addr-count-8",
"log"
]
#For debugging: "log", "verbose"
+1 -1
View File
@@ -81,7 +81,7 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> {
fn main() {
redox_daemon::Daemon::new(move |daemon| {
logger::init_logger();
logger::init_logger("dnsd");
if let Err(err) = run(daemon) {
error!("dnsd: {}", err);
process::exit(1);
+13 -19
View File
@@ -1,22 +1,16 @@
use log::{set_logger_raw, Log, LogLevelFilter, LogMetadata, LogRecord};
use redox_log::{OutputBuilder, RedoxLogger};
struct Logger;
impl Log for Logger {
fn enabled(&self, _: &LogMetadata) -> bool {
true
}
fn log(&self, record: &LogRecord) {
println!("{}: {}", record.target(), record.args());
}
}
pub fn init_logger() {
unsafe {
set_logger_raw(|max_log_level| {
max_log_level.set(LogLevelFilter::Trace);
&Logger
}).expect("Can't initialize logger");
pub fn init_logger(process_name: &str) {
if let Err(_) = RedoxLogger::new()
.with_output(
OutputBuilder::stdout()
.with_ansi_escape_codes()
.flush_on_newline(true)
.with_filter(log::LevelFilter::Trace)
.build(),
)
.with_process_name(process_name.into())
.enable() {
eprintln!("{process_name}: Failed to init logger")
}
}
-123
View File
@@ -1,123 +0,0 @@
use smoltcp;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Write;
use std::rc::Rc;
use smoltcp::time::Instant;
use smoltcp::wire::EthernetAddress;
use crate::buffer_pool::{Buffer, BufferPool};
struct NetworkDeviceData {
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
}
pub struct NetworkDevice {
data: Rc<RefCell<NetworkDeviceData>>,
}
impl NetworkDevice {
pub const MTU: usize = 1520;
pub fn new(
network_file: Rc<RefCell<File>>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
local_hwaddr: smoltcp::wire::EthernetAddress,
buffer_pool: Rc<RefCell<BufferPool>>,
) -> NetworkDevice {
NetworkDevice {
data: Rc::new(RefCell::new(NetworkDeviceData {
network_file,
input_queue,
local_hwaddr,
buffer_pool,
})),
}
}
}
pub struct RxToken {
buffer: Buffer,
}
impl smoltcp::phy::RxToken for RxToken {
fn consume<R, F>(mut self, _timestamp: Instant, f: F) -> smoltcp::Result<R>
where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{
f(&mut self.buffer)
}
}
pub struct TxToken {
data: Rc<RefCell<NetworkDeviceData>>,
}
impl smoltcp::phy::TxToken for TxToken {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result<R>
where
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>,
{
let data = self.data.borrow_mut();
let mut buffer = data.buffer_pool.borrow_mut().get_buffer();
buffer.resize(len);
let res = f(&mut buffer)?;
let mut loopback = false;
if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut buffer) {
if frame.dst_addr() == EthernetAddress::default() {
frame.set_dst_addr(data.local_hwaddr);
loopback = true;
}
}
if loopback {
data.input_queue.borrow_mut().push_back(buffer.move_out());
} else {
data.network_file
.borrow_mut()
.write(&buffer)
.map_err(|_| smoltcp::Error::Dropped)?;
}
Ok(res)
}
}
impl<'a> smoltcp::phy::Device<'a> for NetworkDevice {
type RxToken = RxToken;
type TxToken = TxToken;
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
let mut limits = smoltcp::phy::DeviceCapabilities::default();
limits.max_transmission_unit = Self::MTU;
limits.max_burst_size = Some(20);
limits
}
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
let data = self.data.borrow_mut();
let buffer = data.input_queue.borrow_mut().pop_front();
if let Some(buffer) = buffer {
Some((
RxToken { buffer },
TxToken {
data: Rc::clone(&self.data),
},
))
} else {
None
}
}
fn transmit(&'a mut self) -> Option<Self::TxToken> {
Some(TxToken {
data: Rc::clone(&self.data),
})
}
}
+401
View File
@@ -0,0 +1,401 @@
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{ErrorKind, Read, Write};
use std::rc::Rc;
use smoltcp::storage::PacketMetadata;
use smoltcp::time::{Duration, Instant};
use smoltcp::wire::{
ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol,
EthernetRepr, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr,
};
use super::LinkDevice;
struct Neighbor {
hardware_address: EthernetAddress,
expires_at: Instant,
}
#[derive(Debug, Default)]
enum ArpState {
#[default]
Discovered,
Discovering {
target: Ipv4Address,
tries: u32,
silent_until: Instant,
},
}
type PacketBuffer = smoltcp::storage::PacketBuffer<'static, IpAddress>;
const EMPTY_MAC: EthernetAddress = EthernetAddress([0; 6]);
pub struct EthernetLink {
name: Rc<str>,
neighbor_cache: BTreeMap<IpAddress, Neighbor>,
arp_state: ArpState,
waiting_packets: PacketBuffer,
input_buffer: Vec<u8>,
output_buffer: Vec<u8>,
network_file: File,
hardware_address: Option<EthernetAddress>,
ip_address: Option<Ipv4Cidr>,
}
impl EthernetLink {
// TODO: Review these constants
const MAX_WAITING_PACKET_COUNT: usize = 10;
const MTU: usize = 1500;
const WAITING_PACKET_BUFFER_SIZE: usize = Self::MTU * Self::MAX_WAITING_PACKET_COUNT;
const NEIGHBOR_LIVE_TIME: Duration = Duration::from_secs(60);
const ARP_SILENCE_TIME: Duration = Duration::from_secs(1);
pub fn new(name: &str, network_file: File) -> Self {
let waiting_packets = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Self::MAX_WAITING_PACKET_COUNT],
vec![0u8; Self::WAITING_PACKET_BUFFER_SIZE],
);
Self {
name: name.into(),
network_file,
waiting_packets,
hardware_address: None,
ip_address: None,
input_buffer: vec![0u8; Self::MTU],
output_buffer: Vec::with_capacity(Self::MTU),
arp_state: Default::default(),
neighbor_cache: Default::default(),
}
}
fn send_to<F>(&mut self, dst: EthernetAddress, size: usize, f: F, proto: EthernetProtocol)
where
F: FnOnce(&mut [u8]),
{
let Some(hardware_address) = self.hardware_address else {
return;
};
let repr = EthernetRepr {
src_addr: hardware_address,
dst_addr: dst,
ethertype: proto,
};
self.output_buffer.clear();
self.output_buffer.resize(repr.buffer_len() + size, 0);
let mut frame = EthernetFrame::new_unchecked(&mut self.output_buffer);
repr.emit(&mut frame);
f(frame.payload_mut());
if let Err(_) = self.network_file.write_all(&self.output_buffer) {
error!(
"Dropped outboud packet on {} (failed to write to network file)",
self.name
)
}
}
fn process_arp(&mut self, packet: &[u8], now: Instant) {
let Some(hardware_address) = self.hardware_address else {
return;
};
let Some(ip_addr) = self.ip_address else {
return;
};
let Ok(repr) = ArpPacket::new_checked(packet).and_then(|packet| ArpRepr::parse(&packet)) else {
debug!("Dropped incomming arp packet on {} (Malformed)", self.name);
return;
};
match repr {
ArpRepr::EthernetIpv4 {
operation,
source_hardware_addr,
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
} => {
if hardware_address != target_hardware_addr {
// Only process packet that are for us
return;
}
if let ArpOperation::Unknown(_) = operation {
return;
}
if !source_hardware_addr.is_unicast() || !source_protocol_addr.is_unicast() {
return;
}
if !ip_addr.contains_addr(&target_protocol_addr) {
return;
}
self.neighbor_cache.insert(
IpAddress::Ipv4(source_protocol_addr),
Neighbor {
hardware_address: source_hardware_addr,
expires_at: now + Self::NEIGHBOR_LIVE_TIME,
},
);
if let ArpOperation::Request = operation {
let response = ArpRepr::EthernetIpv4 {
operation: ArpOperation::Reply,
source_hardware_addr: hardware_address,
source_protocol_addr: ip_addr.address(),
target_hardware_addr: source_hardware_addr,
target_protocol_addr: source_protocol_addr,
};
self.send_to(
source_hardware_addr,
response.buffer_len(),
|buf| response.emit(&mut ArpPacket::new_unchecked(buf)),
EthernetProtocol::Arp,
);
}
self.check_waiting_packets(source_protocol_addr, source_hardware_addr, now);
}
_ => {}
}
}
fn check_waiting_packets(&mut self, ip: Ipv4Address, mac: EthernetAddress, now: Instant) {
let mut waiting_packets =
std::mem::replace(&mut self.waiting_packets, PacketBuffer::new(vec![], vec![]));
loop {
match waiting_packets.peek() {
Ok((IpAddress::Ipv4(dst), _)) if dst == &ip => {}
Ok((IpAddress::Ipv4(dst), _)) => {
self.arp_state = ArpState::Discovering {
target: *dst,
tries: 0,
silent_until: Instant::ZERO,
};
self.send_arp(now);
break;
}
Err(_) => {
self.arp_state = ArpState::Discovered;
break;
}
}
let (_, packet) = waiting_packets.dequeue().unwrap();
self.send_to(
mac,
packet.len(),
|buf| buf.copy_from_slice(packet),
EthernetProtocol::Ipv4,
);
}
self.waiting_packets = waiting_packets;
}
fn drop_waiting_packets(&mut self, ip: Ipv4Address, now: Instant) {
loop {
match self.waiting_packets.peek() {
Ok((IpAddress::Ipv4(dst), _)) if dst == &ip => {}
Ok((IpAddress::Ipv4(dst), _)) => {
self.arp_state = ArpState::Discovering {
target: *dst,
tries: 0,
silent_until: Instant::ZERO,
};
self.send_arp(now);
return;
}
Err(_) => {
self.arp_state = ArpState::Discovered;
return;
}
}
let _ = self.waiting_packets.dequeue();
debug!(
"Dropped packet on {} because neighbor was not found",
self.name
)
}
}
fn handle_missing_neighbor(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) {
let Ok(buf) = self.waiting_packets.enqueue(packet.len(), next_hop) else {
warn!("Dropped packet on {} because waiting queue was full", self.name);
return;
};
buf.copy_from_slice(packet);
let IpAddress::Ipv4(next_hop) = next_hop;
if let ArpState::Discovered = self.arp_state {
self.arp_state = ArpState::Discovering {
target: next_hop,
tries: 0,
silent_until: Instant::ZERO,
};
self.send_arp(now)
}
}
fn send_arp(&mut self, now: Instant) {
let Some(hardware_address) = self.hardware_address else {
return;
};
let Some(ip_address) = self.ip_address else {
return;
};
match self.arp_state {
ArpState::Discovered => {}
ArpState::Discovering { silent_until, .. } if silent_until > now => {}
ArpState::Discovering { target, tries, .. } if tries >= 3 => {
self.drop_waiting_packets(target, now)
}
ArpState::Discovering {
target,
ref mut tries,
ref mut silent_until,
} => {
let arp_repr = ArpRepr::EthernetIpv4 {
operation: ArpOperation::Request,
source_hardware_addr: hardware_address,
source_protocol_addr: ip_address.address(),
target_hardware_addr: EthernetAddress::BROADCAST,
target_protocol_addr: target,
};
*tries += 1;
*silent_until = now + Self::ARP_SILENCE_TIME;
self.send_to(
EthernetAddress::BROADCAST,
arp_repr.buffer_len(),
|buf| arp_repr.emit(&mut ArpPacket::new_unchecked(buf)),
EthernetProtocol::Arp,
);
}
}
}
}
impl LinkDevice for EthernetLink {
fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) {
let local_broadcast = match self.ip_address.and_then(|cidr| cidr.broadcast()) {
Some(addr) => IpAddress::Ipv4(addr) == next_hop,
None => false,
};
if local_broadcast || next_hop.is_broadcast() {
self.send_to(
EthernetAddress::BROADCAST,
packet.len(),
|buf| buf.copy_from_slice(packet),
EthernetProtocol::Ipv4,
);
return;
}
match self.neighbor_cache.entry(next_hop) {
Entry::Vacant(_) => self.handle_missing_neighbor(next_hop, packet, now),
Entry::Occupied(e) => {
if e.get().expires_at < now {
e.remove();
self.handle_missing_neighbor(next_hop, packet, now)
} else {
let mac = e.get().hardware_address;
self.send_to(
mac,
packet.len(),
|buf| buf.copy_from_slice(packet),
EthernetProtocol::Ipv4,
)
}
}
}
}
fn recv(&mut self, now: Instant) -> Option<&[u8]> {
let Some(hardware_address) = self.hardware_address else {
return None;
};
let mut input_buffer = std::mem::replace(&mut self.input_buffer, Vec::new());
loop {
if let Err(e) = self.network_file.read(&mut input_buffer) {
if e.kind() != ErrorKind::WouldBlock {
error!("Failed to read ethernet device on link {}", self.name);
} else {
// No packet to read but we check if we have arp to send
self.send_arp(now);
}
self.input_buffer = input_buffer;
return None;
}
let packet = EthernetFrame::new_unchecked(&input_buffer[..]);
let Ok(repr) = EthernetRepr::parse(&packet) else {
debug!("Dropped incomming frame on {} (Malformed)", self.name);
continue;
};
// We let EMPTY_MAC pass because somehow this is the mac used when net=redir is used
if !repr.dst_addr.is_broadcast()
&& repr.dst_addr != EMPTY_MAC
&& repr.dst_addr != hardware_address
{
// Drop packets which are not for us
continue;
}
match repr.ethertype {
EthernetProtocol::Ipv4 => {
self.input_buffer = input_buffer;
return Some(EthernetFrame::new_unchecked(&self.input_buffer[..]).payload());
}
EthernetProtocol::Arp => self.process_arp(packet.payload(), now),
_ => continue,
}
}
}
fn name(&self) -> &Rc<str> {
&self.name
}
fn can_recv(&self) -> bool {
// We don't buffer any packets so we can't receive immediatly
false
}
fn mac_address(&self) -> Option<EthernetAddress> {
self.hardware_address
}
fn set_mac_address(&mut self, addr: EthernetAddress) {
self.hardware_address = Some(addr)
}
fn ip_address(&self) -> Option<IpCidr> {
Some(IpCidr::Ipv4(self.ip_address?))
}
fn set_ip_address(&mut self, addr: IpCidr) {
let IpCidr::Ipv4(addr) = addr;
self.ip_address = Some(addr);
}
}
+66
View File
@@ -0,0 +1,66 @@
use std::rc::Rc;
use smoltcp::storage::PacketMetadata;
use smoltcp::time::Instant;
use crate::scheme::Smolnetd;
use super::LinkDevice;
pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
pub struct LoopbackDevice {
name: Rc<str>,
buffer: PacketBuffer,
}
impl Default for LoopbackDevice {
fn default() -> Self {
let buffer = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0u8; 1500 * Smolnetd::SOCKET_BUFFER_SIZE],
);
LoopbackDevice {
name: "loopback".into(),
buffer,
}
}
}
impl LinkDevice for LoopbackDevice {
fn send(&mut self, _next_hop: smoltcp::wire::IpAddress, packet: &[u8], _now: Instant) {
match self.buffer.enqueue(packet.len(), ()) {
Err(_) => warn!("loopback dropped packet because buffer was full"),
Ok(buf) => buf.copy_from_slice(packet),
}
}
fn recv(&mut self, _now: Instant) -> Option<&[u8]> {
self.buffer.dequeue().ok().map(|((), buf)| &*buf)
}
fn name(&self) -> &std::rc::Rc<str> {
&self.name
}
fn can_recv(&self) -> bool {
!self.buffer.is_empty()
}
fn mac_address(&self) -> Option<smoltcp::wire::EthernetAddress> {
None
}
fn set_mac_address(&mut self, _addr: smoltcp::wire::EthernetAddress) {
}
fn ip_address(&self) -> Option<smoltcp::wire::IpCidr> {
Some("127.0.0.1/8".parse().unwrap())
}
fn set_ip_address(&mut self, _addr: smoltcp::wire::IpCidr) {
todo!()
}
}
+66
View File
@@ -0,0 +1,66 @@
pub mod loopback;
pub mod ethernet;
use std::rc::Rc;
use smoltcp::time::Instant;
use smoltcp::wire::{IpAddress, EthernetAddress, IpCidr};
/// Represent a link layer device (eth0, loopback...)
pub trait LinkDevice {
/// Send the given packet to the machine with the `next_hop` ip address
/// This method cannot fail so it's the implementor responsability
/// to buffer packets which can't be sent immediatly or decide to
/// drop them if necessary
fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant);
/// Returns None if nothing is received.
/// Returns an Ip packet otherwise
fn recv(&mut self, now: Instant) -> Option<&[u8]>;
/// Returns the LinkDevice display name used to refer to it and for lookups
fn name(&self) -> &Rc<str>;
/// Returns wether this device have packets pending
fn can_recv(&self) -> bool;
fn mac_address(&self) -> Option<EthernetAddress>;
fn set_mac_address(&mut self, addr: EthernetAddress);
fn ip_address(&self) -> Option<IpCidr>;
fn set_ip_address(&mut self, addr: IpCidr);
}
#[derive(Default)]
pub struct DeviceList {
inner: Vec<Box<dyn LinkDevice>>,
}
impl DeviceList {
pub fn push<T: LinkDevice + 'static>(&mut self, dev: T) {
self.inner.push(Box::new(dev))
}
pub fn get(&self, device_name: &str) -> Option<&dyn LinkDevice> {
self.inner
.iter()
.find(|dev| dev.name().as_ref() == device_name)
.map(|device| device.as_ref())
}
pub fn get_mut(&mut self, device_name: &str) -> Option<&mut (dyn LinkDevice + 'static)> {
self.inner
.iter_mut()
.find(|dev| dev.name().as_ref() == device_name)
.map(|device| device.as_mut())
}
pub fn iter(&self) -> impl Iterator<Item = &(dyn LinkDevice + 'static)> {
self.inner.iter().map(|b| b.as_ref())
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (dyn LinkDevice + 'static)> {
self.inner.iter_mut().map(|b| b.as_mut())
}
}
+8 -6
View File
@@ -3,11 +3,11 @@
extern crate event;
#[macro_use]
extern crate log;
extern crate byteorder;
extern crate netutils;
extern crate redox_netstack;
extern crate smoltcp;
extern crate syscall;
extern crate byteorder;
use std::cell::RefCell;
use std::fs::File;
@@ -15,14 +15,15 @@ use std::os::unix::io::{FromRawFd, RawFd};
use std::process;
use std::rc::Rc;
use event::EventQueue;
use redox_netstack::error::{Error, Result};
use redox_netstack::logger;
use event::EventQueue;
use scheme::Smolnetd;
mod buffer_pool;
mod device;
mod link;
mod port_set;
mod router;
mod scheme;
fn run(daemon: redox_daemon::Daemon) -> Result<()> {
@@ -143,7 +144,7 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> {
event_queue.trigger_all(event::Event {
fd: 0,
flags: EventFlags::empty()
flags: EventFlags::empty(),
})?;
event_queue.run()
@@ -151,12 +152,13 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> {
fn main() {
redox_daemon::Daemon::new(move |daemon| {
logger::init_logger();
logger::init_logger("smolnetd");
if let Err(err) = run(daemon) {
error!("smoltcpd: {}", err);
process::exit(1);
}
process::exit(0);
}).expect("smoltcp: failed to daemonize");
})
.expect("smoltcp: failed to daemonize");
}
+191
View File
@@ -0,0 +1,191 @@
use std::cell::RefCell;
use std::rc::Rc;
use smoltcp::phy::{Device, DeviceCapabilities, Medium};
use smoltcp::storage::PacketMetadata;
use smoltcp::time::Instant;
use smoltcp::wire::IpAddress;
use self::route_table::RouteTable;
use crate::link::DeviceList;
use crate::scheme::Smolnetd;
pub mod route_table;
pub type PacketBuffer = smoltcp::storage::PacketBuffer<'static, ()>;
pub struct Router {
rx_buffer: PacketBuffer,
tx_buffer: PacketBuffer,
devices: Rc<RefCell<DeviceList>>,
route_table: Rc<RefCell<RouteTable>>,
}
impl Router {
pub fn new(devices: Rc<RefCell<DeviceList>>, route_table: Rc<RefCell<RouteTable>>) -> Self {
let rx_buffer = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
);
let tx_buffer = PacketBuffer::new(
vec![PacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0u8; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE],
);
Self {
rx_buffer,
tx_buffer,
devices,
route_table,
}
}
pub const MTU: usize = 1486;
pub fn can_recv(&self) -> bool {
let mut can_recv = false;
for dev in self.devices.borrow().iter() {
can_recv |= dev.can_recv();
}
can_recv
}
pub fn poll(&mut self, now: Instant) {
for dev in self.devices.borrow_mut().iter_mut() {
if self.rx_buffer.is_full() {
break;
}
loop {
if self.rx_buffer.is_full() {
break;
}
let Some(buf) = dev.recv(now) else {
break;
};
self.rx_buffer
.enqueue(buf.len(), ())
.expect("We checked if it was full")
.copy_from_slice(buf);
}
}
}
pub fn dispatch(&mut self, now: Instant) {
while let Ok(((), packet)) = self.tx_buffer.dequeue() {
if let Ok(mut packet) = smoltcp::wire::Ipv4Packet::new_checked(packet) {
let dst_addr = IpAddress::Ipv4(packet.dst_addr());
if packet.dst_addr().is_broadcast() {
let buf = packet.into_inner();
for dev in self.devices.borrow_mut().iter_mut() {
dev.send(dst_addr, buf, now)
}
} else {
let route_table = self.route_table.borrow();
let Some(rule) = route_table.lookup_rule(&dst_addr) else {
warn!("No route found for destination: {}", dst_addr);
continue;
};
let next_hop = match rule.via {
Some(via) => via,
None => dst_addr,
};
let mut devices = self.devices.borrow_mut();
let Some(dev) = devices.get_mut(&rule.dev) else {
warn!("Device {} not found", rule.dev);
// TODO: Remove route if device doesn't exist anymore ?
continue;
};
let IpAddress::Ipv4(src) = rule.src;
if src != packet.src_addr() {
error!("Changed packet source {} -> {}", packet.src_addr(), src);
packet.set_src_addr(src);
packet.fill_checksum()
}
dev.send(next_hop, packet.into_inner(), now);
}
}
}
}
}
impl Device for Router {
type RxToken<'a> = RxToken<'a>;
type TxToken<'a> = TxToken<'a>;
fn receive(
&mut self,
_timestamp: smoltcp::time::Instant,
) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
if self.rx_buffer.is_empty() || self.tx_buffer.is_full() {
None
} else {
Some((
RxToken {
rx_buffer: &mut self.rx_buffer,
},
TxToken {
tx_buffer: &mut self.tx_buffer,
},
))
}
}
fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
if self.tx_buffer.is_full() {
None
} else {
Some(TxToken {
tx_buffer: &mut self.tx_buffer,
})
}
}
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.medium = Medium::Ip;
caps.max_transmission_unit = Router::MTU;
caps.max_burst_size = Some(Smolnetd::SOCKET_BUFFER_SIZE);
caps
}
}
pub struct TxToken<'a> {
tx_buffer: &'a mut PacketBuffer,
}
impl smoltcp::phy::TxToken for TxToken<'_> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(self
.tx_buffer
.enqueue(len, ())
.expect("This was checked before creating the TxToken"))
}
}
pub struct RxToken<'a> {
rx_buffer: &'a mut PacketBuffer,
}
impl<'a> smoltcp::phy::RxToken for RxToken<'a> {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let ((), buf) = self
.rx_buffer
.dequeue()
.expect("This was checked before creating the RxToken");
f(buf)
}
}
+99
View File
@@ -0,0 +1,99 @@
use std::fmt::Display;
use std::rc::Rc;
use smoltcp::wire::{IpAddress, IpCidr};
#[derive(Debug)]
pub struct Rule {
pub filter: IpCidr,
pub via: Option<IpAddress>,
pub dev: Rc<str>,
pub src: IpAddress,
}
impl Rule {
pub fn new(filter: IpCidr, via: Option<IpAddress>, dev: Rc<str>, src: IpAddress) -> Self {
Self {
filter,
via,
dev,
src,
}
}
}
impl Display for Rule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.filter.prefix_len() == 0 {
write!(f, "default")?;
} else {
write!(f, "{} ", self.filter)?;
}
if let Some(via) = self.via {
write!(f, " via {}", via)?;
}
write!(f, " dev {}", self.dev)?;
write!(f, " src {}", self.src)?;
Ok(())
}
}
#[derive(Debug, Default)]
pub struct RouteTable {
rules: Vec<Rule>,
}
impl RouteTable {
pub fn lookup_rule(&self, dst: &IpAddress) -> Option<&Rule> {
self.rules
.iter()
.rev()
.find(|rule| rule.filter.contains_addr(dst))
}
pub fn lookup_src_addr(&self, dst: &IpAddress) -> Option<IpAddress> {
Some(self.lookup_rule(dst)?.src)
}
pub fn lookup_gateway(&self, dst: &IpAddress) -> Option<IpAddress> {
self.lookup_rule(dst)?.via
}
pub fn lookup_device(&self, dst: &IpAddress) -> Option<Rc<str>> {
Some(self.lookup_rule(dst)?.dev.clone())
}
pub fn insert_rule(&mut self, new_rule: Rule) {
let i = match self
.rules
.binary_search_by_key(&new_rule.filter.prefix_len(), |rule| {
rule.filter.prefix_len()
}) {
Ok(i) | Err(i) => i,
};
self.rules.insert(i, new_rule);
}
pub fn remove_rule(&mut self, filter: IpCidr) {
self.rules.retain(|rule| rule.filter != filter);
}
pub fn change_src(&mut self, old_src: IpAddress, new_src: IpAddress) {
for rule in self.rules.iter_mut().filter(|rule| rule.src == old_src) {
rule.src = new_src;
}
}
}
impl Display for RouteTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for rule in self.rules.iter() {
writeln!(f, "{}", rule)?;
}
Ok(())
}
}
+15 -13
View File
@@ -1,17 +1,18 @@
use smoltcp::socket::{IcmpEndpoint, IcmpPacketMetadata, IcmpSocket, IcmpSocketBuffer, SocketHandle};
use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, IpAddress, IpEndpoint};
use smoltcp::socket::icmp::{Endpoint as IcmpEndpoint, PacketMetadata as IcmpPacketMetadata, Socket as IcmpSocket, PacketBuffer as IcmpSocketBuffer};
use smoltcp::iface::SocketHandle;
use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, IpAddress, IpListenEndpoint};
use std::mem;
use std::str;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use byteorder::{ByteOrder, NetworkEndian};
use crate::device::NetworkDevice;
use crate::port_set::PortSet;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use crate::router::Router;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
use super::{Smolnetd, SocketSet};
pub type IcmpScheme = SocketScheme<IcmpSocket<'static, 'static>>;
pub type IcmpScheme = SocketScheme<IcmpSocket<'static>>;
enum IcmpSocketType {
Echo,
@@ -24,7 +25,7 @@ pub struct IcmpData {
ident: u16,
}
impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> {
impl<'a> SchemeSocket for IcmpSocket<'a> {
type SchemeDataT = PortSet;
type DataT = IcmpData;
type SettingT = ();
@@ -74,6 +75,7 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> {
path: &str,
_uid: u32,
ident_set: &mut Self::SchemeDataT,
_context: &Context
) -> SyscallResult<(SocketHandle, Self::DataT)> {
use std::str::FromStr;
@@ -93,15 +95,15 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> {
let socket = IcmpSocket::new(
IcmpSocketBuffer::new(
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
),
IcmpSocketBuffer::new(
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
)
);
let handle = socket_set.add(socket);
let mut icmp_socket = socket_set.get::<IcmpSocket>(handle);
let icmp_socket = socket_set.get_mut::<IcmpSocket>(handle);
let ident = ident_set
.get_port()
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
@@ -125,20 +127,20 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> {
let socket = IcmpSocket::new(
IcmpSocketBuffer::new(
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
),
IcmpSocketBuffer::new(
vec![IcmpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
)
);
let handle = socket_set.add(socket);
let mut icmp_socket = socket_set.get::<IcmpSocket>(handle);
let icmp_socket = socket_set.get_mut::<IcmpSocket>(handle);
let ident = ident_set
.get_port()
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
icmp_socket
.bind(IcmpEndpoint::Udp(IpEndpoint::from(ident)))
.bind(IcmpEndpoint::Udp(IpListenEndpoint::from(ident)))
.map_err(|_| syscall::Error::new(syscall::EINVAL))?;
let socket_data = IcmpData {
socket_type: IcmpSocketType::Udp,
+10 -7
View File
@@ -1,16 +1,18 @@
use smoltcp::socket::{RawPacketMetadata, RawSocket, RawSocketBuffer, SocketHandle};
use smoltcp::socket::raw::{PacketMetadata as RawPacketMetadata, Socket as RawSocket, PacketBuffer as RawSocketBuffer};
use smoltcp::iface::SocketHandle;
use smoltcp::wire::{IpProtocol, IpVersion};
use std::str;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use crate::device::NetworkDevice;
use crate::router::Router;
use super::{Smolnetd, SocketSet};
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
pub type IpScheme = SocketScheme<RawSocket<'static, 'static>>;
pub type IpScheme = SocketScheme<RawSocket<'static>>;
impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
impl<'a> SchemeSocket for RawSocket<'a> {
type SchemeDataT = ();
type DataT = ();
type SettingT = ();
@@ -58,6 +60,7 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
path: &str,
uid: u32,
_: &mut Self::SchemeDataT,
_context: &Context
) -> SyscallResult<(SocketHandle, Self::DataT)> {
if uid != 0 {
return Err(SyscallError::new(syscall::EACCES));
@@ -67,11 +70,11 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
let rx_buffer = RawSocketBuffer::new(
vec![RawPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
);
let tx_buffer = RawSocketBuffer::new(
vec![RawPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
);
let ip_socket = RawSocket::new(
IpVersion::Ipv4,
+119 -100
View File
@@ -1,47 +1,51 @@
use crate::link::ethernet::EthernetLink;
use crate::link::LinkDevice;
use crate::link::{loopback::LoopbackDevice, DeviceList};
use crate::router::route_table::{RouteTable, Rule};
use crate::router::Router;
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
use netutils::getcfg;
use smoltcp;
use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder, NeighborCache, Routes};
use smoltcp::phy::EthernetTracer;
use smoltcp::socket::SocketSet as SmoltcpSocketSet;
use smoltcp::iface::{Config, Interface as SmoltcpInterface};
use smoltcp::phy::Tracer;
use smoltcp::time::{Duration, Instant};
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address};
use smoltcp::wire::{
EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address,
};
use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{self, Read, Write};
use std::io::{Read, Write};
use std::mem::size_of;
use std::rc::Rc;
use std::str::FromStr;
use syscall::data::TimeSpec;
use syscall;
use syscall::data::TimeSpec;
use crate::buffer_pool::{Buffer, BufferPool};
use crate::device::NetworkDevice;
use redox_netstack::error::{Error, Result};
use self::icmp::IcmpScheme;
use self::ip::IpScheme;
use self::netcfg::NetCfgScheme;
use self::tcp::TcpScheme;
use self::udp::UdpScheme;
use self::icmp::IcmpScheme;
use self::netcfg::NetCfgScheme;
use redox_netstack::error::{Error, Result};
mod icmp;
mod ip;
mod netcfg;
mod socket;
mod tcp;
mod udp;
mod icmp;
mod netcfg;
type SocketSet = SmoltcpSocketSet<'static, 'static, 'static>;
type Interface = Rc<RefCell<EthernetInterface<'static, 'static, 'static, EthernetTracer<NetworkDevice>>>>;
type SocketSet = SmoltcpSocketSet<'static>;
type Interface = Rc<RefCell<SmoltcpInterface>>;
const MAX_DURATION: Duration = Duration { millis: ::std::u64::MAX };
const MIN_DURATION: Duration = Duration { millis: 0 };
const MAX_DURATION: Duration = Duration::from_millis(u64::MAX);
const MIN_DURATION: Duration = Duration::from_millis(0);
pub struct Smolnetd {
network_file: Rc<RefCell<File>>,
router_device: Tracer<Router>,
iface: Interface,
time_file: File,
iface: Interface,
socket_set: Rc<RefCell<SocketSet>>,
timer: ::std::time::Instant,
@@ -50,16 +54,13 @@ pub struct Smolnetd {
tcp_scheme: TcpScheme,
icmp_scheme: IcmpScheme,
netcfg_scheme: NetCfgScheme,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
buffer_pool: Rc<RefCell<BufferPool>>,
}
impl Smolnetd {
const MAX_PACKET_SIZE: usize = 2048;
const SOCKET_BUFFER_SIZE: usize = 128; //packets
const MIN_CHECK_TIMEOUT: Duration = Duration { millis: 10 };
const MAX_CHECK_TIMEOUT: Duration = Duration { millis: 500 };
pub const MAX_PACKET_SIZE: usize = 2048;
pub const SOCKET_BUFFER_SIZE: usize = 128; //packets
pub const MIN_CHECK_TIMEOUT: Duration = Duration::from_millis(10);
pub const MAX_CHECK_TIMEOUT: Duration = Duration::from_millis(500);
pub fn new(
network_file: File,
@@ -72,56 +73,90 @@ impl Smolnetd {
) -> Smolnetd {
let hardware_addr = EthernetAddress::from_str(getcfg("mac").unwrap().trim())
.expect("Can't parse the 'mac' cfg");
let local_ip =
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
let protocol_addrs = vec![
IpCidr::new(local_ip, 24),
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
];
let default_gw = Ipv4Address::from_str(getcfg("ip_router").unwrap().trim())
.expect("Can't parse the 'ip_router' cfg.");
let buffer_pool = Rc::new(RefCell::new(BufferPool::new(Self::MAX_PACKET_SIZE)));
let input_queue = Rc::new(RefCell::new(VecDeque::new()));
let network_file = Rc::new(RefCell::new(network_file));
let network_device = EthernetTracer::new(NetworkDevice::new(
Rc::clone(&network_file),
Rc::clone(&input_queue),
hardware_addr,
Rc::clone(&buffer_pool),
), |_timestamp, printer| {
trace!("{}", printer)
});
let mut routes = Routes::new(BTreeMap::new());
routes.add_default_ipv4_route(default_gw).expect("Failed to add default gateway");
let iface = EthernetInterfaceBuilder::new(network_device)
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
.ethernet_addr(hardware_addr)
.ip_addrs(protocol_addrs)
.routes(routes)
.finalize();
let devices = Rc::new(RefCell::new(DeviceList::default()));
let route_table = Rc::new(RefCell::new(RouteTable::default()));
let mut network_device = Tracer::new(
Router::new(Rc::clone(&devices), Rc::clone(&route_table)),
|_timestamp, printer| trace!("{}", printer),
);
let config = Config::new(HardwareAddress::Ip);
let mut iface = SmoltcpInterface::new(config, &mut network_device, Instant::now());
iface.update_ip_addrs(|ip_addrs| ip_addrs.extend(protocol_addrs));
iface
.routes_mut()
.add_default_ipv4_route(default_gw)
.expect("Failed to add default gateway");
let iface = Rc::new(RefCell::new(iface));
let socket_set = Rc::new(RefCell::new(SocketSet::new(vec![])));
let loopback = LoopbackDevice::default();
route_table.borrow_mut().insert_rule(Rule::new(
"127.0.0.0/8".parse().unwrap(),
None,
Rc::clone(loopback.name()),
"127.0.0.1".parse().unwrap(),
));
let mut eth0 = EthernetLink::new(
"eth0",
network_file,
);
eth0.set_mac_address(hardware_addr);
devices.borrow_mut().push(loopback);
devices.borrow_mut().push(eth0);
Smolnetd {
iface: Rc::clone(&iface),
router_device: network_device,
socket_set: Rc::clone(&socket_set),
timer: ::std::time::Instant::now(),
time_file,
ip_scheme: IpScheme::new(Rc::clone(&socket_set), ip_file),
udp_scheme: UdpScheme::new(Rc::clone(&socket_set), udp_file),
tcp_scheme: TcpScheme::new(Rc::clone(&socket_set), tcp_file),
icmp_scheme: IcmpScheme::new(Rc::clone(&socket_set), icmp_file),
netcfg_scheme: NetCfgScheme::new(Rc::clone(&iface), netcfg_file),
input_queue,
network_file,
buffer_pool,
ip_scheme: IpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
ip_file,
),
udp_scheme: UdpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
udp_file,
),
tcp_scheme: TcpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
tcp_file,
),
icmp_scheme: IcmpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
icmp_file,
),
netcfg_scheme: NetCfgScheme::new(
Rc::clone(&iface),
netcfg_file,
Rc::clone(&route_table),
Rc::clone(&devices),
),
}
}
pub fn on_network_scheme_event(&mut self) -> Result<Option<()>> {
if self.read_frames()? > 0 {
self.poll()?;
}
self.poll()?;
Ok(None)
}
@@ -184,55 +219,39 @@ impl Smolnetd {
let mut iter_limit = 10usize;
let mut iface = self.iface.borrow_mut();
let mut socket_set = self.socket_set.borrow_mut();
let timestamp = Instant::from(self.timer);
loop {
let timestamp = Instant::from(self.timer);
if iter_limit == 0 {
break MIN_DURATION;
}
iter_limit -= 1;
match iface.poll(&mut socket_set, timestamp) {
Ok(_) | Err(smoltcp::Error::Unrecognized) => (),
Err(e) => {
error!("poll error: {}", e);
break MIN_DURATION;
}
}
match iface.poll_delay(&socket_set, timestamp) {
Some(Duration { millis: 0 }) => { }
Some(delay) => {
break ::std::cmp::min(MAX_DURATION, delay)
}
None => break MAX_DURATION
self.router_device.get_mut().poll(timestamp);
// TODO: Check what if the bool returned by poll can be useful
iface.poll(timestamp, &mut self.router_device, &mut socket_set);
self.router_device.get_mut().dispatch(timestamp);
if !self.router_device.get_ref().can_recv() {
match iface.poll_delay(timestamp, &socket_set) {
Some(delay) if delay == Duration::ZERO => {}
Some(delay) => break ::std::cmp::min(MAX_DURATION, delay),
None => break MAX_DURATION,
};
}
}
};
self.notify_sockets()?;
Ok(::std::cmp::min(
::std::cmp::max(Smolnetd::MIN_CHECK_TIMEOUT, timeout),
Smolnetd::MAX_CHECK_TIMEOUT,
))
}
fn read_frames(&mut self) -> Result<usize> {
let mut total_frames = 0;
loop {
let mut buffer = self.buffer_pool.borrow_mut().get_buffer();
let count = match self.network_file.borrow_mut().read(&mut buffer) {
Ok(count) => count,
Err(err) => match err.kind() {
io::ErrorKind::WouldBlock => break,
_ => return Err(
Error::from_io_error(err, "Failed to read from network file")
)
}
};
buffer.resize(count);
self.input_queue.borrow_mut().push_back(buffer);
total_frames += 1;
}
Ok(total_frames)
}
fn notify_sockets(&mut self) -> Result<()> {
self.ip_scheme.notify_sockets()?;
self.udp_scheme.notify_sockets()?;
@@ -257,17 +276,17 @@ fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize)
.map_err(|e| Error::from_io_error(e, "failed to post fevent"))
}
fn parse_endpoint(socket: &str) -> IpEndpoint {
fn parse_endpoint(socket: &str) -> IpListenEndpoint {
let mut socket_parts = socket.split(':');
let host = IpAddress::Ipv4(
Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
.unwrap_or_else(|_| Ipv4Address::new(0, 0, 0, 0)),
);
let host = Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
.ok()
.filter(|addr| !addr.is_unspecified())
.map(IpAddress::Ipv4);
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
IpEndpoint::new(host, port)
IpListenEndpoint { addr: host, port }
}
+165 -158
View File
@@ -2,24 +2,30 @@
mod nodes;
mod notifier;
use smoltcp::wire::{IpAddress, EthernetAddress, IpCidr, Ipv4Address};
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{ErrorKind, Read, Write};
use std::rc::Rc;
use std::mem;
use std::str::FromStr;
use std::rc::Rc;
use std::str;
use std::str::FromStr;
use syscall;
use syscall::data::Stat;
use syscall::flag::{MODE_DIR, MODE_FILE};
use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
use syscall;
use syscall::{
Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket,
Result as SyscallResult, SchemeMut,
};
use crate::link::DeviceList;
use crate::router::route_table::{RouteTable, Rule};
use self::nodes::*;
use self::notifier::*;
use redox_netstack::error::{Error, Result};
use super::{post_fevent, Interface};
use redox_netstack::error::{Error, Result};
const WRITE_BUFFER_MAX_SIZE: usize = 0xffff;
@@ -28,27 +34,44 @@ fn gateway_cidr() -> IpCidr {
IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0)
}
fn parse_default_gw(value: &str) -> SyscallResult<Ipv4Address> {
let mut routes = value.lines();
if let Some(route) = routes.next() {
if !routes.next().is_none() {
return Err(SyscallError::new(syscall::EINVAL));
}
let mut words = route.split_whitespace();
if let Some("default") = words.next() {
if let Some("via") = words.next() {
if let Some(ip) = words.next() {
return Ipv4Address::from_str(ip)
.map_err(|_| SyscallError::new(syscall::EINVAL));
}
}
}
fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult<Rule> {
let mut parts = value.split_whitespace();
let cidr_str = parts.next().ok_or(SyscallError::new(syscall::EINVAL))?;
let cidr = match cidr_str {
"default" => gateway_cidr(),
cidr_str => cidr_str
.parse()
.map_err(|_| SyscallError::new(syscall::EINVAL))?,
};
let via: IpAddress = match parts.next().ok_or(SyscallError::new(syscall::EINVAL))? {
"via" => parts
.next()
.ok_or(SyscallError::new(syscall::EINVAL))?
.parse()
.map_err(|_| SyscallError::new(syscall::EINVAL))?,
_ => return Err(SyscallError::new(syscall::EINVAL)),
};
if !via.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
Err(SyscallError::new(syscall::EINVAL))
let rule = route_table
.lookup_rule(&via)
.ok_or(SyscallError::new(syscall::EINVAL))?;
Ok(Rule::new(cidr, Some(via), rule.dev.clone(), rule.src))
}
fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRef) -> CfgNodeRef {
cfg_node!{
fn mk_root_node(
iface: Interface,
notifier: NotifierRef,
dns_config: DNSConfigRef,
route_table: Rc<RefCell<RouteTable>>,
devices: Rc<RefCell<DeviceList>>,
) -> CfgNodeRef {
cfg_node! {
"resolv" => {
"nameserver" => {
rw [dns_config, notifier] (Option<Ipv4Address>, None)
@@ -79,37 +102,24 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
},
"route" => {
"list" => {
ro [iface] || {
let mut gateway = None;
iface.borrow_mut().routes_mut().update(|map| {
gateway = map.get(&gateway_cidr()).map(|route| route.via_router);
});
if let Some(ip) = gateway {
format!("default via {}\n", ip)
} else {
String::new()
}
ro [route_table] || {
format!("{}", route_table.borrow())
}
},
"add" => {
wo [iface, notifier] (Option<Ipv4Address>, None)
wo [iface, notifier, route_table] (Option<Rule>, None)
|cur_value, line| {
if cur_value.is_none() {
let default_gw = parse_default_gw(line)?;
if !default_gw.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
*cur_value = Some(default_gw);
let route = parse_route(line, &route_table.borrow())?;
*cur_value = Some(route);
Ok(())
} else {
Err(SyscallError::new(syscall::EINVAL))
}
}
|cur_value| {
if let Some(default_gw) = *cur_value {
if iface.borrow_mut().routes_mut().add_default_ipv4_route(default_gw).is_err() {
return Err(SyscallError::new(syscall::EINVAL));
}
if let Some(route) = cur_value.take() {
route_table.borrow_mut().insert_rule(route);
notifier.borrow_mut().schedule_notify("route/list");
Ok(())
} else {
@@ -118,32 +128,23 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
}
},
"rm" => {
wo [iface, notifier] (Option<Ipv4Address>, None)
wo [iface, notifier, route_table] (Option<IpCidr>, None)
|cur_value, line| {
if cur_value.is_none() {
let default_gw = parse_default_gw(line)?;
if !default_gw.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
match line.parse() {
Ok(cidr) => {
*cur_value = Some(cidr);
Ok(())
}
Err(_) => Err(SyscallError::new(syscall::EINVAL))
}
*cur_value = Some(default_gw);
Ok(())
} else {
Err(SyscallError::new(syscall::EINVAL))
}
}
|cur_value| {
if let Some(default_gw) = *cur_value {
let mut iface = iface.borrow_mut();
let mut gateway = None;
iface.routes_mut().update(|map| {
gateway = map.get(&gateway_cidr()).map(|route| route.via_router);
});
if gateway != Some(IpAddress::Ipv4(default_gw)) {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.routes_mut().update(|map| {
map.remove(&gateway_cidr());
});
if let Some(cidr) = *cur_value {
route_table.borrow_mut().remove_rule(cidr);
notifier.borrow_mut().schedule_notify("route/list");
Ok(())
} else {
@@ -155,9 +156,17 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
"ifaces" => {
"eth0" => {
"mac" => {
rw [iface, notifier] (Option<EthernetAddress>, None)
rw [iface, notifier, devices] (Option<EthernetAddress>, None)
|| {
format!("{}\n", iface.borrow().ethernet_addr())
match devices.borrow().get("eth0") {
Some(dev) => {
match dev.mac_address() {
Some(addr) => format!("{addr}\n"),
None => "Not configured\n".into(),
}
}
None => "Device not found\n".into(),
}
}
|cur_value, line| {
if cur_value.is_none() {
@@ -174,96 +183,76 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe
}
|cur_value| {
if let Some(mac) = *cur_value {
iface.borrow_mut().set_ethernet_addr(mac);
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
if let Some(dev) = devices.borrow_mut().get_mut("eth0") {
dev.set_mac_address(mac);
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
}
}
Ok(())
}
},
"addr" => {
"list" => {
ro [iface]
ro [devices]
|| {
let mut ips = String::new();
for cidr in iface.borrow().ip_addrs() {
ips += &format!("{}\n", cidr);
}
ips
let res = match devices.borrow().get("eth0") {
Some(dev) => {
match dev.ip_address() {
Some(addr) => format!("{addr}\n"),
None => "Not configured\n".into(),
}
}
None => "Device not found\n".into(),
};
res
}
},
"set" => {
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
wo [iface, notifier, devices, route_table] (Option<IpCidr>, None)
|cur_value, line| {
let cidr = IpCidr::from_str(line)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
cur_value.push(cidr);
Ok(())
}
|cur_value| {
if !cur_value.is_empty() {
let mut iface = iface.borrow_mut();
let mut cidrs = vec![];
mem::swap(cur_value, &mut cidrs);
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
}
Ok(())
}
},
"add" => {
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|cur_value, line| {
let cidr = IpCidr::from_str(line)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
cur_value.push(cidr);
Ok(())
}
|cur_value| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().to_vec();
for cidr in cur_value {
cidrs.insert(0, *cidr);
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
Ok(())
}
},
"rm" => {
wo [iface, notifier] (Vec<IpCidr>, Vec::new())
|cur_value, line| {
let cidr = IpCidr::from_str(line)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
cur_value.push(cidr);
Ok(())
}
|cur_value| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().to_vec();
for cidr in cur_value {
let pre_retain_len = cidrs.len();
cidrs.retain(|&c| c != *cidr);
if pre_retain_len == cidrs.len() {
if cur_value.is_none() {
let cidr = IpCidr::from_str(line)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
*cur_value = Some(cidr);
Ok(())
} else {
Err(SyscallError::new(syscall::EINVAL))
}
}
|cur_value| {
// TODO: Multiple IPs
if let Some(cidr) = cur_value.take() {
if let Some(dev) = devices.borrow_mut().get_mut("eth0") {
let mut route_table = route_table.borrow_mut();
if let Some(old_addr) = dev.ip_address() {
let IpCidr::Ipv4(old_v4_cidr) = old_addr;
let old_network = IpCidr::Ipv4(old_v4_cidr.network());
route_table.remove_rule(old_network);
route_table.change_src(old_addr.address(), cidr.address());
iface.borrow_mut().update_ip_addrs(|addrs| addrs.retain(|addr| *addr != old_addr))
}
dev.set_ip_address(cidr);
// FIXME: Here, the insert 0 is a workaround to let UDP sockets
// work with this interface only.
// Smoltcp takes the first ip address when looking for a source
// ip address when sending UDP packets.
// This behavior will have to be fixed as it's our route table
// job to find give this source.
iface.borrow_mut().update_ip_addrs(|addrs| addrs.insert(0, cidr).unwrap());
let IpCidr::Ipv4(v4_cidr) = cidr;
let network_cidr = IpCidr::Ipv4(v4_cidr.network());
route_table.insert_rule(Rule::new(network_cidr, None, dev.name().clone(), cidr.address()))
}
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
notifier.borrow_mut().schedule_notify("route/list");
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
Ok(())
}
},
@@ -345,7 +334,12 @@ pub struct NetCfgScheme {
}
impl NetCfgScheme {
pub fn new(iface: Interface, scheme_file: File) -> NetCfgScheme {
pub fn new(
iface: Interface,
scheme_file: File,
route_table: Rc<RefCell<RouteTable>>,
devices: Rc<RefCell<DeviceList>>,
) -> NetCfgScheme {
let notifier = Notifier::new_ref();
let dns_config = Rc::new(RefCell::new(DNSConfig {
name_server: Ipv4Address::new(8, 8, 8, 8),
@@ -354,7 +348,13 @@ impl NetCfgScheme {
scheme_file,
next_fd: 1,
files: BTreeMap::new(),
root_node: mk_root_node(iface, Rc::clone(&notifier), dns_config),
root_node: mk_root_node(
iface,
Rc::clone(&notifier),
dns_config,
route_table,
devices,
),
notifier,
}
}
@@ -366,12 +366,14 @@ impl NetCfgScheme {
Ok(0) => {
//TODO: Cleanup must occur
break Some(());
},
}
Ok(_) => (),
Err(err) => if err.kind() == ErrorKind::WouldBlock {
break None;
} else {
return Err(Error::from(err));
Err(err) => {
if err.kind() == ErrorKind::WouldBlock {
break None;
} else {
return Err(Error::from(err));
}
}
}
self.handle(&mut packet);
@@ -414,7 +416,11 @@ impl SchemeMut for NetCfgScheme {
is_dir: current_node.is_dir(),
is_writable: current_node.is_writable(),
is_readable: current_node.is_readable(),
node_writer: if current_node.is_writable() { current_node.new_writer() } else { None },
node_writer: if current_node.is_writable() {
current_node.new_writer()
} else {
None
},
uid,
pos: 0,
read_buf,
@@ -440,7 +446,8 @@ impl SchemeMut for NetCfgScheme {
}
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
@@ -468,7 +475,8 @@ impl SchemeMut for NetCfgScheme {
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
@@ -482,15 +490,12 @@ impl SchemeMut for NetCfgScheme {
}
fn fstat(&mut self, fd: usize, stat: &mut Stat) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
stat.st_mode = if file.is_dir {
MODE_DIR
} else {
MODE_FILE
};
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
if file.is_writable {
stat.st_mode |= 0o222;
}
@@ -505,7 +510,8 @@ impl SchemeMut for NetCfgScheme {
}
fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult<SyscallEventFlags> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if events.contains(syscall::EVENT_READ) {
@@ -517,7 +523,8 @@ impl SchemeMut for NetCfgScheme {
}
fn fsync(&mut self, fd: usize) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
+188 -68
View File
@@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{ErrorKind, Read, Write};
@@ -10,15 +11,26 @@ use std::rc::Rc;
use std::str;
use syscall;
use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, Result as SyscallResult, SchemeBlockMut};
use syscall::data::TimeSpec;
use syscall::flag::{EVENT_READ, EVENT_WRITE};
use syscall::{
Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket,
Result as SyscallResult, SchemeBlockMut,
};
use super::Interface;
use crate::router::route_table::RouteTable;
use crate::scheme::smoltcp::iface::SocketHandle;
use redox_netstack::error::{Error, Result};
use smoltcp::socket::{AnySocket, SocketHandle};
use smoltcp::socket::AnySocket;
use super::{post_fevent, SocketSet};
pub struct Context {
pub iface: Interface,
pub route_table: Rc<RefCell<RouteTable>>,
}
pub struct NullFile {
pub flags: usize,
pub uid: u32,
@@ -70,7 +82,8 @@ enum Setting<SettingT: Copy> {
Ttl,
ReadTimeout,
WriteTimeout,
#[allow(dead_code)] Other(SettingT),
#[allow(dead_code)]
Other(SettingT),
}
pub struct SettingFile<SettingT: Copy> {
@@ -98,7 +111,10 @@ where
}
}
pub fn events(&mut self, socket_set: &mut SocketSet) -> usize where SocketT: AnySocket<'static, 'static> {
pub fn events(&mut self, socket_set: &mut SocketSet) -> usize
where
SocketT: AnySocket<'static>,
{
let mut revents = 0;
if let &mut SchemeFile::Socket(SocketFile {
socket_handle,
@@ -110,7 +126,9 @@ where
{
let socket = socket_set.get::<SocketT>(socket_handle);
if events & syscall::EVENT_READ.bits() == syscall::EVENT_READ.bits() && (socket.can_recv() || !socket.may_recv()) {
if events & syscall::EVENT_READ.bits() == syscall::EVENT_READ.bits()
&& (socket.can_recv() || !socket.may_recv())
{
if !*read_notified {
*read_notified = true;
revents |= EVENT_READ.bits();
@@ -119,7 +137,9 @@ where
*read_notified = false;
}
if events & syscall::EVENT_WRITE.bits() == syscall::EVENT_WRITE.bits() && socket.can_send() {
if events & syscall::EVENT_WRITE.bits() == syscall::EVENT_WRITE.bits()
&& socket.can_send()
{
if !*write_notified {
*write_notified = true;
revents |= EVENT_WRITE.bits();
@@ -162,21 +182,42 @@ where
fn hop_limit(&self) -> u8;
fn set_hop_limit(&mut self, hop_limit: u8);
fn get_setting(file: &SocketFile<Self::DataT>, setting: Self::SettingT, buf: &mut [u8]) -> SyscallResult<usize>;
fn set_setting(file: &mut SocketFile<Self::DataT>, setting: Self::SettingT, buf: &[u8]) -> SyscallResult<usize>;
fn get_setting(
file: &SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &mut [u8],
) -> SyscallResult<usize>;
fn set_setting(
file: &mut SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &[u8],
) -> SyscallResult<usize>;
fn new_socket(
sockets: &mut SocketSet,
path: &str,
uid: u32,
data: &mut Self::SchemeDataT,
context: &Context,
) -> SyscallResult<(SocketHandle, Self::DataT)>;
fn close_file(&self, file: &SchemeFile<Self>, data: &mut Self::SchemeDataT) -> SyscallResult<()>;
fn close_file(
&self,
file: &SchemeFile<Self>,
data: &mut Self::SchemeDataT,
) -> SyscallResult<()>;
fn write_buf(&mut self, file: &mut SocketFile<Self::DataT>, buf: &[u8]) -> SyscallResult<Option<usize>>;
fn write_buf(
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> SyscallResult<Option<usize>>;
fn read_buf(&mut self, file: &mut SocketFile<Self::DataT>, buf: &mut [u8]) -> SyscallResult<Option<usize>>;
fn read_buf(
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<Option<usize>>;
fn fpath(&self, file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize>;
@@ -190,11 +231,13 @@ where
pub struct SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static, 'static>,
SocketT: SchemeSocket + AnySocket<'static>,
{
next_fd: usize,
nulls: BTreeMap<usize, NullFile>,
files: BTreeMap<usize, SchemeFile<SocketT>>,
ref_counts: BTreeMap<SocketHandle, usize>,
context: Context,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: File,
wait_queue: WaitQueue,
@@ -204,18 +247,25 @@ where
impl<SocketT> SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static, 'static>,
SocketT: SchemeSocket + AnySocket<'static>,
{
pub fn new(socket_set: Rc<RefCell<SocketSet>>, scheme_file: File) -> SocketScheme<SocketT> {
pub fn new(
iface: Interface,
route_table: Rc<RefCell<RouteTable>>,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: File,
) -> SocketScheme<SocketT> {
SocketScheme {
next_fd: 1,
nulls: BTreeMap::new(),
files: BTreeMap::new(),
ref_counts: BTreeMap::new(),
socket_set,
scheme_data: SocketT::new_scheme_data(),
scheme_file,
wait_queue: Vec::new(),
_phantom_socket: PhantomData,
context: Context { iface, route_table },
}
}
@@ -226,12 +276,14 @@ where
Ok(0) => {
//TODO: Cleanup must occur
break Some(());
},
}
Ok(_) => (),
Err(err) => if err.kind() == ErrorKind::WouldBlock {
break None;
} else {
return Err(Error::from(err));
Err(err) => {
if err.kind() == ErrorKind::WouldBlock {
break None;
} else {
return Err(Error::from(err));
}
}
}
if let Some(a) = self.handle(&mut packet) {
@@ -244,7 +296,7 @@ where
until: timeout,
packet,
});
},
}
Err(err) => {
packet.a = (-err.errno) as usize;
self.scheme_file.write_all(&packet)?;
@@ -293,7 +345,7 @@ where
self.wait_queue.remove(i);
packet.a = (-syscall::ETIMEDOUT) as usize;
self.scheme_file.write_all(&packet)?;
},
}
_ => {
i += 1;
}
@@ -307,15 +359,13 @@ where
fn handle_block(&mut self, packet: &mut SyscallPacket) -> SyscallResult<Option<TimeSpec>> {
let fd = packet.b;
let (read_timeout, write_timeout) = {
let file = self.files
let file = self
.files
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref scheme_file) = *file {
Ok((
scheme_file.read_timeout,
scheme_file.write_timeout,
))
Ok((scheme_file.read_timeout, scheme_file.write_timeout))
} else {
Err(SyscallError::new(syscall::EBADF))
}
@@ -342,7 +392,8 @@ where
setting: Setting<SocketT::SettingT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
@@ -354,14 +405,16 @@ where
match setting {
Setting::Other(setting) => SocketT::get_setting(file, setting, buf),
Setting::Ttl => if let Some(hop_limit) = buf.get_mut(0) {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get::<SocketT>(file.socket_handle);
*hop_limit = socket.hop_limit();
Ok(1)
} else {
Err(SyscallError::new(syscall::EIO))
},
Setting::Ttl => {
if let Some(hop_limit) = buf.get_mut(0) {
let socket_set = self.socket_set.borrow();
let socket = socket_set.get::<SocketT>(file.socket_handle);
*hop_limit = socket.hop_limit();
Ok(1)
} else {
Err(SyscallError::new(syscall::EIO))
}
}
Setting::ReadTimeout | Setting::WriteTimeout => {
let timespec = match (setting, file.read_timeout, file.write_timeout) {
(Setting::ReadTimeout, Some(read_timeout), _) => read_timeout,
@@ -389,7 +442,8 @@ where
setting: Setting<SocketT::SettingT>,
buf: &[u8],
) -> SyscallResult<usize> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
@@ -422,14 +476,16 @@ where
};
Ok(count)
}
Setting::Ttl => if let Some(hop_limit) = buf.get(0) {
let mut socket_set = self.socket_set.borrow_mut();
let mut socket = socket_set.get::<SocketT>(file.socket_handle);
socket.set_hop_limit(*hop_limit);
Ok(1)
} else {
Err(SyscallError::new(syscall::EIO))
},
Setting::Ttl => {
if let Some(hop_limit) = buf.get(0) {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
socket.set_hop_limit(*hop_limit);
Ok(1)
} else {
Err(SyscallError::new(syscall::EIO))
}
}
Setting::Other(setting) => SocketT::set_setting(file, setting, buf),
}
}
@@ -437,9 +493,15 @@ where
impl<SocketT> syscall::SchemeBlockMut for SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static, 'static>,
SocketT: SchemeSocket + AnySocket<'static>,
{
fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> SyscallResult<Option<usize>> {
fn open(
&mut self,
path: &str,
flags: usize,
uid: u32,
_gid: u32,
) -> SyscallResult<Option<usize>> {
if path.is_empty() {
let null = NullFile {
flags,
@@ -459,6 +521,7 @@ where
path,
uid,
&mut self.scheme_data,
&self.context,
)?;
let file = SchemeFile::Socket(SocketFile {
@@ -475,6 +538,7 @@ where
let id = self.next_fd;
self.next_fd += 1;
self.ref_counts.insert(socket_handle, 1);
self.files.insert(id, file);
Ok(Some(id))
@@ -487,7 +551,8 @@ where
}
let socket_handle = {
let file = self.files
let file = self
.files
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
file.socket_handle()
@@ -506,15 +571,38 @@ where
}| a != fd,
);
socket_set.release(socket_handle);
//TODO: removing sockets in release should make prune unnecessary
socket_set.prune();
let remove = match self.ref_counts.entry(socket_handle) {
Entry::Vacant(_) => {
warn!("Closing a socket_handle with no ref");
true
}
Entry::Occupied(mut e) => {
if *e.get() == 0 {
warn!("Closing a socket_handle with no ref");
e.remove();
true
} else {
*e.get_mut() -= 1;
if *e.get() == 0 {
e.remove();
true
} else {
false
}
}
}
};
if remove {
socket_set.remove(socket_handle);
}
Ok(Some(0))
}
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<Option<usize>> {
let (fd, setting) = {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
@@ -524,8 +612,13 @@ where
}
SchemeFile::Socket(ref mut file) => {
let mut socket_set = self.socket_set.borrow_mut();
let mut socket = socket_set.get::<SocketT>(file.socket_handle);
return SocketT::write_buf(&mut socket, file, buf);
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
let ret = SocketT::write_buf(socket, file, buf);
match ret {
Ok(None) => {}
_ => file.write_notified = false,
}
return ret;
}
}
};
@@ -534,7 +627,8 @@ where
fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<Option<usize>> {
let (fd, setting) = {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
@@ -543,8 +637,15 @@ where
}
SchemeFile::Socket(ref mut file) => {
let mut socket_set = self.socket_set.borrow_mut();
let mut socket = socket_set.get::<SocketT>(file.socket_handle);
return SocketT::read_buf(&mut socket, file, buf);
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
let ret = SocketT::read_buf(socket, file, buf);
match ret {
Ok(None) => {}
_ => file.read_notified = false
}
return ret;
}
}
};
@@ -554,7 +655,8 @@ where
fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<Option<usize>> {
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
if let Some((flags, uid, gid)) = self.nulls
if let Some((flags, uid, gid)) = self
.nulls
.get(&fd)
.map(|null| (null.flags, null.uid, null.gid))
{
@@ -562,7 +664,8 @@ where
}
let new_file = {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
@@ -606,14 +709,23 @@ where
if let Some((socket_handle, data)) = update_with {
if let SchemeFile::Socket(ref mut file) = *file {
// We replace the socket_handle pointed by file so update the ref_counts
// accordingly
self.ref_counts
.entry(file.socket_handle)
.and_modify(|e| *e = e.saturating_sub(1))
.or_insert(0);
*self.ref_counts.entry(socket_handle).or_insert(0) += 1;
file.socket_handle = socket_handle;
file.data = data;
} else {
self.socket_set.borrow_mut().retain(file.socket_handle());
}
} else {
self.socket_set.borrow_mut().retain(file.socket_handle());
}
*self
.ref_counts
.entry(new_handle.socket_handle())
.or_insert(0) += 1;
new_handle
};
@@ -624,8 +736,13 @@ where
Ok(Some(id))
}
fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult<Option<SyscallEventFlags>> {
let file = self.files
fn fevent(
&mut self,
fd: usize,
events: SyscallEventFlags,
) -> SyscallResult<Option<SyscallEventFlags>> {
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
@@ -643,7 +760,8 @@ where
fn fsync(&mut self, fd: usize) -> SyscallResult<Option<usize>> {
{
let _file = self.files
let _file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
}
@@ -653,11 +771,12 @@ where
}
fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<Option<usize>> {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket_set = self.socket_set.borrow();
let socket = socket_set.get::<SocketT>(file.socket_handle());
socket.fpath(file, buf).map(Some)
@@ -674,7 +793,8 @@ where
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
let file = self.files
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
+121 -43
View File
@@ -1,17 +1,20 @@
use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer};
use smoltcp::iface::SocketHandle;
use smoltcp::socket::tcp::{Socket as TcpSocket, SocketBuffer as TcpSocketBuffer};
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
use std::fmt::Write;
use std::str;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use syscall::{Error as SyscallError, Result as SyscallResult};
use crate::port_set::PortSet;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use super::{parse_endpoint, SocketSet};
use crate::port_set::PortSet;
pub type TcpScheme = SocketScheme<TcpSocket<'static>>;
impl<'a> SchemeSocket for TcpSocket<'a> {
type SchemeDataT = PortSet;
type DataT = ();
type DataT = Option<IpListenEndpoint>;
type SettingT = ();
fn new_scheme_data() -> Self::SchemeDataT {
@@ -59,6 +62,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
path: &str,
uid: u32,
port_set: &mut Self::SchemeDataT,
context: &Context,
) -> SyscallResult<(SocketHandle, Self::DataT)> {
trace!("TCP open {}", path);
let mut parts = path.split('/');
@@ -85,21 +89,44 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
let socket_handle = socket_set.add(socket);
let mut tcp_socket = socket_set.get::<TcpSocket>(socket_handle);
let tcp_socket = socket_set.get_mut::<TcpSocket>(socket_handle);
let listen_enpoint = if remote_endpoint.is_specified() {
let local_endpoint_addr = match local_endpoint.addr {
Some(addr) if !addr.is_unspecified() => Some(addr),
_ => {
let route_table = context.route_table.borrow();
let addr = route_table
.lookup_src_addr(&remote_endpoint.addr.expect("Checked in is_specified"));
if matches!(addr, None) {
error!("Opening a TCP connection with a probably invalid source IP as no route have been found for destination: {}", remote_endpoint);
}
addr
}
};
let local_endpoint = IpListenEndpoint {
addr: local_endpoint_addr,
port: local_endpoint.port,
};
if remote_endpoint.is_specified() {
trace!("Connecting tcp {} {}", local_endpoint, remote_endpoint);
tcp_socket
.connect(remote_endpoint, local_endpoint)
.connect(
context.iface.borrow_mut().context(),
IpEndpoint::new(remote_endpoint.addr.unwrap(), remote_endpoint.port),
local_endpoint,
)
.expect("Can't connect tcp socket ");
None
} else {
trace!("Listening tcp {}", local_endpoint);
tcp_socket
.listen(local_endpoint)
.expect("Can't listen on local endpoint");
}
Some(local_endpoint)
};
Ok((socket_handle, ()))
Ok((socket_handle, listen_enpoint))
}
fn close_file(
@@ -107,8 +134,14 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
file: &SchemeFile<Self>,
port_set: &mut Self::SchemeDataT,
) -> SyscallResult<()> {
if let SchemeFile::Socket(_) = *file {
port_set.release_port(self.local_endpoint().port);
if let SchemeFile::Socket(SocketFile { data, .. }) = *file {
if let Some(endpoint) = self.local_endpoint() {
// Socket was connected on some port
port_set.release_port(endpoint.port);
} else if let Some(endpoint) = data {
// Socket was listening on some port
port_set.release_port(endpoint.port);
}
}
Ok(())
}
@@ -163,53 +196,98 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
};
let file = match path {
"listen" => if let SchemeFile::Socket(ref tcp_handle) = *file {
if !is_active {
if tcp_handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
return Err(SyscallError::new(syscall::EAGAIN));
} else {
return Ok(None);
}
}
trace!("TCP creating new listening socket");
let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(()));
"listen" => {
if let SchemeFile::Socket(ref tcp_handle) = *file {
let Some(listen_enpoint) = tcp_handle.data else {
// This socket is not listening so we can't accept a connection
return Err(SyscallError::new(syscall::EINVAL));
};
let rx_packets = vec![0; 0xffff];
let tx_packets = vec![0; 0xffff];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
let new_socket_handle = socket_set.add(socket);
{
let mut tcp_socket = socket_set.get::<TcpSocket>(new_socket_handle);
tcp_socket
.listen(local_endpoint)
.expect("Can't listen on local endpoint");
if !is_active {
// Socket listening but no connection received
if tcp_handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
return Err(SyscallError::new(syscall::EAGAIN));
} else {
return Ok(None);
}
}
trace!("TCP creating new listening socket");
// We pass None as data because this new handle is to the active connection so
// not a listening socket
let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(None));
// Creating a socket to continue listening
let rx_packets = vec![0; 0xffff];
let tx_packets = vec![0; 0xffff];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
let new_socket_handle = socket_set.add(socket);
{
let tcp_socket = socket_set.get_mut::<TcpSocket>(new_socket_handle);
tcp_socket
.listen(listen_enpoint)
.expect("Can't listen on local endpoint");
}
// We got a new connection to the socket so acquire the port
port_set.acquire_port(
local_endpoint
.expect("Socket was active so local endpoint must be set")
.port,
);
return Ok(Some((
new_handle,
Some((new_socket_handle, Some(listen_enpoint))),
)));
} else {
return Err(SyscallError::new(syscall::EBADF));
}
port_set.acquire_port(local_endpoint.port);
return Ok(Some((new_handle, Some((new_socket_handle, ())))));
} else {
return Err(SyscallError::new(syscall::EBADF));
},
}
_ => {
trace!("TCP dup unknown {}", path);
if let SchemeFile::Socket(ref tcp_handle) = *file {
SchemeFile::Socket(tcp_handle.clone_with_data(()))
SchemeFile::Socket(tcp_handle.clone_with_data(tcp_handle.data))
} else {
SchemeFile::Socket(SocketFile::new_with_data(socket_handle, ()))
SchemeFile::Socket(SocketFile::new_with_data(socket_handle, None))
}
}
};
if let SchemeFile::Socket(_) = file {
port_set.acquire_port(local_endpoint.port);
if let Some(local_endpoint) = local_endpoint {
port_set.acquire_port(local_endpoint.port);
}
}
Ok(Some((file, None)))
}
fn fpath(&self, _: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
let path = format!("tcp:{}/{}", self.remote_endpoint(), self.local_endpoint());
fn fpath(&self, file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
let unspecified = "0.0.0.0:0";
let mut path = String::from("tcp:");
match self.remote_endpoint() {
Some(endpoint) => write!(&mut path, "{}", endpoint).unwrap(),
None => path.push_str(unspecified),
}
path.push('/');
match (self.local_endpoint(), file) {
(Some(endpoint), _) => write!(&mut path, "{}", endpoint).unwrap(),
(
None,
SchemeFile::Socket(SocketFile {
data: Some(endpoint),
..
}),
) => {
if endpoint.is_specified() {
write!(&mut path, "{}", endpoint).unwrap()
} else {
write!(&mut path, "0.0.0.0:{}", endpoint.port).unwrap()
}
}
_ => path.push_str(unspecified),
}
trace!("fpath: {}", path);
let path = path.as_bytes();
let mut i = 0;
+16 -11
View File
@@ -1,19 +1,20 @@
use smoltcp::socket::{SocketHandle, UdpPacketMetadata, UdpSocket, UdpSocketBuffer};
use smoltcp::wire::IpEndpoint;
use smoltcp::socket::udp::{PacketMetadata as UdpPacketMetadata, Socket as UdpSocket, PacketBuffer as UdpSocketBuffer};
use smoltcp::iface::SocketHandle;
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
use std::str;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use crate::device::NetworkDevice;
use crate::port_set::PortSet;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use crate::router::Router;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme, Context};
use super::{parse_endpoint, Smolnetd, SocketSet};
pub type UdpScheme = SocketScheme<UdpSocket<'static, 'static>>;
pub type UdpScheme = SocketScheme<UdpSocket<'static>>;
impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
impl<'a> SchemeSocket for UdpSocket<'a> {
type SchemeDataT = PortSet;
type DataT = IpEndpoint;
type DataT = IpListenEndpoint;
type SettingT = ();
fn new_scheme_data() -> Self::SchemeDataT {
@@ -61,6 +62,7 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
path: &str,
uid: u32,
port_set: &mut Self::SchemeDataT,
_context: &Context
) -> SyscallResult<(SocketHandle, Self::DataT)> {
let mut parts = path.split('/');
let remote_endpoint = parse_endpoint(parts.next().unwrap_or(""));
@@ -72,11 +74,11 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
let rx_buffer = UdpSocketBuffer::new(
vec![UdpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
);
let tx_buffer = UdpSocketBuffer::new(
vec![UdpPacketMetadata::EMPTY; Smolnetd::SOCKET_BUFFER_SIZE],
vec![0; NetworkDevice::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
vec![0; Router::MTU * Smolnetd::SOCKET_BUFFER_SIZE]
);
let udp_socket = UdpSocket::new(rx_buffer, tx_buffer);
@@ -90,11 +92,12 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
let socket_handle = socket_set.add(udp_socket);
let mut udp_socket = socket_set.get::<UdpSocket>(socket_handle);
let udp_socket = socket_set.get_mut::<UdpSocket>(socket_handle);
udp_socket
.bind(local_endpoint)
.expect("Can't bind udp socket to local endpoint");
Ok((socket_handle, remote_endpoint))
}
@@ -118,7 +121,9 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
return Err(SyscallError::new(syscall::EADDRNOTAVAIL));
}
if self.can_send() {
self.send_slice(buf, file.data).expect("Can't send slice");
let endpoint = file.data;
let endpoint = IpEndpoint::new(endpoint.addr.expect("If we can send, this should be specified"), endpoint.port);
self.send_slice(buf, endpoint).expect("Can't send slice");
Ok(Some(buf.len()))
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Err(SyscallError::new(syscall::EAGAIN))