From 11b6ca12669c8e8caf92e1a009c0a5c33ef04732 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 26 Sep 2023 15:09:13 +0800 Subject: [PATCH 01/11] add Send trait to the xous Message type --- xous-rs/src/definitions/messages/envelope.rs | 1 + xous-rs/src/definitions/messages/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/xous-rs/src/definitions/messages/envelope.rs b/xous-rs/src/definitions/messages/envelope.rs index 61c3eb3cc..cc9ba3fcf 100644 --- a/xous-rs/src/definitions/messages/envelope.rs +++ b/xous-rs/src/definitions/messages/envelope.rs @@ -7,6 +7,7 @@ pub struct Envelope { pub sender: MessageSender, pub body: Message, } +unsafe impl Send for Envelope {} impl Envelope { pub fn to_usize(&self) -> [usize; 7] { diff --git a/xous-rs/src/definitions/messages/mod.rs b/xous-rs/src/definitions/messages/mod.rs index 714b7549c..5b93bf45a 100644 --- a/xous-rs/src/definitions/messages/mod.rs +++ b/xous-rs/src/definitions/messages/mod.rs @@ -132,6 +132,7 @@ pub enum Message { Scalar(ScalarMessage), BlockingScalar(ScalarMessage), } +unsafe impl Send for Message {} impl Message { pub fn new_scalar( From 64e9248815826d2b190e95364231dd8dfbd7446c Mon Sep 17 00:00:00 2001 From: bunnie Date: Fri, 29 Sep 2023 05:30:55 +0800 Subject: [PATCH 02/11] move smoltcp to latest; no hard errors, but also panics --- Cargo.lock | 146 ++++--- Cargo.toml | 4 +- services/net/Cargo.toml | 4 +- services/net/src/api.rs | 1 + services/net/src/device.rs | 112 +++--- services/net/src/main.rs | 568 +++++++++++----------------- services/net/src/std_tcplistener.rs | 28 +- services/net/src/std_tcpstream.rs | 40 +- services/net/src/std_udp.rs | 53 +-- 9 files changed, 427 insertions(+), 529 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f17a9c2e9..525e26f81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,7 +74,7 @@ dependencies = [ "aes 0.8.1", "hex-literal", "log", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", ] @@ -264,7 +264,7 @@ dependencies = [ "num-derive", "num-traits", "trng", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -586,7 +586,7 @@ dependencies = [ "pddb", "rkyv", "trng", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -705,7 +705,7 @@ dependencies = [ "rkyv", "trng", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -736,7 +736,7 @@ dependencies = [ "trng", "typenum", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -793,7 +793,7 @@ dependencies = [ "graphics-server", "log", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-names", ] @@ -834,7 +834,7 @@ version = "0.1.0" dependencies = [ "log", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -850,7 +850,7 @@ dependencies = [ "num-derive", "num-traits", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -864,7 +864,7 @@ dependencies = [ "num-derive", "num-traits", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -1439,7 +1439,7 @@ dependencies = [ "trng", "userprefs", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -1464,7 +1464,7 @@ dependencies = [ "rkyv", "spinor", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -1619,7 +1619,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -1778,7 +1778,7 @@ dependencies = [ "num-derive", "num-traits", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2002,7 +2002,7 @@ dependencies = [ "trng", "tts-frontend", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2068,7 +2068,7 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", "wasm-bindgen-test", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2103,7 +2103,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2156,9 +2156,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heapless" -version = "0.7.13" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a08e755adbc0ad283725b29f4a4883deee15336f372d5f61fae59efec40f983" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" dependencies = [ "atomic-polyfill", "hash32", @@ -2193,7 +2193,7 @@ dependencies = [ "num-derive", "num-traits", "tts-frontend", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2336,7 +2336,7 @@ dependencies = [ "rkyv", "tts-frontend", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2352,7 +2352,7 @@ dependencies = [ "num-derive", "num-traits", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2367,7 +2367,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2386,7 +2386,7 @@ dependencies = [ "rkyv", "tts-frontend", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2496,7 +2496,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2516,7 +2516,7 @@ version = "0.1.0" dependencies = [ "log", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-ticktimer", ] @@ -2533,7 +2533,7 @@ dependencies = [ "rkyv", "spinor", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2614,7 +2614,7 @@ dependencies = [ "num-derive", "num-traits", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2638,7 +2638,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -2801,7 +2801,7 @@ dependencies = [ "trng", "tts-frontend", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2837,7 +2837,7 @@ dependencies = [ "trng", "ureq", "url", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2867,7 +2867,7 @@ dependencies = [ "serde", "trng", "ureq", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -2907,7 +2907,7 @@ dependencies = [ "smoltcp", "trng", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -3298,7 +3298,7 @@ dependencies = [ "trng", "tts-frontend", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -3331,7 +3331,7 @@ version = "0.1.0" dependencies = [ "log", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", ] [[package]] @@ -3884,7 +3884,7 @@ dependencies = [ "num-derive", "num-traits", "trng", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -3926,7 +3926,7 @@ dependencies = [ "spin 0.5.2", "untrusted", "winapi", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4010,7 +4010,7 @@ dependencies = [ "tts-frontend", "usb-device-xous", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -4333,7 +4333,7 @@ dependencies = [ "rkyv", "trng", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -4427,7 +4427,7 @@ dependencies = [ "usb-device-xous", "utralib", "x25519-dalek", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -4465,12 +4465,13 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smoltcp" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72165c4af59f5f19c7fb774b88b95660591b612380305b5f4503157341a9f7ee" +version = "0.10.0" dependencies = [ "bitflags 1.3.2", "byteorder", + "cfg-if", + "defmt", + "heapless", "libc", "log", "managed", @@ -4514,7 +4515,7 @@ dependencies = [ "rkyv", "trng", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -4575,7 +4576,7 @@ dependencies = [ "usb-device-xous", "userprefs", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -4762,7 +4763,7 @@ name = "ticktimer-test-client" version = "0.1.0" dependencies = [ "log", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", ] @@ -4856,7 +4857,7 @@ dependencies = [ "sha2 0.9.8", "webpki-roots 0.24.0", "x509-parser", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -4973,7 +4974,7 @@ dependencies = [ "num-derive", "num-traits", "usb-device-xous", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4991,7 +4992,7 @@ dependencies = [ "rand_core 0.5.1", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -5009,7 +5010,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-ticktimer", @@ -5173,7 +5174,7 @@ dependencies = [ "usbd_scsi 0.1.1", "utralib", "vcell", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -5198,7 +5199,7 @@ dependencies = [ "usbd-human-interface-device 0.1.1", "utralib", "vcell", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -5261,7 +5262,7 @@ dependencies = [ "typenum", "usb-device", "usbd_mass_storage 0.1.0", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-ticktimer", ] @@ -5335,7 +5336,7 @@ dependencies = [ "usb-device", "usbd_bulk_only_transport 0.1.0", "usbd_mass_storage 0.1.0", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-ticktimer", ] @@ -5414,7 +5415,7 @@ dependencies = [ "usbd-human-interface-device 0.2.1", "userprefs", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -5959,15 +5960,6 @@ dependencies = [ "rustc-std-workspace-core", ] -[[package]] -name = "xous" -version = "0.9.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4d8c91009ed676410e747425107cfe4afc3dd9d3bf502a87542a353173b09e8" -dependencies = [ - "lazy_static", -] - [[package]] name = "xous-api-log" version = "0.1.47" @@ -5977,7 +5969,7 @@ dependencies = [ "log", "num-derive", "num-traits", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5991,7 +5983,7 @@ dependencies = [ "num-derive", "num-traits", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6007,7 +5999,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6023,7 +6015,7 @@ dependencies = [ "num-derive", "num-traits", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -6037,7 +6029,7 @@ version = "0.9.51" dependencies = [ "bitflags 1.3.2", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", ] [[package]] @@ -6048,7 +6040,7 @@ checksum = "549eacc8d02d5e4c49559840fc3ec7f16e9a2c0a5bd27ae94da9c3e6ef9bc210" dependencies = [ "bitflags 1.3.2", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", ] [[package]] @@ -6068,7 +6060,7 @@ dependencies = [ "rand_chacha 0.3.1", "stats_alloc", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-riscv", ] @@ -6082,7 +6074,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6096,7 +6088,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6111,7 +6103,7 @@ dependencies = [ "pio", "pio-proc", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", ] [[package]] @@ -6123,7 +6115,7 @@ dependencies = [ "pio", "pio-proc", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-pio", ] @@ -6152,7 +6144,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -6169,7 +6161,7 @@ dependencies = [ "num-traits", "rkyv", "utralib", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-log", "xous-api-names", "xous-api-susres", @@ -6188,7 +6180,7 @@ dependencies = [ "num-derive", "num-traits", "rkyv", - "xous 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", + "xous", "xous-api-names", "xous-ipc 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 85906d56c..0f764a7f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -177,8 +177,8 @@ rev="4296c2e7904898766cf7d8d589759a129794783b" # use the commitref because we're path = "./utralib" [patch.crates-io.svd2utra] path = "./svd2utra" -# [patch.crates-io.xous] -# path = "./xous-rs" +[patch.crates-io.xous] +path = "./xous-rs" # [patch.crates-io.xous-ipc] # path = "./xous-ipc" # [patch.crates-io.xous-api-names] diff --git a/services/net/Cargo.toml b/services/net/Cargo.toml index 01d513f6c..ede19d370 100644 --- a/services/net/Cargo.toml +++ b/services/net/Cargo.toml @@ -34,12 +34,12 @@ xous-semver = "0.1.2" [dependencies.smoltcp] # some historical notes for development on branches in the future -# path = "../../../smoltcp" +path = "../../../smoltcp" #git = "https://github.com/smoltcp-rs/smoltcp.git" #git = "https://github.com/betrusted-io/smoltcp.git" #rev = "35c8ec3d30c846442a1faae01fb0537641aef898" # 0.8.1 drops the rand_core dep and doesn't have the breaking IPv4 change (see issue #613) -version = "0.8.1" +# version = "0.8.1" default-features = false features = [ "std", "log", # needed for `cargo test --no-default-features --features default` :/ diff --git a/services/net/src/api.rs b/services/net/src/api.rs index f37f9cf9c..8166894bd 100644 --- a/services/net/src/api.rs +++ b/services/net/src/api.rs @@ -37,6 +37,7 @@ pub const MIN_EC_REV: SemVer = SemVer { #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] #[repr(C)] pub(crate) enum Opcode { + SetupMpsc = 0, /// Calls for UDP implementation (now deprecated to libstd) //UdpBind = 0, //UdpClose = 1, diff --git a/services/net/src/device.rs b/services/net/src/device.rs index c837c9772..0984099f3 100644 --- a/services/net/src/device.rs +++ b/services/net/src/device.rs @@ -1,7 +1,6 @@ use com::Com; use com::api::NET_MTU; -use smoltcp::Result; use smoltcp::phy::{self, DeviceCapabilities, Medium}; use smoltcp::wire::{ArpPacket, ArpRepr, ArpOperation, Ipv4Address, EthernetAddress, EthernetFrame, EthernetProtocol}; use num_traits::*; @@ -49,11 +48,11 @@ impl<'a> NetPhy { } } -impl<'a> phy::Device<'a> for NetPhy { - type RxToken = NetPhyRxToken<'a>; - type TxToken = NetPhyTxToken<'a>; +impl phy::Device for NetPhy { + type RxToken<'a> = NetPhyRxToken<'a>; + type TxToken<'a> = NetPhyTxToken<'a>; - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive(&mut self, _instant: smoltcp::time::Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { if let Some(rx_len) = self.loopback_pending.lock().unwrap().pop_front() { // loopback takes precedence self.com.wlan_fetch_loopback_packet(&mut self.rx_buffer[..rx_len as usize]).expect("Couldn't call wlan_fetch_packet in device adapter"); @@ -72,7 +71,7 @@ impl<'a> phy::Device<'a> for NetPhy { } } - fn transmit(&'a mut self) -> Option { + fn transmit(&mut self, _instant: smoltcp::time::Instant) -> Option> { Some(NetPhyTxToken{buf: &mut self.tx_buffer[..], com: &self.com, loopback_conn: self.loopback_conn, loopback_count: self.loopback_pending.clone()}) } @@ -90,8 +89,8 @@ pub struct NetPhyRxToken<'a> { } impl<'a, 'c> phy::RxToken for NetPhyRxToken<'a> { - fn consume(mut self, _timestamp: Instant, f: F) -> Result - where F: FnOnce(&mut [u8]) -> Result + fn consume(mut self, f: F) -> R + where F: FnOnce(&mut [u8]) -> R { let result = f(&mut self.buf); //log::info!("rx: {:x?}", self.buf); @@ -152,8 +151,8 @@ impl <'a> NetPhyTxToken<'a> { } impl<'a> phy::TxToken for NetPhyTxToken<'a> { - fn consume(mut self, _timestamp: Instant, len: usize, f: F) -> Result - where F: FnOnce(&mut [u8]) -> Result + fn consume(mut self, len: usize, f: F) -> R + where F: FnOnce(&mut [u8]) -> R { let result = f(&mut self.buf[..len]); //log::info!("txlen: {}", len); @@ -177,59 +176,58 @@ impl<'a> phy::TxToken for NetPhyTxToken<'a> { loopback = true; } } - - if result.is_ok() { - if loopback { - self.com.wlan_queue_loopback(&self.buf[..len]); - self.loopback_rx(len); - } else { - { - // this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue as well: - // https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55 - // this part of the hack finds ARP packets to and from the local device, and responds to them with packet injections - let pkt = &self.buf[..len]; - if let Ok(frame) = EthernetFrame::new_checked(pkt) { - if frame.ethertype() == EthernetProtocol::Arp { - // we're parsing packets that came from our own stack -- they better be OK! - let arp_packet = ArpPacket::new_checked(frame.payload()).unwrap(); - let arp_repr = ArpRepr::parse(&arp_packet).unwrap(); - match arp_repr { - ArpRepr::EthernetIpv4 { - operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, .. - } => { - log::trace!("outgoing arp: {:?} {:?} {:?}", source_hardware_addr, source_protocol_addr, target_protocol_addr); - if target_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { - log::trace!("intercepted outgoing arp for 127.0.0.1: {:?}", pkt); - self.wlan_queue_localhost_arp( - source_hardware_addr.as_bytes().try_into().unwrap(), - source_protocol_addr, - EthernetAddress([0, 0, 0, 0, 0, 0,]), - Ipv4Address([127, 0, 0, 1]), - ); - return result; - } else if source_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { - // reverse lookup case - log::trace!("intercepted outgoing arp for own IP: {:?} {:?}", target_protocol_addr, pkt); - self.wlan_queue_localhost_arp( - source_hardware_addr.as_bytes().try_into().unwrap(), - source_protocol_addr, - source_hardware_addr, - target_protocol_addr, - ); - return result; - } else { - // don't do anything, pass it on - } + // NOTE: was protected by if result.is_ok(), but looking at smoltcp, the calling routines + // *always* return OK, or nothing. So we are removing the protecting .is_ok()... + if loopback { + self.com.wlan_queue_loopback(&self.buf[..len]); + self.loopback_rx(len); + } else { + { + // this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue as well: + // https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55 + // this part of the hack finds ARP packets to and from the local device, and responds to them with packet injections + let pkt = &self.buf[..len]; + if let Ok(frame) = EthernetFrame::new_checked(pkt) { + if frame.ethertype() == EthernetProtocol::Arp { + // we're parsing packets that came from our own stack -- they better be OK! + let arp_packet = ArpPacket::new_checked(frame.payload()).unwrap(); + let arp_repr = ArpRepr::parse(&arp_packet).unwrap(); + match arp_repr { + ArpRepr::EthernetIpv4 { + operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, .. + } => { + log::trace!("outgoing arp: {:?} {:?} {:?}", source_hardware_addr, source_protocol_addr, target_protocol_addr); + if target_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { + log::trace!("intercepted outgoing arp for 127.0.0.1: {:?}", pkt); + self.wlan_queue_localhost_arp( + source_hardware_addr.as_bytes().try_into().unwrap(), + source_protocol_addr, + EthernetAddress([0, 0, 0, 0, 0, 0,]), + Ipv4Address([127, 0, 0, 1]), + ); + return result; + } else if source_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { + // reverse lookup case + log::trace!("intercepted outgoing arp for own IP: {:?} {:?}", target_protocol_addr, pkt); + self.wlan_queue_localhost_arp( + source_hardware_addr.as_bytes().try_into().unwrap(), + source_protocol_addr, + source_hardware_addr, + target_protocol_addr, + ); + return result; + } else { + // don't do anything, pass it on } - _ => {}, // pass it on } + _ => {}, // pass it on } } } - - // normally this would be the only line! - self.com.wlan_send_packet(&self.buf[..len]).map_err(|_| smoltcp::Error::Dropped)?; } + + // normally this would be the only line! + self.com.wlan_send_packet(&self.buf[..len]).expect("driver error sending WLAN packet"); } } result diff --git a/services/net/src/main.rs b/services/net/src/main.rs index 1ae9f004a..1a6130411 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -29,18 +29,14 @@ use xous::{msg_blocking_scalar_unpack, msg_scalar_unpack, send_message, Message, use xous_ipc::Buffer; use byteorder::{ByteOrder, NetworkEndian}; -use smoltcp::iface::{Interface, InterfaceBuilder, NeighborCache, Routes}; -use smoltcp::phy::{Device, Medium}; -use smoltcp::socket::{IcmpEndpoint, IcmpPacketMetadata, IcmpSocket, IcmpSocketBuffer}; +use smoltcp::iface::{Interface, Config, SocketSet}; +use smoltcp::phy::{Device, Medium, Tracer}; +use smoltcp::socket::{tcp, udp, icmp}; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr, IpEndpoint}; use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, Icmpv6Packet, Icmpv6Repr}; -use crate::device::NetPhy; use core::num::NonZeroU64; use core::sync::atomic::{AtomicU32, AtomicU16, Ordering}; -use smoltcp::socket::{ - TcpSocket, TcpSocketBuffer, UdpPacketMetadata, UdpSocket, UdpSocketBuffer, -}; use smoltcp::iface::SocketHandle; use smoltcp::time::{Duration, Instant}; use std::sync::Arc; @@ -58,24 +54,6 @@ const PING_DEFAULT_TIMEOUT_MS: u32 = 10_000; const MAX_DELAY_THREADS: u32 = 9; const PING_IDENT: u16 = 0x22b; -fn set_ipv4_addr(iface: &mut Interface<'_, DeviceT>, cidr: Ipv4Cidr) -where - DeviceT: for<'d> Device<'d>, -{ - iface.update_ip_addrs(|addrs| { - let dest = addrs - .iter_mut() - .next() - .expect("trouble updating ipv4 addresses in routing table"); - if *dest.address().as_bytes() != [127, 0, 0, 1] { - log::info!("updating to address {:?}", cidr); - *dest = IpCidr::Ipv4(cidr); - } else { - log::info!("not updating loopback address"); - } - }); -} - #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] enum WaitOp { WaitMs, @@ -161,36 +139,6 @@ fn set_com_ints(com_int_list: &mut Vec) { com_int_list.push(ComIntSources::Invalid); } -fn setup_icmp(iface: &mut Interface::) -> SocketHandle { - // ping storage - // up to four concurrent pings in the queue - let icmp_rx_buffer = IcmpSocketBuffer::new( - vec![ - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - ], - vec![0; 1024], - ); - let icmp_tx_buffer = IcmpSocketBuffer::new( - vec![ - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - IcmpPacketMetadata::EMPTY, - ], - vec![0; 1024], - ); - let icmp_socket = IcmpSocket::new(icmp_rx_buffer, icmp_tx_buffer); - let icmp_handle = iface.add_socket(icmp_socket); - let icmp_socket = iface.get_socket::(icmp_handle); - icmp_socket - .bind(IcmpEndpoint::Ident(PING_IDENT)) - .expect("couldn't bind to icmp socket"); - icmp_handle -} - fn main() -> ! { log_server::init_wait().unwrap(); log::set_max_level(log::LevelFilter::Info); @@ -227,6 +175,79 @@ fn main() -> ! { log::debug!("COM pending interrupts after enabling: {:?}", com_int_list); let mut net_config: Option = None; + // ----------- build the device + let hw_config = match com.wlan_get_config() { + Ok(config) => config, + Err(e) => { + log::error!("Something is wrong with the EC, got {:?} when requesting a MAC address. Trying our best to bodge through it.", e); + Ipv4Conf { + dhcp: com_rs::DhcpState::Invalid, + mac: [2, 2, 4, 5, 6, 2], + addr: [169, 254, 0, 2], // link local address + gtwy: [169, 254, 0, 1], // something bogus + mask: [255, 255, 0, 0,], + dns1: [1, 1, 1, 1], + dns2: [8, 8, 8, 8], + } + } + }; + log::debug!("My MAC address is: {:x?}", hw_config.mac); + MAC_ADDRESS_LSB.store(u32::from_be_bytes(hw_config.mac[2..6].try_into().unwrap()), Ordering::SeqCst); + MAC_ADDRESS_MSB.store(u16::from_be_bytes(hw_config.mac[0..2].try_into().unwrap()), Ordering::SeqCst); + + let mut config = Config::new(EthernetAddress(hw_config.mac).into()); + config.random_seed = trng.get_u64().unwrap(); + + let device = device::NetPhy::new(&xns, net_cid); + let mut device = Tracer::new(device, |_timestamp, _printer| { + log::trace!("{}", _printer); + }); + let device_caps = device.capabilities(); + let mut iface = Interface::new(config, &mut device, Instant::now()); + + // Create sockets + /* + let udp_rx_buffer = udp::PacketBuffer::new( + vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], + vec![0; 65535], + ); + let udp_tx_buffer = udp::PacketBuffer::new( + vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], + vec![0; 65535], + ); + let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer); + + let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp1_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp1_socket = tcp::Socket::new(tcp1_rx_buffer, tcp1_tx_buffer); + + let tcp2_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp2_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp2_socket = tcp::Socket::new(tcp2_rx_buffer, tcp2_tx_buffer); + + let tcp3_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp3_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp3_socket = tcp::Socket::new(tcp3_rx_buffer, tcp3_tx_buffer); + + let tcp4_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp4_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); + let tcp4_socket = tcp::Socket::new(tcp4_rx_buffer, tcp4_tx_buffer); + */ + + let icmp_rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]); + let icmp_tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]); + let icmp_socket = icmp::Socket::new(icmp_rx_buffer, icmp_tx_buffer); + + let mut sockets = SocketSet::new(vec![]); + /* + let udp_handle = sockets.add(udp_socket); + let tcp1_handle = sockets.add(tcp1_socket); + let tcp2_handle = sockets.add(tcp2_socket); + let tcp3_handle = sockets.add(tcp3_socket); + let tcp4_handle = sockets.add(tcp4_socket); + */ + let icmp_handle = sockets.add(icmp_socket); + // ------------- libstd variant ----------- // Each process keeps track of its own sockets. These are kept in a Vec. When a handle // is destroyed, it is turned into a `None`. @@ -269,49 +290,7 @@ fn main() -> ! { // incoming UDP socket data. let mut udp_rx_waiting: Vec> = Vec::new(); - // --------------- other link storage ------------- - let neighbor_cache = NeighborCache::new(BTreeMap::new()); - let ip_addrs = [ - IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0), - IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8) - ]; - let routes = Routes::new(BTreeMap::new()); - - // build the device - let hw_config = match com.wlan_get_config() { - Ok(config) => config, - Err(e) => { - log::error!("Something is wrong with the EC, got {:?} when requesting a MAC address. Trying our best to bodge through it.", e); - Ipv4Conf { - dhcp: com_rs::DhcpState::Invalid, - mac: [2, 2, 4, 5, 6, 2], - addr: [169, 254, 0, 2], // link local address - gtwy: [169, 254, 0, 1], // something bogus - mask: [255, 255, 0, 0,], - dns1: [1, 1, 1, 1], - dns2: [8, 8, 8, 8], - } - } - }; - log::debug!("My MAC address is: {:x?}", hw_config.mac); - MAC_ADDRESS_LSB.store(u32::from_be_bytes(hw_config.mac[2..6].try_into().unwrap()), Ordering::SeqCst); - MAC_ADDRESS_MSB.store(u16::from_be_bytes(hw_config.mac[0..2].try_into().unwrap()), Ordering::SeqCst); - let device = device::NetPhy::new(&xns, net_cid); - // needed by ICMP to determine if we should compute checksums - let device_caps = device.capabilities(); - let medium = device.capabilities().medium; - let mut builder = InterfaceBuilder::new(device, vec![]) - .ip_addrs(ip_addrs) - .routes(routes); - if medium == Medium::Ethernet { - builder = builder - .hardware_addr(EthernetAddress::from_bytes(&hw_config.mac).into()) - .neighbor_cache(neighbor_cache); - } - let mut iface = builder.finalize(); - // ------------- native variant ----------- - let icmp_handle = setup_icmp(&mut iface); let mut seq: u16 = 0; // this record stores the origin time + IP address of the outgoing ping sequence number let mut ping_destinations = HashMap::>::new(); @@ -326,53 +305,6 @@ fn main() -> ! { let mut dns_ipv6_hook = XousScalarEndpoint::new(); let mut dns_allclear_hook = XousScalarEndpoint::new(); - // wakeup polling management - kick off worker threads to wake up a poll in the future for certain rx events required by smoltcp - // this is not reset on connection reset, because the stale timers are still - // running and there is no way to reset them mid-run. - let mut wakeup_time: BTreeSet = BTreeSet::new(); - let mut wakeup_workers = Vec::::new(); - for _ in 0..MAX_DELAY_THREADS { - let (tx, rx) = channel(); - wakeup_workers.push(WorkerState { - tx, - is_busy: false, - time_replica: 0, - }); - thread::spawn({ - let parent_conn = net_conn.clone(); - move || { - let tt = ticktimer_server::Ticktimer::new().unwrap(); - loop { - let target = rx.recv().unwrap(); - let now = tt.elapsed_ms(); - // arbitrary time can pass between the target issuance and receive - let wakeup = if now >= target { - 0 - } else { - target - now - }; - if wakeup > 100_000 { - log::warn!("long wakeup detected: {}", wakeup); - } - if wakeup != 0 { // only issue the sleep if the wakeup time is non-zero - tt.sleep_ms(wakeup as usize).unwrap(); - } - xous::try_send_message( - parent_conn, - Message::new_scalar( - Opcode::NetPump.to_usize().unwrap(), - (target >> 32) as usize, - (target & 0xffff_ffff) as usize, - 0, - 0, - ), - ) - .ok(); - } - } - }); - } - log::trace!("ready to accept requests"); // register a suspend/resume listener let sr_cid = xous::connect(net_sid).expect("couldn't create suspend callback connection"); @@ -397,8 +329,58 @@ fn main() -> ! { }); let mut cid_to_disconnect: Option = None; + + let (core_tx, core_rx) = channel(); + thread::spawn({ + let parent_conn = net_conn.clone(); + move || { + xous::try_send_message( + parent_conn, + Message::new_scalar( + Opcode::SetupMpsc.to_usize().unwrap(), + 0, + 0, + 0, + 0, + ), + ) + .ok(); + loop { + let msg = xous::receive_message(net_sid).unwrap(); + core_tx.send(msg).unwrap(); + } + } + }); + let mut self_sender: Option:: = None; loop { - let mut msg = xous::receive_message(net_sid).unwrap(); + let timestamp = Instant::now(); + let deadline = match iface.poll_at(timestamp, &sockets) { + Some(poll_at) if timestamp < poll_at => poll_at - timestamp, + _ => Duration::from_millis(0), + }; + + let msg_or_timeout = core_rx.recv_timeout( + std::time::Duration::from_millis(deadline.millis()) + ); + let mut msg = match msg_or_timeout { + Ok(m) => m, + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { + // originate a Pump call when a timeout is reached + xous::envelope::Envelope { + // self_sender should be safe to unwrap because it is the first thing + // set by the loop, there would not be a timeout + sender: xous::MessageSender::from_usize(self_sender.unwrap()), + body: Message::new_scalar( + Opcode::NetPump.to_usize().unwrap(), + 0, + 0, + 0, + 0, + ), + } + } + _ => panic!("Unhandled MPSC error in core tx/rx of net thread") + }; if let Some(dc_cid) = cid_to_disconnect.take() { // disconnect previous loop iter's connection after d/c OK response was sent unsafe { @@ -420,13 +402,25 @@ fn main() -> ! { let nonblocking = (msg.body.id() & NONBLOCKING_FLAG) != 0; log::debug!("{:?}", op); match op { + Some(Opcode::SetupMpsc) => { + self_sender = Some(msg.sender.to_usize()); + } Some(Opcode::Ping) => { log::debug!("Ping"); let mut buf = unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) }; let mut pkt = buf.to_original::().unwrap(); - let socket = iface.get_socket::(icmp_handle); + + let timestamp = Instant::now(); + iface.poll(timestamp, &mut device, &mut sockets); + + let timestamp = Instant::now(); + let socket = sockets.get_mut::(icmp_handle); + if !socket.is_open() { + socket.bind(icmp::Endpoint::Ident(PING_IDENT)).unwrap(); + } + if socket.can_send() { log::debug!("sending ping to {:?}", pkt.endpoint); let remote = IpAddress::from(pkt.endpoint); @@ -473,10 +467,9 @@ fn main() -> ! { new_queue.insert(seq, now); ping_destinations.insert(conn, new_queue); }; - - // now emit the actual packet let mut echo_payload = [0xffu8; 40]; - NetworkEndian::write_i64(&mut echo_payload, now as i64); + NetworkEndian::write_i64(&mut echo_payload, timestamp.total_millis()); + match remote { IpAddress::Ipv4(_) => { let icmp_repr = Icmpv4Repr::EchoRequest { @@ -523,11 +516,11 @@ fn main() -> ! { } Some(Opcode::PingSetTtl) => msg_scalar_unpack!(msg, ttl, _, _, _, { let checked_ttl = if ttl > 255 { 255 as u8 } else { ttl as u8 }; - let socket = iface.get_socket::(icmp_handle); + let socket = sockets.get_mut::(icmp_handle); socket.set_hop_limit(Some(checked_ttl)); }), Some(Opcode::PingGetTtl) => msg_blocking_scalar_unpack!(msg, _, _, _, _, { - let socket = iface.get_socket::(icmp_handle); + let socket = sockets.get::(icmp_handle); let checked_ttl = if let Some(ttl) = socket.hop_limit() { ttl } else { @@ -605,6 +598,7 @@ fn main() -> ! { msg, local_port, &mut iface, + &mut sockets, &mut tcp_connect_waiting, process_sockets.entry(pid).or_default(), ); @@ -624,6 +618,7 @@ fn main() -> ! { msg, &timer, &mut iface, + &mut sockets, &mut tcp_tx_waiting, process_sockets.entry(pid).or_default(), ); @@ -643,6 +638,7 @@ fn main() -> ! { msg, &timer, &mut iface, + &mut sockets, process_sockets.entry(pid).or_default(), &mut tcp_peek_waiting, nonblocking, @@ -663,6 +659,7 @@ fn main() -> ! { msg, &timer, &mut iface, + &mut sockets, &mut tcp_rx_waiting, process_sockets.entry(pid).or_default(), nonblocking, @@ -694,7 +691,7 @@ fn main() -> ! { respond_with_error(msg, NetError::Invalid); continue; }; - let socket = iface.get_socket::(handle); + let socket = sockets.get_mut::(handle); log::debug!("StdTcpClose {:?}", socket.local_endpoint()); if !std_tcp_can_close(&tcp_tx_waiting, handle) { log::trace!("def"); // these are short because the extra delay of a long message affects the computation @@ -845,6 +842,7 @@ fn main() -> ! { std_tcp_listen( msg, &mut iface, + &mut sockets, process_sockets.entry(pid).or_default(), &trng, ); @@ -863,6 +861,7 @@ fn main() -> ! { std_tcp_accept( msg, &mut iface, + &mut sockets, &mut tcp_accept_waiting, &mut tcp_server_remote_close_poll, process_sockets.entry(pid).or_default(), @@ -892,11 +891,17 @@ fn main() -> ! { .or_default() .get_mut(connection_idx) { - let socket = iface.get_socket::(*connection); - body.valid = xous::MemorySize::new( - write_address(socket.local_endpoint().addr, unsafe { body.buf.as_slice_mut() }) - .unwrap_or_default(), - ); + let socket = sockets.get::(*connection); + match socket.local_endpoint() { + Some(ep) => { + body.valid = xous::MemorySize::new( + write_address(ep.addr, + unsafe { body.buf.as_slice_mut() }) + .unwrap_or_default(), + ) + } + None => respond_with_error(msg, NetError::Invalid).unwrap(), + } } else { respond_with_error(msg, NetError::Invalid); } @@ -918,10 +923,10 @@ fn main() -> ! { { let args = msg.body.scalar_message().unwrap(); let limit = if args.arg4 == 1 { - let socket = iface.get_socket::(*connection); + let socket = sockets.get::(*connection); socket.hop_limit().unwrap_or(64) as usize } else { - let socket = iface.get_socket::(*connection); + let socket = sockets.get::(*connection); socket.hop_limit().unwrap_or(64) as usize }; xous::return_scalar( @@ -956,10 +961,10 @@ fn main() -> ! { Some(args.arg1 as u8) }; if args.arg4 == 1 { - let socket = iface.get_socket::(*connection); + let socket = sockets.get_mut::(*connection); socket.set_hop_limit(hop_limit); } else { - let socket = iface.get_socket::(*connection); + let socket = sockets.get_mut::(*connection); socket.set_hop_limit(hop_limit); } xous::return_scalar(msg.sender, 0).ok(); @@ -983,11 +988,8 @@ fn main() -> ! { .or_default() .get_mut(connection_idx) { - let socket = iface.get_socket::(*connection); - // this is actually broken right now; it's fixed in https://github.com/smoltcp-rs/smoltcp/commit/8090469c2a1456b87a3e277e5b2f2e34e4f7555b - // not worth forking over this, though. We'll leave this as an erratum. - let nagle_enabled = socket.nagle_enabled().is_some(); // this return type will turn to bool on the next release. - log::warn!("Issue #210: nagle value read is always incorrect. Setting works, however. Returning nagle value of {}", nagle_enabled); + let socket = sockets.get::(*connection); + let nagle_enabled = socket.nagle_enabled(); let no_delay = !nagle_enabled; xous::return_scalar( msg.sender, @@ -1017,7 +1019,7 @@ fn main() -> ! { .or_default() .get_mut(connection_idx) { - let socket = iface.get_socket::(*connection); + let socket = sockets.get_mut::(*connection); let args = msg.body.scalar_message().unwrap(); let no_delay = args.arg1 != 0; log::warn!("Setting nagle to {}, see issue #210 about readback!", !no_delay); @@ -1034,6 +1036,7 @@ fn main() -> ! { std_udp_bind( msg, &mut iface, + &mut sockets, process_sockets.entry(pid).or_default(), ); } @@ -1045,6 +1048,7 @@ fn main() -> ! { msg, &timer, &mut iface, + &mut sockets, &mut udp_rx_waiting, process_sockets.entry(pid).or_default(), ); @@ -1056,6 +1060,7 @@ fn main() -> ! { std_udp_tx( msg, &mut iface, + &mut sockets, process_sockets.entry(pid).or_default(), ); xous::try_send_message( @@ -1086,8 +1091,8 @@ fn main() -> ! { std_failure(msg, NetError::Invalid); continue; }; - iface.get_socket::(handle).close(); - iface.remove_socket(handle); + sockets.get_mut::(handle).close(); + sockets.remove(handle); if let Some(response) = msg.body.memory_message_mut() { unsafe { response.buf.as_slice_mut::()[0] = 0 }; } else if !msg.body.has_memory() && msg.body.is_blocking() { @@ -1152,34 +1157,33 @@ fn main() -> ! { // update a static variable that tracks this, useful for e.g. UDP bind address checking IPV4_ADDRESS.store(u32::from_be_bytes(config.addr), Ordering::SeqCst); - // note: ARP cache is stale. Maybe that's ok? - - let ip_addr = Ipv4Cidr::new( - Ipv4Address::new( - config.addr[0], - config.addr[1], - config.addr[2], - config.addr[3], - ), - 24, - ); - set_ipv4_addr(&mut iface, ip_addr); - let default_v4_gw = Ipv4Address::new( - config.gtwy[0], - config.gtwy[1], - config.gtwy[2], - config.gtwy[3], - ); - + if config.addr != [127, 0, 0, 1] { + // note: ARP cache is stale. Maybe that's ok? + iface.update_ip_addrs(|ip_addrs| { + ip_addrs + .push(IpCidr::new(IpAddress::v4( + config.addr[0], + config.addr[1], + config.addr[2], + config.addr[3], + ), 24)) + .unwrap(); + }); + } else { + log::info!("not updating loopback address"); + } // reset the default route, in case it has changed iface.routes_mut().remove_default_ipv4_route(); - match iface.routes_mut().add_default_ipv4_route(default_v4_gw) { - Ok(route) => log::info!( - "routing table updated successfully [{:?}]", - route - ), - Err(e) => log::error!("routing table update error: {}", e), - } + iface + .routes_mut() + .add_default_ipv4_route(Ipv4Address::new( + config.gtwy[0], + config.gtwy[1], + config.gtwy[2], + config.gtwy[3], + )) + .unwrap(); + dns_allclear_hook.notify(); dns_ipv4_hook.notify_custom_args([ Some(u32::from_be_bytes(config.dns1)), @@ -1202,7 +1206,7 @@ fn main() -> ! { activity_interval.store(0, Ordering::Relaxed); // reset the activity interval to 0 if let Some(_config) = net_config { if let Some(rxlen) = maybe_rxlen { - match iface.device_mut().push_rx_avail(rxlen) { + match device.get_mut().push_rx_avail(rxlen) { None => {} //log::info!("pushed {} bytes avail to iface", rxlen), Some(_) => log::warn!("Got more packets, but smoltcp didn't drain them in time"), } @@ -1293,38 +1297,16 @@ fn main() -> ! { }), Some(Opcode::NetPump) => msg_scalar_unpack!(msg, wup_hi, wup_lo, _, _, { log::trace!("NetPump"); - // assume: if wup_hi/wup_lo == 0, then the wakeup is from a non-timer thread - let wakeup: u64 = (wup_hi as u64) << 32 | (wup_lo as u64); - if wakeup != 0 { - if let Some(wup) = wakeup_time.take(& Wakeup{tx_index: 0, time: wakeup}) { - wakeup_workers[wup.tx_index].is_busy = false; - } else { - log::warn!("wakeup time {} was not in the wakeup queue!", wakeup); - } - if wakeup_time.len() == 0 { - for (index, worker) in wakeup_workers.iter().enumerate() { - if worker.is_busy { - log::warn!("stranded worker at {}", index) - } - } - } - log::trace!("pending wakeups: {}", wakeup_time.len()); - } - let now = timer.elapsed_ms(); let timestamp = Instant::from_millis(now as i64); - match iface.poll(timestamp) { - Ok(_) => {} - Err(e) => { - log::debug!("poll error: {}", e); - } + if !iface.poll(timestamp, &mut device, &mut sockets) { + log::debug!("poll error"); } // Connect calls take time to establish. This block checks to see if connections // have been made and issues callbacks as necessary. log::trace!("pump: tcpconnect"); for connection in tcp_connect_waiting.iter_mut() { - use smoltcp::socket::TcpState; let socket; let (env, _handle, fd, local_port, remote_port) = { // If the connection is blank, or if it's still waiting to get @@ -1332,10 +1314,10 @@ fn main() -> ! { match connection { &mut None => continue, Some(s) => { - socket = iface.get_socket::(s.1); + socket = sockets.get::(s.1); log::debug!("connect state: {:?}", socket.state()); - if socket.state() == TcpState::SynSent - || socket.state() == TcpState::SynReceived + if socket.state() == smoltcp::socket::tcp::State::SynSent + || socket.state() == smoltcp::socket::tcp::State::SynReceived { continue; } @@ -1345,7 +1327,7 @@ fn main() -> ! { }; log::debug!("tcp state is {:?}", socket.state()); - if socket.state() == TcpState::Established { + if socket.state() == smoltcp::socket::tcp::State::Established { respond_with_connected(env, fd, local_port, remote_port); } else { respond_with_error(env, NetError::TimedOut); @@ -1364,7 +1346,7 @@ fn main() -> ! { match connection { &mut None => continue, Some(s) => { - socket = iface.get_socket::(s.handle); + socket = sockets.get_mut::(s.handle); log::debug!("rx_state: {:?} {:?}", socket.state(), socket.local_endpoint()); if !socket.can_recv() { if let Some(trigger) = s.expiry { @@ -1374,9 +1356,9 @@ fn main() -> ! { } else { continue; } - } else if socket.state() == smoltcp::socket::TcpState::CloseWait + } else if socket.state() == smoltcp::socket::tcp::State::CloseWait // this state added to handle the auto-close edge case on a remote hang-up - || socket.state() == smoltcp::socket::TcpState::Closed { + || socket.state() == smoltcp::socket::tcp::State::Closed { // stop waiting if we're in CloseWait, as we don't plan to transmit } else { continue; @@ -1389,9 +1371,9 @@ fn main() -> ! { // If it can't receive, then the only explanation was that it timed out if !socket.can_recv() { - if socket.state() == smoltcp::socket::TcpState::CloseWait + if socket.state() == smoltcp::socket::tcp::State::CloseWait // this state added to handle the auto-close edge case on a remote hang-up - || socket.state() == smoltcp::socket::TcpState::Closed { + || socket.state() == smoltcp::socket::tcp::State::Closed { log::debug!("rxrcv connection closed"); let body = env.body.memory_message_mut().unwrap(); log::debug!("rxrcv of {}", 0); @@ -1437,7 +1419,7 @@ fn main() -> ! { match connection { &mut None => continue, Some(s) => { - socket = iface.get_socket::(s.handle); + socket = sockets.get_mut::(s.handle); log::debug!("peek_state: {:?} {:?}", socket.state(), socket.local_endpoint()); if !socket.can_recv() { if let Some(trigger) = s.expiry { @@ -1447,9 +1429,9 @@ fn main() -> ! { } else { continue; } - } else if socket.state() == smoltcp::socket::TcpState::CloseWait + } else if socket.state() == smoltcp::socket::tcp::State::CloseWait // this state added to handle the auto-close edge case on a remote hang-up - || socket.state() == smoltcp::socket::TcpState::Closed { + || socket.state() == smoltcp::socket::tcp::State::Closed { // stop waiting if we're in CloseWait, as we don't plan to transmit } else { continue; @@ -1462,9 +1444,9 @@ fn main() -> ! { // If it can't receive, then the only explanation was that it timed out if !socket.can_recv() { - if socket.state() == smoltcp::socket::TcpState::CloseWait + if socket.state() == smoltcp::socket::tcp::State::CloseWait // this state added to handle the auto-close edge case on a remote hang-up - || socket.state() == smoltcp::socket::TcpState::Closed { + || socket.state() == smoltcp::socket::tcp::State::Closed { log::debug!("peekrcv connection closed"); let body = env.body.memory_message_mut().unwrap(); log::debug!("peekrcv of {}", 0); @@ -1510,9 +1492,9 @@ fn main() -> ! { match connection { &mut None => continue, Some(s) => { - socket = iface.get_socket::(s.handle); + socket = sockets.get_mut::(s.handle); log::debug!("tx_state: {:?} {:?}", socket.state(), socket.local_endpoint()); - if socket.state() == smoltcp::socket::TcpState::Closed { + if socket.state() == smoltcp::socket::tcp::State::Closed { // stop waiting if the stocket just closed on us outright } else if !socket.can_send() { if let Some(trigger) = s.expiry { @@ -1530,7 +1512,7 @@ fn main() -> ! { connection.take().unwrap() }; - if !socket.can_send() || socket.state() == smoltcp::socket::TcpState::Closed { + if !socket.can_send() || socket.state() == smoltcp::socket::tcp::State::Closed { respond_with_error(env, NetError::TimedOut); continue; } @@ -1577,10 +1559,10 @@ fn main() -> ! { } = match connection { &mut None => continue, Some(s) => { - let socket = iface.get_socket::(s.handle); + let socket = sockets.get_mut::(s.handle); if socket.is_active() { tcp_server_remote_close_poll.push(s.handle); - ep = socket.remote_endpoint(); + ep = socket.remote_endpoint().expect("TCP socket lacked remote endpoint"); connection.take().unwrap() } else { continue; @@ -1605,7 +1587,7 @@ fn main() -> ! { match connection { &mut None => continue, Some(s) => { - socket = iface.get_socket::(s.handle); + socket = sockets.get_mut::(s.handle); if !socket.can_recv() { if let Some(trigger) = s.expiry { if trigger < now { @@ -1638,7 +1620,7 @@ fn main() -> ! { // unwrap is safe here because the message was type-checked prior to insertion into the waiting queue unsafe { msg.body.memory_message_mut().unwrap().buf.as_slice_mut() }, data, - *endpoint // have to duplicate the code between peek and recv because of this type difference + endpoint.endpoint // have to duplicate the code between peek and recv because of this type difference ); } Err(e) => { @@ -1654,7 +1636,7 @@ fn main() -> ! { // unwrap is safe here because the message was type-checked prior to insertion into the waiting queue unsafe { msg.body.memory_message_mut().unwrap().buf.as_slice_mut() }, data, - endpoint + endpoint.endpoint ); } Err(e) => { @@ -1668,7 +1650,7 @@ fn main() -> ! { log::trace!("pump: tcp close"); tcp_tx_closing.retain(|(handle, sender)| { if std_tcp_can_close(&tcp_tx_waiting, *handle) { - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); log::trace!("may_send: {}, send_queue: {}", socket.may_send(), socket.send_queue()); // different condition than the previous wait -- here we opportunistically close // when either condition is met. @@ -1687,7 +1669,7 @@ fn main() -> ! { }); tcp_tx_wait_fin.retain_mut(|(handle, sender, count)| { - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); // count is a heuristic to stop TcpClose from blocking too long // most implementations are fully non-blocking, we need to block on Xous // to allow smoltcp to process correctly. However, the socket will stick @@ -1701,7 +1683,7 @@ fn main() -> ! { log::warn!("forced close on {:?}", socket.local_endpoint()); } log::debug!("socket closed {:?}", socket.local_endpoint()); - iface.remove_socket(*handle); + sockets.remove(*handle); tcp_server_remote_close_poll.retain(|x| { *x != *handle }); @@ -1716,9 +1698,9 @@ fn main() -> ! { }); tcp_server_remote_close_poll.retain(|handle| { - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); log::debug!("remote close poll: state {:?} local {:?}", socket.state(), socket.local_endpoint()); - if socket.state() == smoltcp::socket::TcpState::CloseWait { + if socket.state() == smoltcp::socket::tcp::State::CloseWait { // initiate the closing ack, but allow the explicit drop to remove the socket once the handle is finished // this handles the special case that a stream was accepted, but then the client hangs up // and the server isn't actively polling the loop. By pushing the socket to the "close" @@ -1736,7 +1718,7 @@ fn main() -> ! { // this block contains the ICMP Rx handler. Tx is initiated by an incoming message to the Net crate. log::trace!("pump: icmp"); { - let socket = iface.get_socket::(icmp_handle); + let socket = sockets.get_mut::(icmp_handle); if !socket.is_open() { log::error!("ICMP socket isn't open, something went wrong..."); } @@ -1954,96 +1936,6 @@ fn main() -> ! { true } ); - - // now: sequence through the waiting_queue and remove entries that have hit our timeout - for (conn, waiting_queue) in ping_destinations.iter_mut() { - let ra = conn.remote.as_bytes(); - waiting_queue.retain(|&seq, &mut start_time| - if now - start_time > ping_timeout_ms as u64 { - log::debug!("timeout - removing {:?}, {}", conn.remote, seq); - match xous::try_send_message(conn.cid, - Message::new_scalar( // we should wait if the queue is full, as the "Drop" message is important - conn.retop, - NetPingCallback::Timeout.to_usize().unwrap(), - u32::from_be_bytes(ra[..4].try_into().unwrap()) as usize, - seq as usize, - (now - start_time) as usize, - ) - ) { - Ok(_) => {}, - Err(xous::Error::ServerQueueFull) => { - log::warn!("Got dst {:?} timeout, but upstream server queue is full; dropping.", conn.remote); - }, - Err(xous::Error::ServerNotFound) => { - log::debug!("Callback server disappeared before we could inform it of timeout on {:?}, seq {}", conn.remote, seq); - }, - Err(e) => { - log::error!("Unhandled error: {:?}; ignoring", e); - } - } - false - } else { - true - } - ); - } - } - - // establish our next check-up interval - log::trace!("pump: checkup"); - let timestamp = Instant::from_millis(now as i64); - if let Some(delay) = iface.poll_delay(timestamp) { - const RANGE_MS: u64 = 100; // this will define the responsivity to "future" events that maybe 100's of ms away - let mut wakeup_needed = false; - // round all short delays to within the next quantum - if (delay.total_millis() as u32) < xous::BASE_QUANTA_MS { - if wakeup_time.range( - .. - Wakeup { tx_index: 0, time: now + xous::BASE_QUANTA_MS as u64 } - ).count() == 0 { - wakeup_needed = true; - } - } - let wakeup = now + delay.total_millis(); - // now check for longer delays over a longer window - if wakeup_time.range( - // "round up" to now if the window goes earlier than now - Wakeup { tx_index: 0, time: (wakeup - RANGE_MS).max(now) } - .. - Wakeup { tx_index: 0, time: wakeup + RANGE_MS } - ).count() == 0 { - wakeup_needed = true; - } - if wakeup_needed { - // find a free worker. this is an O(n) search right now, but generally (n) is small - let mut found = false; - for (index, worker) in wakeup_workers.iter_mut().enumerate() { - if !worker.is_busy { - worker.is_busy = true; - worker.time_replica = wakeup; - match worker.tx.send(wakeup) { - Err(e) => log::error!("{}: Couldn't send wakeup time to worker {}: {}", e, index, wakeup), - _ => {} - }; - wakeup_time.insert(Wakeup { - tx_index: index, - time: wakeup, - }); - found = true; - break; - } - } - if !found { - log::warn!("All wakeup threads occupied, punting on wakeup at {}ms in the future", delay.total_millis()); - let mut dbg = String::from("Now pending: "); - for (index, worker) in wakeup_workers.iter().enumerate() { - if worker.is_busy { - dbg.push_str(&format!("{}[{}], ", index, worker.time_replica as i64 - now as i64)); - } - } - log::info!("{}", dbg); - } - } } }), Some(Opcode::GetIpv4Config) => { diff --git a/services/net/src/std_tcplistener.rs b/services/net/src/std_tcplistener.rs index 9cd829e94..a92a41e73 100644 --- a/services/net/src/std_tcplistener.rs +++ b/services/net/src/std_tcplistener.rs @@ -1,10 +1,11 @@ use crate::*; -use crate::device::NetPhy; use smoltcp::wire::{IpEndpoint, IpAddress}; +use smoltcp::socket::tcp; pub(crate) fn std_tcp_listen( mut msg: xous::MessageEnvelope, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, our_sockets: &mut Vec>, trng: &trng::Trng, ) { @@ -40,18 +41,20 @@ pub(crate) fn std_tcp_listen( return; } - let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); - let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); - let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); - let handle = iface.add_socket(tcp_socket); - let tcp_socket = iface.get_socket::(handle); + let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); + let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); + let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); + + let handle = sockets.add(tcp_socket); + let cx = iface.context(); + let tcp_socket = sockets.get_mut::(handle); loop { if let Err(e) = tcp_socket .listen(local_port) .map_err(|e| match e { - smoltcp::Error::Illegal => NetError::SocketInUse, - smoltcp::Error::Unaddressable => NetError::Unaddressable, + smoltcp::socket::tcp::ListenError::InvalidState => NetError::SocketInUse, + smoltcp::socket::tcp::ListenError::Unaddressable => NetError::Unaddressable, _ => NetError::LibraryError, }) { @@ -94,7 +97,8 @@ pub(crate) fn std_tcp_listen( pub(crate) fn std_tcp_accept( mut msg: xous::MessageEnvelope, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, tcp_accept_waiting: &mut Vec>, tcp_server_remote_close_poll: &mut Vec, our_sockets: &Vec>, @@ -122,13 +126,13 @@ pub(crate) fn std_tcp_accept( let args = unsafe { body.buf.as_slice::() }; let nonblocking = args[0] == 0; - let socket = iface.get_socket::(*handle); + let socket = sockets.get::(*handle); if socket.is_active() { log::debug!("accept did not block; immediately returning TcpSocket"); let buf = unsafe { body.buf.as_slice_mut::() }; tcp_server_remote_close_poll.push(*handle); - tcp_accept_success(buf, fd as u16, socket.remote_endpoint()); + tcp_accept_success(buf, fd as u16, socket.remote_endpoint().expect("TCP accept missing remote endpoint")); return; } diff --git a/services/net/src/std_tcpstream.rs b/services/net/src/std_tcpstream.rs index 6d79de4ee..703a25989 100644 --- a/services/net/src/std_tcpstream.rs +++ b/services/net/src/std_tcpstream.rs @@ -3,17 +3,15 @@ use ticktimer_server::Ticktimer; use std::convert::TryInto; use core::num::NonZeroU64; -use smoltcp::socket::{ - TcpSocket, TcpSocketBuffer, -}; use smoltcp::iface::{Interface, SocketHandle}; +use smoltcp::socket::tcp; use crate::*; -use crate::device::NetPhy; pub(crate) fn std_tcp_connect( mut msg: xous::MessageEnvelope, local_port: u16, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, tcp_connect_waiting: &mut Vec>, our_sockets: &mut Vec>, ) { @@ -41,19 +39,20 @@ pub(crate) fn std_tcp_connect( // initiates a new connection to a remote server consisting of an (Address:Port) tuple. // multiple connections can exist to a server, and they are further differentiated by the return port - let tcp_socket = TcpSocket::new( - TcpSocketBuffer::new(vec![0; TCP_BUFFER_SIZE]), - TcpSocketBuffer::new(vec![0; TCP_BUFFER_SIZE]), - ); - let handle = iface.add_socket(tcp_socket); - let (tcp_socket, cx) = iface.get_socket_and_context::(handle); + let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); + let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]); + let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); + + let handle = sockets.add(tcp_socket); + let cx = iface.context(); + let tcp_socket = sockets.get_mut::(handle); // Attempt to connect, returning the error if there is one if let Err(e) = tcp_socket .connect(cx, (address, remote_port), local_port) .map_err(|e| match e { - smoltcp::Error::Illegal => NetError::SocketInUse, - smoltcp::Error::Unaddressable => NetError::Unaddressable, + smoltcp::socket::tcp::ConnectError::InvalidState => NetError::SocketInUse, + smoltcp::socket::tcp::ConnectError::Unaddressable => NetError::Unaddressable, _ => NetError::LibraryError, }) { @@ -77,7 +76,8 @@ pub(crate) fn std_tcp_connect( pub(crate) fn std_tcp_tx( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, tcp_tx_waiting: &mut Vec>, our_sockets: &Vec>, ) { @@ -98,7 +98,7 @@ pub(crate) fn std_tcp_tx( } }; - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); // handle the case that the connection closed due to the receiver quitting if !socket.can_send() { log::trace!("tx can't send, will retry"); @@ -150,7 +150,8 @@ pub(crate) fn std_tcp_tx( pub(crate) fn std_tcp_rx( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, tcp_rx_waiting: &mut Vec>, our_sockets: &Vec>, nonblocking: bool, @@ -178,7 +179,7 @@ pub(crate) fn std_tcp_rx( } }; - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); if socket.can_recv() { log::debug!("receiving data right away"); let buflen = if let Some(valid) = body.valid { @@ -227,7 +228,8 @@ pub(crate) fn std_tcp_rx( pub(crate) fn std_tcp_peek( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, our_sockets: &Vec>, tcp_peek_waiting: &mut Vec>, nonblocking: bool, @@ -255,7 +257,7 @@ pub(crate) fn std_tcp_peek( } }; - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); if socket.can_recv() { log::debug!("peeking data right away"); let buflen = if let Some(valid) = body.valid { diff --git a/services/net/src/std_udp.rs b/services/net/src/std_udp.rs index 0f7865acb..f8ff4c8ea 100644 --- a/services/net/src/std_udp.rs +++ b/services/net/src/std_udp.rs @@ -12,7 +12,8 @@ const BUFLEN: usize = NET_MTU as usize; pub(crate) fn std_udp_bind( mut msg: xous::MessageEnvelope, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, our_sockets: &mut Vec>, ) { // Ignore nonblocking and scalar messages @@ -36,20 +37,24 @@ pub(crate) fn std_udp_bind( } }; - let udp_rx_buffer = - UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; BUFLEN]); - let udp_tx_buffer = - UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; BUFLEN]); - let udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer); - let handle = iface.add_socket(udp_socket); - let udp_socket = iface.get_socket::(handle); + let udp_rx_buffer = udp::PacketBuffer::new( + vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], + vec![0; 65535], + ); + let udp_tx_buffer = udp::PacketBuffer::new( + vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], + vec![0; 65535], + ); + let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer); + let handle = sockets.add(udp_socket); + let udp_socket = sockets.get_mut::(handle); // Attempt to connect, returning the error if there is one if let Err(e) = udp_socket .bind(IpEndpoint{addr: address, port: local_port}) .map_err(|e| match e { - smoltcp::Error::Illegal => NetError::SocketInUse, - smoltcp::Error::Unaddressable => NetError::Unaddressable, + smoltcp::socket::udp::BindError::InvalidState => NetError::SocketInUse, + smoltcp::socket::udp::BindError::Unaddressable => NetError::Unaddressable, _ => NetError::LibraryError, }) { @@ -71,7 +76,8 @@ pub(crate) fn std_udp_bind( pub(crate) fn std_udp_rx( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, udp_rx_waiting: &mut Vec>, our_sockets: &Vec>, ) { @@ -116,20 +122,22 @@ pub(crate) fn std_udp_rx( return; } }; - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); let port = socket.endpoint().port; + // TODO: comment below may be invalid after port to latest smoltcp. Error handler + // is also suspect. + // // force the local address to correspond to our (one and only) IP address // the underlying smoltcp library can't handle unspecified source addresses // because the library itself works with multiple interfaces and has no default resolution mechanism // this may eventually get fixed see https://github.com/smoltcp-rs/smoltcp/issues/599 - if socket.endpoint().addr != IpAddress::Ipv4(local_addr) { + if socket.endpoint().addr.expect("UDP endpoint missing") != IpAddress::Ipv4(local_addr) { if socket.is_open() { socket.close(); } if let Err(e) = socket.bind(IpEndpoint{addr: IpAddress::Ipv4(local_addr), port}) .map_err(|e| match e { - smoltcp::Error::Illegal => NetError::SocketInUse, - smoltcp::Error::Unaddressable => NetError::Unaddressable, + smoltcp::socket::udp::BindError::Unaddressable => NetError::WouldBlock, _ => NetError::LibraryError, }) { std_failure(msg, e); @@ -143,7 +151,7 @@ pub(crate) fn std_udp_rx( // difference in types means you can't do a pattern match assign to a common variable. match socket.peek() { Ok((data, endpoint)) => { - udp_rx_success(unsafe { body.buf.as_slice_mut() }, data, *endpoint); + udp_rx_success(unsafe { body.buf.as_slice_mut() }, data, endpoint.endpoint); } Err(e) => { log::error!("unable to receive: {:?}", e); @@ -154,7 +162,7 @@ pub(crate) fn std_udp_rx( match socket.recv() { Ok((data, endpoint)) => { log::debug!("immediate udp rx"); - udp_rx_success(unsafe { body.buf.as_slice_mut() }, data, endpoint); + udp_rx_success(unsafe { body.buf.as_slice_mut() }, data, endpoint.endpoint); } Err(e) => { log::error!("unable to receive: {:?}", e); @@ -185,7 +193,8 @@ pub(crate) fn std_udp_rx( pub(crate) fn std_udp_tx( mut msg: xous::MessageEnvelope, - iface: &mut Interface::, + iface: &mut Interface, + sockets: &mut SocketSet, our_sockets: &Vec>, ) { // unpack meta @@ -226,20 +235,20 @@ pub(crate) fn std_udp_tx( return; } }; - let socket = iface.get_socket::(*handle); + let socket = sockets.get_mut::(*handle); let port = socket.endpoint().port; // force the local address to correspond to our (one and only) IP address // the underlying smoltcp library can't handle unspecified source addresses // because the library itself works with multiple interfaces and has no default resolution mechanism // this may eventually get fixed see https://github.com/smoltcp-rs/smoltcp/issues/599 - if socket.endpoint().addr != IpAddress::Ipv4(local_addr) { + if socket.endpoint().addr.expect("UDP TX endpoint missing") != IpAddress::Ipv4(local_addr) { if socket.is_open() { socket.close(); } if let Err(e) = socket.bind(IpEndpoint{addr: IpAddress::Ipv4(local_addr), port}) .map_err(|e| match e { - smoltcp::Error::Illegal => NetError::SocketInUse, - smoltcp::Error::Unaddressable => NetError::Unaddressable, + smoltcp::socket::udp::BindError::InvalidState => NetError::WouldBlock, + smoltcp::socket::udp::BindError::Unaddressable => NetError::Unaddressable, _ => NetError::LibraryError, }) { std_failure(msg, e); From 5e411f3562cd7eb7ddbfd9a632a46c96554bb527 Mon Sep 17 00:00:00 2001 From: bunnie Date: Fri, 29 Sep 2023 06:36:27 +0800 Subject: [PATCH 03/11] clean up warnings, fix icmp init --- services/net/src/api.rs | 1 - services/net/src/api/rkyv_enum.rs | 3 --- services/net/src/device.rs | 4 ---- services/net/src/main.rs | 19 +++++++++++-------- services/net/src/std_glue.rs | 4 ---- services/net/src/std_tcplistener.rs | 9 ++------- services/net/src/std_tcpstream.rs | 7 +++---- services/net/src/std_udp.rs | 10 +--------- 8 files changed, 17 insertions(+), 40 deletions(-) diff --git a/services/net/src/api.rs b/services/net/src/api.rs index 8166894bd..1e1461bc4 100644 --- a/services/net/src/api.rs +++ b/services/net/src/api.rs @@ -458,7 +458,6 @@ pub fn ipaddress_to_ipaddr(other: IpAddress) -> IpAddr { let octets = ipv6.0; IpAddr::V6(Ipv6Addr::from(octets)) } - _ => unimplemented!(), } } diff --git a/services/net/src/api/rkyv_enum.rs b/services/net/src/api/rkyv_enum.rs index b2c4f72ef..ad8dade13 100644 --- a/services/net/src/api/rkyv_enum.rs +++ b/services/net/src/api/rkyv_enum.rs @@ -59,9 +59,6 @@ impl From for NetIpAddr { match other { IpAddress::Ipv4(ipv4) => NetIpAddr::Ipv4(ipv4.0), IpAddress::Ipv6(ipv6) => NetIpAddr::Ipv6(ipv6.0), - _ => { - panic!("Invalid IpAddress") - } } } } diff --git a/services/net/src/device.rs b/services/net/src/device.rs index 0984099f3..c33b68fbf 100644 --- a/services/net/src/device.rs +++ b/services/net/src/device.rs @@ -6,10 +6,6 @@ use smoltcp::wire::{ArpPacket, ArpRepr, ArpOperation, Ipv4Address, EthernetAddre use num_traits::*; use std::convert::TryInto; -use smoltcp::{ - time::Instant, -}; - use crate::{MAC_ADDRESS_LSB, MAC_ADDRESS_MSB}; use core::sync::atomic::Ordering; use std::collections::VecDeque; diff --git a/services/net/src/main.rs b/services/net/src/main.rs index 1a6130411..0e45f450b 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -12,7 +12,7 @@ use std_udp::*; mod std_tcplistener; use std_tcplistener::*; -use com::api::{ComIntSources, Ipv4Conf, NET_MTU}; +use com::api::{ComIntSources, Ipv4Conf}; use num_traits::*; mod connection_manager; @@ -23,16 +23,16 @@ mod tests; #[cfg(feature="btest")] mod btests; -use std::collections::{BTreeMap, HashMap, BTreeSet}; +use std::collections::HashMap; use std::convert::TryInto; use xous::{msg_blocking_scalar_unpack, msg_scalar_unpack, send_message, Message, CID, SID}; use xous_ipc::Buffer; use byteorder::{ByteOrder, NetworkEndian}; use smoltcp::iface::{Interface, Config, SocketSet}; -use smoltcp::phy::{Device, Medium, Tracer}; +use smoltcp::phy::{Device, Tracer}; use smoltcp::socket::{tcp, udp, icmp}; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Cidr, IpEndpoint}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, IpEndpoint}; use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, Icmpv6Packet, Icmpv6Repr}; use core::num::NonZeroU64; @@ -51,7 +51,6 @@ pub static MAC_ADDRESS_LSB: AtomicU32 = AtomicU32::new(0); pub static MAC_ADDRESS_MSB: AtomicU16 = AtomicU16::new(0); const PING_DEFAULT_TIMEOUT_MS: u32 = 10_000; -const MAX_DELAY_THREADS: u32 = 9; const PING_IDENT: u16 = 0x22b; #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] @@ -247,6 +246,12 @@ fn main() -> ! { let tcp4_handle = sockets.add(tcp4_socket); */ let icmp_handle = sockets.add(icmp_socket); + { // put in a block to retire the icmp_socket variable in this scope + let icmp_socket = sockets.get_mut::(icmp_handle); + icmp_socket + .bind(icmp::Endpoint::Ident(PING_IDENT)) + .expect("couldn't bind to icmp socket"); + } // ------------- libstd variant ----------- // Each process keeps track of its own sockets. These are kept in a Vec. When a handle @@ -498,7 +503,6 @@ fn main() -> ! { &device_caps.checksum, ); } - _ => unimplemented!(), } seq += 1; // fire off a Pump to get the stack to actually transmit the ping; this call merely queues it for sending @@ -1295,7 +1299,7 @@ fn main() -> ! { } } }), - Some(Opcode::NetPump) => msg_scalar_unpack!(msg, wup_hi, wup_lo, _, _, { + Some(Opcode::NetPump) => msg_scalar_unpack!(msg, _, _, _, _, { log::trace!("NetPump"); let now = timer.elapsed_ms(); let timestamp = Instant::from_millis(now as i64); @@ -1890,7 +1894,6 @@ fn main() -> ! { log::error!("got unhandled ICMP type, ignoring!"); } } - _ => unimplemented!(), } } } diff --git a/services/net/src/std_glue.rs b/services/net/src/std_glue.rs index 5deb96f75..7bc33b355 100644 --- a/services/net/src/std_glue.rs +++ b/services/net/src/std_glue.rs @@ -40,10 +40,6 @@ pub(crate) fn write_address(address: IpAddress, data: &mut [u8]) -> Option { - *i.next()? = 0; - Some(1) - } } } diff --git a/services/net/src/std_tcplistener.rs b/services/net/src/std_tcplistener.rs index a92a41e73..8995b6763 100644 --- a/services/net/src/std_tcplistener.rs +++ b/services/net/src/std_tcplistener.rs @@ -4,7 +4,7 @@ use smoltcp::socket::tcp; pub(crate) fn std_tcp_listen( mut msg: xous::MessageEnvelope, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, our_sockets: &mut Vec>, trng: &trng::Trng, @@ -46,7 +46,6 @@ pub(crate) fn std_tcp_listen( let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer); let handle = sockets.add(tcp_socket); - let cx = iface.context(); let tcp_socket = sockets.get_mut::(handle); loop { @@ -55,7 +54,6 @@ pub(crate) fn std_tcp_listen( .map_err(|e| match e { smoltcp::socket::tcp::ListenError::InvalidState => NetError::SocketInUse, smoltcp::socket::tcp::ListenError::Unaddressable => NetError::Unaddressable, - _ => NetError::LibraryError, }) { match e { @@ -97,7 +95,7 @@ pub(crate) fn std_tcp_listen( pub(crate) fn std_tcp_accept( mut msg: xous::MessageEnvelope, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, tcp_accept_waiting: &mut Vec>, tcp_server_remote_close_poll: &mut Vec, @@ -174,9 +172,6 @@ pub(crate) fn tcp_accept_success(buf: &mut [u8], fd: u16, ep: IpEndpoint) { *d = s; } } - _ => { - buf[3] = 0; // this is the invalid/error type - } } let port = ep.port.to_le_bytes(); buf[20] = port[0]; diff --git a/services/net/src/std_tcpstream.rs b/services/net/src/std_tcpstream.rs index 703a25989..5e440c587 100644 --- a/services/net/src/std_tcpstream.rs +++ b/services/net/src/std_tcpstream.rs @@ -53,7 +53,6 @@ pub(crate) fn std_tcp_connect( .map_err(|e| match e { smoltcp::socket::tcp::ConnectError::InvalidState => NetError::SocketInUse, smoltcp::socket::tcp::ConnectError::Unaddressable => NetError::Unaddressable, - _ => NetError::LibraryError, }) { log::debug!("couldn't connect: {:?}", e); @@ -76,7 +75,7 @@ pub(crate) fn std_tcp_connect( pub(crate) fn std_tcp_tx( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, tcp_tx_waiting: &mut Vec>, our_sockets: &Vec>, @@ -150,7 +149,7 @@ pub(crate) fn std_tcp_tx( pub(crate) fn std_tcp_rx( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, tcp_rx_waiting: &mut Vec>, our_sockets: &Vec>, @@ -228,7 +227,7 @@ pub(crate) fn std_tcp_rx( pub(crate) fn std_tcp_peek( mut msg: xous::MessageEnvelope, timer: &Ticktimer, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, our_sockets: &Vec>, tcp_peek_waiting: &mut Vec>, diff --git a/services/net/src/std_udp.rs b/services/net/src/std_udp.rs index f8ff4c8ea..cf4f9a965 100644 --- a/services/net/src/std_udp.rs +++ b/services/net/src/std_udp.rs @@ -1,5 +1,4 @@ use crate::*; -use crate::device::NetPhy; use smoltcp::wire::{IpEndpoint, IpAddress}; use ticktimer_server::Ticktimer; @@ -8,11 +7,9 @@ use ticktimer_server::Ticktimer; /// Sockets are stored in the PID/SocketHandle HashMap `process_sockets` (this is shared with TCP) /// `recv` requests create `UpdStdState` objects, that are stored in a `udp_rx` Vec. -const BUFLEN: usize = NET_MTU as usize; - pub(crate) fn std_udp_bind( mut msg: xous::MessageEnvelope, - iface: &mut Interface, + _iface: &mut Interface, sockets: &mut SocketSet, our_sockets: &mut Vec>, ) { @@ -55,7 +52,6 @@ pub(crate) fn std_udp_bind( .map_err(|e| match e { smoltcp::socket::udp::BindError::InvalidState => NetError::SocketInUse, smoltcp::socket::udp::BindError::Unaddressable => NetError::Unaddressable, - _ => NetError::LibraryError, }) { log::trace!("couldn't connect: {:?}", e); @@ -249,7 +245,6 @@ pub(crate) fn std_udp_tx( .map_err(|e| match e { smoltcp::socket::udp::BindError::InvalidState => NetError::WouldBlock, smoltcp::socket::udp::BindError::Unaddressable => NetError::Unaddressable, - _ => NetError::LibraryError, }) { std_failure(msg, e); return; @@ -286,9 +281,6 @@ pub(crate) fn udp_rx_success(buf: &mut [u8], rx: &[u8], ep: IpEndpoint) { *d = s; } } - _ => { - buf[3] = 0; // this is the invalid/error type - } } let port = ep.port.to_le_bytes(); buf[20] = port[0]; From e78b40aa3627f17f5075756b10db4544258eb0d6 Mon Sep 17 00:00:00 2001 From: bunnie Date: Fri, 29 Sep 2023 11:48:52 +0800 Subject: [PATCH 04/11] cleanup the poll timeouts --- services/net/src/main.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/net/src/main.rs b/services/net/src/main.rs index 0e45f450b..2d4d5aa25 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -52,6 +52,11 @@ pub static MAC_ADDRESS_MSB: AtomicU16 = AtomicU16::new(0); const PING_DEFAULT_TIMEOUT_MS: u32 = 10_000; const PING_IDENT: u16 = 0x22b; +/// This sets the default poll time on the net interface. +/// Anything smaller than 1 ms is rounded up to 1ms; increasing this +/// number saves power. In general, most network events create an interrupt +/// so the poll interval should be OK to be set quite high. +const NET_DEFAULT_POLL_MS: u64 = 500; #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] enum WaitOp { @@ -140,7 +145,7 @@ fn set_com_ints(com_int_list: &mut Vec) { fn main() -> ! { log_server::init_wait().unwrap(); - log::set_max_level(log::LevelFilter::Info); + log::set_max_level(log::LevelFilter::Debug); log::info!("my PID is {}", xous::process::id()); let xns = xous_names::XousNames::new().unwrap(); @@ -361,7 +366,7 @@ fn main() -> ! { let timestamp = Instant::now(); let deadline = match iface.poll_at(timestamp, &sockets) { Some(poll_at) if timestamp < poll_at => poll_at - timestamp, - _ => Duration::from_millis(0), + _ => Duration::from_millis(NET_DEFAULT_POLL_MS), }; let msg_or_timeout = core_rx.recv_timeout( @@ -1304,7 +1309,8 @@ fn main() -> ! { let now = timer.elapsed_ms(); let timestamp = Instant::from_millis(now as i64); if !iface.poll(timestamp, &mut device, &mut sockets) { - log::debug!("poll error"); + // nothing to do, continue on. + continue } // Connect calls take time to establish. This block checks to see if connections From c8b5ba40dafcfc3e9acc82413eedc7bb62507922 Mon Sep 17 00:00:00 2001 From: bunnie Date: Fri, 29 Sep 2023 14:01:29 +0800 Subject: [PATCH 05/11] temporarily move smoltcp to track git URL this needs to stabilize once they tag out a release but for now it cleans up the warnings. will have to remember to do a cargo updae on that repository though from time to time to get the latest code... --- Cargo.lock | 1 + services/net/Cargo.toml | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 525e26f81..41d41d531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4466,6 +4466,7 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smoltcp" version = "0.10.0" +source = "git+https://github.com/smoltcp-rs/smoltcp.git?branch=main#edfdb23243a973d458397a2b4e76f527bacb1fd6" dependencies = [ "bitflags 1.3.2", "byteorder", diff --git a/services/net/Cargo.toml b/services/net/Cargo.toml index ede19d370..6330a96ce 100644 --- a/services/net/Cargo.toml +++ b/services/net/Cargo.toml @@ -34,8 +34,9 @@ xous-semver = "0.1.2" [dependencies.smoltcp] # some historical notes for development on branches in the future -path = "../../../smoltcp" -#git = "https://github.com/smoltcp-rs/smoltcp.git" +# path = "../../../smoltcp" +git = "https://github.com/smoltcp-rs/smoltcp.git" +branch = "main" #git = "https://github.com/betrusted-io/smoltcp.git" #rev = "35c8ec3d30c846442a1faae01fb0537641aef898" # 0.8.1 drops the rand_core dep and doesn't have the breaking IPv4 change (see issue #613) From ee18cb8e14052b39c7bb181ed79bf69a38d8a2cf Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 17:12:34 +0800 Subject: [PATCH 06/11] passing most nettests now. mostly an issue of poking at loopbacks. --- services/net/src/api.rs | 2 +- services/net/src/device.rs | 265 ++++++++++++++++++++++------- services/net/src/main.rs | 89 ++++------ services/shellchat/Cargo.toml | 2 +- services/shellchat/src/nettests.rs | 35 ++-- 5 files changed, 264 insertions(+), 129 deletions(-) diff --git a/services/net/src/api.rs b/services/net/src/api.rs index 1e1461bc4..76d764d5c 100644 --- a/services/net/src/api.rs +++ b/services/net/src/api.rs @@ -34,7 +34,7 @@ pub const MIN_EC_REV: SemVer = SemVer { }; /// Dispatch opcodes to the Net crate main loop. -#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] +#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug, PartialEq, Eq)] #[repr(C)] pub(crate) enum Opcode { SetupMpsc = 0, diff --git a/services/net/src/device.rs b/services/net/src/device.rs index c33b68fbf..c3d732535 100644 --- a/services/net/src/device.rs +++ b/services/net/src/device.rs @@ -1,12 +1,14 @@ use com::Com; use com::api::NET_MTU; -use smoltcp::phy::{self, DeviceCapabilities, Medium}; -use smoltcp::wire::{ArpPacket, ArpRepr, ArpOperation, Ipv4Address, EthernetAddress, EthernetFrame, EthernetProtocol}; +use smoltcp::phy::{self, DeviceCapabilities, Medium, ChecksumCapabilities}; +use smoltcp::wire::{ArpPacket, ArpRepr, ArpOperation, Ipv4Address, + EthernetAddress, EthernetFrame, EthernetProtocol, Ipv4Packet, + Ipv4Repr, /* IpProtocol, TcpPacket, TcpRepr, IpAddress, UdpPacket, UdpRepr */}; use num_traits::*; use std::convert::TryInto; -use crate::{MAC_ADDRESS_LSB, MAC_ADDRESS_MSB}; +use crate::{MAC_ADDRESS_LSB, MAC_ADDRESS_MSB, IPV4_ADDRESS}; use core::sync::atomic::Ordering; use std::collections::VecDeque; use std::sync::{Arc, Mutex}; @@ -49,26 +51,50 @@ impl phy::Device for NetPhy { type TxToken<'a> = NetPhyTxToken<'a>; fn receive(&mut self, _instant: smoltcp::time::Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { + let csum_copy = self.capabilities().checksum.clone(); if let Some(rx_len) = self.loopback_pending.lock().unwrap().pop_front() { + log::debug!("loopback injected {} bytes", rx_len); // loopback takes precedence self.com.wlan_fetch_loopback_packet(&mut self.rx_buffer[..rx_len as usize]).expect("Couldn't call wlan_fetch_packet in device adapter"); Some((NetPhyRxToken{buf: &mut self.rx_buffer[..rx_len as usize]}, - NetPhyTxToken{buf: &mut self.tx_buffer[..], com: & self.com, loopback_conn: self.loopback_conn, loopback_count: self.loopback_pending.clone()})) + NetPhyTxToken{ + buf: &mut self.tx_buffer[..], + com: & self.com, + loopback_conn: self.loopback_conn, + loopback_count: self.loopback_pending.clone(), + caps: csum_copy + })) } else { if let Some(rx_len) = self.rx_avail.take() { + log::debug!("device rx of {} bytes", rx_len); self.com.wlan_fetch_packet(&mut self.rx_buffer[..rx_len as usize]).expect("Couldn't call wlan_fetch_packet in device adapter"); Some((NetPhyRxToken{buf: &mut self.rx_buffer[..rx_len as usize]}, - NetPhyTxToken{buf: &mut self.tx_buffer[..], com: & self.com, loopback_conn: self.loopback_conn, loopback_count: self.loopback_pending.clone()})) + NetPhyTxToken{ + buf: &mut self.tx_buffer[..], + com: & self.com, + loopback_conn: self.loopback_conn, + loopback_count: self.loopback_pending.clone(), + caps: csum_copy + })) } else { + log::trace!("nothing to rx"); None } } } fn transmit(&mut self, _instant: smoltcp::time::Instant) -> Option> { - Some(NetPhyTxToken{buf: &mut self.tx_buffer[..], com: &self.com, loopback_conn: self.loopback_conn, loopback_count: self.loopback_pending.clone()}) + let csum_copy = self.capabilities().checksum.clone(); + log::debug!("device tx"); + Some(NetPhyTxToken{ + buf: &mut self.tx_buffer[..], + com: &self.com, + loopback_conn: self.loopback_conn, + loopback_count: self.loopback_pending.clone(), + caps: csum_copy + }) } fn capabilities(&self) -> DeviceCapabilities { @@ -99,10 +125,13 @@ pub struct NetPhyTxToken<'a> { com: &'a Com, loopback_conn: xous::CID, loopback_count: Arc::>>, + caps: ChecksumCapabilities, } impl <'a> NetPhyTxToken<'a> { /// Initiates the Rx side of things to read out the loopback packet that was queued fn loopback_rx(&self, rxlen: usize) { + // this will initiate a target trace + // log::set_max_level(log::LevelFilter::Trace); self.loopback_count.lock().unwrap().push_back(rxlen as u16); xous::try_send_message(self.loopback_conn, xous::Message::new_scalar(crate::Opcode::LoopbackRx.to_usize().unwrap(), rxlen, 0, 0, 0) @@ -147,85 +176,197 @@ impl <'a> NetPhyTxToken<'a> { } impl<'a> phy::TxToken for NetPhyTxToken<'a> { - fn consume(mut self, len: usize, f: F) -> R + fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R { let result = f(&mut self.buf[..len]); - //log::info!("txlen: {}", len); + log::debug!("txlen: {}", len); { // this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue as well: // https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55 // detect an outbound loopback packet, and shove it back in - let mut loopback = false; - if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut self.buf) { + if let Ok(mut eth_frame) = EthernetFrame::new_checked(&mut self.buf[..len]) { let mut local_hwaddr = [0u8; 6]; local_hwaddr[2..6].copy_from_slice(&MAC_ADDRESS_LSB.load(Ordering::SeqCst).to_be_bytes()); local_hwaddr[0..2].copy_from_slice(&MAC_ADDRESS_MSB.load(Ordering::SeqCst).to_be_bytes()); - if frame.dst_addr() == EthernetAddress::default() { + if eth_frame.dst_addr() == EthernetAddress::default() { log::debug!("loopback packet redirect"); // override the destination address to be our own address - frame.set_dst_addr(smoltcp::wire::EthernetAddress(local_hwaddr)); - loopback = true; - } else if frame.dst_addr().as_bytes() == local_hwaddr { + eth_frame.set_dst_addr(smoltcp::wire::EthernetAddress(local_hwaddr)); + self.com.wlan_queue_loopback(&self.buf[..len]); + self.loopback_rx(len); + return result; + } else if eth_frame.dst_addr().as_bytes() == local_hwaddr { log::debug!("loopback return packet redirect"); - loopback = true; + self.com.wlan_queue_loopback(&self.buf[..len]); + self.loopback_rx(len); + return result; } - } - // NOTE: was protected by if result.is_ok(), but looking at smoltcp, the calling routines - // *always* return OK, or nothing. So we are removing the protecting .is_ok()... - if loopback { - self.com.wlan_queue_loopback(&self.buf[..len]); - self.loopback_rx(len); - } else { - { - // this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue as well: - // https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55 - // this part of the hack finds ARP packets to and from the local device, and responds to them with packet injections - let pkt = &self.buf[..len]; - if let Ok(frame) = EthernetFrame::new_checked(pkt) { - if frame.ethertype() == EthernetProtocol::Arp { - // we're parsing packets that came from our own stack -- they better be OK! - let arp_packet = ArpPacket::new_checked(frame.payload()).unwrap(); - let arp_repr = ArpRepr::parse(&arp_packet).unwrap(); - match arp_repr { - ArpRepr::EthernetIpv4 { - operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, .. - } => { - log::trace!("outgoing arp: {:?} {:?} {:?}", source_hardware_addr, source_protocol_addr, target_protocol_addr); - if target_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { - log::trace!("intercepted outgoing arp for 127.0.0.1: {:?}", pkt); - self.wlan_queue_localhost_arp( - source_hardware_addr.as_bytes().try_into().unwrap(), - source_protocol_addr, - EthernetAddress([0, 0, 0, 0, 0, 0,]), - Ipv4Address([127, 0, 0, 1]), - ); - return result; - } else if source_protocol_addr.as_bytes() == [127, 0, 0, 1] && operation == ArpOperation::Request { - // reverse lookup case - log::trace!("intercepted outgoing arp for own IP: {:?} {:?}", target_protocol_addr, pkt); - self.wlan_queue_localhost_arp( - source_hardware_addr.as_bytes().try_into().unwrap(), - source_protocol_addr, - source_hardware_addr, - target_protocol_addr, - ); - return result; - } else { - // don't do anything, pass it on + // make a copy of the packet so we can meet mutability requirements of the routines below... + let mut packet_clone = [0u8; NET_MTU]; + let payload_len = eth_frame.payload_mut().len(); + packet_clone[..payload_len].copy_from_slice(ð_frame.payload_mut()[..payload_len]); + match eth_frame.ethertype() { + EthernetProtocol::Ipv4 => { + if let Ok(packet) = Ipv4Packet::new_checked(&packet_clone[..payload_len]) { + log::debug!("IPV4 packet checksum: {:x} ({:?})", packet.checksum(), packet.verify_checksum()); + if let Ok(ipv4_parsed) = Ipv4Repr::parse(&packet, &self.caps) { + log::debug!("IPV4 parsed: {:?}", ipv4_parsed); + if ipv4_parsed.dst_addr.as_bytes() == [127, 0, 0, 1] { + log::debug!("patching destination 127.0.0.1"); + // patch the destination MAC address + let mut local_hwaddr = [0u8; 6]; + local_hwaddr[2..6].copy_from_slice(&MAC_ADDRESS_LSB.load(Ordering::SeqCst).to_be_bytes()); + local_hwaddr[0..2].copy_from_slice(&MAC_ADDRESS_MSB.load(Ordering::SeqCst).to_be_bytes()); + eth_frame.set_dst_addr(smoltcp::wire::EthernetAddress(local_hwaddr)); + + /* this is no longer necessary in smoltcp 0.9 or later - an interface can bind to multiple sockets, one of which being 127.0.0.1 + // patch the destination IP address + let orig_dst_addr = ipv4_parsed.dst_addr; + ipv4_parsed.dst_addr = smoltcp::wire::Ipv4Address::from_bytes(&IPV4_ADDRESS.load(Ordering::SeqCst).to_be_bytes()); + + // extract the buffer region from the original frame and overwrite it + let payload_buf = eth_frame.payload_mut(); + let mut mut_pkt = Ipv4Packet::new_unchecked(payload_buf); + // recompute inner-checksums for TCP and UDP cases... + match ipv4_parsed.next_header { + IpProtocol::Tcp => { + let tcp_packet = TcpPacket::new_unchecked(packet.payload()); + if let Ok(tcp_repr) = TcpRepr::parse( + &tcp_packet, + &IpAddress::Ipv4(ipv4_parsed.src_addr), + &IpAddress::Ipv4(orig_dst_addr), + &self.caps + ) { + log::trace!("tcp checksum: {:x}", tcp_packet.checksum()); + let mut mut_tcp_packet = TcpPacket::new_unchecked(mut_pkt.payload_mut()); + tcp_repr.emit( + &mut mut_tcp_packet, + &IpAddress::Ipv4(ipv4_parsed.src_addr), + &IpAddress::Ipv4(ipv4_parsed.dst_addr), + &self.caps + ); + log::trace!("tcp new checksum: {:x}", tcp_packet.checksum()); + } else { + log::error!("Transmitted TCP packet did not unpack correctly! checksum: {:?}", tcp_packet.verify_checksum( + &IpAddress::Ipv4(ipv4_parsed.src_addr), &IpAddress::Ipv4(orig_dst_addr))); + } + } + IpProtocol::Udp => { + let udp_packet = UdpPacket::new_unchecked(packet.payload()); + if let Ok(udp_repr) = UdpRepr::parse( + &udp_packet, + &IpAddress::Ipv4(ipv4_parsed.src_addr), + &IpAddress::Ipv4(orig_dst_addr), + &self.caps + ) { + log::debug!("udp checksum: {:x}", udp_packet.checksum()); + let mut mut_udp_packet = UdpPacket::new_unchecked(mut_pkt.payload_mut()); + udp_repr.emit( + &mut mut_udp_packet, + &IpAddress::Ipv4(ipv4_parsed.src_addr), + &IpAddress::Ipv4(ipv4_parsed.dst_addr), + udp_packet.len() as usize, + |buf| buf.copy_from_slice(packet.payload()), + &self.caps + ); + log::debug!("udp new checksum: {:x}", udp_packet.checksum()); + } else { + log::error!("Transmitted UDP packet did not unpack correctly! checksum: {:?}", udp_packet.verify_checksum( + &IpAddress::Ipv4(ipv4_parsed.src_addr), &IpAddress::Ipv4(orig_dst_addr))); + } + } + _ => { + log::warn!("Unhandled packet type in loopback! Checksum will be incorrect."); + } } + + log::trace!("checksum: {:x}", mut_pkt.checksum()); + ipv4_parsed.emit(&mut mut_pkt, &self.caps); + log::trace!("new checksum: {:x}", mut_pkt.checksum()); + */ + + let buf_to_send = eth_frame.into_inner(); + self.com.wlan_queue_loopback(buf_to_send); + /* // for double-checking the RX packet + if let Ok(check_frame) = EthernetFrame::new_checked(&buf_to_send) { + if let Ok(check_pkt) = Ipv4Packet::new_checked(&check_frame.payload()) { + if let Ok(check_parsed) = Ipv4Repr::parse(&check_pkt, &self.caps) { + log::debug!("CHECK: checksum: {:x}, valid: {:?}, patched packet: {:?}", + check_pkt.checksum(), + check_pkt.verify_checksum(), + check_parsed); + } else { + log::debug!("CHECK: FAILED - invalid IPv4 packet"); + } + } else { + log::debug!("CHECK: FAILED - invalid payload"); + } + } else { + log::debug!("CHECK: FAILED - invalid ethernet frame"); + } + */ + self.loopback_rx(len); + // exit here without sending the packet on, because it went to Rx + return result; } - _ => {}, // pass it on } } } + EthernetProtocol::Arp => { + // this is a hack to make loopbacks work on smoltcp. Work-around taken from Redox, but tracking this issue as well: + // https://github.com/smoltcp-rs/smoltcp/issues/50 and https://github.com/smoltcp-rs/smoltcp/issues/55 + // this part of the hack finds ARP packets to and from the local device, and responds to them with packet injections + // we're parsing packets that came from our own stack -- they better be OK! + let arp_packet = ArpPacket::new_checked(eth_frame.payload_mut()).unwrap(); + let arp_repr = ArpRepr::parse(&arp_packet).unwrap(); + match arp_repr { + ArpRepr::EthernetIpv4 { + operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, .. + } => { + log::debug!("outgoing arp: {:?} {:?} {:?}", source_hardware_addr, source_protocol_addr, target_protocol_addr); + let local_addr = IPV4_ADDRESS.load(Ordering::SeqCst).to_be_bytes(); + if (target_protocol_addr.as_bytes() == [127, 0, 0, 1] + || target_protocol_addr.as_bytes() == local_addr) + && operation == ArpOperation::Request { + log::debug!("intercepted outgoing arp for localhost: {:?}", arp_repr); + let mut local_hwaddr = [0u8; 6]; + local_hwaddr[2..6].copy_from_slice(&MAC_ADDRESS_LSB.load(Ordering::SeqCst).to_be_bytes()); + local_hwaddr[0..2].copy_from_slice(&MAC_ADDRESS_MSB.load(Ordering::SeqCst).to_be_bytes()); + self.wlan_queue_localhost_arp( + source_hardware_addr.as_bytes().try_into().unwrap(), + source_protocol_addr, + EthernetAddress(local_hwaddr), + Ipv4Address(target_protocol_addr.as_bytes().try_into().unwrap()), + ); + return result; + } /* else if (source_protocol_addr.as_bytes() == [127, 0, 0, 1] + || source_protocol_addr.as_bytes() == local_addr) + && operation == ArpOperation::Request { + // reverse lookup case + log::debug!("intercepted outgoing arp for own IP: {:?} {:?}", target_protocol_addr, arp_repr); + self.wlan_queue_localhost_arp( + source_hardware_addr.as_bytes().try_into().unwrap(), + source_protocol_addr, + source_hardware_addr, + target_protocol_addr, + ); + return result; + } else { + // don't do anything, pass it on + } */ + } + _ => {}, // pass it on + } + } + _ => {} } - - // normally this would be the only line! - self.com.wlan_send_packet(&self.buf[..len]).expect("driver error sending WLAN packet"); } } + // forward the packet on if it's not a loopback (loopback will call return early and exit before getting to this line) + self.com.wlan_send_packet(&self.buf[..len]).expect("driver error sending WLAN packet"); + result } } \ No newline at end of file diff --git a/services/net/src/main.rs b/services/net/src/main.rs index 2d4d5aa25..e7b85e283 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -56,7 +56,7 @@ const PING_IDENT: u16 = 0x22b; /// Anything smaller than 1 ms is rounded up to 1ms; increasing this /// number saves power. In general, most network events create an interrupt /// so the poll interval should be OK to be set quite high. -const NET_DEFAULT_POLL_MS: u64 = 500; +const NET_DEFAULT_POLL_MS: u64 = 900; #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] enum WaitOp { @@ -145,7 +145,7 @@ fn set_com_ints(com_int_list: &mut Vec) { fn main() -> ! { log_server::init_wait().unwrap(); - log::set_max_level(log::LevelFilter::Debug); + log::set_max_level(log::LevelFilter::Info); log::info!("my PID is {}", xous::process::id()); let xns = xous_names::XousNames::new().unwrap(); @@ -207,49 +207,14 @@ fn main() -> ! { log::trace!("{}", _printer); }); let device_caps = device.capabilities(); - let mut iface = Interface::new(config, &mut device, Instant::now()); + let mut iface = Interface::new(config, &mut device, Instant::from_millis(timer.elapsed_ms() as i64)); // Create sockets - /* - let udp_rx_buffer = udp::PacketBuffer::new( - vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], - vec![0; 65535], - ); - let udp_tx_buffer = udp::PacketBuffer::new( - vec![udp::PacketMetadata::EMPTY, udp::PacketMetadata::EMPTY], - vec![0; 65535], - ); - let udp_socket = udp::Socket::new(udp_rx_buffer, udp_tx_buffer); - - let tcp1_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp1_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp1_socket = tcp::Socket::new(tcp1_rx_buffer, tcp1_tx_buffer); - - let tcp2_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp2_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp2_socket = tcp::Socket::new(tcp2_rx_buffer, tcp2_tx_buffer); - - let tcp3_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp3_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp3_socket = tcp::Socket::new(tcp3_rx_buffer, tcp3_tx_buffer); - - let tcp4_rx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp4_tx_buffer = tcp::SocketBuffer::new(vec![0; 65535]); - let tcp4_socket = tcp::Socket::new(tcp4_rx_buffer, tcp4_tx_buffer); - */ - let icmp_rx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]); let icmp_tx_buffer = icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY], vec![0; 256]); let icmp_socket = icmp::Socket::new(icmp_rx_buffer, icmp_tx_buffer); let mut sockets = SocketSet::new(vec![]); - /* - let udp_handle = sockets.add(udp_socket); - let tcp1_handle = sockets.add(tcp1_socket); - let tcp2_handle = sockets.add(tcp2_socket); - let tcp3_handle = sockets.add(tcp3_socket); - let tcp4_handle = sockets.add(tcp4_socket); - */ let icmp_handle = sockets.add(icmp_socket); { // put in a block to retire the icmp_socket variable in this scope let icmp_socket = sockets.get_mut::(icmp_handle); @@ -363,18 +328,19 @@ fn main() -> ! { }); let mut self_sender: Option:: = None; loop { - let timestamp = Instant::now(); + let now = timer.elapsed_ms(); + let timestamp = Instant::from_millis(now as i64); let deadline = match iface.poll_at(timestamp, &sockets) { Some(poll_at) if timestamp < poll_at => poll_at - timestamp, _ => Duration::from_millis(NET_DEFAULT_POLL_MS), }; - let msg_or_timeout = core_rx.recv_timeout( std::time::Duration::from_millis(deadline.millis()) ); let mut msg = match msg_or_timeout { Ok(m) => m, Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { + log::trace!("poll timeout; issuing NetPump"); // originate a Pump call when a timeout is reached xous::envelope::Envelope { // self_sender should be safe to unwrap because it is the first thing @@ -410,7 +376,11 @@ fn main() -> ! { } let op = FromPrimitive::from_usize(msg.body.id() & 0x7fff); let nonblocking = (msg.body.id() & NONBLOCKING_FLAG) != 0; - log::debug!("{:?}", op); + if op != Some(Opcode::NetPump) { + log::debug!("{:?}", op); + } else { + log::trace!("{:?}", op); + } match op { Some(Opcode::SetupMpsc) => { self_sender = Some(msg.sender.to_usize()); @@ -422,10 +392,10 @@ fn main() -> ! { }; let mut pkt = buf.to_original::().unwrap(); - let timestamp = Instant::now(); + let timestamp = Instant::from_millis(timer.elapsed_ms() as i64); iface.poll(timestamp, &mut device, &mut sockets); - let timestamp = Instant::now(); + let timestamp = Instant::from_millis(timer.elapsed_ms() as i64); let socket = sockets.get_mut::(icmp_handle); if !socket.is_open() { socket.bind(icmp::Endpoint::Ident(PING_IDENT)).unwrap(); @@ -1031,7 +1001,6 @@ fn main() -> ! { let socket = sockets.get_mut::(*connection); let args = msg.body.scalar_message().unwrap(); let no_delay = args.arg1 != 0; - log::warn!("Setting nagle to {}, see issue #210 about readback!", !no_delay); socket.set_nagle_enabled(!no_delay); xous::return_scalar(msg.sender, 0).ok(); } else { @@ -1169,6 +1138,7 @@ fn main() -> ! { if config.addr != [127, 0, 0, 1] { // note: ARP cache is stale. Maybe that's ok? iface.update_ip_addrs(|ip_addrs| { + ip_addrs.clear(); ip_addrs .push(IpCidr::new(IpAddress::v4( config.addr[0], @@ -1177,9 +1147,15 @@ fn main() -> ! { config.addr[3], ), 24)) .unwrap(); + // ...and the loopback interface + ip_addrs + .push(IpCidr::new(IpAddress::v4( + 127, 0, 0, 1 + ), 8)) + .unwrap(); }); } else { - log::info!("not updating loopback address"); + log::warn!("Attempt to update the loopback interface! Ignoring."); } // reset the default route, in case it has changed iface.routes_mut().remove_default_ipv4_route(); @@ -1310,12 +1286,15 @@ fn main() -> ! { let timestamp = Instant::from_millis(now as i64); if !iface.poll(timestamp, &mut device, &mut sockets) { // nothing to do, continue on. + log::debug!("No change to socket readiness"); continue + } else { + log::debug!("Socket readiness changed"); } // Connect calls take time to establish. This block checks to see if connections // have been made and issues callbacks as necessary. - log::trace!("pump: tcpconnect"); + // log::trace!("pump: tcpconnect"); for connection in tcp_connect_waiting.iter_mut() { let socket; let (env, _handle, fd, local_port, remote_port) = { @@ -1345,7 +1324,7 @@ fn main() -> ! { } // This block handles TCP Rx for libstd callers - log::trace!("pump: tcp rx"); + // log::trace!("pump: tcp rx"); for connection in tcp_rx_waiting.iter_mut() { let socket; let WaitingSocket { @@ -1418,7 +1397,7 @@ fn main() -> ! { } // This block handles TCP Peek for libstd callers - log::trace!("pump: tcp peek"); + // log::trace!("pump: tcp peek"); for connection in tcp_peek_waiting.iter_mut() { let socket; let WaitingSocket { @@ -1491,7 +1470,7 @@ fn main() -> ! { } // This block handles TCP Tx for libstd callers - log::trace!("pump: tcp tx"); + // log::trace!("pump: tcp tx"); for connection in tcp_tx_waiting.iter_mut() { let socket; let WaitingSocket { @@ -1559,7 +1538,7 @@ fn main() -> ! { } // this handles TCP std listeners - log::trace!("pump: tcp listen"); + // log::trace!("pump: tcp listen"); for connection in tcp_accept_waiting.iter_mut() { let ep: IpEndpoint; let AcceptingSocket { @@ -1586,7 +1565,7 @@ fn main() -> ! { } // this block handles StdUdp - log::trace!("pump: udp"); + // log::trace!("pump: udp"); for connection in udp_rx_waiting.iter_mut() { let socket; let UdpStdState { @@ -1657,7 +1636,7 @@ fn main() -> ! { } } - log::trace!("pump: tcp close"); + // log::trace!("pump: tcp close"); tcp_tx_closing.retain(|(handle, sender)| { if std_tcp_can_close(&tcp_tx_waiting, *handle) { let socket = sockets.get_mut::(*handle); @@ -1726,7 +1705,7 @@ fn main() -> ! { }); // this block contains the ICMP Rx handler. Tx is initiated by an incoming message to the Net crate. - log::trace!("pump: icmp"); + // log::trace!("pump: icmp"); { let socket = sockets.get_mut::(icmp_handle); if !socket.is_open() { @@ -1905,7 +1884,7 @@ fn main() -> ! { } } // this block handles ICMP retirement; it runs everytime we pump the block - log::trace!("pump: icmp retirement"); + // log::trace!("pump: icmp retirement"); { // notify the callback to drop its connection, because the queue is now empty // do this before we clear the queue, because we want the Drop message to come on the iteration @@ -1946,6 +1925,8 @@ fn main() -> ! { } ); } + // use this to revert targeted tracing + // log::set_max_level(log::LevelFilter::Info); }), Some(Opcode::GetIpv4Config) => { let mut buffer = unsafe { diff --git a/services/shellchat/Cargo.toml b/services/shellchat/Cargo.toml index 671557f04..679f35ec9 100644 --- a/services/shellchat/Cargo.toml +++ b/services/shellchat/Cargo.toml @@ -132,4 +132,4 @@ websocket = ["tls", "tungstenite", "url"] shellperf = ["ring", "perflib", "xous/v2p", "random-pick"] # this also needs the project-wide "perfcounter" feature to be selected. shellchat is the exclusive manager of the performance counter, do not use with e.g. "vaultperf" feature extra-tests = [] mass-storage = [] -default = [] # "debugprint" +default = ["nettest"] # "debugprint" diff --git a/services/shellchat/src/nettests.rs b/services/shellchat/src/nettests.rs index a45c16531..08ed982e9 100644 --- a/services/shellchat/src/nettests.rs +++ b/services/shellchat/src/nettests.rs @@ -10,9 +10,9 @@ use std::sync::atomic::{AtomicUsize, Ordering}; pub(crate) fn start_batch_tests() { let _ = thread::spawn({ move || { - let run_passing = true; + let run_passing = false; let tt = ticktimer_server::Ticktimer::new().unwrap(); - const PRINT_DELAY: usize = 3000; + const PRINT_DELAY: usize = 2000; if run_passing { log::info!("################################################## bind_error"); tt.sleep_ms(PRINT_DELAY).ok(); @@ -32,6 +32,18 @@ pub(crate) fn start_batch_tests() { log::info!("################################################## read_eof"); tt.sleep_ms(PRINT_DELAY).ok(); read_eof(); + + // This test can fail if there is a ticktimer scheduling error: + /* + INFO:shellchat::nettests: ################################################## write_close (services\shellchat\src\nettests.rs:35) + INFO:shellchat::nettests: ++++++++++++++++++++++++++create server (services\shellchat\src\nettests.rs:252) + INFO:shellchat::nettests: ++++++++++++++++++++++++++try to establish connection (services\shellchat\src\nettests.rs:265) + INFO:shellchat::nettests: ++++++++++++++++++++++++++established (services\shellchat\src\nettests.rs:267) + INFO:shellchat::nettests: ----------------------------create and drop connection to server (services\shellchat\src\nettests.rs:257) + INFO:shellchat::nettests: ----------------------------signal that we should proceed to send the data to the closed server (services\shellchat\src\nettests.rs:262) + ERR :xous_ticktimer: requested to wake 1 entries, which is more than the current 2 waiting entries (services\xous-ticktimer\src\main.rs:429) + -- hangs here forever. + */ log::info!("################################################## write_close"); tt.sleep_ms(PRINT_DELAY).ok(); write_close(); @@ -49,9 +61,9 @@ pub(crate) fn start_batch_tests() { tt.sleep_ms(PRINT_DELAY).ok(); write_vectored(); - // This test cannot be run until issue #210 is fixed see https://github.com/betrusted-io/xous-core/issues/210 - //log::info!("################################################## nodelay"); - //nodelay(); + log::info!("################################################## nodelay"); + nodelay(); + tt.sleep_ms(PRINT_DELAY).ok(); log::info!("################################################## ttl"); tt.sleep_ms(PRINT_DELAY).ok(); ttl(); @@ -90,14 +102,15 @@ pub(crate) fn start_batch_tests() { log::info!("################################################## clone_while_reading"); tt.sleep_ms(PRINT_DELAY).ok(); clone_while_reading(); - log::info!("################################################## clone_accept_smoke"); - tt.sleep_ms(PRINT_DELAY).ok(); - clone_accept_smoke(); - log::info!("################################################## clone_accept_concurrent"); - tt.sleep_ms(PRINT_DELAY).ok(); - clone_accept_concurrent(); } + log::info!("################################################## clone_accept_smoke"); + tt.sleep_ms(PRINT_DELAY).ok(); + clone_accept_smoke(); + log::info!("################################################## clone_accept_concurrent"); + tt.sleep_ms(PRINT_DELAY).ok(); + clone_accept_concurrent(); + log::info!("################################################## multiple_connect_serial"); tt.sleep_ms(PRINT_DELAY).ok(); multiple_connect_serial(); From 2faa518df8e8a0a7dd3381390bc58c13c0ce1408 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 17:18:07 +0800 Subject: [PATCH 07/11] add debug level setting on net stack --- services/net/src/api.rs | 1 + services/net/src/lib.rs | 12 ++++++++++++ services/net/src/main.rs | 8 ++++++++ services/shellchat/src/nettests.rs | 5 +++++ 4 files changed, 26 insertions(+) diff --git a/services/net/src/api.rs b/services/net/src/api.rs index 76d764d5c..041420d64 100644 --- a/services/net/src/api.rs +++ b/services/net/src/api.rs @@ -38,6 +38,7 @@ pub const MIN_EC_REV: SemVer = SemVer { #[repr(C)] pub(crate) enum Opcode { SetupMpsc = 0, + SetDebug = 1, /// Calls for UDP implementation (now deprecated to libstd) //UdpBind = 0, //UdpClose = 1, diff --git a/services/net/src/lib.rs b/services/net/src/lib.rs index 9a140cd2b..681302e7d 100644 --- a/services/net/src/lib.rs +++ b/services/net/src/lib.rs @@ -59,6 +59,18 @@ impl NetManager { wifi_state_sid: None, } } + pub fn set_debug_level(&self, level: log::LevelFilter) { + let code = match level { + log::LevelFilter::Info => 0, + log::LevelFilter::Debug => 1, + log::LevelFilter::Trace => 2, + _ => 0, + }; + send_message( + self.netconn.conn(), + Message::new_scalar(Opcode::SetDebug.to_usize().unwrap(), code, 0, 0, 0), + ).expect("couldn't set debug"); + } pub fn get_ipv4_config(&self) -> Option { let storage = Some(Ipv4Conf::default().encode_u16()); let mut buf = Buffer::into_buf(storage).expect("Couldn't convert to memory structure"); diff --git a/services/net/src/main.rs b/services/net/src/main.rs index e7b85e283..d612f1f9e 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -385,6 +385,14 @@ fn main() -> ! { Some(Opcode::SetupMpsc) => { self_sender = Some(msg.sender.to_usize()); } + Some(Opcode::SetDebug) => msg_scalar_unpack!(msg, level, _, _, _, { + match level { + 0 => log::set_max_level(log::LevelFilter::Info), + 1 => log::set_max_level(log::LevelFilter::Debug), + 2 => log::set_max_level(log::LevelFilter::Trace), + _ => log::set_max_level(log::LevelFilter::Info), + } + }), Some(Opcode::Ping) => { log::debug!("Ping"); let mut buf = unsafe { diff --git a/services/shellchat/src/nettests.rs b/services/shellchat/src/nettests.rs index 08ed982e9..9497fcaa7 100644 --- a/services/shellchat/src/nettests.rs +++ b/services/shellchat/src/nettests.rs @@ -8,6 +8,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::atomic::{AtomicUsize, Ordering}; pub(crate) fn start_batch_tests() { + let netmgr = net::NetManager::new(); let _ = thread::spawn({ move || { let run_passing = false; @@ -106,10 +107,14 @@ pub(crate) fn start_batch_tests() { log::info!("################################################## clone_accept_smoke"); tt.sleep_ms(PRINT_DELAY).ok(); + netmgr.set_debug_level(log::LevelFilter::Trace); clone_accept_smoke(); + netmgr.set_debug_level(log::LevelFilter::Info); log::info!("################################################## clone_accept_concurrent"); tt.sleep_ms(PRINT_DELAY).ok(); + netmgr.set_debug_level(log::LevelFilter::Trace); clone_accept_concurrent(); + netmgr.set_debug_level(log::LevelFilter::Info); log::info!("################################################## multiple_connect_serial"); tt.sleep_ms(PRINT_DELAY).ok(); From 3dda5b967ba5d995e89968dbba24fe5b700811f3 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 18:39:50 +0800 Subject: [PATCH 08/11] add notes about net-tests that are intermittent or failing but waiving --- services/shellchat/src/nettests.rs | 53 +++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/services/shellchat/src/nettests.rs b/services/shellchat/src/nettests.rs index 9497fcaa7..d634080c0 100644 --- a/services/shellchat/src/nettests.rs +++ b/services/shellchat/src/nettests.rs @@ -103,28 +103,40 @@ pub(crate) fn start_batch_tests() { log::info!("################################################## clone_while_reading"); tt.sleep_ms(PRINT_DELAY).ok(); clone_while_reading(); + + // these tests fail after being called in the long series of tests, but when run on their + // own they pass... + log::info!("################################################## clone_accept_smoke"); + tt.sleep_ms(PRINT_DELAY).ok(); + //netmgr.set_debug_level(log::LevelFilter::Trace); + clone_accept_smoke(); + //netmgr.set_debug_level(log::LevelFilter::Info); + log::info!("################################################## clone_accept_concurrent"); + tt.sleep_ms(PRINT_DELAY).ok(); + //netmgr.set_debug_level(log::LevelFilter::Trace); + clone_accept_concurrent(); + //netmgr.set_debug_level(log::LevelFilter::Info); } - log::info!("################################################## clone_accept_smoke"); - tt.sleep_ms(PRINT_DELAY).ok(); - netmgr.set_debug_level(log::LevelFilter::Trace); - clone_accept_smoke(); - netmgr.set_debug_level(log::LevelFilter::Info); - log::info!("################################################## clone_accept_concurrent"); - tt.sleep_ms(PRINT_DELAY).ok(); - netmgr.set_debug_level(log::LevelFilter::Trace); - clone_accept_concurrent(); - netmgr.set_debug_level(log::LevelFilter::Info); - + // These tests seem to fail unless you insert some debug prints in them. This is a problem + // likely related to race conditions in condvars and ticktimers. We're going to waive this + // for now because the tests themselves are pretty synthetic, it's rare that you create + // multiple sockets simply for the purpose of abandoning them? Or at least, not when + // used as a client; perhaps in a server environment this is common, but Xous isn't targeting + // a server (yet). log::info!("################################################## multiple_connect_serial"); tt.sleep_ms(PRINT_DELAY).ok(); multiple_connect_serial(); log::info!("################################################## multiple_connect_interleaved_greedy_schedule"); tt.sleep_ms(PRINT_DELAY).ok(); + netmgr.set_debug_level(log::LevelFilter::Debug); multiple_connect_interleaved_greedy_schedule(); + netmgr.set_debug_level(log::LevelFilter::Info); log::info!("################################################## multiple_connect_interleaved_lazy_schedule"); tt.sleep_ms(PRINT_DELAY).ok(); + netmgr.set_debug_level(log::LevelFilter::Trace); multiple_connect_interleaved_lazy_schedule(); + netmgr.set_debug_level(log::LevelFilter::Info); log::info!("################################################## FIN"); log::info!("################################################## FIN"); @@ -326,6 +338,7 @@ fn multiple_connect_serial() { fn multiple_connect_interleaved_greedy_schedule() { const MAX: usize = 3; each_ip(&mut |addr| { + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~bind to addr: {:?}", addr); let acceptor = t!(TcpListener::bind(&addr)); let _t = thread::spawn(move || { @@ -333,28 +346,35 @@ fn multiple_connect_interleaved_greedy_schedule() { for (i, stream) in acceptor.incoming().enumerate().take(MAX) { // Start another thread to handle the connection let _t = thread::spawn(move || { + log::info!("++++++++++++++++++++++++++++++++ start thread {}", i); let mut stream = t!(stream); let mut buf = [0]; t!(stream.read(&mut buf)); + log::info!("++++++++++++++++++++++++++++++++ thread {} read: {:?}", i, buf); assert!(buf[0] == i as u8); }); } }); connect(0, addr); + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~after connect(0)"); }); fn connect(i: usize, addr: SocketAddr) { + log::info!("******************************* connect {}", i); if i == MAX { return; } let t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); + log::info!("******************************* connect {:?}", addr); + let mut stream = t!(TcpStream::connect(&addr)); // errors out here // Connect again before writing connect(i + 1, addr); + log::info!("******************************* writing {:?}", i); t!(stream.write(&[i as u8])); }); + log::info!("******************************* joining... {}", i); t.join().ok().expect("thread panicked"); } } @@ -598,18 +618,27 @@ fn clone_while_reading() { fn clone_accept_smoke() { each_ip(&mut |addr| { + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~bind to addr: {:?}", addr); let a = t!(TcpListener::bind(&addr)); + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~bind to addr clone"); let a2 = t!(a.try_clone()); let _t = thread::spawn(move || { + log::info!("++++++++++++++++++++++++++++++++connect #1"); let _ = TcpStream::connect(&addr); + log::info!("++++++++++++++++++++++++++++++++#1 connected"); }); let _t = thread::spawn(move || { + log::info!("--------------------------------connect #2"); let _ = TcpStream::connect(&addr); + log::info!("--------------------------------#2 connected"); }); + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#1 accept"); t!(a.accept()); + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#2 accept"); t!(a2.accept()); + log::info!("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~FINISH"); }) } From c072b18df63ae35170bac5c86f177b75f889487e Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 18:43:38 +0800 Subject: [PATCH 09/11] remove nettest from the default args --- services/shellchat/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/shellchat/Cargo.toml b/services/shellchat/Cargo.toml index 679f35ec9..671557f04 100644 --- a/services/shellchat/Cargo.toml +++ b/services/shellchat/Cargo.toml @@ -132,4 +132,4 @@ websocket = ["tls", "tungstenite", "url"] shellperf = ["ring", "perflib", "xous/v2p", "random-pick"] # this also needs the project-wide "perfcounter" feature to be selected. shellchat is the exclusive manager of the performance counter, do not use with e.g. "vaultperf" feature extra-tests = [] mass-storage = [] -default = ["nettest"] # "debugprint" +default = [] # "debugprint" From 765a3e6294fabb7597a4884493414848ba597771 Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 19:12:15 +0800 Subject: [PATCH 10/11] harden against invalid EC configurations panics happen due to certain default states of the EC wire protocol, due to a MAC address being passed in that is not unicast when garbage data is present. --- services/net/src/main.rs | 49 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/services/net/src/main.rs b/services/net/src/main.rs index d612f1f9e..83f710c7d 100644 --- a/services/net/src/main.rs +++ b/services/net/src/main.rs @@ -32,7 +32,7 @@ use byteorder::{ByteOrder, NetworkEndian}; use smoltcp::iface::{Interface, Config, SocketSet}; use smoltcp::phy::{Device, Tracer}; use smoltcp::socket::{tcp, udp, icmp}; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, IpEndpoint}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, IpEndpoint, HardwareAddress}; use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, Icmpv6Packet, Icmpv6Repr}; use core::num::NonZeroU64; @@ -161,7 +161,7 @@ fn main() -> ! { let timer = ticktimer_server::Ticktimer::new().unwrap(); // we need a trng for port numbers - let trng = trng::Trng::new(&xns).unwrap(); + let mut trng = trng::Trng::new(&xns).unwrap(); // hook the COM interrupt listener let net_cid = xous::connect(net_sid).unwrap(); @@ -180,13 +180,18 @@ fn main() -> ! { let mut net_config: Option = None; // ----------- build the device + let mut config_valid = true; let hw_config = match com.wlan_get_config() { Ok(config) => config, Err(e) => { log::error!("Something is wrong with the EC, got {:?} when requesting a MAC address. Trying our best to bodge through it.", e); + let mut fake_mac = [0u8; 6]; + trng.fill_bytes_via_next(&mut fake_mac); + fake_mac[0] = 2; // locally administered + config_valid = false; Ipv4Conf { dhcp: com_rs::DhcpState::Invalid, - mac: [2, 2, 4, 5, 6, 2], + mac: fake_mac, addr: [169, 254, 0, 2], // link local address gtwy: [169, 254, 0, 1], // something bogus mask: [255, 255, 0, 0,], @@ -198,8 +203,19 @@ fn main() -> ! { log::debug!("My MAC address is: {:x?}", hw_config.mac); MAC_ADDRESS_LSB.store(u32::from_be_bytes(hw_config.mac[2..6].try_into().unwrap()), Ordering::SeqCst); MAC_ADDRESS_MSB.store(u16::from_be_bytes(hw_config.mac[0..2].try_into().unwrap()), Ordering::SeqCst); - - let mut config = Config::new(EthernetAddress(hw_config.mac).into()); + let mac_unchecked: HardwareAddress = EthernetAddress(hw_config.mac).into(); + let mut config = if !mac_unchecked.is_unicast() { + Config::new(mac_unchecked) + } else { + let mut fake_mac = [0u8; 6]; + trng.fill_bytes_via_next(&mut fake_mac); + fake_mac[0] = 2; // locally administered + MAC_ADDRESS_LSB.store(u32::from_be_bytes(fake_mac[2..6].try_into().unwrap()), Ordering::SeqCst); + MAC_ADDRESS_MSB.store(u16::from_be_bytes(fake_mac[0..2].try_into().unwrap()), Ordering::SeqCst); + config_valid = false; + log::warn!("We had a bogus MAC address from the EC, filling in a temporary fake one to avoid panics: {:x?}", fake_mac); + Config::new(EthernetAddress(fake_mac).into()) + }; config.random_seed = trng.get_u64().unwrap(); let device = device::NetPhy::new(&xns, net_cid); @@ -328,6 +344,29 @@ fn main() -> ! { }); let mut self_sender: Option:: = None; loop { + if !config_valid { // try to fix our configuration from a bogus default to something valid... + match com.wlan_get_config() { + Ok(hw_config) => { + let mac_unchecked: HardwareAddress = EthernetAddress(hw_config.mac).into(); + if mac_unchecked.is_unicast() { + MAC_ADDRESS_LSB.store(u32::from_be_bytes(hw_config.mac[2..6].try_into().unwrap()), Ordering::SeqCst); + MAC_ADDRESS_MSB.store(u16::from_be_bytes(hw_config.mac[0..2].try_into().unwrap()), Ordering::SeqCst); + config = Config::new(mac_unchecked); + config.random_seed = trng.get_u64().unwrap(); + // rebuild the interface with the new config + iface = Interface::new(config, &mut device, Instant::from_millis(timer.elapsed_ms() as i64)); + config_valid = true; + } else { + // else, config_valid stays false, and we try again next time around + log::warn!("Non-unicast MAC address reported by the EC: {:x?}, config invalid!", hw_config.mac); + timer.sleep_ms(900).unwrap(); // throttle the net crate so that the COM may have a chance to restore the EC. + } + } + Err(e) => { + log::warn!("Something is still wrong in the EC, got {:?}", e); + } + } + } let now = timer.elapsed_ms(); let timestamp = Instant::from_millis(now as i64); let deadline = match iface.poll_at(timestamp, &sockets) { From d330376fba0b80c2256af57c30a99f1e4cb92a6b Mon Sep 17 00:00:00 2001 From: bunnie Date: Tue, 3 Oct 2023 19:12:49 +0800 Subject: [PATCH 11/11] update release notes --- RELEASE-v0.9.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE-v0.9.md b/RELEASE-v0.9.md index 5cb095678..f80095e0b 100644 --- a/RELEASE-v0.9.md +++ b/RELEASE-v0.9.md @@ -408,6 +408,9 @@ perform the Xous firmware upgrade. This requires running manual update commands, ## New in v0.9.15 - refresh item cache after leaving vault host readout mode - Regressions have bee found in Rust 1.72. We suspect the llvm back-end for RV32 is emitting invalid code, see issue #416 and #417 for more details. For now, the optimization level has been set to `s` as a work-around. +- Network stack is updated to work with the `main` branch of `smoltcp`. This is not intended as a release configuration -- this note is here so that when a release is snapshotted out, we remember to pin to a particular commit (or ideally an official release, if one happens in time). + - This fixes a number of long-standing issues, including #210 and #407. + - Fairly major overhaul to the network stack. We now use mspc primitives to implement the wait/poll loop, which should make the net stack much more efficient and robust. ## Roadmap - Lots of testing and bug fixes