wl-nl80211-0.2.0/.cargo_vcs_info.json0000644000000001360000000000100124600ustar { "git": { "sha1": "e0580ec9fab48b4634dc6ad1b982dcbadc3d5a3d" }, "path_in_vcs": "" }wl-nl80211-0.2.0/.github/workflows/clippy-rustfmt.yml000064400000000000000000000012701046102023000203720ustar 00000000000000name: Rustfmt and clippy check on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: rustfmt_clippy: strategy: fail-fast: true name: Rustfmt and clippy check runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust Nightly run: | rustup override set nightly rustup update nightly rustup component add rustfmt clippy - name: rustfmt run: cargo fmt --all -- --check - name: clippy-tokio-socket run: cargo clippy - name: clippy-smol-socket run: cargo clippy --no-default-features --features smol_socket wl-nl80211-0.2.0/.github/workflows/license.yml000064400000000000000000000005201046102023000170070ustar 00000000000000name: license on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: check-license: name: Check License runs-on: ubuntu-latest timeout-minutes: 3 steps: - uses: actions/checkout@v3 - name: Check License Header uses: apache/skywalking-eyes@v0.3.0 wl-nl80211-0.2.0/.github/workflows/main.yml000064400000000000000000000011021046102023000163060ustar 00000000000000name: CI on: pull_request: types: [opened, synchronize, reopened] push: branches: - main jobs: ci: name: CI (stable) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install Rust Stable run: | rustup override set stable rustup update stable - name: Test with default feature run: cargo test - name: Test with tokio feature run: cargo test --features tokio_socket - name: Test with smol_socket feature run: cargo test --features smol_socket wl-nl80211-0.2.0/.gitignore000064400000000000000000000000411046102023000132330ustar 00000000000000Cargo.lock target vendor/ *.swp wl-nl80211-0.2.0/.licenserc.yaml000064400000000000000000000003711046102023000141620ustar 00000000000000header: license: content: | SPDX-License-Identifier: MIT paths-ignore: - 'target' - '**/*.toml' - '**/*.lock' - '**/*.yml' - '**/*.md' - 'CHANGELOG' - 'LICENSE-MIT' - '.gitignore' comment: on-failure wl-nl80211-0.2.0/.rustfmt.toml000064400000000000000000000001141046102023000137230ustar 00000000000000max_width = 80 wrap_comments = true reorder_imports = true edition = "2021" wl-nl80211-0.2.0/CHANGELOG000064400000000000000000000012641046102023000124650ustar 00000000000000# Changelog ## [0.2.0] - 2024-09-21 ### Breaking changes - Changed `Nl80211Attr::WiPhyFreq` to `Nl80211Attr::WiphyFreq`. (2a4dbe1) - Changed `Nl80211StationInfo::Signal` from u8 to i8. (79e4010) - Changed Nl80211Message.nlas to Nl80211Message.attributes. (1b6679d) ### New features - Add support of parsing netlink message reply of `iw phy`. (2a4dbe1) - Add support of station. (19d03a5) ### Bug fixes - N/A ## [0.1.2] - 2023-07-10 ### Breaking changes - N/A ### New features - N/A ### Bug fixes - Use latest rust-netlink crates. (9e67599) ## [0.1.1] - 2023-01-28 ### Breaking changes - N/A ### New features - N/A ### Bug fixes - Use latest rust-netlink crates. (a5f55b5) wl-nl80211-0.2.0/Cargo.lock0000644000000773710000000000100104520ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anyhow" version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" [[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-channel" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", "fastrand 2.1.1", "futures-lite 2.3.0", "slab", ] [[package]] name = "async-global-executor" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", "async-io 2.3.4", "async-lock 3.4.0", "blocking", "futures-lite 2.3.0", "once_cell", ] [[package]] name = "async-io" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", "futures-lite 1.13.0", "log", "parking", "polling 2.8.0", "rustix 0.37.27", "slab", "socket2 0.4.10", "waker-fn", ] [[package]] name = "async-io" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", "polling 3.7.3", "rustix 0.38.36", "slab", "tracing", "windows-sys 0.59.0", ] [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ "event-listener 2.5.3", ] [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-std" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-channel 1.9.0", "async-global-executor", "async-io 2.3.4", "async-lock 3.4.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite 2.3.0", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", "winapi", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", "futures-lite 2.3.0", "piper", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "env_logger" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", "log", "regex", "termcolor", ] [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", "pin-project-lite", ] [[package]] name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] [[package]] name = "fastrand" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "futures" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ "fastrand 1.9.0", "futures-core", "futures-io", "memchr", "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "futures-lite" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "fastrand 2.1.1", "futures-core", "futures-io", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-sink" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "genetlink" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f890076c1faa1298bf747ce3694a8d9e0d2cc4b06fe293f12dd95742bfd079f" dependencies = [ "futures", "log", "netlink-packet-core", "netlink-packet-generic", "netlink-packet-utils", "netlink-proto", "thiserror", ] [[package]] name = "gimli" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gloo-timers" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "instant" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "io-lifetimes" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] [[package]] name = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", ] [[package]] name = "mio" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", ] [[package]] name = "netlink-packet-core" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", "netlink-packet-utils", ] [[package]] name = "netlink-packet-generic" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd7eb8ad331c84c6b8cb7f685b448133e5ad82e1ffd5acafac374af4a5a308b" dependencies = [ "anyhow", "byteorder", "netlink-packet-core", "netlink-packet-utils", ] [[package]] name = "netlink-packet-utils" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", "paste", "thiserror", ] [[package]] name = "netlink-proto" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", "thiserror", "tokio", ] [[package]] name = "netlink-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ "async-io 1.13.0", "bytes", "futures", "libc", "log", "tokio", ] [[package]] name = "object" version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand 2.1.1", "futures-io", ] [[package]] name = "polling" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", "log", "pin-project-lite", "windows-sys 0.48.0", ] [[package]] name = "polling" version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", "rustix 0.38.36", "tracing", "windows-sys 0.59.0", ] [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", "windows-sys 0.48.0", ] [[package]] name = "rustix" version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "socket2" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "syn" version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tokio" version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2 0.5.7", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "value-bag" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" [[package]] name = "waker-fn" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wl-nl80211" version = "0.2.0" dependencies = [ "anyhow", "async-std", "bitflags 2.6.0", "byteorder", "env_logger", "futures", "genetlink", "log", "netlink-packet-core", "netlink-packet-generic", "netlink-packet-utils", "netlink-proto", "netlink-sys", "thiserror", "tokio", ] wl-nl80211-0.2.0/Cargo.toml0000644000000044400000000000100104600ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "wl-nl80211" version = "0.2.0" authors = ["Gris Ge "] build = false autobins = false autoexamples = false autotests = false autobenches = false description = "Linux kernel wireless(802.11) netlink Library" homepage = "https://github.com/rust-netlink/wl-nl80211" readme = "README.md" keywords = ["network"] categories = [ "network-programming", "os", ] license = "MIT" repository = "https://github.com/rust-netlink/wl-nl80211" [lib] name = "wl_nl80211" crate-type = ["lib"] path = "src/lib.rs" [[example]] name = "dump_nl80211_iface" path = "examples/dump_nl80211_iface.rs" [[example]] name = "dump_nl80211_station" path = "examples/dump_nl80211_station.rs" [[example]] name = "dump_nl80211_wiphy" path = "examples/dump_nl80211_wiphy.rs" [dependencies.anyhow] version = "1.0.44" [dependencies.async-std] version = "1.9.0" optional = true [dependencies.bitflags] version = "2" [dependencies.byteorder] version = "1.4.3" [dependencies.futures] version = "0.3.17" [dependencies.genetlink] version = "0.2.5" default-features = false [dependencies.log] version = "0.4.14" [dependencies.netlink-packet-core] version = "0.7.0" [dependencies.netlink-packet-generic] version = "0.3.3" [dependencies.netlink-packet-utils] version = "0.5.2" [dependencies.netlink-proto] version = "0.11.2" default-features = false [dependencies.netlink-sys] version = "0.8.4" [dependencies.thiserror] version = "1.0.29" [dependencies.tokio] version = "1.0.1" features = ["rt"] optional = true [dev-dependencies.env_logger] version = "0.9.0" [dev-dependencies.tokio] version = "1.11.0" features = [ "macros", "rt", "rt-multi-thread", ] [features] default = ["tokio_socket"] smol_socket = [ "netlink-proto/smol_socket", "async-std", ] tokio_socket = [ "netlink-proto/tokio_socket", "tokio", ] wl-nl80211-0.2.0/Cargo.toml.orig000064400000000000000000000024211046102023000141360ustar 00000000000000[package] # The crate name `nl80211` is occupied name = "wl-nl80211" version = "0.2.0" authors = ["Gris Ge "] license = "MIT" edition = "2021" description = "Linux kernel wireless(802.11) netlink Library" homepage = "https://github.com/rust-netlink/wl-nl80211" repository = "https://github.com/rust-netlink/wl-nl80211" keywords = ["network"] categories = ["network-programming", "os"] readme = "README.md" [lib] name = "wl_nl80211" path = "src/lib.rs" crate-type = ["lib"] [features] default = ["tokio_socket"] tokio_socket = ["netlink-proto/tokio_socket", "tokio"] smol_socket = ["netlink-proto/smol_socket", "async-std"] [dependencies] anyhow = "1.0.44" async-std = { version = "1.9.0", optional = true} bitflags = "2" byteorder = "1.4.3" futures = "0.3.17" log = "0.4.14" thiserror = "1.0.29" tokio = { version = "1.0.1", features = ["rt"], optional = true} genetlink = { default-features = false, version = "0.2.5" } netlink-packet-core = { version = "0.7.0" } netlink-packet-generic = { version = "0.3.3" } netlink-packet-utils = { version = "0.5.2" } netlink-proto = { default-features = false, version = "0.11.2" } netlink-sys = { version = "0.8.4" } [dev-dependencies] tokio = { version = "1.11.0", features = ["macros", "rt", "rt-multi-thread"] } env_logger = "0.9.0" wl-nl80211-0.2.0/LICENSE-MIT000064400000000000000000000027731046102023000127150ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Distributions of all or part of the Software intended to be used by the recipients as they would use the unmodified Software, containing modifications that substantially alter, remove, or disable functionality of the Software, outside of the documented configuration mechanisms provided by the Software, shall be modified such that the Original Author's bug reporting email addresses and urls are either replaced with the contact information of the parties responsible for the changes, or removed entirely. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. wl-nl80211-0.2.0/README.md000064400000000000000000000000721046102023000125260ustar 00000000000000# Rust crate for linux wireless nl80211 netlink interface wl-nl80211-0.2.0/examples/dump_nl80211_iface.rs000064400000000000000000000012311046102023000166120ustar 00000000000000// SPDX-License-Identifier: MIT use futures::stream::TryStreamExt; fn main() { let rt = tokio::runtime::Builder::new_current_thread() .enable_io() .build() .unwrap(); rt.block_on(get_interfaces()); } async fn get_interfaces() { let (connection, handle, _) = wl_nl80211::new_connection().unwrap(); tokio::spawn(connection); let mut interface_handle = handle.interface().get().execute().await; let mut msgs = Vec::new(); while let Some(msg) = interface_handle.try_next().await.unwrap() { msgs.push(msg); } assert!(!msgs.is_empty()); for msg in msgs { println!("{:?}", msg); } } wl-nl80211-0.2.0/examples/dump_nl80211_station.rs000064400000000000000000000020741046102023000172320ustar 00000000000000// SPDX-License-Identifier: MIT use std::env::args; use anyhow::{bail, Context, Error}; use futures::stream::TryStreamExt; fn main() -> Result<(), Error> { let argv: Vec<_> = args().collect(); if argv.len() < 2 { eprintln!("Usage: dump_nl80211_station "); bail!("Required arguments not given"); } let err_msg = format!("Invalid interface index value: {}", argv[1]); let index = argv[1].parse::().context(err_msg)?; let rt = tokio::runtime::Builder::new_current_thread() .enable_io() .build() .unwrap(); rt.block_on(dump_station(index)); Ok(()) } async fn dump_station(if_index: u32) { let (connection, handle, _) = wl_nl80211::new_connection().unwrap(); tokio::spawn(connection); let mut sta_handle = handle.station().dump(if_index).execute().await; let mut msgs = Vec::new(); while let Some(msg) = sta_handle.try_next().await.unwrap() { msgs.push(msg); } assert!(!msgs.is_empty()); for msg in msgs { println!("{:?}", msg); } } wl-nl80211-0.2.0/examples/dump_nl80211_wiphy.rs000064400000000000000000000012371046102023000167110ustar 00000000000000// SPDX-License-Identifier: MIT use futures::stream::TryStreamExt; fn main() { let rt = tokio::runtime::Builder::new_current_thread() .enable_io() .build() .unwrap(); rt.block_on(get_wireless_physics()); } async fn get_wireless_physics() { let (connection, handle, _) = wl_nl80211::new_connection().unwrap(); tokio::spawn(connection); let mut phy_handle = handle.wireless_physic().get().execute().await; let mut msgs = Vec::new(); while let Some(msg) = phy_handle.try_next().await.unwrap() { msgs.push(msg); } assert!(!msgs.is_empty()); for msg in msgs { println!("{:?}", msg); } } wl-nl80211-0.2.0/src/attr.rs000064400000000000000000001611371046102023000133700ustar 00000000000000// SPDX-License-Identifier: MIT // Most documentation comments are copied and modified from linux kernel // include/uapi/linux/nl80211.h which is holding these license disclaimer: /* * 802.11 netlink interface public header * * Copyright 2006-2010 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch * Copyright 2008, 2009 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH * Copyright (C) 2018-2024 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_string, parse_u16, parse_u32, parse_u64, parse_u8}, DecodeError, Emitable, Parseable, ParseableParametrized, }; use crate::{ bytes::{write_u16, write_u32, write_u64}, wiphy::Nl80211Commands, Nl80211Band, Nl80211BandTypes, Nl80211ChannelWidth, Nl80211CipherSuit, Nl80211Command, Nl80211ExtFeature, Nl80211ExtFeatures, Nl80211ExtendedCapability, Nl80211Features, Nl80211HtCapabilityMask, Nl80211HtWiphyChannelType, Nl80211IfMode, Nl80211IfTypeExtCapa, Nl80211IfTypeExtCapas, Nl80211IfaceComb, Nl80211IfaceFrameType, Nl80211InterfaceType, Nl80211InterfaceTypes, Nl80211MloLink, Nl80211StationInfo, Nl80211TransmitQueueStat, Nl80211VhtCapability, Nl80211WowlanTrigersSupport, }; struct MacAddressNlas(Vec); impl std::ops::Deref for MacAddressNlas { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From<&Vec<[u8; ETH_ALEN]>> for MacAddressNlas { fn from(macs: &Vec<[u8; ETH_ALEN]>) -> Self { let mut nlas = Vec::new(); for (i, mac) in macs.iter().enumerate() { let nla = MacAddressNla { index: i as u16, mac: *mac, }; nlas.push(nla); } MacAddressNlas(nlas) } } impl From for Vec<[u8; ETH_ALEN]> { fn from(macs: MacAddressNlas) -> Self { let mut macs = macs; macs.0.drain(..).map(|c| c.mac).collect() } } impl MacAddressNlas { pub fn parse(payload: &[u8]) -> Result { let mut macs: Vec = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let error_msg = format!("Invalid NL80211_ATTR_MAC_ADDRS: {nla:?}"); let nla = &nla.context(error_msg.clone())?; let mut mac = [0u8; ETH_ALEN]; mac.copy_from_slice(&nla.value()[..ETH_ALEN]); macs.push(MacAddressNla { index: index as u16, mac, }); } Ok(Self(macs)) } } struct MacAddressNla { index: u16, mac: [u8; ETH_ALEN], } impl Nla for MacAddressNla { fn value_len(&self) -> usize { ETH_ALEN } fn emit_value(&self, buffer: &mut [u8]) { buffer[..ETH_ALEN].copy_from_slice(&self.mac) } fn kind(&self) -> u16 { self.index } } // const NL80211_ATTR_UNSPEC:u16 = 0; const NL80211_ATTR_WIPHY: u16 = 1; const NL80211_ATTR_WIPHY_NAME: u16 = 2; const NL80211_ATTR_IFINDEX: u16 = 3; const NL80211_ATTR_IFNAME: u16 = 4; const NL80211_ATTR_IFTYPE: u16 = 5; const NL80211_ATTR_MAC: u16 = 6; // const NL80211_ATTR_KEY_DATA:u16 = 7; // const NL80211_ATTR_KEY_IDX:u16 = 8; // const NL80211_ATTR_KEY_CIPHER:u16 = 9; // const NL80211_ATTR_KEY_SEQ:u16 = 10; // const NL80211_ATTR_KEY_DEFAULT:u16 = 11; // const NL80211_ATTR_BEACON_INTERVAL:u16 = 12; // const NL80211_ATTR_DTIM_PERIOD:u16 = 13; // const NL80211_ATTR_BEACON_HEAD:u16 = 14; // const NL80211_ATTR_BEACON_TAIL:u16 = 15; // const NL80211_ATTR_STA_AID:u16 = 16; // const NL80211_ATTR_STA_FLAGS:u16 = 17; // const NL80211_ATTR_STA_LISTEN_INTERVAL:u16 = 18; // const NL80211_ATTR_STA_SUPPORTED_RATES:u16 = 19; // const NL80211_ATTR_STA_VLAN:u16 = 20; const NL80211_ATTR_STA_INFO: u16 = 21; const NL80211_ATTR_WIPHY_BANDS: u16 = 22; // const NL80211_ATTR_MNTR_FLAGS:u16 = 23; // const NL80211_ATTR_MESH_ID:u16 = 24; // const NL80211_ATTR_STA_PLINK_ACTION:u16 = 25; // const NL80211_ATTR_MPATH_NEXT_HOP:u16 = 26; // const NL80211_ATTR_MPATH_INFO:u16 = 27; // const NL80211_ATTR_BSS_CTS_PROT:u16 = 28; // const NL80211_ATTR_BSS_SHORT_PREAMBLE:u16 = 29; // const NL80211_ATTR_BSS_SHORT_SLOT_TIME:u16 = 30; // const NL80211_ATTR_HT_CAPABILITY:u16 = 31; const NL80211_ATTR_SUPPORTED_IFTYPES: u16 = 32; // const NL80211_ATTR_REG_ALPHA2:u16 = 33; // const NL80211_ATTR_REG_RULES:u16 = 34; // const NL80211_ATTR_MESH_CONFIG:u16 = 35; // const NL80211_ATTR_BSS_BASIC_RATES:u16 = 36; // const NL80211_ATTR_WIPHY_TXQ_PARAMS:u16 = 37; const NL80211_ATTR_WIPHY_FREQ: u16 = 38; const NL80211_ATTR_WIPHY_CHANNEL_TYPE: u16 = 39; // const NL80211_ATTR_KEY_DEFAULT_MGMT:u16 = 40; // const NL80211_ATTR_MGMT_SUBTYPE:u16 = 41; // const NL80211_ATTR_IE:u16 = 42; const NL80211_ATTR_MAX_NUM_SCAN_SSIDS: u16 = 43; // const NL80211_ATTR_SCAN_FREQUENCIES:u16 = 44; // const NL80211_ATTR_SCAN_SSIDS:u16 = 45; const NL80211_ATTR_GENERATION: u16 = 46; // const NL80211_ATTR_BSS:u16 = 47; // const NL80211_ATTR_REG_INITIATOR:u16 = 48; // const NL80211_ATTR_REG_TYPE:u16 = 49; const NL80211_ATTR_SUPPORTED_COMMANDS: u16 = 50; // const NL80211_ATTR_FRAME:u16 = 51; const NL80211_ATTR_SSID: u16 = 52; // const NL80211_ATTR_AUTH_TYPE:u16 = 53; // const NL80211_ATTR_REASON_CODE:u16 = 54; // const NL80211_ATTR_KEY_TYPE:u16 = 55; const NL80211_ATTR_MAX_SCAN_IE_LEN: u16 = 56; const NL80211_ATTR_CIPHER_SUITES: u16 = 57; // const NL80211_ATTR_FREQ_BEFORE:u16 = 58; // const NL80211_ATTR_FREQ_AFTER:u16 = 59; // const NL80211_ATTR_FREQ_FIXED:u16 = 60; const NL80211_ATTR_WIPHY_RETRY_SHORT: u16 = 61; const NL80211_ATTR_WIPHY_RETRY_LONG: u16 = 62; const NL80211_ATTR_WIPHY_FRAG_THRESHOLD: u16 = 63; const NL80211_ATTR_WIPHY_RTS_THRESHOLD: u16 = 64; // const NL80211_ATTR_TIMED_OUT:u16 = 65; // const NL80211_ATTR_USE_MFP:u16 = 66; // const NL80211_ATTR_STA_FLAGS2:u16 = 67; // const NL80211_ATTR_CONTROL_PORT:u16 = 68; // const NL80211_ATTR_TESTDATA:u16 = 69; // const NL80211_ATTR_PRIVACY:u16 = 70; // const NL80211_ATTR_DISCONNECTED_BY_AP:u16 = 71; // const NL80211_ATTR_STATUS_CODE:u16 = 72; // const NL80211_ATTR_CIPHER_SUITES_PAIRWISE:u16 = 73; // const NL80211_ATTR_CIPHER_SUITE_GROUP:u16 = 74; // const NL80211_ATTR_WPA_VERSIONS:u16 = 75; // const NL80211_ATTR_AKM_SUITES:u16 = 76; // const NL80211_ATTR_REQ_IE:u16 = 77; // const NL80211_ATTR_RESP_IE:u16 = 78; // const NL80211_ATTR_PREV_BSSID:u16 = 79; // const NL80211_ATTR_KEY:u16 = 80; // const NL80211_ATTR_KEYS:u16 = 81; // const NL80211_ATTR_PID:u16 = 82; const NL80211_ATTR_4ADDR: u16 = 83; // const NL80211_ATTR_SURVEY_INFO:u16 = 84; // const NL80211_ATTR_PMKID:u16 = 85; const NL80211_ATTR_MAX_NUM_PMKIDS: u16 = 86; // const NL80211_ATTR_DURATION:u16 = 87; // const NL80211_ATTR_COOKIE:u16 = 88; const NL80211_ATTR_WIPHY_COVERAGE_CLASS: u16 = 89; // const NL80211_ATTR_TX_RATES:u16 = 90; // const NL80211_ATTR_FRAME_MATCH:u16 = 91; // const NL80211_ATTR_ACK:u16 = 92; // const NL80211_ATTR_PS_STATE:u16 = 93; // const NL80211_ATTR_CQM:u16 = 94; // const NL80211_ATTR_LOCAL_STATE_CHANGE:u16 = 95; // const NL80211_ATTR_AP_ISOLATE:u16 = 96; // const NL80211_ATTR_WIPHY_TX_POWER_SETTING:u16 = 97; const NL80211_ATTR_WIPHY_TX_POWER_LEVEL: u16 = 98; const NL80211_ATTR_TX_FRAME_TYPES: u16 = 99; const NL80211_ATTR_RX_FRAME_TYPES: u16 = 100; // Covered by frame_type.rs // const NL80211_ATTR_FRAME_TYPE:u16 = 101; const NL80211_ATTR_CONTROL_PORT_ETHERTYPE: u16 = 102; // const NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT:u16 = 103; const NL80211_ATTR_SUPPORT_IBSS_RSN: u16 = 104; const NL80211_ATTR_WIPHY_ANTENNA_TX: u16 = 105; const NL80211_ATTR_WIPHY_ANTENNA_RX: u16 = 106; // const NL80211_ATTR_MCAST_RATE:u16 = 107; const NL80211_ATTR_OFFCHANNEL_TX_OK: u16 = 108; // const NL80211_ATTR_BSS_HT_OPMODE:u16 = 109; // const NL80211_ATTR_KEY_DEFAULT_TYPES:u16 = 110; const NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: u16 = 111; // const NL80211_ATTR_MESH_SETUP:u16 = 112; const NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: u16 = 113; const NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: u16 = 114; const NL80211_ATTR_SUPPORT_MESH_AUTH: u16 = 115; // const NL80211_ATTR_STA_PLINK_STATE:u16 = 116; // const NL80211_ATTR_WOWLAN_TRIGGERS:u16 = 117; const NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: u16 = 118; // const NL80211_ATTR_SCHED_SCAN_INTERVAL:u16 = 119; const NL80211_ATTR_INTERFACE_COMBINATIONS: u16 = 120; const NL80211_ATTR_SOFTWARE_IFTYPES: u16 = 121; // const NL80211_ATTR_REKEY_DATA:u16 = 122; const NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: u16 = 123; const NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: u16 = 124; // const NL80211_ATTR_SCAN_SUPP_RATES:u16 = 125; // const NL80211_ATTR_HIDDEN_SSID:u16 = 126; // const NL80211_ATTR_IE_PROBE_RESP:u16 = 127; // const NL80211_ATTR_IE_ASSOC_RESP:u16 = 128; // const NL80211_ATTR_STA_WME:u16 = 129; const NL80211_ATTR_SUPPORT_AP_UAPSD: u16 = 130; const NL80211_ATTR_ROAM_SUPPORT: u16 = 131; // const NL80211_ATTR_SCHED_SCAN_MATCH:u16 = 132; const NL80211_ATTR_MAX_MATCH_SETS: u16 = 133; // const NL80211_ATTR_PMKSA_CANDIDATE:u16 = 134; // const NL80211_ATTR_TX_NO_CCK_RATE:u16 = 135; // const NL80211_ATTR_TDLS_ACTION:u16 = 136; // const NL80211_ATTR_TDLS_DIALOG_TOKEN:u16 = 137; // const NL80211_ATTR_TDLS_OPERATION:u16 = 138; const NL80211_ATTR_TDLS_SUPPORT: u16 = 139; const NL80211_ATTR_TDLS_EXTERNAL_SETUP: u16 = 140; // const NL80211_ATTR_DEVICE_AP_SME:u16 = 141; // const NL80211_ATTR_DONT_WAIT_FOR_ACK:u16 = 142; const NL80211_ATTR_FEATURE_FLAGS: u16 = 143; const NL80211_ATTR_PROBE_RESP_OFFLOAD: u16 = 144; // const NL80211_ATTR_PROBE_RESP:u16 = 145; // const NL80211_ATTR_DFS_REGION:u16 = 146; // const NL80211_ATTR_DISABLE_HT:u16 = 147; const NL80211_ATTR_HT_CAPABILITY_MASK: u16 = 148; // const NL80211_ATTR_NOACK_MAP:u16 = 149; // const NL80211_ATTR_INACTIVITY_TIMEOUT:u16 = 150; // const NL80211_ATTR_RX_SIGNAL_DBM:u16 = 151; // const NL80211_ATTR_BG_SCAN_PERIOD:u16 = 152; const NL80211_ATTR_WDEV: u16 = 153; // const NL80211_ATTR_USER_REG_HINT_TYPE:u16 = 154; // const NL80211_ATTR_CONN_FAILED_REASON:u16 = 155; // const NL80211_ATTR_AUTH_DATA:u16 = 156; const NL80211_ATTR_VHT_CAPABILITY: u16 = 157; // const NL80211_ATTR_SCAN_FLAGS:u16 = 158; const NL80211_ATTR_CHANNEL_WIDTH: u16 = 159; const NL80211_ATTR_CENTER_FREQ1: u16 = 160; const NL80211_ATTR_CENTER_FREQ2: u16 = 161; // const NL80211_ATTR_P2P_CTWINDOW:u16 = 162; // const NL80211_ATTR_P2P_OPPPS:u16 = 163; // const NL80211_ATTR_LOCAL_MESH_POWER_MODE:u16 = 164; // const NL80211_ATTR_ACL_POLICY:u16 = 165; const NL80211_ATTR_MAC_ADDRS: u16 = 166; // const NL80211_ATTR_MAC_ACL_MAX:u16 = 167; // const NL80211_ATTR_RADAR_EVENT:u16 = 168; const NL80211_ATTR_EXT_CAPA: u16 = 169; const NL80211_ATTR_EXT_CAPA_MASK: u16 = 170; // const NL80211_ATTR_STA_CAPABILITY:u16 = 171; // const NL80211_ATTR_STA_EXT_CAPABILITY:u16 = 172; // const NL80211_ATTR_PROTOCOL_FEATURES:u16 = 173; const NL80211_ATTR_SPLIT_WIPHY_DUMP: u16 = 174; // const NL80211_ATTR_DISABLE_VHT:u16 = 175; const NL80211_ATTR_VHT_CAPABILITY_MASK: u16 = 176; // const NL80211_ATTR_MDID:u16 = 177; // const NL80211_ATTR_IE_RIC:u16 = 178; // const NL80211_ATTR_CRIT_PROT_ID:u16 = 179; // const NL80211_ATTR_MAX_CRIT_PROT_DURATION:u16 = 180; // const NL80211_ATTR_PEER_AID:u16 = 181; // const NL80211_ATTR_COALESCE_RULE:u16 = 182; // const NL80211_ATTR_CH_SWITCH_COUNT:u16 = 183; // const NL80211_ATTR_CH_SWITCH_BLOCK_TX:u16 = 184; // const NL80211_ATTR_CSA_IES:u16 = 185; // const NL80211_ATTR_CNTDWN_OFFS_BEACON:u16 = 186; // const NL80211_ATTR_CNTDWN_OFFS_PRESP:u16 = 187; // const NL80211_ATTR_RXMGMT_FLAGS:u16 = 188; // const NL80211_ATTR_STA_SUPPORTED_CHANNELS:u16 = 189; // const NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES:u16 = 190; // const NL80211_ATTR_HANDLE_DFS:u16 = 191; // const NL80211_ATTR_SUPPORT_5_MHZ:u16 = 192; // const NL80211_ATTR_SUPPORT_10_MHZ:u16 = 193; // const NL80211_ATTR_OPMODE_NOTIF:u16 = 194; // const NL80211_ATTR_VENDOR_ID:u16 = 195; // const NL80211_ATTR_VENDOR_SUBCMD:u16 = 196; // const NL80211_ATTR_VENDOR_DATA:u16 = 197; // const NL80211_ATTR_VENDOR_EVENTS:u16 = 198; // const NL80211_ATTR_QOS_MAP:u16 = 199; // const NL80211_ATTR_MAC_HINT:u16 = 200; // const NL80211_ATTR_WIPHY_FREQ_HINT:u16 = 201; // const NL80211_ATTR_MAX_AP_ASSOC_STA:u16 = 202; // const NL80211_ATTR_TDLS_PEER_CAPABILITY:u16 = 203; // const NL80211_ATTR_SOCKET_OWNER:u16 = 204; // const NL80211_ATTR_CSA_C_OFFSETS_TX:u16 = 205; const NL80211_ATTR_MAX_CSA_COUNTERS: u16 = 206; // const NL80211_ATTR_TDLS_INITIATOR:u16 = 207; // const NL80211_ATTR_USE_RRM:u16 = 208; // const NL80211_ATTR_WIPHY_DYN_ACK:u16 = 209; // const NL80211_ATTR_TSID:u16 = 210; // const NL80211_ATTR_USER_PRIO:u16 = 211; // const NL80211_ATTR_ADMITTED_TIME:u16 = 212; // const NL80211_ATTR_SMPS_MODE:u16 = 213; // const NL80211_ATTR_OPER_CLASS:u16 = 214; // const NL80211_ATTR_MAC_MASK:u16 = 215; const NL80211_ATTR_WIPHY_SELF_MANAGED_REG: u16 = 216; const NL80211_ATTR_EXT_FEATURES: u16 = 217; // const NL80211_ATTR_SURVEY_RADIO_STATS:u16 = 218; // const NL80211_ATTR_NETNS_FD:u16 = 219; // const NL80211_ATTR_SCHED_SCAN_DELAY:u16 = 220; // const NL80211_ATTR_REG_INDOOR:u16 = 221; const NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS: u16 = 222; const NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL: u16 = 223; const NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS: u16 = 224; // const NL80211_ATTR_SCHED_SCAN_PLANS:u16 = 225; // const NL80211_ATTR_PBSS:u16 = 226; // const NL80211_ATTR_BSS_SELECT:u16 = 227; // const NL80211_ATTR_STA_SUPPORT_P2P_PS:u16 = 228; // const NL80211_ATTR_PAD:u16 = 229; const NL80211_ATTR_IFTYPE_EXT_CAPA: u16 = 230; // const NL80211_ATTR_MU_MIMO_GROUP_DATA:u16 = 231; // const NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR:u16 = 232; // const NL80211_ATTR_SCAN_START_TIME_TSF:u16 = 233; // const NL80211_ATTR_SCAN_START_TIME_TSF_BSSID:u16 = 234; // const NL80211_ATTR_MEASUREMENT_DURATION:u16 = 235; // const NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY:u16 = 236; // const NL80211_ATTR_MESH_PEER_AID:u16 = 237; // const NL80211_ATTR_NAN_MASTER_PREF:u16 = 238; const NL80211_ATTR_BANDS: u16 = 239; // const NL80211_ATTR_NAN_FUNC:u16 = 240; // const NL80211_ATTR_NAN_MATCH:u16 = 241; // const NL80211_ATTR_FILS_KEK:u16 = 242; // const NL80211_ATTR_FILS_NONCES:u16 = 243; // const NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED:u16 = 244; // const NL80211_ATTR_BSSID:u16 = 245; // const NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI:u16 = 246; // const NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST:u16 = 247; // const NL80211_ATTR_TIMEOUT_REASON:u16 = 248; // const NL80211_ATTR_FILS_ERP_USERNAME:u16 = 249; // const NL80211_ATTR_FILS_ERP_REALM:u16 = 250; // const NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM:u16 = 251; // const NL80211_ATTR_FILS_ERP_RRK:u16 = 252; // const NL80211_ATTR_FILS_CACHE_ID:u16 = 253; // const NL80211_ATTR_PMK:u16 = 254; // const NL80211_ATTR_SCHED_SCAN_MULTI:u16 = 255; const NL80211_ATTR_SCHED_SCAN_MAX_REQS: u16 = 256; // const NL80211_ATTR_WANT_1X_4WAY_HS:u16 = 257; // const NL80211_ATTR_PMKR0_NAME:u16 = 258; // const NL80211_ATTR_PORT_AUTHORIZED:u16 = 259; // const NL80211_ATTR_EXTERNAL_AUTH_ACTION:u16 = 260; // const NL80211_ATTR_EXTERNAL_AUTH_SUPPORT:u16 = 261; // const NL80211_ATTR_NSS:u16 = 262; // const NL80211_ATTR_ACK_SIGNAL:u16 = 263; // const NL80211_ATTR_CONTROL_PORT_OVER_NL80211:u16 = 264; const NL80211_ATTR_TXQ_STATS: u16 = 265; const NL80211_ATTR_TXQ_LIMIT: u16 = 266; const NL80211_ATTR_TXQ_MEMORY_LIMIT: u16 = 267; const NL80211_ATTR_TXQ_QUANTUM: u16 = 268; // const NL80211_ATTR_HE_CAPABILITY:u16 = 269; // const NL80211_ATTR_FTM_RESPONDER:u16 = 270; // const NL80211_ATTR_FTM_RESPONDER_STATS:u16 = 271; // const NL80211_ATTR_TIMEOUT:u16 = 272; // const NL80211_ATTR_PEER_MEASUREMENTS:u16 = 273; // const NL80211_ATTR_AIRTIME_WEIGHT:u16 = 274; // const NL80211_ATTR_STA_TX_POWER_SETTING:u16 = 275; // const NL80211_ATTR_STA_TX_POWER:u16 = 276; // const NL80211_ATTR_SAE_PASSWORD:u16 = 277; // const NL80211_ATTR_TWT_RESPONDER:u16 = 278; // const NL80211_ATTR_HE_OBSS_PD:u16 = 279; // const NL80211_ATTR_WIPHY_EDMG_CHANNELS:u16 = 280; // const NL80211_ATTR_WIPHY_EDMG_BW_CONFIG:u16 = 281; // const NL80211_ATTR_VLAN_ID:u16 = 282; // const NL80211_ATTR_HE_BSS_COLOR:u16 = 283; // const NL80211_ATTR_IFTYPE_AKM_SUITES:u16 = 284; // const NL80211_ATTR_TID_CONFIG:u16 = 285; // const NL80211_ATTR_CONTROL_PORT_NO_PREAUTH:u16 = 286; // const NL80211_ATTR_PMK_LIFETIME:u16 = 287; // const NL80211_ATTR_PMK_REAUTH_THRESHOLD:u16 = 288; // const NL80211_ATTR_RECEIVE_MULTICAST:u16 = 289; const NL80211_ATTR_WIPHY_FREQ_OFFSET: u16 = 290; // const NL80211_ATTR_CENTER_FREQ1_OFFSET:u16 = 291; // const NL80211_ATTR_SCAN_FREQ_KHZ:u16 = 292; // const NL80211_ATTR_HE_6GHZ_CAPABILITY:u16 = 293; // const NL80211_ATTR_FILS_DISCOVERY:u16 = 294; // const NL80211_ATTR_UNSOL_BCAST_PROBE_RESP:u16 = 295; // const NL80211_ATTR_S1G_CAPABILITY:u16 = 296; // const NL80211_ATTR_S1G_CAPABILITY_MASK:u16 = 297; // const NL80211_ATTR_SAE_PWE:u16 = 298; // const NL80211_ATTR_RECONNECT_REQUESTED:u16 = 299; // const NL80211_ATTR_SAR_SPEC:u16 = 300; // const NL80211_ATTR_DISABLE_HE:u16 = 301; // const NL80211_ATTR_OBSS_COLOR_BITMAP:u16 = 302; // const NL80211_ATTR_COLOR_CHANGE_COUNT:u16 = 303; // const NL80211_ATTR_COLOR_CHANGE_COLOR:u16 = 304; // const NL80211_ATTR_COLOR_CHANGE_ELEMS:u16 = 305; // const NL80211_ATTR_MBSSID_CONFIG:u16 = 306; // const NL80211_ATTR_MBSSID_ELEMS:u16 = 307; // const NL80211_ATTR_RADAR_BACKGROUND:u16 = 308; // const NL80211_ATTR_AP_SETTINGS_FLAGS:u16 = 309; // const NL80211_ATTR_EHT_CAPABILITY:u16 = 310; // const NL80211_ATTR_DISABLE_EHT:u16 = 311; const NL80211_ATTR_MLO_LINKS: u16 = 312; // Covered in mlo.rs // const NL80211_ATTR_MLO_LINK_ID: u16 = 313; // const NL80211_ATTR_MLD_ADDR:u16 = 314; // const NL80211_ATTR_MLO_SUPPORT:u16 = 315; const NL80211_ATTR_MAX_NUM_AKM_SUITES: u16 = 316; const NL80211_ATTR_EML_CAPABILITY: u16 = 317; const NL80211_ATTR_MLD_CAPA_AND_OPS: u16 = 318; // const NL80211_ATTR_TX_HW_TIMESTAMP:u16 = 319; // const NL80211_ATTR_RX_HW_TIMESTAMP:u16 = 320; // const NL80211_ATTR_TD_BITMAP:u16 = 321; // const NL80211_ATTR_PUNCT_BITMAP:u16 = 322; const NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: u16 = 323; // const NL80211_ATTR_HW_TIMESTAMP_ENABLED:u16 = 324; // const NL80211_ATTR_EMA_RNR_ELEMS:u16 = 325; // const NL80211_ATTR_MLO_LINK_DISABLED:u16 = 326; // const NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA:u16 = 327; // const NL80211_ATTR_MLO_TTLM_DLINK:u16 = 328; // const NL80211_ATTR_MLO_TTLM_ULINK:u16 = 329; // const NL80211_ATTR_ASSOC_SPP_AMSDU:u16 = 330; // const NL80211_ATTR_WIPHY_RADIOS:u16 = 331; // const NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS:u16 = 332; const ETH_ALEN: usize = 6; #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum Nl80211Attr { Wiphy(u32), WiphyName(String), IfIndex(u32), IfName(String), IfType(Nl80211InterfaceType), IfTypeExtCap(Vec), Mac([u8; ETH_ALEN]), MacAddrs(Vec<[u8; ETH_ALEN]>), Wdev(u64), Generation(u32), Use4Addr(bool), WiphyFreq(u32), WiphyFreqOffset(u32), WiphyChannelType(Nl80211HtWiphyChannelType), ChannelWidth(Nl80211ChannelWidth), CenterFreq1(u32), CenterFreq2(u32), WiphyTxPowerLevel(u32), Ssid(String), StationInfo(Vec), TransmitQueueStats(Vec), TransmitQueueLimit(u32), TransmitQueueMemoryLimit(u32), TransmitQueueQuantum(u32), MloLinks(Vec), WiphyRetryShort(u8), WiphyRetryLong(u8), WiphyFragThreshold(u32), WiphyRtsThreshold(u32), WiphyCoverageClass(u8), MaxNumScanSsids(u8), MaxNumSchedScanSsids(u8), MaxScanIeLen(u16), MaxSchedScanIeLen(u16), MaxMatchSets(u8), SupportIbssRsn, SupportMeshAuth, SupportApUapsd, RoamSupport, TdlsSupport, TdlsExternalSetup, CipherSuites(Vec), MaxNumPmkids(u8), ControlPortEthertype, WiphyAntennaAvailTx(u32), WiphyAntennaAvailRx(u32), ApProbeRespOffload(u32), WiphyAntennaTx(u32), WiphyAntennaRx(u32), SupportedIftypes(Vec), WiphyBands(Vec), /// flag attribute, indicate userspace supports /// receiving the data for a single wiphy split across multiple /// messages, given with wiphy dump message SplitWiphyDump, SupportedCommand(Vec), /// in milliseconds MaxRemainOnChannelDuration(u32), OffchannelTxOk, WowlanTrigersSupport(Vec), SoftwareIftypes(Vec), Features(Nl80211Features), ExtFeatures(Vec), InterfaceCombination(Vec), HtCapabilityMask(Nl80211HtCapabilityMask), TxFrameTypes(Vec), RxFrameTypes(Vec), MaxNumSchedScanPlans(u32), MaxScanPlanInterval(u32), MaxScanPlanIterations(u32), ExtCap(Nl80211ExtendedCapability), ExtCapMask(Nl80211ExtendedCapability), VhtCap(Nl80211VhtCapability), VhtCapMask(Nl80211VhtCapability), MaxCsaCounters(u8), WiphySelfManagedReg, SchedScanMaxReqs(u32), EmlCapability(u16), MldCapaAndOps(u16), Bands(Nl80211BandTypes), /// Maximum number of AKM suites allowed for connect command. MaxNumAkmSuites(u16), /// Maximum number of peers that HW timestamping can be enabled for /// concurrently. A value of 0xffff indicates setting for all peers(i.e. /// not specifying an address with set hardware timestamp) is /// supported. MaxHwTimestampPeers(u16), Other(DefaultNla), } impl Nla for Nl80211Attr { fn value_len(&self) -> usize { match self { Self::IfIndex(_) | Self::Wiphy(_) | Self::IfType(_) | Self::Generation(_) | Self::WiphyFreq(_) | Self::WiphyFreqOffset(_) | Self::WiphyChannelType(_) | Self::CenterFreq1(_) | Self::CenterFreq2(_) | Self::WiphyTxPowerLevel(_) | Self::ChannelWidth(_) | Self::WiphyFragThreshold(_) | Self::WiphyRtsThreshold(_) | Self::WiphyAntennaAvailTx(_) | Self::WiphyAntennaAvailRx(_) | Self::ApProbeRespOffload(_) | Self::WiphyAntennaTx(_) | Self::WiphyAntennaRx(_) | Self::MaxNumSchedScanPlans(_) | Self::MaxScanPlanInterval(_) | Self::MaxScanPlanIterations(_) | Self::SchedScanMaxReqs(_) | Self::TransmitQueueLimit(_) | Self::TransmitQueueMemoryLimit(_) | Self::TransmitQueueQuantum(_) => 4, Self::Wdev(_) => 8, Self::IfName(s) | Self::Ssid(s) | Self::WiphyName(s) => s.len() + 1, Self::Mac(_) => ETH_ALEN, Self::MacAddrs(s) => { MacAddressNlas::from(s).as_slice().buffer_len() } Self::Use4Addr(_) => 1, Self::WiphyRetryShort(_) | Self::WiphyRetryLong(_) | Self::WiphyCoverageClass(_) | Self::MaxNumScanSsids(_) | Self::MaxNumSchedScanSsids(_) | Self::MaxMatchSets(_) | Self::MaxNumPmkids(_) => 1, Self::TransmitQueueStats(nlas) => nlas.as_slice().buffer_len(), Self::StationInfo(nlas) => nlas.as_slice().buffer_len(), Self::MloLinks(links) => links.as_slice().buffer_len(), Self::MaxScanIeLen(_) | Self::MaxSchedScanIeLen(_) => 2, Self::SupportIbssRsn | Self::SupportMeshAuth | Self::SupportApUapsd | Self::RoamSupport | Self::TdlsSupport | Self::TdlsExternalSetup | Self::ControlPortEthertype | Self::OffchannelTxOk | Self::WiphySelfManagedReg => 0, Self::CipherSuites(s) => 4 * s.len(), Self::SupportedIftypes(s) => s.as_slice().buffer_len(), Self::WiphyBands(s) => s.as_slice().buffer_len(), Self::SplitWiphyDump => 0, Self::SupportedCommand(s) => { Nl80211Commands::from(s).as_slice().buffer_len() } Self::MaxRemainOnChannelDuration(_) => 4, Self::WowlanTrigersSupport(s) => s.as_slice().buffer_len(), Self::SoftwareIftypes(s) => { Nl80211InterfaceTypes::from(s).as_slice().buffer_len() } Self::Features(_) => 4, Self::ExtFeatures(_) => Nl80211ExtFeatures::LENGTH, Self::InterfaceCombination(s) => s.as_slice().buffer_len(), Self::HtCapabilityMask(_) => Nl80211HtCapabilityMask::LENGTH, Self::TxFrameTypes(s) => s.as_slice().buffer_len(), Self::RxFrameTypes(s) => s.as_slice().buffer_len(), Self::ExtCap(v) => v.len(), Self::ExtCapMask(v) => v.len(), Self::VhtCap(v) => v.buffer_len(), Self::VhtCapMask(v) => v.buffer_len(), Self::MaxCsaCounters(_) => 1, Self::IfTypeExtCap(s) => { Nl80211IfTypeExtCapas::from(s).as_slice().buffer_len() } Self::EmlCapability(_) | Self::MldCapaAndOps(_) | Self::MaxNumAkmSuites(_) | Self::MaxHwTimestampPeers(_) => 2, Self::Bands(_) => Nl80211BandTypes::LENGTH, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Wiphy(_) => NL80211_ATTR_WIPHY, Self::WiphyName(_) => NL80211_ATTR_WIPHY_NAME, Self::IfIndex(_) => NL80211_ATTR_IFINDEX, Self::IfName(_) => NL80211_ATTR_IFNAME, Self::IfType(_) => NL80211_ATTR_IFTYPE, Self::Mac(_) => NL80211_ATTR_MAC, Self::MacAddrs(_) => NL80211_ATTR_MAC_ADDRS, Self::Wdev(_) => NL80211_ATTR_WDEV, Self::Generation(_) => NL80211_ATTR_GENERATION, Self::Use4Addr(_) => NL80211_ATTR_4ADDR, Self::WiphyFreq(_) => NL80211_ATTR_WIPHY_FREQ, Self::WiphyFreqOffset(_) => NL80211_ATTR_WIPHY_FREQ_OFFSET, Self::WiphyChannelType(_) => NL80211_ATTR_WIPHY_CHANNEL_TYPE, Self::ChannelWidth(_) => NL80211_ATTR_CHANNEL_WIDTH, Self::CenterFreq1(_) => NL80211_ATTR_CENTER_FREQ1, Self::CenterFreq2(_) => NL80211_ATTR_CENTER_FREQ2, Self::WiphyTxPowerLevel(_) => NL80211_ATTR_WIPHY_TX_POWER_LEVEL, Self::Ssid(_) => NL80211_ATTR_SSID, Self::StationInfo(_) => NL80211_ATTR_STA_INFO, Self::TransmitQueueStats(_) => NL80211_ATTR_TXQ_STATS, Self::TransmitQueueLimit(_) => NL80211_ATTR_TXQ_LIMIT, Self::TransmitQueueMemoryLimit(_) => NL80211_ATTR_TXQ_MEMORY_LIMIT, Self::TransmitQueueQuantum(_) => NL80211_ATTR_TXQ_QUANTUM, Self::MloLinks(_) => NL80211_ATTR_MLO_LINKS, Self::WiphyRetryShort(_) => NL80211_ATTR_WIPHY_RETRY_SHORT, Self::WiphyRetryLong(_) => NL80211_ATTR_WIPHY_RETRY_LONG, Self::WiphyFragThreshold(_) => NL80211_ATTR_WIPHY_FRAG_THRESHOLD, Self::WiphyRtsThreshold(_) => NL80211_ATTR_WIPHY_RTS_THRESHOLD, Self::WiphyCoverageClass(_) => NL80211_ATTR_WIPHY_COVERAGE_CLASS, Self::MaxNumScanSsids(_) => NL80211_ATTR_MAX_NUM_SCAN_SSIDS, Self::MaxNumSchedScanSsids(_) => { NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS } Self::MaxScanIeLen(_) => NL80211_ATTR_MAX_SCAN_IE_LEN, Self::MaxSchedScanIeLen(_) => NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, Self::MaxMatchSets(_) => NL80211_ATTR_MAX_MATCH_SETS, Self::SupportIbssRsn => NL80211_ATTR_SUPPORT_IBSS_RSN, Self::SupportMeshAuth => NL80211_ATTR_SUPPORT_MESH_AUTH, Self::SupportApUapsd => NL80211_ATTR_SUPPORT_AP_UAPSD, Self::RoamSupport => NL80211_ATTR_ROAM_SUPPORT, Self::TdlsSupport => NL80211_ATTR_TDLS_SUPPORT, Self::TdlsExternalSetup => NL80211_ATTR_TDLS_EXTERNAL_SETUP, Self::CipherSuites(_) => NL80211_ATTR_CIPHER_SUITES, Self::MaxNumPmkids(_) => NL80211_ATTR_MAX_NUM_PMKIDS, Self::ControlPortEthertype => NL80211_ATTR_CONTROL_PORT_ETHERTYPE, Self::WiphyAntennaAvailTx(_) => NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, Self::WiphyAntennaAvailRx(_) => NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, Self::ApProbeRespOffload(_) => NL80211_ATTR_PROBE_RESP_OFFLOAD, Self::WiphyAntennaTx(_) => NL80211_ATTR_WIPHY_ANTENNA_TX, Self::WiphyAntennaRx(_) => NL80211_ATTR_WIPHY_ANTENNA_RX, Self::SupportedIftypes(_) => NL80211_ATTR_SUPPORTED_IFTYPES, Self::WiphyBands(_) => NL80211_ATTR_WIPHY_BANDS, Self::SplitWiphyDump => NL80211_ATTR_SPLIT_WIPHY_DUMP, Self::SupportedCommand(_) => NL80211_ATTR_SUPPORTED_COMMANDS, Self::MaxRemainOnChannelDuration(_) => { NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION } Self::OffchannelTxOk => NL80211_ATTR_OFFCHANNEL_TX_OK, Self::WowlanTrigersSupport(_) => { NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED } Self::SoftwareIftypes(_) => NL80211_ATTR_SOFTWARE_IFTYPES, Self::Features(_) => NL80211_ATTR_FEATURE_FLAGS, Self::ExtFeatures(_) => NL80211_ATTR_EXT_FEATURES, Self::InterfaceCombination(_) => { NL80211_ATTR_INTERFACE_COMBINATIONS } Self::HtCapabilityMask(_) => NL80211_ATTR_HT_CAPABILITY_MASK, Self::TxFrameTypes(_) => NL80211_ATTR_TX_FRAME_TYPES, Self::RxFrameTypes(_) => NL80211_ATTR_RX_FRAME_TYPES, Self::MaxNumSchedScanPlans(_) => { NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS } Self::MaxScanPlanInterval(_) => NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL, Self::MaxScanPlanIterations(_) => { NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS } Self::ExtCap(_) => NL80211_ATTR_EXT_CAPA, Self::ExtCapMask(_) => NL80211_ATTR_EXT_CAPA_MASK, Self::VhtCap(_) => NL80211_ATTR_VHT_CAPABILITY, Self::VhtCapMask(_) => NL80211_ATTR_VHT_CAPABILITY_MASK, Self::MaxCsaCounters(_) => NL80211_ATTR_MAX_CSA_COUNTERS, Self::WiphySelfManagedReg => NL80211_ATTR_WIPHY_SELF_MANAGED_REG, Self::SchedScanMaxReqs(_) => NL80211_ATTR_SCHED_SCAN_MAX_REQS, Self::IfTypeExtCap(_) => NL80211_ATTR_IFTYPE_EXT_CAPA, Self::EmlCapability(_) => NL80211_ATTR_EML_CAPABILITY, Self::MldCapaAndOps(_) => NL80211_ATTR_MLD_CAPA_AND_OPS, Self::Bands(_) => NL80211_ATTR_BANDS, Self::MaxNumAkmSuites(_) => NL80211_ATTR_MAX_NUM_AKM_SUITES, Self::MaxHwTimestampPeers(_) => NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::IfIndex(d) | Self::Wiphy(d) | Self::Generation(d) | Self::WiphyFreq(d) | Self::WiphyFreqOffset(d) | Self::CenterFreq1(d) | Self::CenterFreq2(d) | Self::WiphyTxPowerLevel(d) | Self::WiphyFragThreshold(d) | Self::WiphyRtsThreshold(d) | Self::WiphyAntennaAvailTx(d) | Self::WiphyAntennaAvailRx(d) | Self::ApProbeRespOffload(d) | Self::WiphyAntennaTx(d) | Self::WiphyAntennaRx(d) | Self::MaxNumSchedScanPlans(d) | Self::MaxScanPlanInterval(d) | Self::MaxScanPlanIterations(d) | Self::SchedScanMaxReqs(d) | Self::TransmitQueueLimit(d) | Self::TransmitQueueMemoryLimit(d) | Self::TransmitQueueQuantum(d) => write_u32(buffer, *d), Self::MaxScanIeLen(d) | Self::MaxSchedScanIeLen(d) => { write_u16(buffer, *d) } Self::Wdev(d) => write_u64(buffer, *d), Self::IfType(d) => write_u32(buffer, (*d).into()), Self::Mac(s) => buffer.copy_from_slice(s), Self::MacAddrs(s) => { MacAddressNlas::from(s).as_slice().emit(buffer) } Self::IfName(s) | Self::Ssid(s) | Self::WiphyName(s) => { buffer[..s.len()].copy_from_slice(s.as_bytes()); buffer[s.len()] = 0; } Self::Use4Addr(d) => buffer[0] = *d as u8, Self::SupportIbssRsn | Self::SupportMeshAuth | Self::SupportApUapsd | Self::RoamSupport | Self::TdlsSupport | Self::TdlsExternalSetup | Self::ControlPortEthertype | Self::OffchannelTxOk | Self::WiphySelfManagedReg => (), Self::WiphyChannelType(d) => write_u32(buffer, (*d).into()), Self::ChannelWidth(d) => write_u32(buffer, (*d).into()), Self::StationInfo(nlas) => nlas.as_slice().emit(buffer), Self::TransmitQueueStats(nlas) => nlas.as_slice().emit(buffer), Self::MloLinks(links) => links.as_slice().emit(buffer), Self::WiphyRetryShort(d) | Self::WiphyRetryLong(d) | Self::WiphyCoverageClass(d) | Self::MaxNumScanSsids(d) | Self::MaxNumSchedScanSsids(d) | Self::MaxMatchSets(d) | Self::MaxNumPmkids(d) => buffer[0] = *d, Self::CipherSuites(suits) => { let nums: Vec = suits.as_slice().iter().map(|s| u32::from(*s)).collect(); for (i, v) in nums.as_slice().iter().enumerate() { buffer[i * 4..(i + 1) * 4] .copy_from_slice(&v.to_ne_bytes()); } } Self::SupportedIftypes(s) => s.as_slice().emit(buffer), Self::WiphyBands(s) => s.as_slice().emit(buffer), Self::SplitWiphyDump => (), Self::SupportedCommand(s) => { Nl80211Commands::from(s).as_slice().emit(buffer) } Self::MaxRemainOnChannelDuration(d) => write_u32(buffer, *d), Self::WowlanTrigersSupport(s) => s.as_slice().emit(buffer), Self::SoftwareIftypes(s) => { Nl80211InterfaceTypes::from(s).as_slice().emit(buffer) } Self::Features(d) => { buffer.copy_from_slice(&d.bits().to_ne_bytes()) } Self::ExtFeatures(s) => Nl80211ExtFeatures::from(s).emit(buffer), Self::InterfaceCombination(s) => s.as_slice().emit(buffer), Self::HtCapabilityMask(s) => s.emit(buffer), Self::TxFrameTypes(s) => s.as_slice().emit(buffer), Self::RxFrameTypes(s) => s.as_slice().emit(buffer), Self::ExtCap(v) => v.emit(buffer), Self::ExtCapMask(v) => v.emit(buffer), Self::VhtCap(v) => v.emit(buffer), Self::VhtCapMask(v) => v.emit(buffer), Self::MaxCsaCounters(v) => buffer[0] = *v, Self::IfTypeExtCap(s) => { Nl80211IfTypeExtCapas::from(s).as_slice().emit(buffer) } Self::EmlCapability(d) | Self::MldCapaAndOps(d) | Self::MaxNumAkmSuites(d) | Self::MaxHwTimestampPeers(d) => write_u16(buffer, *d), Self::Bands(v) => v.emit(buffer), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211Attr { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_ATTR_IFINDEX => { let err_msg = format!("Invalid NL80211_ATTR_IFINDEX value {:?}", payload); Self::IfIndex(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY => { let err_msg = format!("Invalid NL80211_ATTR_WIPHY value {:?}", payload); Self::Wiphy(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_NAME => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_NAME value {:?}", payload ); Self::WiphyName(parse_string(payload).context(err_msg)?) } NL80211_ATTR_IFNAME => { let err_msg = format!("Invalid NL80211_ATTR_IFNAME value {:?}", payload); Self::IfName(parse_string(payload).context(err_msg)?) } NL80211_ATTR_IFTYPE => { Self::IfType(Nl80211InterfaceType::parse(payload)?) } NL80211_ATTR_WDEV => { let err_msg = format!("Invalid NL80211_ATTR_WDEV value {:?}", payload); Self::Wdev(parse_u64(payload).context(err_msg)?) } NL80211_ATTR_MAC => Self::Mac(if payload.len() == ETH_ALEN { let mut ret = [0u8; ETH_ALEN]; ret.copy_from_slice(&payload[..ETH_ALEN]); ret } else { return Err(format!( "Invalid length of NL80211_ATTR_MAC, expected length {} got {:?}", ETH_ALEN, payload ) .into()); }), NL80211_ATTR_MAC_ADDRS => { Self::MacAddrs(MacAddressNlas::parse(payload)?.into()) } NL80211_ATTR_GENERATION => { let err_msg = format!( "Invalid NL80211_ATTR_GENERATION value {:?}", payload ); Self::Generation(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_4ADDR => { let err_msg = format!("Invalid NL80211_ATTR_4ADDR value {:?}", payload); Self::Use4Addr(parse_u8(payload).context(err_msg)? > 0) } NL80211_ATTR_WIPHY_FREQ => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_FREQ value {:?}", payload ); Self::WiphyFreq(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_FREQ_OFFSET => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_FREQ_OFFSET value {:?}", payload ); Self::WiphyFreqOffset(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_CHANNEL_TYPE => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_CHANNEL_TYPE value {:?}", payload ); Self::WiphyChannelType( parse_u32(payload).context(err_msg)?.into(), ) } NL80211_ATTR_CHANNEL_WIDTH => { let err_msg = format!( "Invalid NL80211_ATTR_CHANNEL_WIDTH value {:?}", payload ); Self::ChannelWidth(parse_u32(payload).context(err_msg)?.into()) } NL80211_ATTR_CENTER_FREQ1 => { let err_msg = format!( "Invalid NL80211_ATTR_CENTER_FREQ1 value {:?}", payload ); Self::CenterFreq1(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_CENTER_FREQ2 => { let err_msg = format!( "Invalid NL80211_ATTR_CENTER_FREQ2 value {:?}", payload ); Self::CenterFreq2(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_TX_POWER_LEVEL => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_TX_POWER_LEVEL value {:?}", payload ); Self::WiphyTxPowerLevel(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_SSID => { let err_msg = format!("Invalid NL80211_ATTR_SSID value {:?}", payload); Self::Ssid(parse_string(payload).context(err_msg)?) } NL80211_ATTR_STA_INFO => { let err_msg = format!( "Invalid NL80211_ATTR_STA_INFO value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211StationInfo::parse(nla) .context(err_msg.clone())?, ); } Self::StationInfo(nlas) } NL80211_ATTR_TXQ_STATS => { let err_msg = format!( "Invalid NL80211_ATTR_TXQ_STATS value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211TransmitQueueStat::parse(nla) .context(err_msg.clone())?, ); } Self::TransmitQueueStats(nlas) } NL80211_ATTR_TXQ_LIMIT => { Self::TransmitQueueLimit(parse_u32(payload).context( format!("Invalid NL80211_ATTR_TXQ_LIMIT {payload:?}"), )?) } NL80211_ATTR_TXQ_MEMORY_LIMIT => Self::TransmitQueueMemoryLimit( parse_u32(payload).context(format!( "Invalid NL80211_ATTR_TXQ_MEMORY_LIMIT {payload:?}" ))?, ), NL80211_ATTR_TXQ_QUANTUM => { Self::TransmitQueueQuantum(parse_u32(payload).context( format!("Invalid NL80211_ATTR_TXQ_QUANTUM {payload:?}"), )?) } NL80211_ATTR_MLO_LINKS => { let err_msg = format!( "Invalid NL80211_ATTR_MLO_LINKS value {:?}", payload ); let mut links = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; links.push( Nl80211MloLink::parse(nla).context(err_msg.clone())?, ); } Self::MloLinks(links) } NL80211_ATTR_WIPHY_RETRY_SHORT => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_RETRY_SHORT value {:?}", payload ); Self::WiphyRetryShort(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_RETRY_LONG => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_RETRY_LONG value {:?}", payload ); Self::WiphyRetryLong(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_FRAG_THRESHOLD => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_FRAG_THRESHOLD value {:?}", payload ); Self::WiphyFragThreshold(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_RTS_THRESHOLD => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_RTS_THRESHOLD value {:?}", payload ); Self::WiphyRtsThreshold(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_COVERAGE_CLASS => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_COVERAGE_CLASS value {:?}", payload ); Self::WiphyCoverageClass(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_MAX_NUM_SCAN_SSIDS => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_NUM_SCAN_SSIDS value {:?}", payload ); Self::MaxNumScanSsids(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS value {:?}", payload ); Self::MaxNumSchedScanSsids(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_MAX_SCAN_IE_LEN => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_SCAN_IE_LEN value {:?}", payload ); Self::MaxScanIeLen(parse_u16(payload).context(err_msg)?) } NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN value {:?}", payload ); Self::MaxSchedScanIeLen(parse_u16(payload).context(err_msg)?) } NL80211_ATTR_MAX_MATCH_SETS => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_MATCH_SETS value {:?}", payload ); Self::MaxMatchSets(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_SUPPORT_IBSS_RSN => Self::SupportIbssRsn, NL80211_ATTR_SUPPORT_MESH_AUTH => Self::SupportMeshAuth, NL80211_ATTR_SUPPORT_AP_UAPSD => Self::SupportApUapsd, NL80211_ATTR_ROAM_SUPPORT => Self::RoamSupport, NL80211_ATTR_TDLS_SUPPORT => Self::TdlsSupport, NL80211_ATTR_TDLS_EXTERNAL_SETUP => Self::TdlsExternalSetup, NL80211_ATTR_CIPHER_SUITES => { let err_msg = format!( "Invalid NL80211_ATTR_CIPHER_SUITES value {:?}", payload ); let mut suits = Vec::new(); for i in 0..(payload.len() / 4) { suits.push( parse_u32(&payload[i * 4..(i + 1) * 4]) .context(err_msg.clone())? .into(), ); } Self::CipherSuites(suits) } NL80211_ATTR_MAX_NUM_PMKIDS => { let err_msg = format!( "Invalid NL80211_ATTR_MAX_NUM_PMKIDS value {:?}", payload ); Self::MaxNumPmkids(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_CONTROL_PORT_ETHERTYPE => Self::ControlPortEthertype, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX value {:?}", payload ); Self::WiphyAntennaAvailTx(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX value {:?}", payload ); Self::WiphyAntennaAvailRx(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_PROBE_RESP_OFFLOAD => { let err_msg = format!( "Invalid NL80211_ATTR_PROBE_RESP_OFFLOAD value {:?}", payload ); Self::ApProbeRespOffload(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_ANTENNA_TX => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_ANTENNA_TX value {:?}", payload ); Self::WiphyAntennaTx(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_WIPHY_ANTENNA_RX => { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_ANTENNA_RX value {:?}", payload ); Self::WiphyAntennaRx(parse_u32(payload).context(err_msg)?) } NL80211_ATTR_SUPPORTED_IFTYPES => { let err_msg = format!( "Invalid NL80211_ATTR_SUPPORTED_IFTYPES value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211IfMode::parse(nla).context(err_msg.clone())?, ); } Self::SupportedIftypes(nlas) } NL80211_ATTR_WIPHY_BANDS => { let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!( "Invalid NL80211_ATTR_WIPHY_BANDS value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211Band::parse(nla)?); } Self::WiphyBands(nlas) } NL80211_ATTR_SPLIT_WIPHY_DUMP => Self::SplitWiphyDump, NL80211_ATTR_SUPPORTED_COMMANDS => { Self::SupportedCommand(Nl80211Commands::parse(payload)?.into()) } NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION => { let err_msg = format!( "Invalid \ NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION {payload:?}" ); Self::MaxRemainOnChannelDuration( parse_u32(payload).context(err_msg)?, ) } NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED => { let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!( "Invalid NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED \ value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211WowlanTrigersSupport::parse(nla)?); } Self::WowlanTrigersSupport(nlas) } NL80211_ATTR_OFFCHANNEL_TX_OK => Self::OffchannelTxOk, NL80211_ATTR_SOFTWARE_IFTYPES => Self::SoftwareIftypes( Nl80211InterfaceTypes::parse( payload, "NL80211_ATTR_SOFTWARE_IFTYPES", )? .0, ), NL80211_ATTR_FEATURE_FLAGS => Self::Features( Nl80211Features::from_bits_retain(parse_u32(payload).context( format!("Invalid NL80211_ATTR_FEATURE_FLAGS {payload:?}"), )?), ), NL80211_ATTR_EXT_FEATURES => { Self::ExtFeatures(Nl80211ExtFeatures::parse(payload)?.0) } NL80211_ATTR_INTERFACE_COMBINATIONS => { let mut nlas = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let err_msg = format!( "Invalid NL80211_ATTR_INTERFACE_COMBINATIONS \ value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211IfaceComb::parse_with_param( nla, index as u16, )?); } Self::InterfaceCombination(nlas) } NL80211_ATTR_HT_CAPABILITY_MASK => { Self::HtCapabilityMask(Nl80211HtCapabilityMask::new(payload)) } NL80211_ATTR_RX_FRAME_TYPES => { let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!( "Invalid NL80211_ATTR_RX_FRAME_TYPES value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211IfaceFrameType::parse(nla)?); } Self::RxFrameTypes(nlas) } NL80211_ATTR_TX_FRAME_TYPES => { let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!( "Invalid NL80211_ATTR_RX_FRAME_TYPES value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211IfaceFrameType::parse(nla)?); } Self::TxFrameTypes(nlas) } NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS => { Self::MaxNumSchedScanPlans(parse_u32(payload).context( format!( "Invalid NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS \ {payload:?}" ), )?) } NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL => Self::MaxScanPlanInterval( parse_u32(payload).context(format!( "Invalid NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL \ {payload:?}" ))?, ), NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS => { Self::MaxScanPlanIterations(parse_u32(payload).context( format!( "Invalid NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS \ {payload:?}" ), )?) } NL80211_ATTR_EXT_CAPA => { Self::ExtCap(Nl80211ExtendedCapability::new(payload)) } NL80211_ATTR_EXT_CAPA_MASK => { Self::ExtCapMask(Nl80211ExtendedCapability::new(payload)) } NL80211_ATTR_VHT_CAPABILITY => { Self::VhtCap(Nl80211VhtCapability::parse(payload)?) } NL80211_ATTR_VHT_CAPABILITY_MASK => { Self::VhtCapMask(Nl80211VhtCapability::parse(payload)?) } NL80211_ATTR_MAX_CSA_COUNTERS => { Self::MaxCsaCounters(parse_u8(payload).context(format!( "Invalid NL80211_ATTR_MAX_CSA_COUNTERS {:?}", payload ))?) } NL80211_ATTR_WIPHY_SELF_MANAGED_REG => Self::WiphySelfManagedReg, NL80211_ATTR_SCHED_SCAN_MAX_REQS => { Self::SchedScanMaxReqs(parse_u32(payload).context(format!( "Invalid NL80211_ATTR_SCHED_SCAN_MAX_REQS {:?}", payload ))?) } NL80211_ATTR_IFTYPE_EXT_CAPA => { Self::IfTypeExtCap(Nl80211IfTypeExtCapas::parse(buf)?.into()) } NL80211_ATTR_EML_CAPABILITY => { Self::EmlCapability(parse_u16(payload).context(format!( "Invalid NL80211_ATTR_EML_CAPABILITY {payload:?}" ))?) } NL80211_ATTR_MLD_CAPA_AND_OPS => { Self::MldCapaAndOps(parse_u16(payload).context(format!( "Invalid NL80211_ATTR_MLD_CAPA_AND_OPS {payload:?}" ))?) } NL80211_ATTR_BANDS => { Self::Bands(Nl80211BandTypes::parse(payload)?) } NL80211_ATTR_MAX_NUM_AKM_SUITES => { Self::MaxNumAkmSuites(parse_u16(payload).context(format!( "Invalid NL80211_ATTR_MAX_NUM_AKM_SUITES {:?}", payload ))?) } NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS => Self::MaxHwTimestampPeers( parse_u16(payload).context(format!( "Invalid NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS {:?}", payload ))?, ), _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } wl-nl80211-0.2.0/src/bytes.rs000064400000000000000000000022661046102023000135410ustar 00000000000000// SPDX-License-Identifier: MIT pub(crate) fn write_u16(buffer: &mut [u8], value: u16) { buffer[..2].copy_from_slice(&value.to_ne_bytes()) } pub(crate) fn write_u16_le(buffer: &mut [u8], value: u16) { buffer[..2].copy_from_slice(&value.to_le_bytes()) } pub(crate) fn write_u32(buffer: &mut [u8], value: u32) { buffer[..4].copy_from_slice(&value.to_ne_bytes()) } pub(crate) fn write_u64(buffer: &mut [u8], value: u64) { buffer[..8].copy_from_slice(&value.to_ne_bytes()) } pub(crate) fn get_bit(data: &[u8], pos: usize) -> bool { let index: usize = pos / 8; let bit_pos: usize = pos % 8; if data.len() < index { panic!( "BUG: get_bit(): out of index: got data {:?} pos {pos}", data ); } (data[index] & 1u8 << bit_pos) >= 1 } pub(crate) fn get_bits_as_u8(data: &[u8], start: usize, end: usize) -> u8 { if (end - start) >= 8 { panic!( "BUG: get_bits_as_u8(): more than 8 bits defined by \ start({start}) and end({end})" ); } let mut ret = 0u8; for pos in start..(end + 1) { if get_bit(data, pos) { ret |= 1 << (pos - start); } } ret } wl-nl80211-0.2.0/src/channel.rs000064400000000000000000000054431046102023000140230ustar 00000000000000// SPDX-License-Identifier: MIT const NL80211_CHAN_WIDTH_20_NOHT: u32 = 0; const NL80211_CHAN_WIDTH_20: u32 = 1; const NL80211_CHAN_WIDTH_40: u32 = 2; const NL80211_CHAN_WIDTH_80: u32 = 3; const NL80211_CHAN_WIDTH_80P80: u32 = 4; const NL80211_CHAN_WIDTH_160: u32 = 5; const NL80211_CHAN_WIDTH_5: u32 = 6; const NL80211_CHAN_WIDTH_10: u32 = 7; const NL80211_CHAN_WIDTH_1: u32 = 8; const NL80211_CHAN_WIDTH_2: u32 = 9; const NL80211_CHAN_WIDTH_4: u32 = 10; const NL80211_CHAN_WIDTH_8: u32 = 11; const NL80211_CHAN_WIDTH_16: u32 = 12; const NL80211_CHAN_WIDTH_320: u32 = 13; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211ChannelWidth { NoHt20, Mhz80Plus80, Mhz(u32), Other(u32), } impl From for Nl80211ChannelWidth { fn from(d: u32) -> Self { match d { NL80211_CHAN_WIDTH_20_NOHT => Self::NoHt20, NL80211_CHAN_WIDTH_20 => Self::Mhz(20), NL80211_CHAN_WIDTH_40 => Self::Mhz(40), NL80211_CHAN_WIDTH_80 => Self::Mhz(80), NL80211_CHAN_WIDTH_80P80 => Self::Mhz80Plus80, NL80211_CHAN_WIDTH_160 => Self::Mhz(160), NL80211_CHAN_WIDTH_5 => Self::Mhz(5), NL80211_CHAN_WIDTH_10 => Self::Mhz(10), NL80211_CHAN_WIDTH_1 => Self::Mhz(1), NL80211_CHAN_WIDTH_2 => Self::Mhz(2), NL80211_CHAN_WIDTH_4 => Self::Mhz(4), NL80211_CHAN_WIDTH_8 => Self::Mhz(8), NL80211_CHAN_WIDTH_16 => Self::Mhz(16), NL80211_CHAN_WIDTH_320 => Self::Mhz(320), _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211ChannelWidth) -> u32 { match v { Nl80211ChannelWidth::NoHt20 => NL80211_CHAN_WIDTH_20_NOHT, Nl80211ChannelWidth::Mhz(20) => NL80211_CHAN_WIDTH_20, Nl80211ChannelWidth::Mhz(40) => NL80211_CHAN_WIDTH_40, Nl80211ChannelWidth::Mhz(80) => NL80211_CHAN_WIDTH_80, Nl80211ChannelWidth::Mhz80Plus80 => NL80211_CHAN_WIDTH_80P80, Nl80211ChannelWidth::Mhz(160) => NL80211_CHAN_WIDTH_160, Nl80211ChannelWidth::Mhz(5) => NL80211_CHAN_WIDTH_5, Nl80211ChannelWidth::Mhz(10) => NL80211_CHAN_WIDTH_10, Nl80211ChannelWidth::Mhz(1) => NL80211_CHAN_WIDTH_1, Nl80211ChannelWidth::Mhz(2) => NL80211_CHAN_WIDTH_2, Nl80211ChannelWidth::Mhz(4) => NL80211_CHAN_WIDTH_4, Nl80211ChannelWidth::Mhz(8) => NL80211_CHAN_WIDTH_8, Nl80211ChannelWidth::Mhz(16) => NL80211_CHAN_WIDTH_16, Nl80211ChannelWidth::Mhz(320) => NL80211_CHAN_WIDTH_320, Nl80211ChannelWidth::Mhz(_) => { log::warn!("Invalid Nl80211ChannelWidth {:?}", v); u32::MAX } Nl80211ChannelWidth::Other(d) => d, } } } wl-nl80211-0.2.0/src/connection.rs000064400000000000000000000016311046102023000145450ustar 00000000000000// SPDX-License-Identifier: MIT use std::io; use futures::channel::mpsc::UnboundedReceiver; use genetlink::message::RawGenlMessage; use netlink_packet_core::NetlinkMessage; use netlink_proto::Connection; use netlink_sys::{AsyncSocket, SocketAddr}; use crate::Nl80211Handle; #[cfg(feature = "tokio_socket")] #[allow(clippy::type_complexity)] pub fn new_connection() -> io::Result<( Connection, Nl80211Handle, UnboundedReceiver<(NetlinkMessage, SocketAddr)>, )> { new_connection_with_socket() } #[allow(clippy::type_complexity)] pub fn new_connection_with_socket() -> io::Result<( Connection, Nl80211Handle, UnboundedReceiver<(NetlinkMessage, SocketAddr)>, )> where S: AsyncSocket, { let (conn, handle, messages) = genetlink::new_connection_with_socket()?; Ok((conn, Nl80211Handle::new(handle), messages)) } wl-nl80211-0.2.0/src/error.rs000064400000000000000000000012601046102023000135350ustar 00000000000000// SPDX-License-Identifier: MIT use thiserror::Error; use netlink_packet_core::{ErrorMessage, NetlinkMessage}; use netlink_packet_generic::GenlMessage; use netlink_packet_utils::DecodeError; use crate::Nl80211Message; #[derive(Debug, Error)] pub enum Nl80211Error { #[error("Received an unexpected message {0:?}")] UnexpectedMessage(NetlinkMessage>), #[error("Received a netlink error message {0}")] NetlinkError(ErrorMessage), #[error("A netlink request failed")] RequestFailed(String), #[error("Failed to decode netlink package: {0}")] DecodeFailed(DecodeError), #[error("A bug in this crate")] Bug(String), } wl-nl80211-0.2.0/src/ext_cap.rs000064400000000000000000000066541046102023000140430ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{Nla, NlaBuffer, NlasIterator}, DecodeError, Emitable, Parseable, }; use crate::Nl80211Attr; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211ExtendedCapability(pub Vec); //TODO: 802.11-2020 section `9.4.2.26 Extended Capabilities element` has // definition on every bit, we can expose getter and setter function // when required. impl Nl80211ExtendedCapability { pub fn new(payload: &[u8]) -> Self { Self(payload.to_vec()) } } impl Emitable for Nl80211ExtendedCapability { fn buffer_len(&self) -> usize { self.0.len() } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < self.0.len() { log::error!( "Buffer size is smaller than desired size {}", self.0.len() ); return; } buffer[..self.0.len()].copy_from_slice(self.0.as_slice()) } } impl std::ops::Deref for Nl80211ExtendedCapability { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211IfTypeExtCapas(pub Vec); impl std::ops::Deref for Nl80211IfTypeExtCapas { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfTypeExtCapas { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); let mut capas: Vec = Vec::new(); let err_msg = format!("Invalid NL80211_ATTR_IFTYPE_EXT_CAPA {payload:?}"); for nla in NlasIterator::new(payload) { let nla = nla.context(err_msg.clone())?; capas.push(Nl80211IfTypeExtCapa::parse(&nla)?); } Ok(Self(capas)) } } impl From<&Vec> for Nl80211IfTypeExtCapas { fn from(v: &Vec) -> Self { Self(v.clone()) } } impl From for Vec { fn from(v: Nl80211IfTypeExtCapas) -> Vec { v.0 } } // For linux kernel, NL80211_ATTR_IFTYPE_EXT_CAPA is indexing from 0 but // `capa_start`, hence we expose the index to user in case they want to generate // identical data as linux kernel does. #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211IfTypeExtCapa { pub index: u16, pub attributes: Vec, } impl Nla for Nl80211IfTypeExtCapa { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer) } fn kind(&self) -> u16 { self.index } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfTypeExtCapa { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let index = buf.kind(); let payload = buf.value(); let mut attributes: Vec = Vec::new(); let err_msg = format!("Invalid NL80211_ATTR_IFTYPE_EXT_CAPA {payload:?}"); for nla in NlasIterator::new(payload) { let nla = nla.context(err_msg.clone())?; attributes.push(Nl80211Attr::parse(&nla).context(err_msg.clone())?); } Ok(Self { index, attributes }) } } wl-nl80211-0.2.0/src/feature.rs000064400000000000000000000334101046102023000140410ustar 00000000000000// SPDX-License-Identifier: MIT use netlink_packet_utils::{DecodeError, Emitable}; const NL80211_FEATURE_SK_TX_STATUS: u32 = 1 << 0; const NL80211_FEATURE_HT_IBSS: u32 = 1 << 1; const NL80211_FEATURE_INACTIVITY_TIMER: u32 = 1 << 2; const NL80211_FEATURE_CELL_BASE_REG_HINTS: u32 = 1 << 3; const NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: u32 = 1 << 4; const NL80211_FEATURE_SAE: u32 = 1 << 5; const NL80211_FEATURE_LOW_PRIORITY_SCAN: u32 = 1 << 6; const NL80211_FEATURE_SCAN_FLUSH: u32 = 1 << 7; const NL80211_FEATURE_AP_SCAN: u32 = 1 << 8; const NL80211_FEATURE_VIF_TXPOWER: u32 = 1 << 9; const NL80211_FEATURE_NEED_OBSS_SCAN: u32 = 1 << 10; const NL80211_FEATURE_P2P_GO_CTWIN: u32 = 1 << 11; const NL80211_FEATURE_P2P_GO_OPPPS: u32 = 1 << 12; // bit 13 is reserved const NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: u32 = 1 << 14; const NL80211_FEATURE_FULL_AP_CLIENT_STATE: u32 = 1 << 15; const NL80211_FEATURE_USERSPACE_MPM: u32 = 1 << 16; const NL80211_FEATURE_ACTIVE_MONITOR: u32 = 1 << 17; const NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: u32 = 1 << 18; const NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES: u32 = 1 << 19; const NL80211_FEATURE_WFA_TPC_IE_IN_PROBES: u32 = 1 << 20; const NL80211_FEATURE_QUIET: u32 = 1 << 21; const NL80211_FEATURE_TX_POWER_INSERTION: u32 = 1 << 22; const NL80211_FEATURE_ACKTO_ESTIMATION: u32 = 1 << 23; const NL80211_FEATURE_STATIC_SMPS: u32 = 1 << 24; const NL80211_FEATURE_DYNAMIC_SMPS: u32 = 1 << 25; const NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: u32 = 1 << 26; const NL80211_FEATURE_MAC_ON_CREATE: u32 = 1 << 27; const NL80211_FEATURE_TDLS_CHANNEL_SWITCH: u32 = 1 << 28; const NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: u32 = 1 << 29; const NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: u32 = 1 << 30; const NL80211_FEATURE_ND_RANDOM_MAC_ADDR: u32 = 1 << 31; bitflags::bitflags! { #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub struct Nl80211Features: u32 { const SkTxStatus = NL80211_FEATURE_SK_TX_STATUS; const HtIbss = NL80211_FEATURE_HT_IBSS; const InactivityTimer = NL80211_FEATURE_INACTIVITY_TIMER; const CellBaseRegHints = NL80211_FEATURE_CELL_BASE_REG_HINTS; const P2pDeviceNeedsChannel = NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL; const Sae = NL80211_FEATURE_SAE; const LowPriorityScan = NL80211_FEATURE_LOW_PRIORITY_SCAN; const ScanFlush = NL80211_FEATURE_SCAN_FLUSH; const ApScan = NL80211_FEATURE_AP_SCAN; const VifTxpower = NL80211_FEATURE_VIF_TXPOWER; const NeedObssScan = NL80211_FEATURE_NEED_OBSS_SCAN; const P2pGoCtwin = NL80211_FEATURE_P2P_GO_CTWIN; const P2pGoOppps = NL80211_FEATURE_P2P_GO_OPPPS; const AdvertiseChanLimits = NL80211_FEATURE_ADVERTISE_CHAN_LIMITS; const FullApClientState = NL80211_FEATURE_FULL_AP_CLIENT_STATE; const UserspaceMpm = NL80211_FEATURE_USERSPACE_MPM; const ActiveMonitor = NL80211_FEATURE_ACTIVE_MONITOR; const ApModeChanWidthChange = NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; const DsParamSetIeInProbes = NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES; const WfaTpcIeInProbes = NL80211_FEATURE_WFA_TPC_IE_IN_PROBES; const Quiet = NL80211_FEATURE_QUIET; const TxPowerInsertion = NL80211_FEATURE_TX_POWER_INSERTION; const AcktoEstimation = NL80211_FEATURE_ACKTO_ESTIMATION; const StaticSmps = NL80211_FEATURE_STATIC_SMPS; const DynamicSmps = NL80211_FEATURE_DYNAMIC_SMPS; const SupportsWmmAdmission = NL80211_FEATURE_SUPPORTS_WMM_ADMISSION; const MacOnCreate = NL80211_FEATURE_MAC_ON_CREATE; const TdlsChannelSwitch = NL80211_FEATURE_TDLS_CHANNEL_SWITCH; const ScanRandomMacAddr = NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; const SchedScanRandomMacAddr = NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; const NdRandomMacAddr = NL80211_FEATURE_ND_RANDOM_MAC_ADDR; const _ = !0; } } // Kernel is using [u8; DIV_ROUND_UP(NUM_NL80211_EXT_FEATURES, 8)] to // store these extended features, allowing it to support any count of // features more than u128. The maximum data type bitflags can use is u128, // which might be not enough in the future, hence we do it by ourselves without // using bitflags. #[derive(Debug, Default, PartialEq, Eq, Clone)] #[non_exhaustive] pub(crate) struct Nl80211ExtFeatures(pub(crate) Vec); impl Nl80211ExtFeatures { // Kernel(6.10.8) is using 9 bytes to store these 68 bits features and // will expand to more bytes pub(crate) const LENGTH: usize = 9; pub(crate) fn parse(payload: &[u8]) -> Result { let mut features = Vec::new(); for (index, byte) in payload.iter().enumerate() { for pos in 0..7 { if (byte & (1 << pos)) >= 1 { let feature = Nl80211ExtFeature::from(index * 8 + pos); if feature != Nl80211ExtFeature::Unknown { features.push(feature); } } } } Ok(Self(features)) } } impl Emitable for Nl80211ExtFeatures { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { for feature in self.0.as_slice() { let index = *feature as usize / 8; let pos = *feature as usize % 8; buffer[index] |= 1 << pos; } } } impl From<&Vec> for Nl80211ExtFeatures { fn from(v: &Vec) -> Self { Self(v.clone()) } } // We cannot have Other() as it would make `repr(usize)` not supporting `as` // casting so we just discard unknown features with a log #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] #[repr(usize)] pub enum Nl80211ExtFeature { VhtIbss = 0, Rrm = 1, MuMimoAirSniffer = 2, ScanStartTime = 3, BssParentTsf = 4, SetScanDwell = 5, BeaconRateLegacy = 6, BeaconRateHt = 7, BeaconRateVht = 8, FilsSta = 9, MgmtTxRandomTa = 10, MgmtTxRandomTaConnected = 11, SchedScanRelativeRssi = 12, CqmRssiList = 13, FilsSkOffload = 14, FourWayHandshakeStaPsk = 15, FourWayHandshakeSta1X = 16, FilsMaxChannelTime = 17, AcceptBcastProbeResp = 18, OceProbeReqHighTxRate = 19, OceProbeReqDeferralSuppression = 20, MfpOptional = 21, LowSpanScan = 22, LowPowerScan = 23, HighAccuracyScan = 24, DfsOffload = 25, ControlPortOverNl80211 = 26, AckSignalSupport = 27, Txqs = 28, ScanRandomSn = 29, ScanMinPreqContent = 30, CanReplacePtk0 = 31, EnableFtmResponder = 32, AirtimeFairness = 33, ApPmksaCaching = 34, SchedScanBandSpecificRssiThold = 35, ExtKeyId = 36, StaTxPwr = 37, SaeOffload = 38, VlanOffload = 39, Aql = 40, BeaconProtection = 41, ControlPortNoPreauth = 42, ProtectedTwt = 43, DelIbssSta = 44, MulticastRegistrations = 45, BeaconProtectionClient = 46, ScanFreqKhz = 47, ControlPortOverNl80211TxStatus = 48, OperatingChannelValidation = 49, FourWayHandshakeApPsk = 50, SaeOffloadAp = 51, FilsDiscovery = 52, UnsolBcastProbeResp = 53, BeaconRateHe = 54, SecureLtf = 55, SecureRtt = 56, ProtRangeNegoAndMeasure = 57, BssColor = 58, FilsCryptoOffload = 59, RadarBackground = 60, PoweredAddrChange = 61, Punct = 62, SecureNan = 63, AuthAndDeauthRandomTa = 64, OweOffload = 65, OweOffloadAp = 66, DfsConcurrent = 67, SppAmsduSupport = 68, // Please check Nl80211ExtFeatures::LENGTH when you adding more features #[default] Unknown = 0xffff, } impl From for Nl80211ExtFeature { fn from(d: usize) -> Self { match d { d if d == Self::VhtIbss as usize => Self::VhtIbss, d if d == Self::Rrm as usize => Self::Rrm, d if d == Self::MuMimoAirSniffer as usize => Self::MuMimoAirSniffer, d if d == Self::ScanStartTime as usize => Self::ScanStartTime, d if d == Self::BssParentTsf as usize => Self::BssParentTsf, d if d == Self::SetScanDwell as usize => Self::SetScanDwell, d if d == Self::BeaconRateLegacy as usize => Self::BeaconRateLegacy, d if d == Self::BeaconRateHt as usize => Self::BeaconRateHt, d if d == Self::BeaconRateVht as usize => Self::BeaconRateVht, d if d == Self::FilsSta as usize => Self::FilsSta, d if d == Self::MgmtTxRandomTa as usize => Self::MgmtTxRandomTa, d if d == Self::MgmtTxRandomTaConnected as usize => { Self::MgmtTxRandomTaConnected } d if d == Self::SchedScanRelativeRssi as usize => { Self::SchedScanRelativeRssi } d if d == Self::CqmRssiList as usize => Self::CqmRssiList, d if d == Self::FilsSkOffload as usize => Self::FilsSkOffload, d if d == Self::FourWayHandshakeStaPsk as usize => { Self::FourWayHandshakeStaPsk } d if d == Self::FourWayHandshakeSta1X as usize => { Self::FourWayHandshakeSta1X } d if d == Self::FilsMaxChannelTime as usize => { Self::FilsMaxChannelTime } d if d == Self::AcceptBcastProbeResp as usize => { Self::AcceptBcastProbeResp } d if d == Self::OceProbeReqHighTxRate as usize => { Self::OceProbeReqHighTxRate } d if d == Self::OceProbeReqDeferralSuppression as usize => { Self::OceProbeReqDeferralSuppression } d if d == Self::MfpOptional as usize => Self::MfpOptional, d if d == Self::LowSpanScan as usize => Self::LowSpanScan, d if d == Self::LowPowerScan as usize => Self::LowPowerScan, d if d == Self::HighAccuracyScan as usize => Self::HighAccuracyScan, d if d == Self::DfsOffload as usize => Self::DfsOffload, d if d == Self::ControlPortOverNl80211 as usize => { Self::ControlPortOverNl80211 } d if d == Self::AckSignalSupport as usize => Self::AckSignalSupport, d if d == Self::Txqs as usize => Self::Txqs, d if d == Self::ScanRandomSn as usize => Self::ScanRandomSn, d if d == Self::ScanMinPreqContent as usize => { Self::ScanMinPreqContent } d if d == Self::CanReplacePtk0 as usize => Self::CanReplacePtk0, d if d == Self::EnableFtmResponder as usize => { Self::EnableFtmResponder } d if d == Self::AirtimeFairness as usize => Self::AirtimeFairness, d if d == Self::ApPmksaCaching as usize => Self::ApPmksaCaching, d if d == Self::SchedScanBandSpecificRssiThold as usize => { Self::SchedScanBandSpecificRssiThold } d if d == Self::ExtKeyId as usize => Self::ExtKeyId, d if d == Self::StaTxPwr as usize => Self::StaTxPwr, d if d == Self::SaeOffload as usize => Self::SaeOffload, d if d == Self::VlanOffload as usize => Self::VlanOffload, d if d == Self::Aql as usize => Self::Aql, d if d == Self::BeaconProtection as usize => Self::BeaconProtection, d if d == Self::ControlPortNoPreauth as usize => { Self::ControlPortNoPreauth } d if d == Self::ProtectedTwt as usize => Self::ProtectedTwt, d if d == Self::DelIbssSta as usize => Self::DelIbssSta, d if d == Self::MulticastRegistrations as usize => { Self::MulticastRegistrations } d if d == Self::BeaconProtectionClient as usize => { Self::BeaconProtectionClient } d if d == Self::ScanFreqKhz as usize => Self::ScanFreqKhz, d if d == Self::ControlPortOverNl80211TxStatus as usize => { Self::ControlPortOverNl80211TxStatus } d if d == Self::OperatingChannelValidation as usize => { Self::OperatingChannelValidation } d if d == Self::FourWayHandshakeApPsk as usize => { Self::FourWayHandshakeApPsk } d if d == Self::SaeOffloadAp as usize => Self::SaeOffloadAp, d if d == Self::FilsDiscovery as usize => Self::FilsDiscovery, d if d == Self::UnsolBcastProbeResp as usize => { Self::UnsolBcastProbeResp } d if d == Self::BeaconRateHe as usize => Self::BeaconRateHe, d if d == Self::SecureLtf as usize => Self::SecureLtf, d if d == Self::SecureRtt as usize => Self::SecureRtt, d if d == Self::ProtRangeNegoAndMeasure as usize => { Self::ProtRangeNegoAndMeasure } d if d == Self::BssColor as usize => Self::BssColor, d if d == Self::FilsCryptoOffload as usize => { Self::FilsCryptoOffload } d if d == Self::RadarBackground as usize => Self::RadarBackground, d if d == Self::PoweredAddrChange as usize => { Self::PoweredAddrChange } d if d == Self::Punct as usize => Self::Punct, d if d == Self::SecureNan as usize => Self::SecureNan, d if d == Self::AuthAndDeauthRandomTa as usize => { Self::AuthAndDeauthRandomTa } d if d == Self::OweOffload as usize => Self::OweOffload, d if d == Self::OweOffloadAp as usize => Self::OweOffloadAp, d if d == Self::DfsConcurrent as usize => Self::DfsConcurrent, d if d == Self::SppAmsduSupport as usize => Self::SppAmsduSupport, _ => { log::info!("Unsupported feature {d}"); Self::Unknown } } } } wl-nl80211-0.2.0/src/frame_type.rs000064400000000000000000000316561046102023000145530ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{Nla, NlaBuffer, NlasIterator}, parsers::parse_u16, DecodeError, Emitable, Parseable, }; use crate::{bytes::write_u16, Nl80211InterfaceType}; #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct Nl80211IfaceFrameType { pub iface_type: Nl80211InterfaceType, pub attributes: Vec, } impl Nla for Nl80211IfaceFrameType { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn kind(&self) -> u16 { u32::from(self.iface_type) as u16 } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer) } } const NL80211_ATTR_FRAME_TYPE: u16 = 101; impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfaceFrameType { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); let iface_type = Nl80211InterfaceType::from(buf.kind() as u32); let err_msg = format!("Invalid NL80211_IFACE_COMB_LIMITS {payload:?}"); let mut attributes = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; // We are discarding other kind of NLA, but linux kernel // most likely will not add new NLA type for // NL80211_ATTR_TX_FRAME_TYPES. if nla.kind() == NL80211_ATTR_FRAME_TYPE { attributes.push(Nl80211FrameType::from( parse_u16(nla.value()).context(format!( "Invalid NL80211_ATTR_FRAME_TYPE {:?}", nla.value() ))?, )); } } Ok(Self { iface_type, attributes, }) } } const IEEE80211_FTYPE_MGMT: u8 = 0x00; const IEEE80211_FTYPE_CTL: u8 = 0x04; const IEEE80211_FTYPE_DATA: u8 = 0x08; const IEEE80211_FTYPE_EXT: u8 = 0x0c; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211FrameType { Management(Nl80211FrameTypeMgmt), Control(Nl80211FrameTypeCtl), Data(Nl80211FrameTypeData), Extension(Nl80211FrameTypeExt), Other(u16), } impl Nla for Nl80211FrameType { fn value_len(&self) -> usize { 2 } fn kind(&self) -> u16 { NL80211_ATTR_FRAME_TYPE } fn emit_value(&self, buffer: &mut [u8]) { write_u16(buffer, u16::from(*self)) } } impl From for Nl80211FrameType { fn from(d: u16) -> Self { let frame_type = (d & 0xf) as u8; let sub_type = d - frame_type as u16; match frame_type { IEEE80211_FTYPE_MGMT => { Self::Management(Nl80211FrameTypeMgmt::from(sub_type)) } IEEE80211_FTYPE_CTL => { Self::Control(Nl80211FrameTypeCtl::from(sub_type)) } IEEE80211_FTYPE_DATA => { Self::Data(Nl80211FrameTypeData::from(sub_type)) } IEEE80211_FTYPE_EXT => { Self::Extension(Nl80211FrameTypeExt::from(sub_type)) } _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211FrameType) -> u16 { match v { Nl80211FrameType::Management(s) => { IEEE80211_FTYPE_MGMT as u16 | u16::from(s) } Nl80211FrameType::Control(s) => { IEEE80211_FTYPE_CTL as u16 | u16::from(s) } Nl80211FrameType::Data(s) => { IEEE80211_FTYPE_DATA as u16 | u16::from(s) } Nl80211FrameType::Extension(s) => { IEEE80211_FTYPE_EXT as u16 | u16::from(s) } Nl80211FrameType::Other(d) => d, } } } const IEEE80211_STYPE_ASSOC_REQ: u16 = 0x0000; const IEEE80211_STYPE_ASSOC_RESP: u16 = 0x0010; const IEEE80211_STYPE_REASSOC_REQ: u16 = 0x0020; const IEEE80211_STYPE_REASSOC_RESP: u16 = 0x0030; const IEEE80211_STYPE_PROBE_REQ: u16 = 0x0040; const IEEE80211_STYPE_PROBE_RESP: u16 = 0x0050; const IEEE80211_STYPE_BEACON: u16 = 0x0080; const IEEE80211_STYPE_ATIM: u16 = 0x0090; const IEEE80211_STYPE_DISASSOC: u16 = 0x00A0; const IEEE80211_STYPE_AUTH: u16 = 0x00B0; const IEEE80211_STYPE_DEAUTH: u16 = 0x00C0; const IEEE80211_STYPE_ACTION: u16 = 0x00D0; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211FrameTypeMgmt { AssocReq, AssocResp, ReassocReq, ReassocResp, ProbeReq, ProbeResp, Beacon, Atim, Disassoc, Auth, Deauth, Action, Other(u16), } impl From for Nl80211FrameTypeMgmt { fn from(d: u16) -> Self { match d { IEEE80211_STYPE_ASSOC_REQ => Self::AssocReq, IEEE80211_STYPE_ASSOC_RESP => Self::AssocResp, IEEE80211_STYPE_REASSOC_REQ => Self::ReassocReq, IEEE80211_STYPE_REASSOC_RESP => Self::ReassocResp, IEEE80211_STYPE_PROBE_REQ => Self::ProbeReq, IEEE80211_STYPE_PROBE_RESP => Self::ProbeResp, IEEE80211_STYPE_BEACON => Self::Beacon, IEEE80211_STYPE_ATIM => Self::Atim, IEEE80211_STYPE_DISASSOC => Self::Disassoc, IEEE80211_STYPE_AUTH => Self::Auth, IEEE80211_STYPE_DEAUTH => Self::Deauth, IEEE80211_STYPE_ACTION => Self::Action, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211FrameTypeMgmt) -> u16 { match v { Nl80211FrameTypeMgmt::AssocReq => IEEE80211_STYPE_ASSOC_REQ, Nl80211FrameTypeMgmt::AssocResp => IEEE80211_STYPE_ASSOC_RESP, Nl80211FrameTypeMgmt::ReassocReq => IEEE80211_STYPE_REASSOC_REQ, Nl80211FrameTypeMgmt::ReassocResp => IEEE80211_STYPE_REASSOC_RESP, Nl80211FrameTypeMgmt::ProbeReq => IEEE80211_STYPE_PROBE_REQ, Nl80211FrameTypeMgmt::ProbeResp => IEEE80211_STYPE_PROBE_RESP, Nl80211FrameTypeMgmt::Beacon => IEEE80211_STYPE_BEACON, Nl80211FrameTypeMgmt::Atim => IEEE80211_STYPE_ATIM, Nl80211FrameTypeMgmt::Disassoc => IEEE80211_STYPE_DISASSOC, Nl80211FrameTypeMgmt::Auth => IEEE80211_STYPE_AUTH, Nl80211FrameTypeMgmt::Deauth => IEEE80211_STYPE_DEAUTH, Nl80211FrameTypeMgmt::Action => IEEE80211_STYPE_ACTION, Nl80211FrameTypeMgmt::Other(d) => d, } } } const IEEE80211_STYPE_TRIGGER: u16 = 0x0020; const IEEE80211_STYPE_CTL_EXT: u16 = 0x0060; const IEEE80211_STYPE_BACK_REQ: u16 = 0x0080; const IEEE80211_STYPE_BACK: u16 = 0x0090; const IEEE80211_STYPE_PSPOLL: u16 = 0x00A0; const IEEE80211_STYPE_RTS: u16 = 0x00B0; const IEEE80211_STYPE_CTS: u16 = 0x00C0; const IEEE80211_STYPE_ACK: u16 = 0x00D0; const IEEE80211_STYPE_CFEND: u16 = 0x00E0; const IEEE80211_STYPE_CFENDACK: u16 = 0x00F0; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211FrameTypeCtl { Trigger, CtlExt, BackReq, Back, Pspoll, Rts, Cts, Ack, Cfend, Cfendack, Other(u16), } impl From for Nl80211FrameTypeCtl { fn from(d: u16) -> Self { match d { IEEE80211_STYPE_TRIGGER => Self::Trigger, IEEE80211_STYPE_CTL_EXT => Self::CtlExt, IEEE80211_STYPE_BACK_REQ => Self::BackReq, IEEE80211_STYPE_BACK => Self::Back, IEEE80211_STYPE_PSPOLL => Self::Pspoll, IEEE80211_STYPE_RTS => Self::Rts, IEEE80211_STYPE_CTS => Self::Cts, IEEE80211_STYPE_ACK => Self::Ack, IEEE80211_STYPE_CFEND => Self::Cfend, IEEE80211_STYPE_CFENDACK => Self::Cfendack, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211FrameTypeCtl) -> u16 { match v { Nl80211FrameTypeCtl::Trigger => IEEE80211_STYPE_TRIGGER, Nl80211FrameTypeCtl::CtlExt => IEEE80211_STYPE_CTL_EXT, Nl80211FrameTypeCtl::BackReq => IEEE80211_STYPE_BACK_REQ, Nl80211FrameTypeCtl::Back => IEEE80211_STYPE_BACK, Nl80211FrameTypeCtl::Pspoll => IEEE80211_STYPE_PSPOLL, Nl80211FrameTypeCtl::Rts => IEEE80211_STYPE_RTS, Nl80211FrameTypeCtl::Cts => IEEE80211_STYPE_CTS, Nl80211FrameTypeCtl::Ack => IEEE80211_STYPE_ACK, Nl80211FrameTypeCtl::Cfend => IEEE80211_STYPE_CFEND, Nl80211FrameTypeCtl::Cfendack => IEEE80211_STYPE_CFENDACK, Nl80211FrameTypeCtl::Other(d) => d, } } } const IEEE80211_STYPE_DATA: u16 = 0x0000; const IEEE80211_STYPE_DATA_CFACK: u16 = 0x0010; const IEEE80211_STYPE_DATA_CFPOLL: u16 = 0x0020; const IEEE80211_STYPE_DATA_CFACKPOLL: u16 = 0x0030; const IEEE80211_STYPE_NULLFUNC: u16 = 0x0040; const IEEE80211_STYPE_CFACK: u16 = 0x0050; const IEEE80211_STYPE_CFPOLL: u16 = 0x0060; const IEEE80211_STYPE_CFACKPOLL: u16 = 0x0070; const IEEE80211_STYPE_QOS_DATA: u16 = 0x0080; const IEEE80211_STYPE_QOS_DATA_CFACK: u16 = 0x0090; const IEEE80211_STYPE_QOS_DATA_CFPOLL: u16 = 0x00A0; const IEEE80211_STYPE_QOS_DATA_CFACKPOLL: u16 = 0x00B0; const IEEE80211_STYPE_QOS_NULLFUNC: u16 = 0x00C0; const IEEE80211_STYPE_QOS_CFACK: u16 = 0x00D0; const IEEE80211_STYPE_QOS_CFPOLL: u16 = 0x00E0; const IEEE80211_STYPE_QOS_CFACKPOLL: u16 = 0x00F0; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211FrameTypeData { Data, DataCfack, DataCfpoll, DataCfackpoll, Nullfunc, Cfack, Cfpoll, Cfackpoll, QosData, QosDataCfack, QosDataCfpoll, QosDataCfackpoll, QosNullfunc, QosCfack, QosCfpoll, QosCfackpoll, Other(u16), } impl From for Nl80211FrameTypeData { fn from(d: u16) -> Self { match d { IEEE80211_STYPE_DATA => Self::Data, IEEE80211_STYPE_DATA_CFACK => Self::DataCfack, IEEE80211_STYPE_DATA_CFPOLL => Self::DataCfpoll, IEEE80211_STYPE_DATA_CFACKPOLL => Self::DataCfackpoll, IEEE80211_STYPE_NULLFUNC => Self::Nullfunc, IEEE80211_STYPE_CFACK => Self::Cfack, IEEE80211_STYPE_CFPOLL => Self::Cfpoll, IEEE80211_STYPE_CFACKPOLL => Self::Cfackpoll, IEEE80211_STYPE_QOS_DATA => Self::QosData, IEEE80211_STYPE_QOS_DATA_CFACK => Self::QosDataCfack, IEEE80211_STYPE_QOS_DATA_CFPOLL => Self::QosDataCfpoll, IEEE80211_STYPE_QOS_DATA_CFACKPOLL => Self::QosDataCfackpoll, IEEE80211_STYPE_QOS_NULLFUNC => Self::QosNullfunc, IEEE80211_STYPE_QOS_CFACK => Self::QosCfack, IEEE80211_STYPE_QOS_CFPOLL => Self::QosCfpoll, IEEE80211_STYPE_QOS_CFACKPOLL => Self::QosCfackpoll, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211FrameTypeData) -> u16 { match v { Nl80211FrameTypeData::Data => IEEE80211_STYPE_DATA, Nl80211FrameTypeData::DataCfack => IEEE80211_STYPE_DATA_CFACK, Nl80211FrameTypeData::DataCfpoll => IEEE80211_STYPE_DATA_CFPOLL, Nl80211FrameTypeData::DataCfackpoll => { IEEE80211_STYPE_DATA_CFACKPOLL } Nl80211FrameTypeData::Nullfunc => IEEE80211_STYPE_NULLFUNC, Nl80211FrameTypeData::Cfack => IEEE80211_STYPE_CFACK, Nl80211FrameTypeData::Cfpoll => IEEE80211_STYPE_CFPOLL, Nl80211FrameTypeData::Cfackpoll => IEEE80211_STYPE_CFACKPOLL, Nl80211FrameTypeData::QosData => IEEE80211_STYPE_QOS_DATA, Nl80211FrameTypeData::QosDataCfack => { IEEE80211_STYPE_QOS_DATA_CFACK } Nl80211FrameTypeData::QosDataCfpoll => { IEEE80211_STYPE_QOS_DATA_CFPOLL } Nl80211FrameTypeData::QosDataCfackpoll => { IEEE80211_STYPE_QOS_DATA_CFACKPOLL } Nl80211FrameTypeData::QosNullfunc => IEEE80211_STYPE_QOS_NULLFUNC, Nl80211FrameTypeData::QosCfack => IEEE80211_STYPE_QOS_CFACK, Nl80211FrameTypeData::QosCfpoll => IEEE80211_STYPE_QOS_CFPOLL, Nl80211FrameTypeData::QosCfackpoll => IEEE80211_STYPE_QOS_CFACKPOLL, Nl80211FrameTypeData::Other(d) => d, } } } const IEEE80211_STYPE_DMG_BEACON: u16 = 0x0000; const IEEE80211_STYPE_S1G_BEACON: u16 = 0x0010; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211FrameTypeExt { DmgBeacon, S1gBeacon, Other(u16), } impl From for Nl80211FrameTypeExt { fn from(d: u16) -> Self { match d { IEEE80211_STYPE_DMG_BEACON => Self::DmgBeacon, IEEE80211_STYPE_S1G_BEACON => Self::S1gBeacon, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211FrameTypeExt) -> u16 { match v { Nl80211FrameTypeExt::DmgBeacon => IEEE80211_STYPE_DMG_BEACON, Nl80211FrameTypeExt::S1gBeacon => IEEE80211_STYPE_S1G_BEACON, Nl80211FrameTypeExt::Other(d) => d, } } } wl-nl80211-0.2.0/src/handle.rs000064400000000000000000000044241046102023000136440ustar 00000000000000// SPDX-License-Identifier: MIT use futures::{future::Either, FutureExt, Stream, StreamExt, TryStream}; use genetlink::GenetlinkHandle; use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST}; use netlink_packet_generic::GenlMessage; use netlink_packet_utils::DecodeError; use crate::{ try_nl80211, Nl80211Error, Nl80211InterfaceHandle, Nl80211Message, Nl80211StationHandle, Nl80211WiphyHandle, }; #[derive(Clone, Debug)] pub struct Nl80211Handle { pub handle: GenetlinkHandle, } impl Nl80211Handle { pub(crate) fn new(handle: GenetlinkHandle) -> Self { Nl80211Handle { handle } } // equivalent to `iw dev` command pub fn interface(&self) -> Nl80211InterfaceHandle { Nl80211InterfaceHandle::new(self.clone()) } // equivalent to `iw dev DEVICE station` command pub fn station(&self) -> Nl80211StationHandle { Nl80211StationHandle::new(self.clone()) } // equivalent to `iw phy` command pub fn wireless_physic(&self) -> Nl80211WiphyHandle { Nl80211WiphyHandle::new(self.clone()) } pub async fn request( &mut self, message: NetlinkMessage>, ) -> Result< impl Stream< Item = Result< NetlinkMessage>, DecodeError, >, >, Nl80211Error, > { self.handle.request(message).await.map_err(|e| { Nl80211Error::RequestFailed(format!( "BUG: Request failed with {}", e )) }) } } pub(crate) async fn nl80211_execute( handle: &mut Nl80211Handle, nl80211_msg: Nl80211Message, ) -> impl TryStream, Error = Nl80211Error> { let nl_header_flags = NLM_F_REQUEST | NLM_F_DUMP; let mut nl_msg = NetlinkMessage::from(GenlMessage::from_payload(nl80211_msg)); nl_msg.header.flags = nl_header_flags; match handle.request(nl_msg).await { Ok(response) => { Either::Left(response.map(move |msg| Ok(try_nl80211!(msg)))) } Err(e) => Either::Right( futures::future::err::, Nl80211Error>( e, ) .into_stream(), ), } } wl-nl80211-0.2.0/src/iface/combination.rs000064400000000000000000000211111046102023000157520ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::parse_u32, DecodeError, Emitable, Parseable, ParseableParametrized, }; use crate::{bytes::write_u32, Nl80211InterfaceType, Nl80211InterfaceTypes}; const NL80211_IFACE_COMB_LIMITS: u16 = 1; const NL80211_IFACE_COMB_MAXNUM: u16 = 2; const NL80211_IFACE_COMB_STA_AP_BI_MATCH: u16 = 3; const NL80211_IFACE_COMB_NUM_CHANNELS: u16 = 4; const NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u16 = 5; const NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u16 = 6; const NL80211_IFACE_COMB_BI_MIN_GCD: u16 = 7; #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct Nl80211IfaceComb { pub index: u16, pub attributes: Vec, } impl Nla for Nl80211IfaceComb { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn kind(&self) -> u16 { self.index + 1 } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer) } } impl<'a, T> ParseableParametrized, u16> for Nl80211IfaceComb where T: AsRef<[u8]> + ?Sized, { fn parse_with_param( buf: &NlaBuffer<&'a T>, index: u16, ) -> Result { let payload = buf.value(); let err_msg = format!( "Invalid NL80211_IFACE_COMB_LIMITS {payload:?} index {index}" ); let mut attributes = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; attributes.push(Nl80211IfaceCombAttribute::parse(nla)?); } Ok(Self { index, attributes }) } } #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum Nl80211IfaceCombAttribute { Limits(Vec), Maxnum(u32), StaApiBiMatch, NumChannels(u32), RadarDetectWidths(u32), RadarDetectRegins(u32), BiMinGcd(u32), Other(DefaultNla), } impl Nla for Nl80211IfaceCombAttribute { fn value_len(&self) -> usize { match self { Self::Limits(v) => v.as_slice().buffer_len(), Self::StaApiBiMatch => 0, Self::Maxnum(_) | Self::NumChannels(_) | Self::RadarDetectWidths(_) | Self::RadarDetectRegins(_) | Self::BiMinGcd(_) => 4, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Limits(_) => NL80211_IFACE_COMB_LIMITS, Self::Maxnum(_) => NL80211_IFACE_COMB_MAXNUM, Self::StaApiBiMatch => NL80211_IFACE_COMB_STA_AP_BI_MATCH, Self::NumChannels(_) => NL80211_IFACE_COMB_NUM_CHANNELS, Self::RadarDetectWidths(_) => { NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS } Self::RadarDetectRegins(_) => { NL80211_IFACE_COMB_RADAR_DETECT_REGIONS } Self::BiMinGcd(_) => NL80211_IFACE_COMB_BI_MIN_GCD, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Maxnum(d) | Self::NumChannels(d) | Self::RadarDetectWidths(d) | Self::RadarDetectRegins(d) | Self::BiMinGcd(d) => write_u32(buffer, *d), Self::StaApiBiMatch => (), Self::Limits(v) => v.as_slice().emit(buffer), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfaceCombAttribute { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_IFACE_COMB_LIMITS => { let err_msg = format!("Invalid NL80211_IFACE_COMB_LIMITS {payload:?}"); let mut nlas = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211IfaceCombLimit::parse_with_param( nla, index as u16, )?); } Self::Limits(nlas) } NL80211_IFACE_COMB_MAXNUM => { Self::Maxnum(parse_u32(payload).context(format!( "Invalid NL80211_IFACE_COMB_MAXNUM {payload:?}" ))?) } NL80211_IFACE_COMB_STA_AP_BI_MATCH => Self::StaApiBiMatch, NL80211_IFACE_COMB_NUM_CHANNELS => { Self::NumChannels(parse_u32(payload).context(format!( "Invalid NL80211_IFACE_COMB_NUM_CHANNELS {payload:?}" ))?) } NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS => { Self::RadarDetectWidths(parse_u32(payload).context(format!( "Invalid NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS \ {payload:?}" ))?) } NL80211_IFACE_COMB_RADAR_DETECT_REGIONS => { Self::RadarDetectRegins(parse_u32(payload).context(format!( "Invalid NL80211_IFACE_COMB_RADAR_DETECT_REGIONS \ {payload:?}" ))?) } NL80211_IFACE_COMB_BI_MIN_GCD => { Self::BiMinGcd(parse_u32(payload).context(format!( "Invalid NL80211_IFACE_COMB_BI_MIN_GCD {payload:?}" ))?) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct Nl80211IfaceCombLimit { pub index: u16, pub attributes: Vec, } impl Nla for Nl80211IfaceCombLimit { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn kind(&self) -> u16 { self.index + 1 } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer) } } impl<'a, T> ParseableParametrized, u16> for Nl80211IfaceCombLimit where T: AsRef<[u8]> + ?Sized, { fn parse_with_param( buf: &NlaBuffer<&'a T>, index: u16, ) -> Result { let payload = buf.value(); let err_msg = format!("Invalid NL80211_IFACE_COMB_LIMITS {:?}", payload); let mut attributes = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; attributes.push(Nl80211IfaceCombLimitAttribute::parse(nla)?); } Ok(Self { index, attributes }) } } const NL80211_IFACE_LIMIT_MAX: u16 = 1; const NL80211_IFACE_LIMIT_TYPES: u16 = 2; #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum Nl80211IfaceCombLimitAttribute { Max(u32), Iftypes(Vec), Other(DefaultNla), } impl Nla for Nl80211IfaceCombLimitAttribute { fn value_len(&self) -> usize { match self { Self::Max(_) => 4, Self::Iftypes(v) => { Nl80211InterfaceTypes::from(v).as_slice().buffer_len() } Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Max(_) => NL80211_IFACE_LIMIT_MAX, Self::Iftypes(_) => NL80211_IFACE_LIMIT_TYPES, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Max(d) => write_u32(buffer, *d), Self::Iftypes(v) => { Nl80211InterfaceTypes::from(v).as_slice().emit(buffer) } Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfaceCombLimitAttribute { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_IFACE_LIMIT_MAX => Self::Max(parse_u32(payload).context( format!("Invalid NL80211_IFACE_LIMIT_MAX {payload:?}"), )?), NL80211_IFACE_LIMIT_TYPES => Self::Iftypes( Nl80211InterfaceTypes::parse( payload, "NL80211_IFACE_LIMIT_TYPES", )? .0, ), _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } wl-nl80211-0.2.0/src/iface/get.rs000064400000000000000000000012771046102023000142420ustar 00000000000000// SPDX-License-Identifier: MIT use futures::TryStream; use netlink_packet_generic::GenlMessage; use crate::{nl80211_execute, Nl80211Error, Nl80211Handle, Nl80211Message}; pub struct Nl80211InterfaceGetRequest { handle: Nl80211Handle, } impl Nl80211InterfaceGetRequest { pub(crate) fn new(handle: Nl80211Handle) -> Self { Nl80211InterfaceGetRequest { handle } } pub async fn execute( self, ) -> impl TryStream, Error = Nl80211Error> { let Nl80211InterfaceGetRequest { mut handle } = self; let nl80211_msg = Nl80211Message::new_interface_get(); nl80211_execute(&mut handle, nl80211_msg).await } } wl-nl80211-0.2.0/src/iface/handle.rs000064400000000000000000000007151046102023000147120ustar 00000000000000// SPDX-License-Identifier: MIT use crate::{Nl80211Handle, Nl80211InterfaceGetRequest}; pub struct Nl80211InterfaceHandle(Nl80211Handle); impl Nl80211InterfaceHandle { pub fn new(handle: Nl80211Handle) -> Self { Nl80211InterfaceHandle(handle) } /// Retrieve the wireless interfaces /// (equivalent to `iw dev`) pub fn get(&mut self) -> Nl80211InterfaceGetRequest { Nl80211InterfaceGetRequest::new(self.0.clone()) } } wl-nl80211-0.2.0/src/iface/iface_type.rs000064400000000000000000000117421046102023000155710ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{Nla, NlasIterator}, parsers::parse_u32, DecodeError, }; #[derive(Debug, PartialEq, Eq, Clone)] pub(crate) struct Nl80211InterfaceTypes(pub(crate) Vec); impl std::ops::Deref for Nl80211InterfaceTypes { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From<&Vec> for Nl80211InterfaceTypes { fn from(iface_types: &Vec) -> Self { Self(iface_types.to_vec()) } } impl From for Vec { fn from(iface_types: Nl80211InterfaceTypes) -> Self { iface_types.0 } } impl Nl80211InterfaceTypes { pub fn parse(payload: &[u8], kind: &str) -> Result { let mut iface_types: Vec = Vec::new(); for nla in NlasIterator::new(payload) { let error_msg = format!("Invalid {kind}: {nla:?}"); let nla = &nla.context(error_msg.clone())?; iface_types.push(Nl80211InterfaceType::from(nla.kind() as u32)); } Ok(Self(iface_types)) } } const NL80211_IFTYPE_UNSPECIFIED: u32 = 0; const NL80211_IFTYPE_ADHOC: u32 = 1; const NL80211_IFTYPE_STATION: u32 = 2; const NL80211_IFTYPE_AP: u32 = 3; const NL80211_IFTYPE_AP_VLAN: u32 = 4; const NL80211_IFTYPE_WDS: u32 = 5; const NL80211_IFTYPE_MONITOR: u32 = 6; const NL80211_IFTYPE_MESH_POINT: u32 = 7; const NL80211_IFTYPE_P2P_CLIENT: u32 = 8; const NL80211_IFTYPE_P2P_GO: u32 = 9; const NL80211_IFTYPE_P2P_DEVICE: u32 = 10; const NL80211_IFTYPE_OCB: u32 = 11; const NL80211_IFTYPE_NAN: u32 = 12; // Linux kernel data type `enum nl80211_iftype` /// (virtual) interface types #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211InterfaceType { /// unspecified type, driver decides Unspecified, /// Independent BSS member, also known as IBSS Adhoc, /// Managed BSS member, also known as managed Station, /// Access point Ap, /// VLAN interface for access points; VLAN interfaces are a bit special in /// that they must always be tied to a pre-existing AP type interface. ApVlan, /// wireless distribution interface Wds, /// Monitor interface receiving all frames Monitor, /// Mesh point MeshPoint, /// P2P client P2pClient, /// P2P group owner P2pGo, /// P2P device interface type, this is not a netdev P2pDevice, /// Outside Context of a BSS, This mode corresponds to the MIB variable /// dot11OCBActivated=true Ocb, /// NAN device interface type (not a netdev) Nan, Other(u32), } impl Nl80211InterfaceType { pub const LENGTH: usize = 4; pub fn parse(payload: &[u8]) -> Result { Ok(parse_u32(payload) .context(format!("Invalid Nl80211InterfaceType data {payload:?}"))? .into()) } } impl Nla for Nl80211InterfaceType { fn value_len(&self) -> usize { Self::LENGTH } fn emit_value(&self, _buffer: &mut [u8]) {} fn kind(&self) -> u16 { u32::from(*self) as u16 } } impl From for Nl80211InterfaceType { fn from(d: u32) -> Self { match d { NL80211_IFTYPE_UNSPECIFIED => Self::Unspecified, NL80211_IFTYPE_ADHOC => Self::Adhoc, NL80211_IFTYPE_STATION => Self::Station, NL80211_IFTYPE_AP => Self::Ap, NL80211_IFTYPE_AP_VLAN => Self::ApVlan, NL80211_IFTYPE_WDS => Self::Wds, NL80211_IFTYPE_MONITOR => Self::Monitor, NL80211_IFTYPE_MESH_POINT => Self::MeshPoint, NL80211_IFTYPE_P2P_CLIENT => Self::P2pClient, NL80211_IFTYPE_P2P_GO => Self::P2pGo, NL80211_IFTYPE_P2P_DEVICE => Self::P2pDevice, NL80211_IFTYPE_OCB => Self::Ocb, NL80211_IFTYPE_NAN => Self::Nan, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211InterfaceType) -> u32 { match v { Nl80211InterfaceType::Unspecified => NL80211_IFTYPE_UNSPECIFIED, Nl80211InterfaceType::Adhoc => NL80211_IFTYPE_ADHOC, Nl80211InterfaceType::Station => NL80211_IFTYPE_STATION, Nl80211InterfaceType::Ap => NL80211_IFTYPE_AP, Nl80211InterfaceType::ApVlan => NL80211_IFTYPE_AP_VLAN, Nl80211InterfaceType::Wds => NL80211_IFTYPE_WDS, Nl80211InterfaceType::Monitor => NL80211_IFTYPE_MONITOR, Nl80211InterfaceType::MeshPoint => NL80211_IFTYPE_MESH_POINT, Nl80211InterfaceType::P2pClient => NL80211_IFTYPE_P2P_CLIENT, Nl80211InterfaceType::P2pGo => NL80211_IFTYPE_P2P_GO, Nl80211InterfaceType::P2pDevice => NL80211_IFTYPE_P2P_DEVICE, Nl80211InterfaceType::Ocb => NL80211_IFTYPE_OCB, Nl80211InterfaceType::Nan => NL80211_IFTYPE_NAN, Nl80211InterfaceType::Other(d) => d, } } } wl-nl80211-0.2.0/src/iface/mod.rs000064400000000000000000000006521046102023000142360ustar 00000000000000// SPDX-License-Identifier: MIT mod combination; mod get; mod handle; mod iface_type; pub use self::combination::{ Nl80211IfaceComb, Nl80211IfaceCombAttribute, Nl80211IfaceCombLimit, Nl80211IfaceCombLimitAttribute, }; pub use self::get::Nl80211InterfaceGetRequest; pub use self::handle::Nl80211InterfaceHandle; pub use self::iface_type::Nl80211InterfaceType; pub(crate) use self::iface_type::Nl80211InterfaceTypes; wl-nl80211-0.2.0/src/lib.rs000064400000000000000000000044441046102023000131610ustar 00000000000000// SPDX-License-Identifier: MIT mod attr; mod channel; mod connection; mod error; mod ext_cap; mod feature; mod frame_type; mod handle; mod iface; mod macros; mod message; mod mlo; mod station; mod stats; mod wifi4; mod wifi5; mod wifi6; mod wifi7; mod wiphy; pub(crate) mod bytes; pub use self::attr::Nl80211Attr; pub use self::channel::Nl80211ChannelWidth; #[cfg(feature = "tokio_socket")] pub use self::connection::new_connection; pub use self::connection::new_connection_with_socket; pub use self::error::Nl80211Error; pub use self::ext_cap::{ Nl80211ExtendedCapability, Nl80211IfTypeExtCapa, Nl80211IfTypeExtCapas, }; pub use self::feature::{Nl80211ExtFeature, Nl80211Features}; pub use self::frame_type::{Nl80211FrameType, Nl80211IfaceFrameType}; pub use self::handle::Nl80211Handle; pub use self::iface::{ Nl80211IfaceComb, Nl80211IfaceCombAttribute, Nl80211IfaceCombLimit, Nl80211IfaceCombLimitAttribute, Nl80211InterfaceGetRequest, Nl80211InterfaceHandle, Nl80211InterfaceType, }; pub use self::message::{Nl80211Cmd, Nl80211Message}; pub use self::mlo::Nl80211MloLink; pub use self::station::{ Nl80211RateInfo, Nl80211StationGetRequest, Nl80211StationHandle, Nl80211StationInfo, }; pub use self::stats::{ NestedNl80211TidStats, Nl80211TidStats, Nl80211TransmitQueueStat, }; pub use self::wifi4::{ Nl80211HtCapabilityMask, Nl80211HtCaps, Nl80211HtMcsInfo, Nl80211HtWiphyChannelType, }; pub use self::wifi5::{ Nl80211VhtCapInfo, Nl80211VhtCapability, Nl80211VhtMcsInfo, }; pub use self::wifi6::{ Nl80211He6GhzCapa, Nl80211HeMacCapInfo, Nl80211HeMcsNssSupp, Nl80211HePhyCapInfo, Nl80211HePpeThreshold, }; pub use self::wifi7::{ Nl80211EhtMacCapInfo, Nl80211EhtMcsNssSupp, Nl80211EhtMcsNssSuppMoreThan20Mhz, Nl80211EhtMcsNssSuppOnly20Mhz, Nl80211EhtPhyCapInfo, Nl80211EhtPpeThres, }; pub use self::wiphy::{ Nl80211Band, Nl80211BandInfo, Nl80211BandType, Nl80211BandTypes, Nl80211CipherSuit, Nl80211Command, Nl80211Frequency, Nl80211FrequencyInfo, Nl80211IfMode, Nl80211WiphyGetRequest, Nl80211WiphyHandle, Nl80211WowlanTcpTrigerSupport, Nl80211WowlanTrigerPatternSupport, Nl80211WowlanTrigersSupport, }; pub(crate) use self::feature::Nl80211ExtFeatures; pub(crate) use self::handle::nl80211_execute; pub(crate) use self::iface::Nl80211InterfaceTypes; wl-nl80211-0.2.0/src/macros.rs000064400000000000000000000017271046102023000137000ustar 00000000000000// SPDX-License-Identifier: MIT #[macro_export] macro_rules! try_nl80211 { ($msg: expr) => {{ use netlink_packet_core::{NetlinkMessage, NetlinkPayload}; use $crate::Nl80211Error; match $msg { Ok(msg) => { let (header, payload) = msg.into_parts(); match payload { NetlinkPayload::InnerMessage(msg) => msg, NetlinkPayload::Error(err) => { return Err(Nl80211Error::NetlinkError(err)) } _ => { return Err(Nl80211Error::UnexpectedMessage( NetlinkMessage::new(header, payload), )) } } } Err(e) => { return Err(Nl80211Error::Bug(format!( "BUG: decode error {:?}", e ))) } } }}; } wl-nl80211-0.2.0/src/message.rs000064400000000000000000000071001046102023000140270ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_generic::{GenlFamily, GenlHeader}; use netlink_packet_utils::{ nla::NlasIterator, DecodeError, Emitable, Parseable, ParseableParametrized, }; use crate::attr::Nl80211Attr; const NL80211_CMD_GET_WIPHY: u8 = 1; const NL80211_CMD_NEW_WIPHY: u8 = 3; const NL80211_CMD_GET_INTERFACE: u8 = 5; const NL80211_CMD_NEW_INTERFACE: u8 = 7; const NL80211_CMD_GET_STATION: u8 = 17; const NL80211_CMD_NEW_STATION: u8 = 19; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211Cmd { InterfaceGet, InterfaceNew, StationGet, StationNew, WiphyGet, WiphyNew, } impl From for u8 { fn from(cmd: Nl80211Cmd) -> Self { match cmd { Nl80211Cmd::InterfaceGet => NL80211_CMD_GET_INTERFACE, Nl80211Cmd::InterfaceNew => NL80211_CMD_NEW_INTERFACE, Nl80211Cmd::StationGet => NL80211_CMD_GET_STATION, Nl80211Cmd::StationNew => NL80211_CMD_NEW_STATION, Nl80211Cmd::WiphyGet => NL80211_CMD_GET_WIPHY, Nl80211Cmd::WiphyNew => NL80211_CMD_NEW_WIPHY, } } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211Message { pub cmd: Nl80211Cmd, pub attributes: Vec, } impl GenlFamily for Nl80211Message { fn family_name() -> &'static str { "nl80211" } fn version(&self) -> u8 { 1 } fn command(&self) -> u8 { self.cmd.into() } } impl Nl80211Message { pub fn new_interface_get() -> Self { Nl80211Message { cmd: Nl80211Cmd::InterfaceGet, attributes: vec![], } } pub fn new_station_get(attributes: Vec) -> Self { Nl80211Message { cmd: Nl80211Cmd::StationGet, attributes, } } pub fn new_wiphy_get() -> Self { Nl80211Message { cmd: Nl80211Cmd::WiphyGet, attributes: vec![Nl80211Attr::SplitWiphyDump], } } } impl Emitable for Nl80211Message { fn buffer_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn emit(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer) } } fn parse_nlas(buffer: &[u8]) -> Result, DecodeError> { let mut nlas = Vec::new(); for nla in NlasIterator::new(buffer) { let error_msg = "Failed to parse nl80211 message attribute".to_string(); let nla = &nla.context(error_msg.clone())?; nlas.push(Nl80211Attr::parse(nla).context(error_msg)?); } Ok(nlas) } impl ParseableParametrized<[u8], GenlHeader> for Nl80211Message { fn parse_with_param( buffer: &[u8], header: GenlHeader, ) -> Result { Ok(match header.cmd { NL80211_CMD_NEW_INTERFACE => Self { cmd: Nl80211Cmd::InterfaceNew, attributes: parse_nlas(buffer)?, }, NL80211_CMD_GET_STATION => Self { cmd: Nl80211Cmd::StationGet, attributes: parse_nlas(buffer)?, }, NL80211_CMD_NEW_STATION => Self { cmd: Nl80211Cmd::StationNew, attributes: parse_nlas(buffer)?, }, NL80211_CMD_NEW_WIPHY => Self { cmd: Nl80211Cmd::WiphyNew, attributes: parse_nlas(buffer)?, }, cmd => { return Err(DecodeError::from(format!( "Unsupported nl80211 reply command: {}", cmd ))) } }) } } wl-nl80211-0.2.0/src/mlo.rs000064400000000000000000000073241046102023000132020ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::parse_u8, DecodeError, Emitable, Parseable, }; const ETH_ALEN: usize = 6; const NL80211_ATTR_MAC: u16 = 6; const NL80211_ATTR_MLO_LINK_ID: u16 = 313; #[derive(Debug, PartialEq, Eq, Clone)] enum Nl80211MloLinkNla { Id(u8), Mac([u8; ETH_ALEN]), Other(DefaultNla), } impl Nla for Nl80211MloLinkNla { fn value_len(&self) -> usize { match self { Self::Id(_) => 1, Self::Mac(_) => ETH_ALEN, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Id(_) => NL80211_ATTR_MLO_LINK_ID, Self::Mac(_) => NL80211_ATTR_MAC, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Id(d) => buffer[0] = *d, Self::Mac(s) => buffer.copy_from_slice(s), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211MloLinkNla { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_ATTR_MLO_LINK_ID => { let err_msg = format!( "Invalid NL80211_ATTR_MLO_LINK_ID value {:?}", payload ); Self::Id(parse_u8(payload).context(err_msg)?) } NL80211_ATTR_MAC => Self::Mac(if payload.len() == ETH_ALEN { let mut ret = [0u8; ETH_ALEN]; ret.copy_from_slice(&payload[..ETH_ALEN]); ret } else { return Err(format!( "Invalid length of NL80211_ATTR_MAC, expected length {} got {:?}", ETH_ALEN, payload ) .into()); }), _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } /// Multi-Link Operation #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] pub struct Nl80211MloLink { pub id: u8, pub mac: [u8; ETH_ALEN], } impl Nla for Nl80211MloLink { fn value_len(&self) -> usize { Vec::::from(self).as_slice().buffer_len() } fn kind(&self) -> u16 { self.id as u16 + 1 } fn emit_value(&self, buffer: &mut [u8]) { Vec::::from(self).as_slice().emit(buffer) } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211MloLink { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut ret = Self::default(); let payload = buf.value(); let err_msg = format!("Invalid NL80211_ATTR_MLO_LINKS value {:?}", payload); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; match Nl80211MloLinkNla::parse(nla).context(err_msg.clone())? { Nl80211MloLinkNla::Id(d) => ret.id = d, Nl80211MloLinkNla::Mac(s) => ret.mac = s, Nl80211MloLinkNla::Other(attr) => { log::warn!( "Got unsupported NL80211_ATTR_MLO_LINKS value {:?}", attr ) } } } Ok(ret) } } impl From<&Nl80211MloLink> for Vec { fn from(link: &Nl80211MloLink) -> Self { vec![ Nl80211MloLinkNla::Id(link.id), Nl80211MloLinkNla::Mac(link.mac), ] } } wl-nl80211-0.2.0/src/station/get.rs000064400000000000000000000022371046102023000146510ustar 00000000000000// SPDX-License-Identifier: MIT use futures::TryStream; use netlink_packet_generic::GenlMessage; use crate::{ nl80211_execute, Nl80211Attr, Nl80211Error, Nl80211Handle, Nl80211Message, }; const ETH_ALEN: usize = 6; pub struct Nl80211StationGetRequest { handle: Nl80211Handle, if_index: u32, mac_address: Option<[u8; ETH_ALEN]>, } impl Nl80211StationGetRequest { pub(crate) fn new( handle: Nl80211Handle, if_index: u32, mac_address: Option<[u8; ETH_ALEN]>, ) -> Self { Nl80211StationGetRequest { handle, if_index, mac_address, } } pub async fn execute( self, ) -> impl TryStream, Error = Nl80211Error> { let Nl80211StationGetRequest { mut handle, if_index, mac_address, } = self; let mut nlas = vec![Nl80211Attr::IfIndex(if_index)]; if let Some(arr) = mac_address { nlas.push(Nl80211Attr::Mac(arr)) } let nl80211_msg = Nl80211Message::new_station_get(nlas); nl80211_execute(&mut handle, nl80211_msg).await } } wl-nl80211-0.2.0/src/station/handle.rs000064400000000000000000000007471046102023000153310ustar 00000000000000// SPDX-License-Identifier: MIT use crate::{Nl80211Handle, Nl80211StationGetRequest}; pub struct Nl80211StationHandle(Nl80211Handle); impl Nl80211StationHandle { pub fn new(handle: Nl80211Handle) -> Self { Nl80211StationHandle(handle) } /// Retrieve the stations /// (equivalent to `iw dev DEV station dump`) pub fn dump(&mut self, if_index: u32) -> Nl80211StationGetRequest { Nl80211StationGetRequest::new(self.0.clone(), if_index, None) } } wl-nl80211-0.2.0/src/station/mod.rs000064400000000000000000000003631046102023000146470ustar 00000000000000// SPDX-License-Identifier: MIT mod get; mod handle; mod rate_info; mod station_info; pub use get::Nl80211StationGetRequest; pub use handle::Nl80211StationHandle; pub use rate_info::Nl80211RateInfo; pub use station_info::Nl80211StationInfo; wl-nl80211-0.2.0/src/station/rate_info.rs000064400000000000000000000512451046102023000160430ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_u16, parse_u32, parse_u8}, DecodeError, Emitable, Parseable, }; pub const NL80211_RATE_INFO_BITRATE: u16 = 1; pub const NL80211_RATE_INFO_MCS: u16 = 2; pub const NL80211_RATE_INFO_40_MHZ_WIDTH: u16 = 3; pub const NL80211_RATE_INFO_SHORT_GI: u16 = 4; pub const NL80211_RATE_INFO_BITRATE32: u16 = 5; pub const NL80211_RATE_INFO_VHT_MCS: u16 = 6; pub const NL80211_RATE_INFO_VHT_NSS: u16 = 7; pub const NL80211_RATE_INFO_80_MHZ_WIDTH: u16 = 8; pub const NL80211_RATE_INFO_80P80_MHZ_WIDTH: u16 = 9; pub const NL80211_RATE_INFO_160_MHZ_WIDTH: u16 = 10; pub const NL80211_RATE_INFO_10_MHZ_WIDTH: u16 = 11; pub const NL80211_RATE_INFO_5_MHZ_WIDTH: u16 = 12; pub const NL80211_RATE_INFO_HE_MCS: u16 = 13; pub const NL80211_RATE_INFO_HE_NSS: u16 = 14; pub const NL80211_RATE_INFO_HE_GI: u16 = 15; pub const NL80211_RATE_INFO_HE_DCM: u16 = 16; pub const NL80211_RATE_INFO_HE_RU_ALLOC: u16 = 17; pub const NL80211_RATE_INFO_320_MHZ_WIDTH: u16 = 18; pub const NL80211_RATE_INFO_EHT_MCS: u16 = 19; pub const NL80211_RATE_INFO_EHT_NSS: u16 = 20; pub const NL80211_RATE_INFO_EHT_GI: u16 = 21; pub const NL80211_RATE_INFO_EHT_RU_ALLOC: u16 = 22; pub const NL80211_RATE_INFO_S1G_MCS: u16 = 23; pub const NL80211_RATE_INFO_S1G_NSS: u16 = 24; pub const NL80211_RATE_INFO_1_MHZ_WIDTH: u16 = 25; pub const NL80211_RATE_INFO_2_MHZ_WIDTH: u16 = 26; pub const NL80211_RATE_INFO_4_MHZ_WIDTH: u16 = 27; pub const NL80211_RATE_INFO_8_MHZ_WIDTH: u16 = 28; pub const NL80211_RATE_INFO_16_MHZ_WIDTH: u16 = 29; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211RateInfo { /// Total bitrate, 100kb/s Bitrate(u16), /// MCS index for 802.11n Mcs(u8), MhzWidth(u32), /// 400ns guard interval ShortGi, /// Total bitrate, 100kb/s Bitrate32(u32), /// MCS index for VHT VhtMcs(u8), /// Number of streams in VHT VhtNss(u8), /// Unused, 80+80 is treated the same as 160 for purposes of the bitrates MhzWidth80Plus80, /// HE MCS index HeMcs(u8), /// HE NSS value HeNss(u8), /// HE guard interval identifier [`Nl80211HeGi`] HeGi(Nl80211HeGi), /// HE DCM value HeDcm(u8), /// HE RU allocation, if not present then non-OFDMA was used. /// See [`Nl80211HeRuAlloc`] HeRuAlloc(Nl80211HeRuAllocation), /// S1G MCS index S1gMcs(u8), /// S1G NSS value S1gNss(u8), /// EHT MCS index EhtMcs(u8), /// EHT NSS value EhtNss(u8), /// EHT guard interval identifier [`Nl80211EhtGi`] EhtGi(Nl80211EhtGi), /// EHT RU allocation, if not present then non-OFDMA was used. /// See [`Nl80211EhtRuAlloc`] EhtRuAlloc(Nl80211EhtRuAllocation), Other(DefaultNla), } impl Nla for Nl80211RateInfo { fn value_len(&self) -> usize { match self { Self::MhzWidth(_) | Self::ShortGi | Self::MhzWidth80Plus80 => 0, Self::Mcs(_) | Self::VhtMcs(_) | Self::VhtNss(_) | Self::HeMcs(_) | Self::HeNss(_) | Self::HeGi(_) | Self::HeDcm(_) | Self::HeRuAlloc(_) | Self::S1gMcs(_) | Self::S1gNss(_) | Self::EhtMcs(_) | Self::EhtNss(_) | Self::EhtGi(_) | Self::EhtRuAlloc(_) => 1, Self::Bitrate(_) => 2, Self::Bitrate32(_) => 4, Self::Other(nlas) => nlas.value_len(), } } fn kind(&self) -> u16 { match self { Self::Bitrate(_) => NL80211_RATE_INFO_BITRATE, Self::Mcs(_) => NL80211_RATE_INFO_MCS, Self::MhzWidth(1) => NL80211_RATE_INFO_1_MHZ_WIDTH, Self::MhzWidth(2) => NL80211_RATE_INFO_2_MHZ_WIDTH, Self::MhzWidth(4) => NL80211_RATE_INFO_4_MHZ_WIDTH, Self::MhzWidth(5) => NL80211_RATE_INFO_5_MHZ_WIDTH, Self::MhzWidth(8) => NL80211_RATE_INFO_8_MHZ_WIDTH, Self::MhzWidth(10) => NL80211_RATE_INFO_10_MHZ_WIDTH, Self::MhzWidth(16) => NL80211_RATE_INFO_16_MHZ_WIDTH, Self::MhzWidth(40) => NL80211_RATE_INFO_40_MHZ_WIDTH, Self::MhzWidth(80) => NL80211_RATE_INFO_80_MHZ_WIDTH, Self::MhzWidth(160) => NL80211_RATE_INFO_160_MHZ_WIDTH, Self::MhzWidth(320) => NL80211_RATE_INFO_320_MHZ_WIDTH, Self::MhzWidth(freq) => { log::warn!("Invalid Nl80211RateInfo::MhzWidth {:?}", freq); u16::MAX } Self::MhzWidth80Plus80 => NL80211_RATE_INFO_80P80_MHZ_WIDTH, Self::ShortGi => NL80211_RATE_INFO_SHORT_GI, Self::Bitrate32(_) => NL80211_RATE_INFO_BITRATE32, Self::VhtMcs(_) => NL80211_RATE_INFO_VHT_MCS, Self::VhtNss(_) => NL80211_RATE_INFO_VHT_NSS, Self::HeMcs(_) => NL80211_RATE_INFO_HE_MCS, Self::HeNss(_) => NL80211_RATE_INFO_HE_NSS, Self::HeGi(_) => NL80211_RATE_INFO_HE_GI, Self::HeDcm(_) => NL80211_RATE_INFO_HE_DCM, Self::HeRuAlloc(_) => NL80211_RATE_INFO_HE_RU_ALLOC, Self::S1gMcs(_) => NL80211_RATE_INFO_S1G_MCS, Self::S1gNss(_) => NL80211_RATE_INFO_S1G_NSS, Self::EhtMcs(_) => NL80211_RATE_INFO_EHT_MCS, Self::EhtNss(_) => NL80211_RATE_INFO_EHT_NSS, Self::EhtGi(_) => NL80211_RATE_INFO_EHT_GI, Self::EhtRuAlloc(_) => NL80211_RATE_INFO_EHT_RU_ALLOC, Self::Other(info) => info.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Bitrate(bitrate) => NativeEndian::write_u16(buffer, *bitrate), Self::Mcs(d) | Self::VhtMcs(d) | Self::VhtNss(d) | Self::HeMcs(d) | Self::HeNss(d) | Self::HeDcm(d) | Self::S1gMcs(d) | Self::S1gNss(d) | Self::EhtMcs(d) | Self::EhtNss(d) => buffer[0] = *d, Self::MhzWidth(_) | Self::ShortGi | Self::MhzWidth80Plus80 => (), Self::Bitrate32(bitrate) => { NativeEndian::write_u32(buffer, *bitrate) } Self::HeGi(d) => buffer[0] = (*d).into(), Self::HeRuAlloc(d) => buffer[0] = (*d).into(), Self::EhtGi(d) => buffer[0] = (*d).into(), Self::EhtRuAlloc(d) => buffer[0] = (*d).into(), Self::Other(nlas) => nlas.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211RateInfo { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_RATE_INFO_BITRATE => { let err_msg = format!( "Invalid NL80211_RATE_INFO_BITRATE value {:?}", payload ); Self::Bitrate(parse_u16(payload).context(err_msg)?) } NL80211_RATE_INFO_MCS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_MCS value {:?}", payload ); Self::Mcs(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_1_MHZ_WIDTH => Self::MhzWidth(1), NL80211_RATE_INFO_2_MHZ_WIDTH => Self::MhzWidth(2), NL80211_RATE_INFO_4_MHZ_WIDTH => Self::MhzWidth(4), NL80211_RATE_INFO_5_MHZ_WIDTH => Self::MhzWidth(5), NL80211_RATE_INFO_8_MHZ_WIDTH => Self::MhzWidth(8), NL80211_RATE_INFO_10_MHZ_WIDTH => Self::MhzWidth(10), NL80211_RATE_INFO_16_MHZ_WIDTH => Self::MhzWidth(16), NL80211_RATE_INFO_40_MHZ_WIDTH => Self::MhzWidth(40), NL80211_RATE_INFO_80_MHZ_WIDTH => Self::MhzWidth(80), NL80211_RATE_INFO_160_MHZ_WIDTH => Self::MhzWidth(160), NL80211_RATE_INFO_320_MHZ_WIDTH => Self::MhzWidth(320), NL80211_RATE_INFO_80P80_MHZ_WIDTH => Self::MhzWidth80Plus80, NL80211_RATE_INFO_SHORT_GI => Self::ShortGi, NL80211_RATE_INFO_BITRATE32 => { let err_msg = format!( "Invalid NL80211_RATE_INFO_BITRATE32 value {:?}", payload ); Self::Bitrate32(parse_u32(payload).context(err_msg)?) } NL80211_RATE_INFO_VHT_MCS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_VHT_MCS value {:?}", payload ); Self::VhtMcs(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_VHT_NSS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_VHT_NSS value {:?}", payload ); Self::VhtNss(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_HE_MCS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_HE_MCS value {:?}", payload ); Self::HeMcs(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_HE_NSS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_HE_NSS value {:?}", payload ); Self::HeNss(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_HE_GI => { // let err_msg = format!( "Invalid NL80211_RATE_INFO_HE_GI value {:?}", payload ); Self::HeGi(parse_u8(payload).context(err_msg)?.into()) } NL80211_RATE_INFO_HE_DCM => { let err_msg = format!( "Invalid NL80211_RATE_INFO_HE_DCM value {:?}", payload ); Self::HeDcm(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_HE_RU_ALLOC => { // let err_msg = format!( "Invalid NL80211_RATE_INFO_HE_RU_ALLOC value {:?}", payload ); Self::HeRuAlloc(parse_u8(payload).context(err_msg)?.into()) } NL80211_RATE_INFO_S1G_MCS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_S1G_MCS value {:?}", payload ); Self::S1gMcs(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_S1G_NSS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_S1G_NSS value {:?}", payload ); Self::S1gNss(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_EHT_MCS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_EHT_MCS value {:?}", payload ); Self::EhtMcs(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_EHT_NSS => { let err_msg = format!( "Invalid NL80211_RATE_INFO_EHT_NSS value {:?}", payload ); Self::EhtNss(parse_u8(payload).context(err_msg)?) } NL80211_RATE_INFO_EHT_GI => { // let err_msg = format!( "Invalid NL80211_RATE_INFO_EHT_GI value {:?}", payload ); Self::EhtGi(parse_u8(payload).context(err_msg)?.into()) } NL80211_RATE_INFO_EHT_RU_ALLOC => { // let err_msg = format!( "Invalid NL80211_RATE_INFO_EHT_RU_ALLOC value {:?}", payload ); Self::EhtRuAlloc(parse_u8(payload).context(err_msg)?.into()) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } const NL80211_RATE_INFO_HE_GI_0_8: u8 = 0; const NL80211_RATE_INFO_HE_GI_1_6: u8 = 1; const NL80211_RATE_INFO_HE_GI_3_2: u8 = 2; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211HeGi { /// 0.8 usec Usec0_8, /// 1.6 usec Usec1_6, /// 3.2 usec Usec3_2, Other(u8), } impl From for Nl80211HeGi { fn from(d: u8) -> Self { match d { NL80211_RATE_INFO_HE_GI_0_8 => Self::Usec0_8, NL80211_RATE_INFO_HE_GI_1_6 => Self::Usec1_6, NL80211_RATE_INFO_HE_GI_3_2 => Self::Usec3_2, _ => Self::Other(d), } } } impl From for u8 { fn from(v: Nl80211HeGi) -> u8 { match v { Nl80211HeGi::Usec0_8 => NL80211_RATE_INFO_HE_GI_0_8, Nl80211HeGi::Usec1_6 => NL80211_RATE_INFO_HE_GI_1_6, Nl80211HeGi::Usec3_2 => NL80211_RATE_INFO_HE_GI_3_2, Nl80211HeGi::Other(d) => d, } } } const NL80211_RATE_INFO_HE_RU_ALLOC_26: u8 = 0; const NL80211_RATE_INFO_HE_RU_ALLOC_52: u8 = 1; const NL80211_RATE_INFO_HE_RU_ALLOC_106: u8 = 2; const NL80211_RATE_INFO_HE_RU_ALLOC_242: u8 = 3; const NL80211_RATE_INFO_HE_RU_ALLOC_484: u8 = 4; const NL80211_RATE_INFO_HE_RU_ALLOC_996: u8 = 5; const NL80211_RATE_INFO_HE_RU_ALLOC_2X996: u8 = 6; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211HeRuAllocation { Tone(u32), Tone2x996, Other(u8), } impl From for Nl80211HeRuAllocation { fn from(d: u8) -> Self { match d { NL80211_RATE_INFO_HE_RU_ALLOC_26 => Self::Tone(26), NL80211_RATE_INFO_HE_RU_ALLOC_52 => Self::Tone(52), NL80211_RATE_INFO_HE_RU_ALLOC_106 => Self::Tone(106), NL80211_RATE_INFO_HE_RU_ALLOC_242 => Self::Tone(242), NL80211_RATE_INFO_HE_RU_ALLOC_484 => Self::Tone(484), NL80211_RATE_INFO_HE_RU_ALLOC_996 => Self::Tone(996), NL80211_RATE_INFO_HE_RU_ALLOC_2X996 => Self::Tone2x996, _ => Self::Other(d), } } } impl From for u8 { fn from(v: Nl80211HeRuAllocation) -> u8 { match v { Nl80211HeRuAllocation::Tone(26) => NL80211_RATE_INFO_HE_RU_ALLOC_26, Nl80211HeRuAllocation::Tone(52) => NL80211_RATE_INFO_HE_RU_ALLOC_52, Nl80211HeRuAllocation::Tone(106) => { NL80211_RATE_INFO_HE_RU_ALLOC_106 } Nl80211HeRuAllocation::Tone(242) => { NL80211_RATE_INFO_HE_RU_ALLOC_242 } Nl80211HeRuAllocation::Tone(484) => { NL80211_RATE_INFO_HE_RU_ALLOC_484 } Nl80211HeRuAllocation::Tone(996) => { NL80211_RATE_INFO_HE_RU_ALLOC_996 } Nl80211HeRuAllocation::Tone(_) => { log::warn!("Invalid Nl80211HeRuAllocation {:?}", v); u8::MAX } Nl80211HeRuAllocation::Tone2x996 => { NL80211_RATE_INFO_HE_RU_ALLOC_2X996 } Nl80211HeRuAllocation::Other(d) => d, } } } const NL80211_RATE_INFO_EHT_GI_0_8: u8 = 0; const NL80211_RATE_INFO_EHT_GI_1_6: u8 = 1; const NL80211_RATE_INFO_EHT_GI_3_2: u8 = 2; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211EhtGi { /// 0.8 usec Usec0_8, /// 1.6 usec Usec1_6, /// 3.2 usec Usec3_2, Other(u8), } impl From for Nl80211EhtGi { fn from(d: u8) -> Self { match d { NL80211_RATE_INFO_EHT_GI_0_8 => Self::Usec0_8, NL80211_RATE_INFO_EHT_GI_1_6 => Self::Usec1_6, NL80211_RATE_INFO_EHT_GI_3_2 => Self::Usec3_2, _ => Self::Other(d), } } } impl From for u8 { fn from(v: Nl80211EhtGi) -> u8 { match v { Nl80211EhtGi::Usec0_8 => NL80211_RATE_INFO_EHT_GI_0_8, Nl80211EhtGi::Usec1_6 => NL80211_RATE_INFO_EHT_GI_1_6, Nl80211EhtGi::Usec3_2 => NL80211_RATE_INFO_EHT_GI_3_2, Nl80211EhtGi::Other(d) => d, } } } const NL80211_RATE_INFO_EHT_RU_ALLOC_26: u8 = 0; const NL80211_RATE_INFO_EHT_RU_ALLOC_52: u8 = 1; const NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: u8 = 2; const NL80211_RATE_INFO_EHT_RU_ALLOC_106: u8 = 3; const NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: u8 = 4; const NL80211_RATE_INFO_EHT_RU_ALLOC_242: u8 = 5; const NL80211_RATE_INFO_EHT_RU_ALLOC_484: u8 = 6; const NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: u8 = 7; const NL80211_RATE_INFO_EHT_RU_ALLOC_996: u8 = 8; const NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: u8 = 9; const NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: u8 = 10; const NL80211_RATE_INFO_EHT_RU_ALLOC_2X996: u8 = 11; const NL80211_RATE_INFO_EHT_RU_ALLOC_2X996P484: u8 = 12; const NL80211_RATE_INFO_EHT_RU_ALLOC_3X996: u8 = 13; const NL80211_RATE_INFO_EHT_RU_ALLOC_3X996P484: u8 = 14; const NL80211_RATE_INFO_EHT_RU_ALLOC_4X996: u8 = 15; /// EHT RU allocation values #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211EhtRuAllocation { Tone(u32), Tone52Plus26, Tone106Plus26, Tone484Plus242, Tone996Plus484, Tone996Plus484Plus242, Tone2x996, Tone2x996Plus484, Tone3x996, Tone3x996Plus484, Tone4x996, Other(u8), } impl From for Nl80211EhtRuAllocation { fn from(d: u8) -> Self { match d { NL80211_RATE_INFO_EHT_RU_ALLOC_26 => Self::Tone(26), NL80211_RATE_INFO_EHT_RU_ALLOC_52 => Self::Tone(52), NL80211_RATE_INFO_EHT_RU_ALLOC_52P26 => Self::Tone52Plus26, NL80211_RATE_INFO_EHT_RU_ALLOC_106 => Self::Tone(106), NL80211_RATE_INFO_EHT_RU_ALLOC_106P26 => Self::Tone106Plus26, NL80211_RATE_INFO_EHT_RU_ALLOC_242 => Self::Tone(242), NL80211_RATE_INFO_EHT_RU_ALLOC_484 => Self::Tone(484), NL80211_RATE_INFO_EHT_RU_ALLOC_484P242 => Self::Tone484Plus242, NL80211_RATE_INFO_EHT_RU_ALLOC_996 => Self::Tone(996), NL80211_RATE_INFO_EHT_RU_ALLOC_996P484 => Self::Tone996Plus484, NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242 => { Self::Tone996Plus484Plus242 } NL80211_RATE_INFO_EHT_RU_ALLOC_2X996 => Self::Tone2x996, NL80211_RATE_INFO_EHT_RU_ALLOC_2X996P484 => Self::Tone2x996Plus484, NL80211_RATE_INFO_EHT_RU_ALLOC_3X996 => Self::Tone3x996, NL80211_RATE_INFO_EHT_RU_ALLOC_3X996P484 => Self::Tone3x996Plus484, NL80211_RATE_INFO_EHT_RU_ALLOC_4X996 => Self::Tone4x996, _ => Self::Other(d), } } } impl From for u8 { fn from(v: Nl80211EhtRuAllocation) -> u8 { match v { Nl80211EhtRuAllocation::Tone(26) => { NL80211_RATE_INFO_EHT_RU_ALLOC_26 } Nl80211EhtRuAllocation::Tone(52) => { NL80211_RATE_INFO_EHT_RU_ALLOC_52 } Nl80211EhtRuAllocation::Tone(106) => { NL80211_RATE_INFO_EHT_RU_ALLOC_106 } Nl80211EhtRuAllocation::Tone(242) => { NL80211_RATE_INFO_EHT_RU_ALLOC_242 } Nl80211EhtRuAllocation::Tone(484) => { NL80211_RATE_INFO_EHT_RU_ALLOC_484 } Nl80211EhtRuAllocation::Tone(996) => { NL80211_RATE_INFO_EHT_RU_ALLOC_996 } Nl80211EhtRuAllocation::Tone(_) => { log::warn!("Invalid Nl80211EhtRuAllocation {:?}", v); u8::MAX } Nl80211EhtRuAllocation::Tone52Plus26 => { NL80211_RATE_INFO_EHT_RU_ALLOC_52P26 } Nl80211EhtRuAllocation::Tone106Plus26 => { NL80211_RATE_INFO_EHT_RU_ALLOC_106P26 } Nl80211EhtRuAllocation::Tone484Plus242 => { NL80211_RATE_INFO_EHT_RU_ALLOC_484P242 } Nl80211EhtRuAllocation::Tone996Plus484 => { NL80211_RATE_INFO_EHT_RU_ALLOC_996P484 } Nl80211EhtRuAllocation::Tone996Plus484Plus242 => { NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242 } Nl80211EhtRuAllocation::Tone2x996 => { NL80211_RATE_INFO_EHT_RU_ALLOC_2X996 } Nl80211EhtRuAllocation::Tone2x996Plus484 => { NL80211_RATE_INFO_EHT_RU_ALLOC_2X996P484 } Nl80211EhtRuAllocation::Tone3x996 => { NL80211_RATE_INFO_EHT_RU_ALLOC_3X996 } Nl80211EhtRuAllocation::Tone3x996Plus484 => { NL80211_RATE_INFO_EHT_RU_ALLOC_3X996P484 } Nl80211EhtRuAllocation::Tone4x996 => { NL80211_RATE_INFO_EHT_RU_ALLOC_4X996 } Nl80211EhtRuAllocation::Other(d) => d, } } } wl-nl80211-0.2.0/src/station/station_info.rs000064400000000000000000001176221046102023000165730ustar 00000000000000// SPDX-License-Identifier: MIT use std::convert::TryInto; use anyhow::Context; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_u16, parse_u32, parse_u64, parse_u8}, Emitable, Parseable, }; use std::fmt::Debug; use crate::NestedNl80211TidStats; use super::Nl80211RateInfo; const NL80211_STA_INFO_INACTIVE_TIME: u16 = 1; const NL80211_STA_INFO_RX_BYTES: u16 = 2; const NL80211_STA_INFO_TX_BYTES: u16 = 3; const NL80211_STA_INFO_LLID: u16 = 4; const NL80211_STA_INFO_PLID: u16 = 5; const NL80211_STA_INFO_PLINK_STATE: u16 = 6; const NL80211_STA_INFO_SIGNAL: u16 = 7; const NL80211_STA_INFO_TX_BITRATE: u16 = 8; const NL80211_STA_INFO_RX_PACKETS: u16 = 9; const NL80211_STA_INFO_TX_PACKETS: u16 = 10; const NL80211_STA_INFO_TX_RETRIES: u16 = 11; const NL80211_STA_INFO_TX_FAILED: u16 = 12; const NL80211_STA_INFO_SIGNAL_AVG: u16 = 13; const NL80211_STA_INFO_RX_BITRATE: u16 = 14; const NL80211_STA_INFO_BSS_PARAM: u16 = 15; const NL80211_STA_INFO_CONNECTED_TIME: u16 = 16; const NL80211_STA_INFO_STA_FLAGS: u16 = 17; const NL80211_STA_INFO_BEACON_LOSS: u16 = 18; const NL80211_STA_INFO_T_OFFSET: u16 = 19; const NL80211_STA_INFO_LOCAL_PM: u16 = 20; const NL80211_STA_INFO_PEER_PM: u16 = 21; const NL80211_STA_INFO_NONPEER_PM: u16 = 22; const NL80211_STA_INFO_RX_BYTES64: u16 = 23; const NL80211_STA_INFO_TX_BYTES64: u16 = 24; const NL80211_STA_INFO_CHAIN_SIGNAL: u16 = 25; const NL80211_STA_INFO_CHAIN_SIGNAL_AVG: u16 = 26; const NL80211_STA_INFO_EXPECTED_THROUGHPUT: u16 = 27; const NL80211_STA_INFO_RX_DROP_MISC: u16 = 28; const NL80211_STA_INFO_BEACON_RX: u16 = 29; const NL80211_STA_INFO_BEACON_SIGNAL_AVG: u16 = 30; const NL80211_STA_INFO_TID_STATS: u16 = 31; const NL80211_STA_INFO_RX_DURATION: u16 = 32; const NL80211_STA_INFO_ACK_SIGNAL: u16 = 34; const NL80211_STA_INFO_ACK_SIGNAL_AVG: u16 = 35; const NL80211_STA_INFO_RX_MPDUS: u16 = 36; const NL80211_STA_INFO_FCS_ERROR_COUNT: u16 = 37; const NL80211_STA_INFO_CONNECTED_TO_GATE: u16 = 38; const NL80211_STA_INFO_TX_DURATION: u16 = 39; const NL80211_STA_INFO_AIRTIME_WEIGHT: u16 = 40; const NL80211_STA_INFO_AIRTIME_LINK_METRIC: u16 = 41; const NL80211_STA_INFO_ASSOC_AT_BOOTTIME: u16 = 42; const NL80211_STA_INFO_CONNECTED_TO_AS: u16 = 43; /// Station information /// /// These attribute types are used with [`Nl80211Attr::Nl80211StationInfo`] /// when getting information about a station. #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211StationInfo { /// Time since last activity (msecs) InactiveTime(u32), /// Total transmitted bytes (MPDU length) TxBytes(u32), /// Total received bytes (MPDU length) RxBytes(u32), /// Total transmitted bytes (MPDU length) TxBytes64(u64), /// Total received bytes (MPDU length) RxBytes64(u64), /// Signal strength of last received PPDU (dBm) Signal(i8), /// Signal strength average (u8, dBm) SignalAvg(i8), /// Current unicast transmission rate, nested attribute containing info as /// possible, see [`Nl80211RateInfo`] TxBitrate(Vec), /// Last unicast data frame receive rate, nested attribute, like /// [`NL80211_STA_INFO_TX_BITRATE`]. RxBitrate(Vec), /// Total transmitted packets (MSDUs and MMPDUs) TxPackets(u32), /// Total received packets (MSDUs and MMPDUs) RxPackets(u32), /// Total number of received packets (MPDUs) RxMpdus(u32), /// Total retries (MPDUs) TxRetries(u32), /// Total failed packets (MPDUs) (u32, to this station) TxFailed(u32), /// Transmitted packets dropped for unspecified reasons RxDropMisc(u64), /// Total number of packets (MPDUs) received with an FCS error . This count /// may not include some packets with an FCS error due to TA corruption. /// Hence this counter might not be fully accurate. FcsErrorCount(u32), /// The station's mesh LLID Llid(u16), /// The station's mesh PLID Plid(u16), /// Peer link state for the station (see [`Nl80211PeerLinkState`]) PeerLinkState(Nl80211PeerLinkState), /// Current station's view of BSS, nested attribute containing info as /// possible, see [`Nl80211StationBssParam`] BssParam(Vec), /// Time since the station is last connected ConnectedTime(u32), /// Contains a [Nl80211StationFlagUpdate] StationFlags(Nl80211StationFlagUpdate), /// Timing offset with respect to this station TimingOffset(i64), /// Local mesh staion link-specific power mode LocalPowerMode(Nl80211MeshPowerMode), /// Peer mesh staion link-specific power mode PeerPowerMode(Nl80211MeshPowerMode), /// Neighbor mesh station power save mode towards non-peer station NonPeerPowerMode(Nl80211MeshPowerMode), /// Per-chain signal strength of last PPDU. Contains a nested array of /// signal strength attributes (dBm) ChainSignal(Vec), /// Per-chain signal strength average. Same format as /// [`Nl80211StationInfo::ChainSignal`] ChainSignalAvg(Vec), /// Expected throughput considering also the 802.11 header (kbps) ExpectedThroughput(u32), /// Number of beacons received from this peer BeaconRx(u64), /// Signal strength average for beacons only (dBm) BeaconSignalAvg(i8), /// Count of times beacon loss was detected BeaconLoss(u32), /// This is a nested attribute where each the inner attribute number is the /// TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS /// frames; each one of those is again nested with &enum nl80211_tid_stats /// attributes carrying the actual values. TidStats(Vec), /// Aggregate PPDU duration for all frames sent to the station (usec) TxDuration(u64), /// Aggregate PPDU duration for all frames received from the station (usec) RxDuration(u64), /// Signal strength of the last ACK frame (dBm) AckSignal(i8), /// Average signal strength of ACK frames (dBm) AckSignalAvg(i8), /// Set to true if the station has a path to a mesh gate ConnectedToGate(bool), /// Current airtime weight for station AirtimeWeight(u16), /// Airtime link metric for mesh station AirtimeLinkMetric(u16), /// Timestamp (nanoseconds) of station's association AssociationAtBoottime(u64), /// Set to true if the station has a path to an authentication server ConnectedToAuthServer(bool), Other(DefaultNla), } impl Nla for Nl80211StationInfo { fn value_len(&self) -> usize { match self { Self::Signal(_) | Self::SignalAvg(_) | Self::AckSignal(_) | Self::AckSignalAvg(_) | Self::BeaconSignalAvg(_) => 1, Self::PeerLinkState(_) | Self::ConnectedToGate(_) | Self::ConnectedToAuthServer(_) => 1, Self::Llid(_) | Self::Plid(_) | Self::AirtimeWeight(_) | Self::AirtimeLinkMetric(_) => 2, Self::InactiveTime(_) | Self::TxBytes(_) | Self::RxBytes(_) | Self::TxPackets(_) | Self::RxPackets(_) | Self::RxMpdus(_) | Self::TxRetries(_) | Self::TxFailed(_) | Self::FcsErrorCount(_) | Self::ConnectedTime(_) | Self::LocalPowerMode(_) | Self::PeerPowerMode(_) | Self::NonPeerPowerMode(_) | Self::ExpectedThroughput(_) | Self::BeaconLoss(_) => 4, Self::TxBytes64(_) | Self::RxBytes64(_) | Self::RxDropMisc(_) | Self::StationFlags(_) | Self::TimingOffset(_) | Self::BeaconRx(_) | Self::TxDuration(_) | Self::RxDuration(_) | Self::AssociationAtBoottime(_) => 8, Self::TxBitrate(nlas) | Self::RxBitrate(nlas) => { nlas.as_slice().buffer_len() } Self::BssParam(nlas) => nlas.as_slice().buffer_len(), Self::ChainSignal(d) | Self::ChainSignalAvg(d) => d.len(), Self::TidStats(nlas) => nlas.as_slice().buffer_len(), Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Nl80211StationInfo::InactiveTime(_) => { NL80211_STA_INFO_INACTIVE_TIME } Nl80211StationInfo::TxBytes(_) => NL80211_STA_INFO_TX_BYTES, Nl80211StationInfo::RxBytes(_) => NL80211_STA_INFO_RX_BYTES, Nl80211StationInfo::TxBytes64(_) => NL80211_STA_INFO_TX_BYTES64, Nl80211StationInfo::RxBytes64(_) => NL80211_STA_INFO_RX_BYTES64, Nl80211StationInfo::Signal(_) => NL80211_STA_INFO_SIGNAL, Nl80211StationInfo::SignalAvg(_) => NL80211_STA_INFO_SIGNAL_AVG, Nl80211StationInfo::TxBitrate(_) => NL80211_STA_INFO_TX_BITRATE, Nl80211StationInfo::RxBitrate(_) => NL80211_STA_INFO_RX_BITRATE, Nl80211StationInfo::TxPackets(_) => NL80211_STA_INFO_TX_PACKETS, Nl80211StationInfo::RxPackets(_) => NL80211_STA_INFO_RX_PACKETS, Nl80211StationInfo::RxMpdus(_) => NL80211_STA_INFO_RX_MPDUS, Nl80211StationInfo::TxRetries(_) => NL80211_STA_INFO_TX_RETRIES, Nl80211StationInfo::TxFailed(_) => NL80211_STA_INFO_TX_FAILED, Nl80211StationInfo::RxDropMisc(_) => NL80211_STA_INFO_RX_DROP_MISC, Nl80211StationInfo::FcsErrorCount(_) => { NL80211_STA_INFO_FCS_ERROR_COUNT } Nl80211StationInfo::Llid(_) => NL80211_STA_INFO_LLID, Nl80211StationInfo::Plid(_) => NL80211_STA_INFO_PLID, Nl80211StationInfo::PeerLinkState(_) => { NL80211_STA_INFO_PLINK_STATE } Nl80211StationInfo::BssParam(_) => NL80211_STA_INFO_BSS_PARAM, Nl80211StationInfo::ConnectedTime(_) => { NL80211_STA_INFO_CONNECTED_TIME } Nl80211StationInfo::StationFlags(_) => NL80211_STA_INFO_STA_FLAGS, Nl80211StationInfo::TimingOffset(_) => NL80211_STA_INFO_T_OFFSET, Nl80211StationInfo::LocalPowerMode(_) => NL80211_STA_INFO_LOCAL_PM, Nl80211StationInfo::PeerPowerMode(_) => NL80211_STA_INFO_PEER_PM, Nl80211StationInfo::NonPeerPowerMode(_) => { NL80211_STA_INFO_NONPEER_PM } Nl80211StationInfo::ChainSignal(_) => NL80211_STA_INFO_CHAIN_SIGNAL, Nl80211StationInfo::ChainSignalAvg(_) => { NL80211_STA_INFO_CHAIN_SIGNAL_AVG } Nl80211StationInfo::ExpectedThroughput(_) => { NL80211_STA_INFO_EXPECTED_THROUGHPUT } Nl80211StationInfo::BeaconRx(_) => NL80211_STA_INFO_BEACON_RX, Nl80211StationInfo::BeaconSignalAvg(_) => { NL80211_STA_INFO_BEACON_SIGNAL_AVG } Nl80211StationInfo::BeaconLoss(_) => NL80211_STA_INFO_BEACON_LOSS, Nl80211StationInfo::TidStats(_) => NL80211_STA_INFO_TID_STATS, Nl80211StationInfo::TxDuration(_) => NL80211_STA_INFO_TX_DURATION, Nl80211StationInfo::RxDuration(_) => NL80211_STA_INFO_RX_DURATION, Nl80211StationInfo::AckSignal(_) => NL80211_STA_INFO_ACK_SIGNAL, Nl80211StationInfo::AckSignalAvg(_) => { NL80211_STA_INFO_ACK_SIGNAL_AVG } Nl80211StationInfo::ConnectedToGate(_) => { NL80211_STA_INFO_CONNECTED_TO_GATE } Nl80211StationInfo::AirtimeWeight(_) => { NL80211_STA_INFO_AIRTIME_WEIGHT } Nl80211StationInfo::AirtimeLinkMetric(_) => { NL80211_STA_INFO_AIRTIME_LINK_METRIC } Nl80211StationInfo::AssociationAtBoottime(_) => { NL80211_STA_INFO_ASSOC_AT_BOOTTIME } Nl80211StationInfo::ConnectedToAuthServer(_) => { NL80211_STA_INFO_CONNECTED_TO_AS } Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Nl80211StationInfo::Signal(d) | Nl80211StationInfo::SignalAvg(d) | Nl80211StationInfo::BeaconSignalAvg(d) | Nl80211StationInfo::AckSignal(d) | Nl80211StationInfo::AckSignalAvg(d) => buffer[0] = *d as u8, Nl80211StationInfo::Llid(d) | Nl80211StationInfo::Plid(d) | Nl80211StationInfo::AirtimeWeight(d) | Nl80211StationInfo::AirtimeLinkMetric(d) => { NativeEndian::write_u16(buffer, *d) } Nl80211StationInfo::InactiveTime(d) | Nl80211StationInfo::TxBytes(d) | Nl80211StationInfo::RxBytes(d) | Nl80211StationInfo::TxPackets(d) | Nl80211StationInfo::RxPackets(d) | Nl80211StationInfo::RxMpdus(d) | Nl80211StationInfo::TxRetries(d) | Nl80211StationInfo::TxFailed(d) | Nl80211StationInfo::FcsErrorCount(d) | Nl80211StationInfo::ConnectedTime(d) | Nl80211StationInfo::ExpectedThroughput(d) | Nl80211StationInfo::BeaconLoss(d) => { NativeEndian::write_u32(buffer, *d) } Nl80211StationInfo::TxBytes64(d) | Nl80211StationInfo::RxBytes64(d) | Nl80211StationInfo::RxDropMisc(d) | Nl80211StationInfo::BeaconRx(d) | Nl80211StationInfo::TxDuration(d) | Nl80211StationInfo::RxDuration(d) | Nl80211StationInfo::AssociationAtBoottime(d) => { NativeEndian::write_u64(buffer, *d) } Nl80211StationInfo::TimingOffset(d) => { NativeEndian::write_i64(buffer, *d) } Nl80211StationInfo::TxBitrate(nlas) | Nl80211StationInfo::RxBitrate(nlas) => { nlas.as_slice().emit(buffer) } Nl80211StationInfo::PeerLinkState(d) => buffer[0] = (*d).into(), Nl80211StationInfo::BssParam(nlas) => nlas.as_slice().emit(buffer), Nl80211StationInfo::StationFlags(d) => { NativeEndian::write_u32(&mut buffer[0..4], (&d.mask).into()); NativeEndian::write_u32(&mut buffer[4..8], (&d.set).into()); } Nl80211StationInfo::LocalPowerMode(d) | Nl80211StationInfo::PeerPowerMode(d) | Nl80211StationInfo::NonPeerPowerMode(d) => { NativeEndian::write_u32(buffer, (*d).into()) } Nl80211StationInfo::ChainSignal(d) | Nl80211StationInfo::ChainSignalAvg(d) => { let data: Vec = d.as_slice().iter().map(|d| *d as u8).collect(); buffer.copy_from_slice(data.as_slice()); } Nl80211StationInfo::TidStats(nlas) => nlas.as_slice().emit(buffer), Nl80211StationInfo::ConnectedToGate(d) | Nl80211StationInfo::ConnectedToAuthServer(d) => { buffer[0] = (*d).into() } Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211StationInfo { fn parse( buf: &NlaBuffer<&'a T>, ) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_STA_INFO_INACTIVE_TIME => { let err_msg = format!( "Invalid NL80211_STA_INFO_INACTIVE_TIME value {:?}", payload ); Self::InactiveTime(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_RX_BYTES => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_BYTES value {:?}", payload ); Self::RxBytes(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_TX_BYTES => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_BYTES value {:?}", payload ); Self::TxBytes(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_LLID => { let err_msg = format!( "Invalid NL80211_STA_INFO_LLID value {:?}", payload ); Self::Llid(parse_u16(payload).context(err_msg)?) } NL80211_STA_INFO_PLID => { let err_msg = format!( "Invalid NL80211_STA_INFO_PLID value {:?}", payload ); Self::Plid(parse_u16(payload).context(err_msg)?) } NL80211_STA_INFO_PLINK_STATE => { let err_msg = format!( "Invalid NL80211_STA_INFO_PLINK_STATE value {:?}", payload ); Self::PeerLinkState(parse_u8(payload).context(err_msg)?.into()) } NL80211_STA_INFO_SIGNAL => { let err_msg = format!( "Invalid NL80211_STA_INFO_SIGNAL value {:?}", payload ); Self::Signal(parse_u8(payload).context(err_msg)? as i8) } NL80211_STA_INFO_TX_BITRATE => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_BITRATE value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211RateInfo::parse(nla).context(err_msg.clone())?, ); } Self::TxBitrate(nlas) } NL80211_STA_INFO_RX_PACKETS => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_PACKETS value {:?}", payload ); Self::RxPackets(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_TX_PACKETS => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_PACKETS value {:?}", payload ); Self::TxPackets(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_TX_RETRIES => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_RETRIES value {:?}", payload ); Self::TxRetries(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_TX_FAILED => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_FAILED value {:?}", payload ); Self::TxFailed(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_SIGNAL_AVG => { let err_msg = format!( "Invalid NL80211_STA_INFO_SIGNAL_AVG value {:?}", payload ); Self::SignalAvg(parse_u8(payload).context(err_msg)? as i8) } NL80211_STA_INFO_RX_BITRATE => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_BITRATE value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211RateInfo::parse(nla).context(err_msg.clone())?, ); } Self::RxBitrate(nlas) } NL80211_STA_INFO_BSS_PARAM => { let err_msg = format!( "Invalid NL80211_STA_INFO_BSS_PARAM value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211StationBssParam::parse(nla) .context(err_msg.clone())?, ); } Self::BssParam(nlas) } NL80211_STA_INFO_CONNECTED_TIME => { let err_msg = format!( "Invalid NL80211_STA_INFO_CONNECTED_TIME value {:?}", payload ); Self::ConnectedTime(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_STA_FLAGS => { Self::StationFlags(if payload.len() == 8 { let err_msg = format!( "Invalid NL80211_STA_INFO_STA_FLAGS value {:?}", payload ); let mask = parse_u32(&payload[0..4]).context(err_msg.clone())?; let set = parse_u32(&payload[4..8]).context(err_msg)?; Nl80211StationFlagUpdate { mask: mask.into(), set: set.into(), } } else { return Err(format!( "Invalid length of NL80211_STA_INFO_STA_FLAGS, expected length {} got {:?}", 8, payload ) .into()); }) } NL80211_STA_INFO_BEACON_LOSS => { let err_msg = format!( "Invalid NL80211_STA_INFO_BEACON_LOSS value {:?}", payload ); Self::BeaconLoss(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_T_OFFSET => { let err_msg = format!( "Invalid NL80211_STA_INFO_T_OFFSET value {:?}", payload ); Self::TimingOffset(i64::from_ne_bytes( payload.try_into().context(err_msg)?, )) } NL80211_STA_INFO_LOCAL_PM => { let err_msg = format!( "Invalid NL80211_STA_INFO_LOCAL_PM value {:?}", payload ); Self::LocalPowerMode( parse_u32(payload).context(err_msg)?.into(), ) } NL80211_STA_INFO_PEER_PM => { let err_msg = format!( "Invalid NL80211_STA_INFO_PEER_PM value {:?}", payload ); Self::PeerPowerMode(parse_u32(payload).context(err_msg)?.into()) } NL80211_STA_INFO_NONPEER_PM => { let err_msg = format!( "Invalid NL80211_STA_INFO_NONPEER_PM value {:?}", payload ); Self::NonPeerPowerMode( parse_u32(payload).context(err_msg)?.into(), ) } NL80211_STA_INFO_RX_BYTES64 => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_BYTES64 value {:?}", payload ); Self::RxBytes64(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_TX_BYTES64 => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_BYTES64 value {:?}", payload ); Self::TxBytes64(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_CHAIN_SIGNAL => { Self::ChainSignal(payload.iter().map(|d| *d as i8).collect()) } NL80211_STA_INFO_CHAIN_SIGNAL_AVG => { Self::ChainSignalAvg(payload.iter().map(|d| *d as i8).collect()) } NL80211_STA_INFO_EXPECTED_THROUGHPUT => { let err_msg = format!( "Invalid NL80211_STA_INFO_EXPECTED_THROUGHPUT value {:?}", payload ); Self::ExpectedThroughput(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_RX_DROP_MISC => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_DROP_MISC value {:?}", payload ); Self::RxDropMisc(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_BEACON_RX => { let err_msg = format!( "Invalid NL80211_STA_INFO_BEACON_RX value {:?}", payload ); Self::BeaconRx(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_BEACON_SIGNAL_AVG => { let err_msg = format!( "Invalid NL80211_STA_INFO_BEACON_SIGNAL_AVG value {:?}", payload ); Self::BeaconSignalAvg(parse_u8(payload).context(err_msg)? as i8) } NL80211_STA_INFO_TID_STATS => { let err_msg = format!( "Invalid NL80211_STA_INFO_TID_STATS value {:?}", payload ); let mut nlas = Vec::new(); let _t = NlasIterator::new(payload); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( NestedNl80211TidStats::parse(nla) .context(err_msg.clone())?, ); } Self::TidStats(nlas) } NL80211_STA_INFO_RX_DURATION => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_DURATION value {:?}", payload ); Self::RxDuration(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_ACK_SIGNAL => { let err_msg = format!( "Invalid NL80211_STA_INFO_ACK_SIGNAL value {:?}", payload ); Self::AckSignal(parse_u8(payload).context(err_msg)? as i8) } NL80211_STA_INFO_ACK_SIGNAL_AVG => { let err_msg = format!( "Invalid NL80211_STA_INFO_ACK_SIGNAL_AVG value {:?}", payload ); Self::AckSignalAvg(*payload.first().context(err_msg)? as i8) } NL80211_STA_INFO_RX_MPDUS => { let err_msg = format!( "Invalid NL80211_STA_INFO_RX_MPDUS value {:?}", payload ); Self::RxMpdus(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_FCS_ERROR_COUNT => { let err_msg = format!( "Invalid NL80211_STA_INFO_FCS_ERROR_COUNT value {:?}", payload ); Self::FcsErrorCount(parse_u32(payload).context(err_msg)?) } NL80211_STA_INFO_CONNECTED_TO_GATE => { let err_msg = format!( "Invalid NL80211_STA_INFO_CONNECTED_TO_GATE value {:?}", payload ); Self::ConnectedToGate(parse_u8(payload).context(err_msg)? == 1) } NL80211_STA_INFO_TX_DURATION => { let err_msg = format!( "Invalid NL80211_STA_INFO_TX_DURATION value {:?}", payload ); Self::TxDuration(parse_u64(payload).context(err_msg)?) } NL80211_STA_INFO_AIRTIME_WEIGHT => { let err_msg = format!( "Invalid NL80211_STA_INFO_AIRTIME_WEIGHT value {:?}", payload ); Self::AirtimeWeight(parse_u16(payload).context(err_msg)?) } NL80211_STA_INFO_AIRTIME_LINK_METRIC => { let err_msg = format!( "Invalid NL80211_STA_INFO_AIRTIME_LINK_METRIC value {:?}", payload ); Self::AirtimeLinkMetric(parse_u16(payload).context(err_msg)?) } NL80211_STA_INFO_ASSOC_AT_BOOTTIME => { let err_msg = format!( "Invalid NL80211_STA_INFO_ASSOC_AT_BOOTTIME value {:?}", payload ); Self::AssociationAtBoottime( parse_u64(payload).context(err_msg)?, ) } NL80211_STA_INFO_CONNECTED_TO_AS => { let err_msg = format!( "Invalid NL80211_STA_INFO_CONNECTED_TO_AS value {:?}", payload ); Self::ConnectedToAuthServer( parse_u8(payload).context(err_msg)? == 1, ) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } pub const NL80211_PLINK_LISTEN: u8 = 0; pub const NL80211_PLINK_OPN_SNT: u8 = 1; pub const NL80211_PLINK_OPN_RCVD: u8 = 2; pub const NL80211_PLINK_CNF_RCVD: u8 = 3; pub const NL80211_PLINK_ESTAB: u8 = 4; pub const NL80211_PLINK_HOLDING: u8 = 5; pub const NL80211_PLINK_BLOCKED: u8 = 6; /// State of a mesh peer link finite state machine #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211PeerLinkState { /// Initial state, considered the implicit state of non existent mesh peer /// links Listen, /// Mesh peer link open frame has been sent to this mesh peer OpenSent, /// Mesh plink open frame has been received from this mesh peer OpenReceived, /// Mesh plink confirm frame has been received from this mesh peer ConfirmReceived, /// Mesh peer link is established Established, /// Mesh peer link is being closed or cancelled Holding, /// All frames transmitted from this mesh plink are discarded, except for /// authentication frames Blocked, Other(u8), } impl From for Nl80211PeerLinkState { fn from(d: u8) -> Self { match d { NL80211_PLINK_LISTEN => Self::Listen, NL80211_PLINK_OPN_SNT => Self::OpenSent, NL80211_PLINK_OPN_RCVD => Self::OpenReceived, NL80211_PLINK_CNF_RCVD => Self::ConfirmReceived, NL80211_PLINK_ESTAB => Self::Established, NL80211_PLINK_HOLDING => Self::Holding, NL80211_PLINK_BLOCKED => Self::Blocked, _ => Self::Other(d), } } } impl From for u8 { fn from(v: Nl80211PeerLinkState) -> u8 { match v { Nl80211PeerLinkState::Listen => NL80211_PLINK_LISTEN, Nl80211PeerLinkState::OpenSent => NL80211_PLINK_OPN_SNT, Nl80211PeerLinkState::OpenReceived => NL80211_PLINK_OPN_RCVD, Nl80211PeerLinkState::ConfirmReceived => NL80211_PLINK_CNF_RCVD, Nl80211PeerLinkState::Established => NL80211_PLINK_ESTAB, Nl80211PeerLinkState::Holding => NL80211_PLINK_HOLDING, Nl80211PeerLinkState::Blocked => NL80211_PLINK_BLOCKED, Nl80211PeerLinkState::Other(d) => d, } } } const NL80211_STA_BSS_PARAM_CTS_PROT: u16 = 1; const NL80211_STA_BSS_PARAM_SHORT_PREAMBLE: u16 = 2; const NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME: u16 = 3; const NL80211_STA_BSS_PARAM_DTIM_PERIOD: u16 = 4; const NL80211_STA_BSS_PARAM_BEACON_INTERVAL: u16 = 5; /// BSS information collected by station /// /// These attribute types are used with [`Nl80211StationInfo::BssParam`] /// when getting information about the bitrate of a station. #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211StationBssParam { CtsProtection, ShortPreamble, ShortSlotTime, /// DTIM period for beaconing DtimPeriod(u8), BeaconInterval(u16), Other(DefaultNla), } impl Nla for Nl80211StationBssParam { fn value_len(&self) -> usize { match self { Self::CtsProtection | Self::ShortPreamble | Self::ShortSlotTime => { 0 } Self::DtimPeriod(_) => 1, Self::BeaconInterval(_) | Self::Other(_) => 2, } } fn kind(&self) -> u16 { match self { Self::CtsProtection => NL80211_STA_BSS_PARAM_CTS_PROT, Self::ShortPreamble => NL80211_STA_BSS_PARAM_SHORT_PREAMBLE, Self::ShortSlotTime => NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME, Self::DtimPeriod(_) => NL80211_STA_BSS_PARAM_DTIM_PERIOD, Self::BeaconInterval(_) => NL80211_STA_BSS_PARAM_BEACON_INTERVAL, Self::Other(d) => d.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::CtsProtection | Self::ShortPreamble | Self::ShortSlotTime => { } Self::DtimPeriod(d) => buffer[0] = *d, Self::BeaconInterval(d) => NativeEndian::write_u16(buffer, *d), Self::Other(d) => (*d).emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211StationBssParam { fn parse( buf: &NlaBuffer<&'a T>, ) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_STA_BSS_PARAM_CTS_PROT => Self::CtsProtection, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE => Self::ShortPreamble, NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME => Self::ShortSlotTime, NL80211_STA_BSS_PARAM_DTIM_PERIOD => { let err_msg = format!( "Invalid NL80211_STA_BSS_PARAM_DTIM_PERIOD value {:?}", payload ); Self::DtimPeriod(parse_u8(payload).context(err_msg)?) } NL80211_STA_BSS_PARAM_BEACON_INTERVAL => { let err_msg = format!( "Invalid NL80211_STA_BSS_PARAM_BEACON_INTERVAL value {:?}", payload ); Self::BeaconInterval(parse_u16(payload).context(err_msg)?) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211StationFlagUpdate { /// Mask of station flags to set mask: VecNl80211StationFlag, /// Which values to set them to set: VecNl80211StationFlag, } pub const NL80211_STA_FLAG_AUTHORIZED: u32 = 1; pub const NL80211_STA_FLAG_SHORT_PREAMBLE: u32 = 2; pub const NL80211_STA_FLAG_WME: u32 = 3; pub const NL80211_STA_FLAG_MFP: u32 = 4; pub const NL80211_STA_FLAG_AUTHENTICATED: u32 = 5; pub const NL80211_STA_FLAG_TDLS_PEER: u32 = 6; pub const NL80211_STA_FLAG_ASSOCIATED: u32 = 7; /// Station flags /// /// When a station is added to an AP interface, it is assumed to /// be already associated (and hence authenticated.) #[derive(Debug, PartialEq, Eq, Clone, Default)] pub(crate) struct VecNl80211StationFlag(pub Vec); #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211StationFlag { /// Station is authorized (802.1X) Authorized, /// Station is capable of receiving frames with short barker preamble ShortPreamble, /// Station is WME/QoS capable Wme, /// Station uses management frame protection Mfp, /// Station is authenticated Authenticated, /// Station is a TDLS peer. This flag should only be used in managed mode /// (even in the flags mask). Note that the flag can't be changed, it is /// only valid while adding a station, and attempts to change it will /// silently be ignored (rather than rejected as errors.) TdlsPeer, /// station is associated; used with drivers that support /// [`NL80211_FEATURE_FULL_AP_CLIENT_STATE`] to transition a previously /// added station into associated state Associated, // Reserved: 25 bits, Other(u32), } impl From for Nl80211StationFlag { fn from(d: u32) -> Self { match d { NL80211_STA_FLAG_AUTHORIZED => Self::Authorized, NL80211_STA_FLAG_SHORT_PREAMBLE => Self::ShortPreamble, NL80211_STA_FLAG_WME => Self::Wme, NL80211_STA_FLAG_MFP => Self::Mfp, NL80211_STA_FLAG_AUTHENTICATED => Self::Authenticated, NL80211_STA_FLAG_TDLS_PEER => Self::TdlsPeer, NL80211_STA_FLAG_ASSOCIATED => Self::Associated, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211StationFlag) -> Self { match v { Nl80211StationFlag::Authorized => NL80211_STA_FLAG_AUTHORIZED, Nl80211StationFlag::ShortPreamble => { NL80211_STA_FLAG_SHORT_PREAMBLE } Nl80211StationFlag::Wme => NL80211_STA_FLAG_WME, Nl80211StationFlag::Mfp => NL80211_STA_FLAG_MFP, Nl80211StationFlag::Authenticated => NL80211_STA_FLAG_AUTHENTICATED, Nl80211StationFlag::TdlsPeer => NL80211_STA_FLAG_TDLS_PEER, Nl80211StationFlag::Associated => NL80211_STA_FLAG_ASSOCIATED, Nl80211StationFlag::Other(d) => d, } } } impl std::fmt::Display for Nl80211StationFlag { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Nl80211StationFlag::Authorized => write!(f, "AUTHORIZED"), Nl80211StationFlag::ShortPreamble => write!(f, "SHORT_PREAMBLE"), Nl80211StationFlag::Wme => write!(f, "WME"), Nl80211StationFlag::Mfp => write!(f, "MFP"), Nl80211StationFlag::Authenticated => write!(f, "AUTHENTICATED"), Nl80211StationFlag::TdlsPeer => write!(f, "TDLS_PEER"), Nl80211StationFlag::Associated => write!(f, "ASSOCIATED"), Nl80211StationFlag::Other(d) => write!(f, "Other({d})"), } } } const ALL_STATION_FLAGS: [Nl80211StationFlag; 7] = [ Nl80211StationFlag::Associated, Nl80211StationFlag::Authenticated, Nl80211StationFlag::Authorized, Nl80211StationFlag::Mfp, Nl80211StationFlag::ShortPreamble, Nl80211StationFlag::TdlsPeer, Nl80211StationFlag::Wme, ]; impl From for VecNl80211StationFlag { fn from(d: u32) -> Self { let mut got: u32 = 0; let mut ret = Vec::new(); for flag in ALL_STATION_FLAGS { if (d & u32::from(flag)) > 0 { ret.push(flag); got += u32::from(flag); } } if got != d { ret.push(Nl80211StationFlag::Other(d - got)); } Self(ret) } } impl From<&VecNl80211StationFlag> for u32 { fn from(v: &VecNl80211StationFlag) -> u32 { let mut d: u32 = 0; for flag in &v.0 { d += u32::from(*flag); } d } } pub const NL80211_MESH_POWER_UNKNOWN: u32 = 0; pub const NL80211_MESH_POWER_ACTIVE: u32 = 1; pub const NL80211_MESH_POWER_LIGHT_SLEEP: u32 = 2; pub const NL80211_MESH_POWER_DEEP_SLEEP: u32 = 3; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211MeshPowerMode { Unknown, Active, LightSleep, DeepSleep, Other(u32), } impl From for Nl80211MeshPowerMode { fn from(d: u32) -> Self { match d { NL80211_MESH_POWER_UNKNOWN => Self::Unknown, NL80211_MESH_POWER_ACTIVE => Self::Active, NL80211_MESH_POWER_LIGHT_SLEEP => Self::LightSleep, NL80211_MESH_POWER_DEEP_SLEEP => Self::DeepSleep, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211MeshPowerMode) -> u32 { match v { Nl80211MeshPowerMode::Unknown => NL80211_MESH_POWER_UNKNOWN, Nl80211MeshPowerMode::Active => NL80211_MESH_POWER_ACTIVE, Nl80211MeshPowerMode::LightSleep => NL80211_MESH_POWER_LIGHT_SLEEP, Nl80211MeshPowerMode::DeepSleep => NL80211_MESH_POWER_DEEP_SLEEP, Nl80211MeshPowerMode::Other(d) => d, } } } wl-nl80211-0.2.0/src/stats.rs000064400000000000000000000262031046102023000135460ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_u32, parse_u64}, DecodeError, Emitable, Parseable, }; #[derive(Debug, PartialEq, Eq, Clone)] pub struct NestedNl80211TidStats(Vec); impl Nla for NestedNl80211TidStats { fn value_len(&self) -> usize { self.0.as_slice().buffer_len() } fn kind(&self) -> u16 { unimplemented!("Variable between 0-16") } fn emit_value(&self, buffer: &mut [u8]) { self.0.as_slice().emit(buffer); } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NestedNl80211TidStats { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); let err_msg = format!("Invalid NestedNl80211TidStats value {:?}", payload); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211TidStats::parse(nla).context(err_msg.clone())?); } Ok(Self(nlas)) } } const NL80211_TID_STATS_RX_MSDU: u16 = 1; const NL80211_TID_STATS_TX_MSDU: u16 = 2; const NL80211_TID_STATS_TX_MSDU_RETRIES: u16 = 3; const NL80211_TID_STATS_TX_MSDU_FAILED: u16 = 4; const NL80211_TID_STATS_TXQ_STATS: u16 = 6; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211TidStats { /// Number of MSDUs received RxMsdu(u64), /// Number of MSDUs transmitted TxMsdu(u64), /// Number of retries for transmitted MSDUs (not counting the first /// attempt) TxMsduRetries(u64), /// Number of failed transmitted MSDUs TxMsduFailed(u64), TransmitQueueStats(Vec), Other(DefaultNla), } impl Nla for Nl80211TidStats { fn value_len(&self) -> usize { match self { Self::RxMsdu(_) | Self::TxMsdu(_) | Self::TxMsduRetries(_) | Self::TxMsduFailed(_) => 4, Self::TransmitQueueStats(nlas) => nlas.as_slice().buffer_len(), Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::RxMsdu(_) => NL80211_TID_STATS_RX_MSDU, Self::TxMsdu(_) => NL80211_TID_STATS_TX_MSDU, Self::TxMsduRetries(_) => NL80211_TID_STATS_TX_MSDU_RETRIES, Self::TxMsduFailed(_) => NL80211_TID_STATS_TX_MSDU_FAILED, Self::TransmitQueueStats(_) => NL80211_TID_STATS_TXQ_STATS, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::RxMsdu(d) | Self::TxMsdu(d) | Self::TxMsduRetries(d) | Self::TxMsduFailed(d) => NativeEndian::write_u64(buffer, *d), Self::TransmitQueueStats(nlas) => nlas.as_slice().emit(buffer), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211TidStats { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_TID_STATS_RX_MSDU => { let err_msg = format!( "Invalid NL80211_TID_STATS_RX_MSDU value: {:?}", payload ); Self::RxMsdu(parse_u64(payload).context(err_msg)?) } NL80211_TID_STATS_TX_MSDU => { let err_msg = format!( "Invalid NL80211_TID_STATS_TX_MSDU value: {:?}", payload ); Self::TxMsdu(parse_u64(payload).context(err_msg)?) } NL80211_TID_STATS_TX_MSDU_RETRIES => { let err_msg = format!( "Invalid NL80211_TID_STATS_TX_MSDU_RETRIES value: {:?}", payload ); Self::TxMsduRetries(parse_u64(payload).context(err_msg)?) } NL80211_TID_STATS_TX_MSDU_FAILED => { let err_msg = format!( "Invalid NL80211_TID_STATS_TX_MSDU_FAILED value: {:?}", payload ); Self::TxMsduFailed(parse_u64(payload).context(err_msg)?) } NL80211_TID_STATS_TXQ_STATS => { let err_msg = format!( "Invalid NL80211_TID_STATS_TXQ_STATS value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211TransmitQueueStat::parse(nla) .context(err_msg.clone())?, ); } Self::TransmitQueueStats(nlas) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } const NL80211_TXQ_STATS_BACKLOG_BYTES: u16 = 1; const NL80211_TXQ_STATS_BACKLOG_PACKETS: u16 = 2; const NL80211_TXQ_STATS_FLOWS: u16 = 3; const NL80211_TXQ_STATS_DROPS: u16 = 4; const NL80211_TXQ_STATS_ECN_MARKS: u16 = 5; const NL80211_TXQ_STATS_OVERLIMIT: u16 = 6; const NL80211_TXQ_STATS_OVERMEMORY: u16 = 7; const NL80211_TXQ_STATS_COLLISIONS: u16 = 8; const NL80211_TXQ_STATS_TX_BYTES: u16 = 9; const NL80211_TXQ_STATS_TX_PACKETS: u16 = 10; const NL80211_TXQ_STATS_MAX_FLOWS: u16 = 11; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211TransmitQueueStat { BacklogBytes(u32), BacklogPackets(u32), Flows(u32), Drops(u32), EcnMarks(u32), Overlimit(u32), Overmemory(u32), Collisions(u32), TxBytes(u32), TxPackets(u32), MaxFlows(u32), Other(DefaultNla), } impl Nla for Nl80211TransmitQueueStat { fn value_len(&self) -> usize { match self { Self::BacklogBytes(_) | Self::BacklogPackets(_) | Self::Flows(_) | Self::Drops(_) | Self::EcnMarks(_) | Self::Overlimit(_) | Self::Overmemory(_) | Self::Collisions(_) | Self::TxBytes(_) | Self::TxPackets(_) | Self::MaxFlows(_) => 4, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::BacklogBytes(_) => NL80211_TXQ_STATS_BACKLOG_BYTES, Self::BacklogPackets(_) => NL80211_TXQ_STATS_BACKLOG_PACKETS, Self::Flows(_) => NL80211_TXQ_STATS_FLOWS, Self::Drops(_) => NL80211_TXQ_STATS_DROPS, Self::EcnMarks(_) => NL80211_TXQ_STATS_ECN_MARKS, Self::Overlimit(_) => NL80211_TXQ_STATS_OVERLIMIT, Self::Overmemory(_) => NL80211_TXQ_STATS_OVERMEMORY, Self::Collisions(_) => NL80211_TXQ_STATS_COLLISIONS, Self::TxBytes(_) => NL80211_TXQ_STATS_TX_BYTES, Self::TxPackets(_) => NL80211_TXQ_STATS_TX_PACKETS, Self::MaxFlows(_) => NL80211_TXQ_STATS_MAX_FLOWS, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::BacklogBytes(d) | Self::BacklogPackets(d) | Self::Flows(d) | Self::Drops(d) | Self::EcnMarks(d) | Self::Overlimit(d) | Self::Overmemory(d) | Self::Collisions(d) | Self::TxBytes(d) | Self::TxPackets(d) | Self::MaxFlows(d) => NativeEndian::write_u32(buffer, *d), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211TransmitQueueStat { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_TXQ_STATS_BACKLOG_BYTES => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_BACKLOG_BYTES value {:?}", payload ); Self::BacklogBytes(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_BACKLOG_PACKETS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_BACKLOG_PACKETS value: {:?}", payload ); Self::BacklogPackets(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_FLOWS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_FLOWS value: {:?}", payload ); Self::Flows(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_DROPS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_DROPS value: {:?}", payload ); Self::Drops(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_ECN_MARKS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_ECN_MARKS value: {:?}", payload ); Self::EcnMarks(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_OVERLIMIT => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_OVERLIMIT value: {:?}", payload ); Self::Overlimit(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_OVERMEMORY => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_OVERMEMORY value: {:?}", payload ); Self::Overmemory(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_COLLISIONS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_COLLISIONS value: {:?}", payload ); Self::Collisions(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_TX_BYTES => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_TX_BYTES value: {:?}", payload ); Self::TxBytes(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_TX_PACKETS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_TX_PACKETS value: {:?}", payload ); Self::TxPackets(parse_u32(payload).context(err_msg)?) } NL80211_TXQ_STATS_MAX_FLOWS => { let err_msg = format!( "Invalid NL80211_TXQ_STATS_MAX_FLOWS value: {:?}", payload ); Self::MaxFlows(parse_u32(payload).context(err_msg)?) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } wl-nl80211-0.2.0/src/wifi4.rs000064400000000000000000000135621046102023000134360ustar 00000000000000// SPDX-License-Identifier: MIT // Hold WIFI 4(802.11n) specific data types use netlink_packet_utils::{DecodeError, Emitable, Parseable}; use crate::bytes::write_u16_le; const NL80211_CHAN_NO_HT: u32 = 0; const NL80211_CHAN_HT20: u32 = 1; const NL80211_CHAN_HT40MINUS: u32 = 2; const NL80211_CHAN_HT40PLUS: u32 = 3; // kernel data type: `enum nl80211_channel_type` #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub enum Nl80211HtWiphyChannelType { NoHt, Ht20, Ht40Minus, Ht40Plus, Other(u32), } impl From for Nl80211HtWiphyChannelType { fn from(d: u32) -> Self { match d { NL80211_CHAN_NO_HT => Self::NoHt, NL80211_CHAN_HT20 => Self::Ht20, NL80211_CHAN_HT40MINUS => Self::Ht40Minus, NL80211_CHAN_HT40PLUS => Self::Ht40Plus, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211HtWiphyChannelType) -> u32 { match v { Nl80211HtWiphyChannelType::NoHt => NL80211_CHAN_NO_HT, Nl80211HtWiphyChannelType::Ht20 => NL80211_CHAN_HT20, Nl80211HtWiphyChannelType::Ht40Minus => NL80211_CHAN_HT40MINUS, Nl80211HtWiphyChannelType::Ht40Plus => NL80211_CHAN_HT40PLUS, Nl80211HtWiphyChannelType::Other(d) => d, } } } const IEEE80211_HT_CAP_LDPC_CODING: u16 = 0x0001; const IEEE80211_HT_CAP_SUP_WIDTH_20_40: u16 = 0x0002; const IEEE80211_HT_CAP_SM_PS: u16 = 0x000C; const IEEE80211_HT_CAP_GRN_FLD: u16 = 0x0010; const IEEE80211_HT_CAP_SGI_20: u16 = 0x0020; const IEEE80211_HT_CAP_SGI_40: u16 = 0x0040; const IEEE80211_HT_CAP_TX_STBC: u16 = 0x0080; const IEEE80211_HT_CAP_RX_STBC: u16 = 0x0300; const IEEE80211_HT_CAP_DELAY_BA: u16 = 0x0400; const IEEE80211_HT_CAP_MAX_AMSDU: u16 = 0x0800; const IEEE80211_HT_CAP_DSSSCCK40: u16 = 0x1000; const IEEE80211_HT_CAP_40MHZ_INTOLERANT: u16 = 0x4000; const IEEE80211_HT_CAP_LSIG_TXOP_PROT: u16 = 0x8000; // For linux kernel `struct ieee80211_ht_cap.cap_info` bitflags::bitflags! { #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub struct Nl80211HtCaps: u16 { const LdpcCoding = IEEE80211_HT_CAP_LDPC_CODING; const SupWidth2040 = IEEE80211_HT_CAP_SUP_WIDTH_20_40; const SmPs = IEEE80211_HT_CAP_SM_PS; const GrnFld = IEEE80211_HT_CAP_GRN_FLD; const Sgi20 = IEEE80211_HT_CAP_SGI_20; const Sgi40 = IEEE80211_HT_CAP_SGI_40; const TxStbc = IEEE80211_HT_CAP_TX_STBC; const RxStbc = IEEE80211_HT_CAP_RX_STBC; const DelayBa = IEEE80211_HT_CAP_DELAY_BA; const MaxAmsdu = IEEE80211_HT_CAP_MAX_AMSDU; const Dssscck40 = IEEE80211_HT_CAP_DSSSCCK40; const Intolerant40Mhz = IEEE80211_HT_CAP_40MHZ_INTOLERANT; const LsigTxopProt = IEEE80211_HT_CAP_LSIG_TXOP_PROT; const _ = !0; } } const IEEE80211_HT_MCS_MASK_LEN: usize = 10; const NL80211_BAND_MCS_INFO_LEN: usize = 16; // kernel data type: `struct ieee80211_mcs_info` #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Nl80211HtMcsInfo { pub rx_mask: [u8; IEEE80211_HT_MCS_MASK_LEN], pub rx_highest: u16, pub tx_params: u8, } impl Emitable for Nl80211HtMcsInfo { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < NL80211_BAND_MCS_INFO_LEN { log::error!( "Buffer size is smaller than NL80211_BAND_MCS_INFO_LEN \ {NL80211_BAND_MCS_INFO_LEN}" ); return; } buffer.iter_mut().for_each(|m| *m = 0); buffer[..IEEE80211_HT_MCS_MASK_LEN].copy_from_slice(&self.rx_mask); write_u16_le( &mut buffer [IEEE80211_HT_MCS_MASK_LEN..IEEE80211_HT_MCS_MASK_LEN + 2], self.rx_highest, ); buffer[IEEE80211_HT_MCS_MASK_LEN + 2] = self.tx_params; } } impl Nl80211HtMcsInfo { // `struct ieee80211_mcs_info`. // Kernel document confirmed this is 16 bytes pub const LENGTH: usize = NL80211_BAND_MCS_INFO_LEN; } impl + ?Sized> Parseable for Nl80211HtMcsInfo { fn parse(buf: &T) -> Result { let buf: &[u8] = buf.as_ref(); if buf.len() < NL80211_BAND_MCS_INFO_LEN { return Err(format!( "Expecting `struct ieee80211_ht_mcs_info` u8 array with \ size {NL80211_BAND_MCS_INFO_LEN}, but got length {}", buf.len() ) .into()); } let mut rx_mask = [0u8; IEEE80211_HT_MCS_MASK_LEN]; rx_mask.copy_from_slice(&buf[..IEEE80211_HT_MCS_MASK_LEN]); Ok(Self { rx_mask, rx_highest: u16::from_le_bytes([ buf[IEEE80211_HT_MCS_MASK_LEN], buf[IEEE80211_HT_MCS_MASK_LEN + 1], ]), tx_params: buf[IEEE80211_HT_MCS_MASK_LEN + 2], }) } } const NL80211_HT_CAPABILITY_LEN: usize = 26; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Nl80211HtCapabilityMask(pub [u8; NL80211_HT_CAPABILITY_LEN]); impl Nl80211HtCapabilityMask { pub const LENGTH: usize = NL80211_HT_CAPABILITY_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } } impl Emitable for Nl80211HtCapabilityMask { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Nl80211HtCapabilityMask buffer size is smaller than \ required size {}", Self::LENGTH ); return; } buffer[..Self::LENGTH].copy_from_slice(&self.0) } } wl-nl80211-0.2.0/src/wifi5.rs000064400000000000000000000211531046102023000134320ustar 00000000000000// SPDX-License-Identifier: MIT // Hold WIFI 5(802.11ac) specific data types use anyhow::Context; use netlink_packet_utils::{ parsers::parse_u32, DecodeError, Emitable, Parseable, }; use crate::bytes::write_u16_le; const NL80211_BAND_VHT_MCS_INFO_LEN: usize = 8; // We cannot use buffer! macro here as these u16 are all little endian while // The `buffer!` does not support little endian yet. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Nl80211VhtMcsInfo { pub rx_mcs_map: u16, pub rx_highest: u16, pub tx_mcs_map: u16, pub tx_highest: u16, } impl Nl80211VhtMcsInfo { // `struct ieee80211_vht_mcs_info` // Kernel document confirmed this is 32 bytes pub const LENGTH: usize = NL80211_BAND_VHT_MCS_INFO_LEN; } impl Emitable for Nl80211VhtMcsInfo { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < NL80211_BAND_VHT_MCS_INFO_LEN { log::error!( "Buffer size is smaller than NL80211_BAND_VHT_MCS_INFO_LEN \ {NL80211_BAND_VHT_MCS_INFO_LEN}" ); return; } write_u16_le(&mut buffer[0..2], self.rx_mcs_map); write_u16_le(&mut buffer[2..4], self.rx_highest); write_u16_le(&mut buffer[4..6], self.tx_mcs_map); write_u16_le(&mut buffer[6..8], self.tx_highest); } } impl + ?Sized> Parseable for Nl80211VhtMcsInfo { fn parse(buf: &T) -> Result { let buf: &[u8] = buf.as_ref(); if buf.len() < NL80211_BAND_VHT_MCS_INFO_LEN { return Err(format!( "Expecting `struct ieee80211_vht_mcs_info` u8 array with \ size {NL80211_BAND_VHT_MCS_INFO_LEN}, but got length {}", buf.len() ) .into()); } Ok(Self { rx_mcs_map: u16::from_le_bytes([buf[0], buf[1]]), rx_highest: u16::from_le_bytes([buf[2], buf[3]]), tx_mcs_map: u16::from_le_bytes([buf[4], buf[5]]), tx_highest: u16::from_le_bytes([buf[6], buf[7]]), }) } } const IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895: u32 = 0x00000000; const IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991: u32 = 0x00000001; const IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: u32 = 0x00000002; const IEEE80211_VHT_CAP_MAX_MPDU_MASK: u32 = 0x00000003; const IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: u32 = 0x00000004; const IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: u32 = 0x00000008; const IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK: u32 = 0x0000000C; const IEEE80211_VHT_CAP_RXLDPC: u32 = 0x00000010; const IEEE80211_VHT_CAP_SHORT_GI_80: u32 = 0x00000020; const IEEE80211_VHT_CAP_SHORT_GI_160: u32 = 0x00000040; const IEEE80211_VHT_CAP_TXSTBC: u32 = 0x00000080; const IEEE80211_VHT_CAP_RXSTBC_1: u32 = 0x00000100; const IEEE80211_VHT_CAP_RXSTBC_2: u32 = 0x00000200; const IEEE80211_VHT_CAP_RXSTBC_3: u32 = 0x00000300; const IEEE80211_VHT_CAP_RXSTBC_4: u32 = 0x00000400; const IEEE80211_VHT_CAP_RXSTBC_MASK: u32 = 0x00000700; const IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE: u32 = 0x00000800; const IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE: u32 = 0x00001000; const IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT: u32 = 13; const IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK: u32 = 7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; const IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT: u32 = 16; const IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK: u32 = 7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; const IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE: u32 = 0x00080000; const IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE: u32 = 0x00100000; const IEEE80211_VHT_CAP_VHT_TXOP_PS: u32 = 0x00200000; const IEEE80211_VHT_CAP_HTC_VHT: u32 = 0x00400000; const IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT: u32 = 23; const IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK: u32 = 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; const IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB: u32 = 0x08000000; const IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB: u32 = 0x0c000000; const IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN: u32 = 0x10000000; const IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN: u32 = 0x20000000; const IEEE80211_VHT_CAP_EXT_NSS_BW_MASK: u32 = 0xc0000000; bitflags::bitflags! { #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub struct Nl80211VhtCapInfo: u32 { const MaxMpduLength3895 = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; const MaxMpduLength7991 = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; const MaxMpduLength11454 = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; const MaxMpduMask = IEEE80211_VHT_CAP_MAX_MPDU_MASK; const SuppChanWidth160mhz = IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; const SuppChanWidth160With80plus80mhz = IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; const SuppChanWidthMask = IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; const Rxldpc = IEEE80211_VHT_CAP_RXLDPC; const ShortGi80 = IEEE80211_VHT_CAP_SHORT_GI_80; const ShortGi160 = IEEE80211_VHT_CAP_SHORT_GI_160; const TxStbc = IEEE80211_VHT_CAP_TXSTBC; const Rxstbc1 = IEEE80211_VHT_CAP_RXSTBC_1; const Rxstbc2 = IEEE80211_VHT_CAP_RXSTBC_2; const Rxstbc3 = IEEE80211_VHT_CAP_RXSTBC_3; const Rxstbc4 = IEEE80211_VHT_CAP_RXSTBC_4; const RxstbcMask = IEEE80211_VHT_CAP_RXSTBC_MASK; const SuBeamformerCapable = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; const SuBeamformeeCapable = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; const BeamformeeStsMask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; const SoundingDimensionsMask = IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; const MuBeamformerCapable = IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; const MuBeamformeeCapable = IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; const VhtTxopPs = IEEE80211_VHT_CAP_VHT_TXOP_PS; const HtcVht = IEEE80211_VHT_CAP_HTC_VHT; const MaxAMpduLengthExponentMask = IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; const VhtLinkAdaptationVhtUnsolMfb = IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB; const VhtLinkAdaptationVhtMrqMfb = IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB; const RxAntennaPattern = IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; const TxAntennaPattern = IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; const ExtNssBwMask = IEEE80211_VHT_CAP_EXT_NSS_BW_MASK; const _ = !0; } } impl + ?Sized> Parseable for Nl80211VhtCapInfo { fn parse(buf: &T) -> Result { let buf: &[u8] = buf.as_ref(); Ok(Self::from_bits_retain(parse_u32(buf).context(format!( "Invalid Nl80211VhtCapInfo payload {buf:?}" ))?)) } } impl Nl80211VhtCapInfo { pub const LENGTH: usize = 4; } impl Emitable for Nl80211VhtCapInfo { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { buffer.copy_from_slice(&self.bits().to_ne_bytes()) } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Nl80211VhtCapability { pub cap_info: Nl80211VhtCapInfo, pub mcs_info: Nl80211VhtMcsInfo, } // TODO: Please add getter and setter function according to // 802.11ac-2013 section '8.4.2.160 VHT Capabilities element' impl Nl80211VhtCapability { pub const LENGTH: usize = 12; } impl Emitable for Nl80211VhtCapability { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Buffer size {} is smaller than desired size {}", buffer.len(), Self::LENGTH, ); return; } self.cap_info.emit(&mut buffer[..Nl80211VhtCapInfo::LENGTH]); self.mcs_info.emit(&mut buffer[Nl80211VhtCapInfo::LENGTH..]); } } impl + ?Sized> Parseable for Nl80211VhtCapability { fn parse(buf: &T) -> Result { let buf: &[u8] = buf.as_ref(); if buf.len() < Self::LENGTH { Err(format!( "Invalid length of payload for Nl80211VhtCapability, \ expecting {}, but got {}", Self::LENGTH, buf.len() ) .into()) } else { Ok(Self { cap_info: Nl80211VhtCapInfo::parse( &buf[..Nl80211VhtCapInfo::LENGTH], )?, mcs_info: Nl80211VhtMcsInfo::parse( &buf[Nl80211VhtCapInfo::LENGTH..], )?, }) } } } wl-nl80211-0.2.0/src/wifi6.rs000064400000000000000000000305321046102023000134340ustar 00000000000000// SPDX-License-Identifier: MIT // Hold WIFI6 (802.11ax) specific data types. use netlink_packet_utils::{ traits::{Emitable, Parseable}, DecodeError, }; use crate::bytes::{get_bit, get_bits_as_u8, write_u16_le}; const HE_MAC_CAP_INFO_LEN: usize = 6; /// "HE MAC Capabilities Information field" /// /// IEEE 802.11ax-2021 section 9.4.2.248.2 #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211HeMacCapInfo(pub [u8; HE_MAC_CAP_INFO_LEN]); impl Nl80211HeMacCapInfo { pub const LENGTH: usize = HE_MAC_CAP_INFO_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } pub fn tc_he_support(&self) -> bool { get_bit(&self.0, 0) } pub fn wt_requester_support(&self) -> bool { get_bit(&self.0, 1) } pub fn wt_responder_support(&self) -> bool { get_bit(&self.0, 2) } pub fn ynamic_fragmentation_support(&self) -> u8 { get_bits_as_u8(&self.0, 3, 4) } pub fn ax_fragmented_msdu_amsdu(&self) -> u8 { get_bits_as_u8(&self.0, 5, 7) } pub fn in_fragment_size(&self) -> u8 { get_bits_as_u8(&self.0, 8, 9) } pub fn rigger_frame_mac_pending_duration(&self) -> u8 { get_bits_as_u8(&self.0, 10, 11) } pub fn ulti_tid_aggregation_rx_support(&self) -> u8 { get_bits_as_u8(&self.0, 12, 14) } pub fn e_link_adapttion_support(&self) -> u8 { get_bits_as_u8(&self.0, 15, 16) } pub fn ll_ack_support(&self) -> bool { get_bit(&self.0, 17) } pub fn ts_support(&self) -> bool { get_bit(&self.0, 18) } pub fn sr_support(&self) -> bool { get_bit(&self.0, 19) } pub fn roadcast_twt_support(&self) -> bool { get_bit(&self.0, 20) } pub fn upport_32_bit_ba_bitmap(&self) -> bool { get_bit(&self.0, 21) } pub fn u_cascading_support(&self) -> bool { get_bit(&self.0, 22) } pub fn ck_enabled_aggregation_support(&self) -> bool { get_bit(&self.0, 23) } // bit 24 is reserved pub fn m_control_support(&self) -> bool { get_bit(&self.0, 25) } pub fn fdma_ra_support(&self) -> bool { get_bit(&self.0, 26) } pub fn ax_a_mpdu_length_exponent_extentsion(&self) -> u8 { get_bits_as_u8(&self.0, 27, 28) } pub fn _msdu_fragmentation_support(&self) -> bool { get_bit(&self.0, 29) } pub fn lexible_twt_scheduler_support(&self) -> bool { get_bit(&self.0, 30) } pub fn x_control_frame_to_multibss(&self) -> bool { get_bit(&self.0, 31) } pub fn srp_bqrp_a_mpdu_aggregation(&self) -> bool { get_bit(&self.0, 32) } pub fn tp_support(&self) -> bool { get_bit(&self.0, 33) } pub fn qr_support(&self) -> bool { get_bit(&self.0, 34) } pub fn sr_responder(&self) -> bool { get_bit(&self.0, 35) } pub fn dp_feedback_report_support(&self) -> bool { get_bit(&self.0, 36) } pub fn ps_support(&self) -> bool { get_bit(&self.0, 37) } pub fn _msdu_not_under_ba_in_ack_enabled_a_mpdu_support(&self) -> bool { get_bit(&self.0, 38) } pub fn ulti_tid_aggregation_tx_support(&self) -> u8 { get_bits_as_u8(&self.0, 39, 41) } pub fn e_subchannel_selective_ransmission_support(&self) -> bool { get_bit(&self.0, 42) } pub fn l_2x_996_tone_ru_support(&self) -> bool { get_bit(&self.0, 43) } pub fn m_control_ul_mu_data_disable_rx_support(&self) -> bool { get_bit(&self.0, 44) } pub fn e_dyanmic_sm_power_save(&self) -> bool { get_bit(&self.0, 45) } pub fn unctured_sounding_support(&self) -> bool { get_bit(&self.0, 46) } pub fn t_and_vht_trigger_frame_rx_support(&self) -> bool { get_bit(&self.0, 47) } } impl Emitable for Nl80211HeMacCapInfo { fn buffer_len(&self) -> usize { HE_MAC_CAP_INFO_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < HE_MAC_CAP_INFO_LEN { log::error!( "Buffer size is smaller than HE_MAC_CAP_INFO_LEN \ {HE_MAC_CAP_INFO_LEN}" ); return; } buffer[..Self::LENGTH].copy_from_slice(&self.0) } } const HE_PHY_CAP_INFO_LEN: usize = 11; /// "HE PHY Capabilities Information field" /// /// IEEE 802.11ax-2021 section 9.4.2.248.3 #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211HePhyCapInfo(pub [u8; HE_PHY_CAP_INFO_LEN]); impl Nl80211HePhyCapInfo { pub const LENGTH: usize = HE_PHY_CAP_INFO_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } pub fn supported_channel_width_set(&self) -> u8 { get_bits_as_u8(&self.0, 1, 7) } // TODO: Add all fields as functions by checking 802.11ax-2021 } impl Emitable for Nl80211HePhyCapInfo { fn buffer_len(&self) -> usize { HE_PHY_CAP_INFO_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < HE_PHY_CAP_INFO_LEN { log::error!( "Buffer size is smaller than HE_PHY_CAP_INFO_LEN \ {HE_PHY_CAP_INFO_LEN}" ); return; } buffer[..HE_PHY_CAP_INFO_LEN].copy_from_slice(&self.0) } } const NL80211_HE_MCS_NSS_SUPP_LEN: usize = 12; /// Tx/Rx HE MCS NSS Support Field /// /// The released 802.11ax-2021 has no `Tx/Rx HE MCS NSS Support` section, this /// struct is merely copy of linux kernel `struct ieee80211_he_mcs_nss_supp`. #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub struct Nl80211HeMcsNssSupp { /// Rx MCS map 2 bits for each stream, total 8 streams, for channel widths /// less than 80MHz. pub rx_mcs_80: u16, /// Tx MCS map 2 bits for each stream, total 8 streams, for channel widths /// less than 80MHz. pub tx_mcs_80: u16, /// Rx MCS map 2 bits for each stream, total 8 streams, for channel width /// 160MHz. pub rx_mcs_160: u16, /// Tx MCS map 2 bits for each stream, total 8 streams, for channel width /// 160MHz. pub tx_mcs_160: u16, /// Rx MCS map 2 bits for each stream, total 8 streams, for channel width /// 80p80MHz. pub rx_mcs_80p80: u16, /// Tx MCS map 2 bits for each stream, total 8 streams, for channel width /// 80p80MHz. pub tx_mcs_80p80: u16, } impl Nl80211HeMcsNssSupp { pub const LENGTH: usize = NL80211_HE_MCS_NSS_SUPP_LEN; } impl Emitable for Nl80211HeMcsNssSupp { fn buffer_len(&self) -> usize { NL80211_HE_MCS_NSS_SUPP_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < NL80211_HE_MCS_NSS_SUPP_LEN { log::error!( "Buffer size is smaller than NL80211_HE_MCS_NSS_SUPP_LEN \ {NL80211_HE_MCS_NSS_SUPP_LEN}" ); return; } write_u16_le(&mut buffer[0..2], self.rx_mcs_80); write_u16_le(&mut buffer[2..4], self.tx_mcs_80); write_u16_le(&mut buffer[4..6], self.rx_mcs_160); write_u16_le(&mut buffer[6..8], self.tx_mcs_160); write_u16_le(&mut buffer[8..10], self.rx_mcs_80p80); write_u16_le(&mut buffer[10..12], self.tx_mcs_80p80); } } impl + ?Sized> Parseable for Nl80211HeMcsNssSupp { fn parse(buf: &T) -> Result { let buf: &[u8] = buf.as_ref(); if buf.len() < Self::LENGTH { Err(format!( "Expecting `struct ieee80211_he_mcs_nss_supp` u8 array \ with size {}, but got length {}", Self::LENGTH, buf.len() ) .into()) } else { Ok(Self { rx_mcs_80: u16::from_le_bytes([buf[0], buf[1]]), tx_mcs_80: u16::from_le_bytes([buf[2], buf[3]]), rx_mcs_160: u16::from_le_bytes([buf[4], buf[5]]), tx_mcs_160: u16::from_le_bytes([buf[6], buf[7]]), rx_mcs_80p80: u16::from_le_bytes([buf[8], buf[9]]), tx_mcs_80p80: u16::from_le_bytes([buf[10], buf[11]]), }) } } } // Kernel says the maximum is 25, but my(Gris Ge) understanding of IEEE // 802.11ax-2021 indicate the maximum size is: // ((NSTS + 1) * 6 * 4 + 4 + 3 ) / 8 + 1 == 28 bytes // | | | | // | | | +---- NSTS // | | +------ RU index bitmask(4 bits) // | +--- RU allocation index, 4 combination // | // +---- PPET 16 (3 bits) and PPET 8 (3 bits) // // The 25 bytes could be using `NSTS` instead of `NSTS +1`. // const IEEE80211_HE_PPE_THRES_MAX_LEN: usize = 25; /// IEEE 802.11ax-2021 section 9.4.2.248.5 /// "PPE Thresholds field" #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211HePpeThreshold(pub [u8; IEEE80211_HE_PPE_THRES_MAX_LEN]); impl Nl80211HePpeThreshold { pub const LENGTH: usize = IEEE80211_HE_PPE_THRES_MAX_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } pub fn nsts(&self) -> u8 { get_bits_as_u8(&self.0, 0, 2) } pub fn ru_index_bitmask(&self) -> u8 { get_bits_as_u8(&self.0, 3, 6) } // TODO, add iterator to access thresholds } impl Emitable for Nl80211HePpeThreshold { fn buffer_len(&self) -> usize { IEEE80211_HE_PPE_THRES_MAX_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < IEEE80211_HE_PPE_THRES_MAX_LEN { log::error!( "Buffer size is smaller than IEEE80211_HE_PPE_THRES_MAX_LEN \ {IEEE80211_HE_PPE_THRES_MAX_LEN}" ); return; } buffer[..IEEE80211_HE_PPE_THRES_MAX_LEN].copy_from_slice(&self.0) } } /* HE 6 GHz band capabilities */ // const IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START: u16 = 0x0007; // const IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP: u16 = 0x0038; // const IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN: u16 = 0x00c0; // const IEEE80211_HE_6GHZ_CAP_SM_PS: u16 = 0x0600; // const IEEE80211_HE_6GHZ_CAP_RD_RESPONDER: u16 = 0x0800; // const IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS: u16 = 0x1000; // const IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS: u16 = 0x2000; const IEEE80211_HE_6GHZ_CAP_LEN: usize = 2; /// "HE 6 GHz Band Capabilities element" /// /// IEEE 802.11ax-2021 section 9.4.2.263 #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211He6GhzCapa(pub [u8; IEEE80211_HE_6GHZ_CAP_LEN]); impl Nl80211He6GhzCapa { pub const LENGTH: usize = IEEE80211_HE_6GHZ_CAP_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } pub fn minimum_mpdu_start_spacing(&self) -> u8 { get_bits_as_u8(&self.0, 0, 2) } pub fn maximum_a_mpdu_length_exponent(&self) -> u8 { get_bits_as_u8(&self.0, 3, 5) } pub fn maximum_mpdu_length(&self) -> u8 { get_bits_as_u8(&self.0, 6, 7) } pub fn sm_power_save(&self) -> u8 { get_bits_as_u8(&self.0, 9, 10) } pub fn rd_responder(&self) -> bool { get_bit(&self.0, 11) } pub fn rx_antenna_pattern_consistency(&self) -> bool { get_bit(&self.0, 12) } pub fn tx_antenna_pattern_consistency(&self) -> bool { get_bit(&self.0, 12) } } impl Emitable for Nl80211He6GhzCapa { fn buffer_len(&self) -> usize { IEEE80211_HE_6GHZ_CAP_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < IEEE80211_HE_6GHZ_CAP_LEN { log::error!( "Buffer size is smaller than IEEE80211_HE_6GHZ_CAP_LEN \ {IEEE80211_HE_6GHZ_CAP_LEN}" ); return; } buffer[..IEEE80211_HE_6GHZ_CAP_LEN].copy_from_slice(&self.0) } } wl-nl80211-0.2.0/src/wifi7.rs000064400000000000000000000210021046102023000134250ustar 00000000000000// SPDX-License-Identifier: MIT // WIFI 7(802.11be) specific data types use netlink_packet_utils::{DecodeError, Emitable}; const EHT_MAC_CAP_INFO_LEN: usize = 2; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtMacCapInfo(pub [u8; EHT_MAC_CAP_INFO_LEN]); // TODO: Failed to get WIFI7(802.11be) SPEC PDF, hence no parsing functions impl Nl80211EhtMacCapInfo { pub const LENGTH: usize = EHT_MAC_CAP_INFO_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } } impl Emitable for Nl80211EhtMacCapInfo { fn buffer_len(&self) -> usize { EHT_MAC_CAP_INFO_LEN } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < EHT_MAC_CAP_INFO_LEN { log::error!( "Buffer size is smaller than EHT_MAC_CAP_INFO_LEN \ {EHT_MAC_CAP_INFO_LEN}" ); return; } buffer[..EHT_MAC_CAP_INFO_LEN].copy_from_slice(&self.0) } } const EHT_PHY_CAP_INFO_LEN: usize = 9; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtPhyCapInfo(pub [u8; EHT_PHY_CAP_INFO_LEN]); impl Nl80211EhtPhyCapInfo { pub const LENGTH: usize = EHT_PHY_CAP_INFO_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } } impl Emitable for Nl80211EhtPhyCapInfo { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < EHT_PHY_CAP_INFO_LEN { log::error!( "Buffer size is smaller than EHT_PHY_CAP_INFO_LEN \ {EHT_PHY_CAP_INFO_LEN}" ); return; } buffer[..EHT_PHY_CAP_INFO_LEN].copy_from_slice(&self.0) } } /// MCS/NSS support for 20 MHz-only STA. // Kernel data type: `struct ieee80211_eht_mcs_nss_supp_20mhz_only` #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtMcsNssSuppOnly20Mhz { /// MCS 0 - 7 pub rx_tx_mcs7_max_nss: u8, /// MCS 8 - 9 pub rx_tx_mcs9_max_nss: u8, /// MCS 10 - 11 pub rx_tx_mcs11_max_nss: u8, /// MCS 12 - 13 pub rx_tx_mcs13_max_nss: u8, } impl Nl80211EhtMcsNssSuppOnly20Mhz { pub const LENGTH: usize = 4; pub fn parse(buf: &[u8]) -> Self { Self { rx_tx_mcs7_max_nss: *buf.first().unwrap_or(&0), rx_tx_mcs9_max_nss: *buf.get(1).unwrap_or(&0), rx_tx_mcs11_max_nss: *buf.get(2).unwrap_or(&0), rx_tx_mcs13_max_nss: *buf.get(3).unwrap_or(&0), } } } impl Emitable for Nl80211EhtMcsNssSuppOnly20Mhz { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Buffer size is smaller than required length {}", Self::LENGTH ); return; } buffer[0] = self.rx_tx_mcs7_max_nss; buffer[1] = self.rx_tx_mcs9_max_nss; buffer[2] = self.rx_tx_mcs11_max_nss; buffer[3] = self.rx_tx_mcs13_max_nss; } } // Kernel data type: `struct ieee80211_eht_mcs_nss_supp_bw` #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtMcsNssSuppBw { /// MCS 8 - 9 pub rx_tx_mcs9_max_nss: u8, /// MCS 10 - 11 pub rx_tx_mcs11_max_nss: u8, /// MCS 12 - 13 pub rx_tx_mcs13_max_nss: u8, } impl Nl80211EhtMcsNssSuppBw { pub const LENGTH: usize = 3; pub fn parse(buf: &[u8]) -> Self { Self { rx_tx_mcs9_max_nss: *buf.first().unwrap_or(&0), rx_tx_mcs11_max_nss: *buf.get(1).unwrap_or(&0), rx_tx_mcs13_max_nss: *buf.get(2).unwrap_or(&0), } } } impl Emitable for Nl80211EhtMcsNssSuppBw { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Buffer size is smaller than required length {}", Self::LENGTH ); return; } buffer[0] = self.rx_tx_mcs9_max_nss; buffer[1] = self.rx_tx_mcs11_max_nss; buffer[2] = self.rx_tx_mcs13_max_nss; } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtMcsNssSuppMoreThan20Mhz { pub mhz_80: Nl80211EhtMcsNssSuppBw, pub mhz_160: Nl80211EhtMcsNssSuppBw, pub mhz_320: Nl80211EhtMcsNssSuppBw, } impl Nl80211EhtMcsNssSuppMoreThan20Mhz { pub const LENGTH: usize = Nl80211EhtMcsNssSuppBw::LENGTH * 3; pub fn parse(buf: &[u8]) -> Self { Self { mhz_80: Nl80211EhtMcsNssSuppBw::parse(buf), mhz_160: Nl80211EhtMcsNssSuppBw::parse( &buf[Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH..], ), mhz_320: Nl80211EhtMcsNssSuppBw::parse( &buf[Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH * 2..], ), } } } impl Emitable for Nl80211EhtMcsNssSuppMoreThan20Mhz { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Buffer size is smaller than required length {}", Self::LENGTH ); return; } self.mhz_80.emit(buffer); self.mhz_160 .emit(&mut buffer[Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH..]); self.mhz_320 .emit(&mut buffer[Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH * 2..]); } } // Kernel data type: `struct ieee80211_eht_mcs_nss_supp` /// EHT max supported NSS per MCS #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211EhtMcsNssSupp { Only20Mhz(Nl80211EhtMcsNssSuppOnly20Mhz), MoreThan20Mhz(Nl80211EhtMcsNssSuppMoreThan20Mhz), /// This other might be removed once 802.11be standard published Other(Vec), } impl Emitable for Nl80211EhtMcsNssSupp { fn buffer_len(&self) -> usize { match self { Self::Only20Mhz(_) => Nl80211EhtMcsNssSuppOnly20Mhz::LENGTH, Self::MoreThan20Mhz(_) => Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH, Self::Other(v) => v.len(), } } fn emit(&self, buffer: &mut [u8]) { match self { Self::Only20Mhz(v) => v.emit(buffer), Self::MoreThan20Mhz(v) => v.emit(buffer), Self::Other(v) => buffer.copy_from_slice(&v[..buffer.len()]), } } } impl Nl80211EhtMcsNssSupp { pub fn parse(buf: &[u8]) -> Result { if buf.len() > Nl80211EhtMcsNssSuppOnly20Mhz::LENGTH { if buf.len() >= Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH { Ok(Self::MoreThan20Mhz( Nl80211EhtMcsNssSuppMoreThan20Mhz::parse(buf), )) } else { Err(format!( "Invalid NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET \ data, expecting u8 array with size {} or {}, but got {}", Nl80211EhtMcsNssSuppOnly20Mhz::LENGTH, Nl80211EhtMcsNssSuppMoreThan20Mhz::LENGTH, buf.len() ) .into()) } } else { Ok(Self::Only20Mhz(Nl80211EhtMcsNssSuppOnly20Mhz::parse(buf))) } } } const IEEE80211_EHT_PPE_THRES_MAX_LEN: usize = 32; /// PPE thresholds // TODO: write passing function #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211EhtPpeThres(pub [u8; IEEE80211_EHT_PPE_THRES_MAX_LEN]); impl Nl80211EhtPpeThres { pub const LENGTH: usize = IEEE80211_EHT_PPE_THRES_MAX_LEN; pub fn new(value: &[u8]) -> Self { let mut data = [0u8; Self::LENGTH]; if value.len() > Self::LENGTH { data.copy_from_slice(&value[..Self::LENGTH]); } else { data[..value.len()].copy_from_slice(value) } Self(data) } } impl Emitable for Nl80211EhtPpeThres { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { if buffer.len() < Self::LENGTH { log::error!( "Buffer size is smaller than required length {}", Self::LENGTH ); return; } buffer[..Self::LENGTH].copy_from_slice(&self.0) } } wl-nl80211-0.2.0/src/wiphy/band.rs000064400000000000000000001436451046102023000144660ustar 00000000000000// SPDX-License-Identifier: MIT // Most documentation comments are copied and modified from linux kernel // include/uapi/linux/nl80211.h which is holding these license disclaimer: /* * 802.11 netlink interface public header * * Copyright 2006-2010 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch * Copyright 2008, 2009 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH * Copyright (C) 2018-2024 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_u16, parse_u32, parse_u8}, DecodeError, Emitable, Parseable, ParseableParametrized, }; use crate::{ bytes::{write_u16, write_u32}, Nl80211EhtMacCapInfo, Nl80211EhtMcsNssSupp, Nl80211EhtPhyCapInfo, Nl80211EhtPpeThres, Nl80211He6GhzCapa, Nl80211HeMacCapInfo, Nl80211HeMcsNssSupp, Nl80211HePhyCapInfo, Nl80211HePpeThreshold, Nl80211HtCaps, Nl80211HtMcsInfo, Nl80211VhtCapInfo, Nl80211VhtMcsInfo, }; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211Band { pub kind: Nl80211BandType, pub info: Vec, } impl Nla for Nl80211Band { fn value_len(&self) -> usize { self.info.as_slice().buffer_len() } fn kind(&self) -> u16 { self.kind.into() } fn emit_value(&self, buffer: &mut [u8]) { self.info.as_slice().emit(buffer) } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211Band { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let band_type = Nl80211BandType::from(buf.kind()); let payload = buf.value(); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!("Invalid NL80211_ATTR_WIPHY_BANDS value {:?}", nla); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211BandInfo::parse(nla)?); } Ok(Self { kind: band_type, info: nlas, }) } } const NL80211_BAND_2GHZ: u16 = 0; const NL80211_BAND_5GHZ: u16 = 1; const NL80211_BAND_60GHZ: u16 = 2; const NL80211_BAND_6GHZ: u16 = 3; const NL80211_BAND_S1GHZ: u16 = 4; const NL80211_BAND_LC: u16 = 5; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211BandType { Band2GHz, Band5GHz, Band60GHz, Band6GHz, BandS1GHz, /// light communication band BandLc, Other(u16), } impl From for Nl80211BandType { fn from(d: u16) -> Self { match d { NL80211_BAND_2GHZ => Self::Band2GHz, NL80211_BAND_5GHZ => Self::Band5GHz, NL80211_BAND_60GHZ => Self::Band60GHz, NL80211_BAND_6GHZ => Self::Band6GHz, NL80211_BAND_S1GHZ => Self::BandS1GHz, NL80211_BAND_LC => Self::BandLc, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211BandType) -> u16 { match v { Nl80211BandType::Band2GHz => NL80211_BAND_2GHZ, Nl80211BandType::Band5GHz => NL80211_BAND_5GHZ, Nl80211BandType::Band60GHz => NL80211_BAND_60GHZ, Nl80211BandType::Band6GHz => NL80211_BAND_6GHZ, Nl80211BandType::BandS1GHz => NL80211_BAND_S1GHZ, Nl80211BandType::BandLc => NL80211_BAND_LC, Nl80211BandType::Other(d) => d, } } } bitflags::bitflags! { /// If not bands are set, it means don't care and the device will decide /// what to use #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] #[non_exhaustive] pub struct Nl80211BandTypes: u32 { const Band2GHz = 1 << NL80211_BAND_2GHZ; const Band5GHz = 1 << NL80211_BAND_5GHZ; const Band60GHz = 1 << NL80211_BAND_60GHZ; const Band6GHz = 1 << NL80211_BAND_6GHZ; const BandS1GHz = 1<< NL80211_BAND_S1GHZ; /// light communication band (placeholder) const BandLc = 1 << NL80211_BAND_LC; } } impl Nl80211BandTypes { pub const LENGTH: usize = 4; pub fn parse(raw: &[u8]) -> Result { Ok(Self::from_bits_retain(parse_u32(raw).context(format!( "Invalid Nl80211BandTypes payload {raw:?}" ))?)) } } impl Emitable for Nl80211BandTypes { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { buffer.copy_from_slice(&self.bits().to_ne_bytes()) } } const NL80211_BAND_ATTR_FREQS: u16 = 1; const NL80211_BAND_ATTR_RATES: u16 = 2; const NL80211_BAND_ATTR_HT_MCS_SET: u16 = 3; const NL80211_BAND_ATTR_HT_CAPA: u16 = 4; const NL80211_BAND_ATTR_HT_AMPDU_FACTOR: u16 = 5; const NL80211_BAND_ATTR_HT_AMPDU_DENSITY: u16 = 6; const NL80211_BAND_ATTR_VHT_MCS_SET: u16 = 7; const NL80211_BAND_ATTR_VHT_CAPA: u16 = 8; const NL80211_BAND_ATTR_IFTYPE_DATA: u16 = 9; const NL80211_BAND_ATTR_EDMG_CHANNELS: u16 = 10; const NL80211_BAND_ATTR_EDMG_BW_CONFIG: u16 = 11; // TODO: Kernel has no properly defined struct for 802.11ah sub-1G MCS and CAPA, // postpone the deserialization. // const NL80211_BAND_ATTR_S1G_MCS_NSS_SET: u16 = 12; // const NL80211_BAND_ATTR_S1G_CAPA: u16 = 13; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211BandInfo { /// Supported frequencies in this band. Freqs(Vec), /// Supported bitrates in this band. Rates(Vec>), /// The MCS set as defined in 802.11n(WIFI 4). HtMcsSet(Nl80211HtMcsInfo), /// HT capabilities, as in the HT information IE. HtCapa(Nl80211HtCaps), /// Maximum A-MPDU length factor, as in 802.11n(WIFI 4). HtAmpduFactor(u8), /// Minimum A-MPDU spacing, as in 802.11n(WIFI 4). HtAmpduDensity(u8), /// The MCS set as defined in 802.11ac(WIFI 5). VhtMcsSet(Nl80211VhtMcsInfo), /// VHT capabilities, as in the HT information IE VhtCap(Nl80211VhtCapInfo), /// Interface type data IftypeData(Vec), /// Bitmap that indicates the 2.16 GHz channel(s) that are allowed to be /// used for EDMG transmissions. Defined by IEEE P802.11ay/D4.0 section /// 9.4.2.251. EdmgChannels(u8), /// Channel BW Configuration subfield encodes the allowed channel bandwidth /// configurations. EdmgBwConfig(u8), Other(DefaultNla), } impl Nla for Nl80211BandInfo { fn value_len(&self) -> usize { match self { Self::Freqs(s) => s.as_slice().buffer_len(), Self::Rates(s) => { Nl80211RateAttrsList::from(s).as_slice().buffer_len() } Self::HtMcsSet(_) => Nl80211HtMcsInfo::LENGTH, Self::HtCapa(_) => 2, Self::HtAmpduFactor(_) => 1, Self::HtAmpduDensity(_) => 1, Self::VhtMcsSet(_) => Nl80211VhtMcsInfo::LENGTH, Self::VhtCap(_) => Nl80211VhtCapInfo::LENGTH, Self::IftypeData(s) => s.as_slice().buffer_len(), Self::EdmgChannels(_) => 1, Self::EdmgBwConfig(_) => 1, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Freqs(_) => NL80211_BAND_ATTR_FREQS, Self::Rates(_) => NL80211_BAND_ATTR_RATES, Self::HtMcsSet(_) => NL80211_BAND_ATTR_HT_MCS_SET, Self::HtCapa(_) => NL80211_BAND_ATTR_HT_CAPA, Self::HtAmpduFactor(_) => NL80211_BAND_ATTR_HT_AMPDU_FACTOR, Self::HtAmpduDensity(_) => NL80211_BAND_ATTR_HT_AMPDU_DENSITY, Self::VhtMcsSet(_) => NL80211_BAND_ATTR_VHT_MCS_SET, Self::VhtCap(_) => NL80211_BAND_ATTR_VHT_CAPA, Self::IftypeData(_) => NL80211_BAND_ATTR_IFTYPE_DATA, Self::EdmgChannels(_) => NL80211_BAND_ATTR_EDMG_CHANNELS, Self::EdmgBwConfig(_) => NL80211_BAND_ATTR_EDMG_BW_CONFIG, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Freqs(d) => d.as_slice().emit(buffer), Self::Rates(s) => { Nl80211RateAttrsList::from(s).as_slice().emit(buffer) } Self::HtMcsSet(d) => d.emit(buffer), Self::HtCapa(d) => buffer.copy_from_slice(&d.bits().to_ne_bytes()), Self::HtAmpduFactor(d) => buffer[0] = *d, Self::HtAmpduDensity(d) => buffer[0] = *d, Self::VhtMcsSet(d) => d.emit(buffer), Self::VhtCap(d) => d.emit(buffer), Self::IftypeData(d) => d.as_slice().emit(buffer), Self::EdmgChannels(d) => buffer[0] = *d, Self::EdmgBwConfig(d) => buffer[0] = *d, Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211BandInfo { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_BAND_ATTR_FREQS => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_FREQS value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211Frequency::parse(nla)?); } Self::Freqs(nlas) } NL80211_BAND_ATTR_RATES => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_RATES value {:?}", payload ); let mut nlas = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211RateAttrs::parse_with_param(nla, index as u16) .context(err_msg.clone())? .attributes, ); } Self::Rates(nlas) } NL80211_BAND_ATTR_HT_MCS_SET => { Self::HtMcsSet(Nl80211HtMcsInfo::parse(payload)?) } NL80211_BAND_ATTR_HT_CAPA => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_HT_CAPA value {:?}", payload ); Self::HtCapa(Nl80211HtCaps::from_bits_retain( parse_u16(payload).context(err_msg)?, )) } NL80211_BAND_ATTR_HT_AMPDU_FACTOR => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_HT_AMPDU_FACTOR value {:?}", payload ); Self::HtAmpduFactor(parse_u8(payload).context(err_msg)?) } NL80211_BAND_ATTR_HT_AMPDU_DENSITY => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_HT_AMPDU_DENSITY value {:?}", payload ); Self::HtAmpduDensity(parse_u8(payload).context(err_msg)?) } NL80211_BAND_ATTR_VHT_MCS_SET => { Self::VhtMcsSet(Nl80211VhtMcsInfo::parse(payload)?) } NL80211_BAND_ATTR_VHT_CAPA => { Self::VhtCap(Nl80211VhtCapInfo::parse(payload)?) } NL80211_BAND_ATTR_IFTYPE_DATA => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_IFTYPE_DATA value {:?}", payload ); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211BandIftypeData::parse(nla) .context(err_msg.clone())?, ); } Self::IftypeData(nlas) } NL80211_BAND_ATTR_EDMG_CHANNELS => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_EDMG_CHANNELS value {:?}", payload ); Self::EdmgChannels(parse_u8(payload).context(err_msg)?) } NL80211_BAND_ATTR_EDMG_BW_CONFIG => { let err_msg = format!( "Invalid NL80211_BAND_ATTR_EDMG_BW_CONFIG value {:?}", payload ); Self::EdmgBwConfig(parse_u8(payload).context(err_msg)?) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } const NL80211_BAND_IFTYPE_ATTR_IFTYPES: u16 = 1; const NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC: u16 = 2; const NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY: u16 = 3; const NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET: u16 = 4; const NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: u16 = 5; const NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: u16 = 6; const NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: u16 = 7; const NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: u16 = 8; const NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: u16 = 9; const NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: u16 = 10; const NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: u16 = 11; #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum Nl80211BandIftypeData { IfTypes(Vec), HeCapMac(Nl80211HeMacCapInfo), HeCapPhy(Nl80211HePhyCapInfo), HeCapMcsSet(Nl80211HeMcsNssSupp), HeCapPpeThreshold(Nl80211HePpeThreshold), He6ghzCapa(Nl80211He6GhzCapa), /// Vendor specific data VendorElems(Vec), EhtCapMac(Nl80211EhtMacCapInfo), EhtCapPhy(Nl80211EhtPhyCapInfo), EhtCapMcsSet(Nl80211EhtMcsNssSupp), EhtCapPpe(Nl80211EhtPpeThres), Other(DefaultNla), } impl Nla for Nl80211BandIftypeData { fn value_len(&self) -> usize { match self { Self::IfTypes(s) => Nl80211IfTypeList(s.clone()).value_len(), Self::HeCapMac(s) => s.buffer_len(), Self::HeCapPhy(s) => s.buffer_len(), Self::HeCapMcsSet(s) => s.buffer_len(), Self::HeCapPpeThreshold(s) => s.buffer_len(), Self::He6ghzCapa(s) => s.buffer_len(), Self::VendorElems(s) => s.len(), Self::EhtCapMac(s) => s.buffer_len(), Self::EhtCapPhy(s) => s.buffer_len(), Self::EhtCapMcsSet(s) => s.buffer_len(), Self::EhtCapPpe(s) => s.buffer_len(), Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::IfTypes(_) => NL80211_BAND_IFTYPE_ATTR_IFTYPES, Self::HeCapMac(_) => NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC, Self::HeCapPhy(_) => NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, Self::HeCapMcsSet(_) => NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, Self::HeCapPpeThreshold(_) => NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, Self::He6ghzCapa(_) => NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, Self::VendorElems(_) => NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, Self::EhtCapMac(_) => NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC, Self::EhtCapPhy(_) => NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, Self::EhtCapMcsSet(_) => NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET, Self::EhtCapPpe(_) => NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::IfTypes(d) => { Nl80211IfTypeList(d.clone()).0.as_slice().emit(buffer) } Self::HeCapMac(d) => d.emit(buffer), Self::HeCapPhy(d) => d.emit(buffer), Self::HeCapMcsSet(d) => d.emit(buffer), Self::HeCapPpeThreshold(d) => d.emit(buffer), Self::He6ghzCapa(d) => d.emit(buffer), Self::VendorElems(d) => buffer[..d.len()].copy_from_slice(d), Self::EhtCapMac(d) => d.emit(buffer), Self::EhtCapPhy(d) => d.emit(buffer), Self::EhtCapMcsSet(d) => d.emit(buffer), Self::EhtCapPpe(d) => d.emit(buffer), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211BandIftypeData { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_BAND_IFTYPE_ATTR_IFTYPES => Self::IfTypes( Nl80211IfTypeList::parse(buf) .context( "Invalid NLA for NL80211_BAND_IFTYPE_ATTR_IFTYPES", )? .0, ), NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC => { if payload.len() < Nl80211HeMacCapInfo::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC value \ length is less than expected {}: {:?}", Nl80211HeMacCapInfo::LENGTH, payload ) .into()); } Self::HeCapMac(Nl80211HeMacCapInfo::new(payload)) } NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY => { if payload.len() < Nl80211HePhyCapInfo::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY value \ length is less than expected {}: {:?}", Nl80211HePhyCapInfo::LENGTH, payload ) .into()); } Self::HeCapPhy(Nl80211HePhyCapInfo::new(payload)) } NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET => { if payload.len() < Nl80211HeMcsNssSupp::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET value \ length is less than expected {}: {:?}", Nl80211HeMcsNssSupp::LENGTH, payload ) .into()); } Self::HeCapMcsSet(Nl80211HeMcsNssSupp::parse(payload)?) } NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE => { if payload.len() < Nl80211HePpeThreshold::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE value \ length is less than expected {}: {:?}", Nl80211HePpeThreshold::LENGTH, payload ) .into()); } Self::HeCapPpeThreshold(Nl80211HePpeThreshold::new(payload)) } NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA => { if payload.len() < Nl80211He6GhzCapa::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA value \ length is less than expected {}: {:?}", Nl80211He6GhzCapa::LENGTH, payload ) .into()); } Self::He6ghzCapa(Nl80211He6GhzCapa::new(payload)) } NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS => { Self::VendorElems(payload.to_vec()) } NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC => { if payload.len() < Nl80211EhtMacCapInfo::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC value \ length is less than expected {}: {:?}", Nl80211EhtMacCapInfo::LENGTH, payload ) .into()); } Self::EhtCapMac(Nl80211EhtMacCapInfo::new(payload)) } NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY => { if payload.len() < Nl80211EhtPhyCapInfo::LENGTH { return Err(format!( "NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY value \ length is less than expected {}: {:?}", Nl80211EhtPhyCapInfo::LENGTH, payload ) .into()); } Self::EhtCapPhy(Nl80211EhtPhyCapInfo::new(payload)) } NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET => { Self::EhtCapMcsSet(Nl80211EhtMcsNssSupp::parse(payload)?) } NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE => { Self::EhtCapPpe(Nl80211EhtPpeThres::new(payload)) } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } const NL80211_IFTYPE_ADHOC: u16 = 1; const NL80211_IFTYPE_STATION: u16 = 2; const NL80211_IFTYPE_AP: u16 = 3; const NL80211_IFTYPE_AP_VLAN: u16 = 4; const NL80211_IFTYPE_WDS: u16 = 5; const NL80211_IFTYPE_MONITOR: u16 = 6; const NL80211_IFTYPE_MESH_POINT: u16 = 7; const NL80211_IFTYPE_P2P_CLIENT: u16 = 8; const NL80211_IFTYPE_P2P_GO: u16 = 9; const NL80211_IFTYPE_P2P_DEVICE: u16 = 10; const NL80211_IFTYPE_OCB: u16 = 11; const NL80211_IFTYPE_NAN: u16 = 12; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211IfType { Adhoc, /// aka: managed or client Station, Ap, ApVlan, Wds, Monitor, MeshPoint, P2pClient, P2pGo, P2pDevice, Ocb, Nan, Other(u16), } impl From for Nl80211IfType { fn from(d: u16) -> Self { match d { NL80211_IFTYPE_ADHOC => Self::Adhoc, NL80211_IFTYPE_STATION => Self::Station, NL80211_IFTYPE_AP => Self::Ap, NL80211_IFTYPE_AP_VLAN => Self::ApVlan, NL80211_IFTYPE_WDS => Self::Wds, NL80211_IFTYPE_MONITOR => Self::Monitor, NL80211_IFTYPE_MESH_POINT => Self::MeshPoint, NL80211_IFTYPE_P2P_CLIENT => Self::P2pClient, NL80211_IFTYPE_P2P_GO => Self::P2pGo, NL80211_IFTYPE_P2P_DEVICE => Self::P2pDevice, NL80211_IFTYPE_OCB => Self::Ocb, NL80211_IFTYPE_NAN => Self::Nan, _ => Self::Other(d), } } } impl From<&Nl80211IfType> for u16 { fn from(v: &Nl80211IfType) -> Self { match v { Nl80211IfType::Adhoc => NL80211_IFTYPE_ADHOC, Nl80211IfType::Station => NL80211_IFTYPE_STATION, Nl80211IfType::Ap => NL80211_IFTYPE_AP, Nl80211IfType::ApVlan => NL80211_IFTYPE_AP_VLAN, Nl80211IfType::Wds => NL80211_IFTYPE_WDS, Nl80211IfType::Monitor => NL80211_IFTYPE_MONITOR, Nl80211IfType::MeshPoint => NL80211_IFTYPE_MESH_POINT, Nl80211IfType::P2pClient => NL80211_IFTYPE_P2P_CLIENT, Nl80211IfType::P2pGo => NL80211_IFTYPE_P2P_GO, Nl80211IfType::P2pDevice => NL80211_IFTYPE_P2P_DEVICE, Nl80211IfType::Ocb => NL80211_IFTYPE_OCB, Nl80211IfType::Nan => NL80211_IFTYPE_NAN, Nl80211IfType::Other(d) => *d, } } } // The kernel function `nl80211_put_iftypes()` is using mode number as NLA kind struct Nl80211IfTypeList(Vec); impl std::ops::Deref for Nl80211IfTypeList { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl Nla for Nl80211IfType { fn value_len(&self) -> usize { 0 } fn emit_value(&self, _buffer: &mut [u8]) {} fn kind(&self) -> u16 { self.into() } } impl Nla for Nl80211IfTypeList { fn value_len(&self) -> usize { self.0.as_slice().buffer_len() } fn emit_value(&self, buffer: &mut [u8]) { self.0.as_slice().emit(buffer) } fn kind(&self) -> u16 { NL80211_BAND_IFTYPE_ATTR_IFTYPES } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfTypeList { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); let mut if_types: Vec = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context("invalid NL80211_BAND_IFTYPE_ATTR_IFTYPES value")?; if_types.push(nla.kind().into()); } Ok(Self(if_types)) } } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211Frequency { pub index: u16, pub info: Vec, } impl Nla for Nl80211Frequency { fn value_len(&self) -> usize { self.info.as_slice().buffer_len() } fn kind(&self) -> u16 { self.index } fn emit_value(&self, buffer: &mut [u8]) { self.info.as_slice().emit(buffer) } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211Frequency { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let index = buf.kind(); let payload = buf.value(); let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!("Invalid NL80211_BAND_ATTR_FREQS value {:?}", nla); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211FrequencyInfo::parse(nla)?); } Ok(Self { index, info: nlas }) } } const NL80211_FREQUENCY_ATTR_FREQ: u16 = 1; const NL80211_FREQUENCY_ATTR_DISABLED: u16 = 2; const NL80211_FREQUENCY_ATTR_NO_IR: u16 = 3; // Obsoleted, same as NL80211_FREQUENCY_ATTR_NO_IR const __NL80211_FREQUENCY_ATTR_NO_IBSS: u16 = 4; const NL80211_FREQUENCY_ATTR_RADAR: u16 = 5; const NL80211_FREQUENCY_ATTR_MAX_TX_POWER: u16 = 6; const NL80211_FREQUENCY_ATTR_DFS_STATE: u16 = 7; const NL80211_FREQUENCY_ATTR_DFS_TIME: u16 = 8; const NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: u16 = 9; const NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: u16 = 10; const NL80211_FREQUENCY_ATTR_NO_80MHZ: u16 = 11; const NL80211_FREQUENCY_ATTR_NO_160MHZ: u16 = 12; const NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: u16 = 13; const NL80211_FREQUENCY_ATTR_INDOOR_ONLY: u16 = 14; const NL80211_FREQUENCY_ATTR_IR_CONCURRENT: u16 = 15; const NL80211_FREQUENCY_ATTR_NO_20MHZ: u16 = 16; const NL80211_FREQUENCY_ATTR_NO_10MHZ: u16 = 17; const NL80211_FREQUENCY_ATTR_WMM: u16 = 18; const NL80211_FREQUENCY_ATTR_NO_HE: u16 = 19; const NL80211_FREQUENCY_ATTR_OFFSET: u16 = 20; const NL80211_FREQUENCY_ATTR_1MHZ: u16 = 21; const NL80211_FREQUENCY_ATTR_2MHZ: u16 = 22; const NL80211_FREQUENCY_ATTR_4MHZ: u16 = 23; const NL80211_FREQUENCY_ATTR_8MHZ: u16 = 24; const NL80211_FREQUENCY_ATTR_16MHZ: u16 = 25; const NL80211_FREQUENCY_ATTR_NO_320MHZ: u16 = 26; const NL80211_FREQUENCY_ATTR_NO_EHT: u16 = 27; const NL80211_FREQUENCY_ATTR_PSD: u16 = 28; const NL80211_FREQUENCY_ATTR_DFS_CONCURRENT: u16 = 29; const NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT: u16 = 30; const NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT: u16 = 31; const NL80211_FREQUENCY_ATTR_CAN_MONITOR: u16 = 32; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211FrequencyInfo { /// Frequency in MHz Freq(u32), /// Channel is disabled in current regulatory domain Disabled, /// No mechanisms that initiate radiation are permitted on this channel, /// this includes sending probe requests, or modes of operation that /// require beaconing. NoIr, /// Obsoleted, same as [Nl80211FrequencyInfo::NoIr] NoIbss, /// Radar detection is mandatory on this channel in current regulatory /// domain. Radar, /// Maximum transmission power in mBm (100 * dBm) MaxTxPower(u32), /// Current state for DFS DfsState(Nl80211DfsState), /// time in milliseconds for how long this channel is in this DFS state DfsTime(u32), /// HT40- isn't possible with this channel as the control channel NoHt40Minus, /// HT40+ isn't possible with this channel as the control channel NoHt40Plus, /// Any 80 MHz channel using this channel as the primary or any of the /// secondary channels isn't possible, this includes 80+80 channels No80Mhz, /// Any 160 MHz (but not 80+80) channel using this channel as the primary /// or any of the secondary channels isn't possible No160Mhz, /// DFS CAC time in milliseconds. DfsCacTime(u32), /// Only indoor use is permitted on this channel. A channel that has the /// INDOOR_ONLY attribute can only be used when there is a clear assessment /// that the device is operating in an indoor surroundings, i.e., it is /// connected to AC power (and not through portable DC inverters) or is /// under the control of a master that is acting as an AP and is connected /// to AC power. IndoorOnly, /// IR operation is allowed on this channel if it's connected concurrently /// to a BSS on the same channel on the 2 GHz band or to a channel in /// the same UNII band (on the 5 GHz band), and IEEE80211_CHAN_RADAR is /// not set. Instantiating a GO or TDLS off-channel on a channel that /// has the IR_CONCURRENT attribute set can be done when there is a /// clear assessment that the device is operating under the guidance of /// an authorized master, i.e., setting up a GO or TDLS off-channel /// while the device is also connected to an AP with DFS and radar /// detection on the UNII band (it is up to user-space, i.e., /// wpa_supplicant to perform the required verifications). Using this /// attribute for IR is disallowed for master interfaces (IBSS, AP). IrConcurrent, /// 20 MHz operation is not allowed on this channel in current regulatory /// domain. No20Mhz, /// 10 MHz operation is not allowed on this channel in current regulatory /// domain. No10Mhz, /// this channel has WMM limitations. Wmm(Vec>), /// HE operation is not allowed on this channel in current regulatory /// domain. NoHe, /// frequency offset in KHz Offset(u32), /// 1 MHz operation is allowed Allow1Mhz, /// 2 MHz operation is allowed Allow2Mhz, /// 4 MHz operation is allowed Allow4Mhz, /// 8 MHz operation is allowed Allow8Mhz, /// 16 MHz operation is allowed Allow16Mhz, /// any 320 MHz channel using this channel /// as the primary or any of the secondary channels isn't possible No320Mhz, /// EHT operation is not allowed on this channel in current regulatory /// domain. NoEht, /// Power spectral density (in dBm) that is allowed on this channel in /// current regulatory domain. Psd(i8), /// Operation on this channel is allowed for peer-to-peer or adhoc /// communication under the control of a DFS master which operates on the /// same channel (FCC-594280 D01 Section B.3). Should be used together with /// `NL80211_RRF_DFS` only. DfsConcurrent, /// Client connection to VLP AP not allowed using this channel No6GhzVlpClient, /// Client connection to AFC AP not allowed using this channel No6GhzAfcclient, /// This channel can be used in monitor mode despite other (regulatory) /// restrictions, even if the channel is otherwise completely disabled. CanMonitor, /// Place holder for new attribute of `NL80211_BAND_ATTR_FREQS` Other(DefaultNla), } impl Nla for Nl80211FrequencyInfo { fn value_len(&self) -> usize { match self { Self::Freq(_) => 4, Self::Disabled => 0, Self::NoIr => 0, Self::Radar => 0, Self::NoIbss => 0, Self::MaxTxPower(_) => 4, Self::DfsState(_) => 4, Self::DfsTime(_) => 4, Self::NoHt40Minus => 0, Self::NoHt40Plus => 0, Self::No80Mhz => 0, Self::No160Mhz => 0, Self::DfsCacTime(_) => 4, Self::IndoorOnly => 0, Self::IrConcurrent => 0, Self::No20Mhz => 0, Self::No10Mhz => 0, Self::Wmm(ref v) => { Nl80211WmmRuleAttrsList::from(v).as_slice().buffer_len() } Self::NoHe => 0, Self::Offset(_) => 4, Self::Allow1Mhz => 0, Self::Allow2Mhz => 0, Self::Allow4Mhz => 0, Self::Allow8Mhz => 0, Self::Allow16Mhz => 0, Self::No320Mhz => 0, Self::NoEht => 0, Self::Psd(_) => 1, Self::DfsConcurrent => 0, Self::No6GhzVlpClient => 0, Self::No6GhzAfcclient => 0, Self::CanMonitor => 0, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Freq(_) => NL80211_FREQUENCY_ATTR_FREQ, Self::Disabled => NL80211_FREQUENCY_ATTR_DISABLED, Self::NoIr => NL80211_FREQUENCY_ATTR_NO_IR, Self::NoIbss => __NL80211_FREQUENCY_ATTR_NO_IBSS, Self::Radar => NL80211_FREQUENCY_ATTR_RADAR, Self::MaxTxPower(_) => NL80211_FREQUENCY_ATTR_MAX_TX_POWER, Self::DfsState(_) => NL80211_FREQUENCY_ATTR_DFS_STATE, Self::DfsTime(_) => NL80211_FREQUENCY_ATTR_DFS_TIME, Self::NoHt40Minus => NL80211_FREQUENCY_ATTR_NO_HT40_MINUS, Self::NoHt40Plus => NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, Self::No80Mhz => NL80211_FREQUENCY_ATTR_NO_80MHZ, Self::No160Mhz => NL80211_FREQUENCY_ATTR_NO_160MHZ, Self::DfsCacTime(_) => NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, Self::IndoorOnly => NL80211_FREQUENCY_ATTR_INDOOR_ONLY, Self::IrConcurrent => NL80211_FREQUENCY_ATTR_IR_CONCURRENT, Self::No20Mhz => NL80211_FREQUENCY_ATTR_NO_20MHZ, Self::No10Mhz => NL80211_FREQUENCY_ATTR_NO_10MHZ, Self::Wmm(_) => NL80211_FREQUENCY_ATTR_WMM, Self::NoHe => NL80211_FREQUENCY_ATTR_NO_HE, Self::Offset(_) => NL80211_FREQUENCY_ATTR_OFFSET, Self::Allow1Mhz => NL80211_FREQUENCY_ATTR_1MHZ, Self::Allow2Mhz => NL80211_FREQUENCY_ATTR_2MHZ, Self::Allow4Mhz => NL80211_FREQUENCY_ATTR_4MHZ, Self::Allow8Mhz => NL80211_FREQUENCY_ATTR_8MHZ, Self::Allow16Mhz => NL80211_FREQUENCY_ATTR_16MHZ, Self::No320Mhz => NL80211_FREQUENCY_ATTR_NO_320MHZ, Self::NoEht => NL80211_FREQUENCY_ATTR_NO_EHT, Self::Psd(_) => NL80211_FREQUENCY_ATTR_PSD, Self::DfsConcurrent => NL80211_FREQUENCY_ATTR_DFS_CONCURRENT, Self::No6GhzVlpClient => NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT, Self::No6GhzAfcclient => NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT, Self::CanMonitor => NL80211_FREQUENCY_ATTR_CAN_MONITOR, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Freq(d) | Self::MaxTxPower(d) | Self::DfsTime(d) | Self::DfsCacTime(d) => write_u32(buffer, *d), Self::DfsState(d) => write_u32(buffer, u32::from(d)), Self::Disabled | Self::NoIr | Self::NoIbss | Self::Radar | Self::NoHt40Minus | Self::NoHt40Plus | Self::No80Mhz | Self::No160Mhz | Self::IndoorOnly | Self::IrConcurrent | Self::No20Mhz | Self::No10Mhz | Self::NoHe | Self::Allow1Mhz | Self::Allow2Mhz | Self::Allow4Mhz | Self::Allow8Mhz | Self::Allow16Mhz | Self::No320Mhz | Self::NoEht | Self::DfsConcurrent | Self::No6GhzVlpClient | Self::No6GhzAfcclient | Self::CanMonitor => (), Self::Psd(d) => buffer[0] = *d as u8, Self::Offset(d) => write_u32(buffer, *d), Self::Wmm(ref v) => { Nl80211WmmRuleAttrsList::from(v).as_slice().emit(buffer) } Self::Other(ref attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211FrequencyInfo { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_FREQUENCY_ATTR_FREQ => { Self::Freq(parse_u32(payload).context(format!( "Invalid NL80211_FREQUENCY_ATTR_FREQ value: {:?}", payload ))?) } NL80211_FREQUENCY_ATTR_DISABLED => Self::Disabled, NL80211_FREQUENCY_ATTR_NO_IR => Self::NoIr, __NL80211_FREQUENCY_ATTR_NO_IBSS => Self::NoIbss, NL80211_FREQUENCY_ATTR_RADAR => Self::Radar, NL80211_FREQUENCY_ATTR_MAX_TX_POWER => { Self::MaxTxPower(parse_u32(payload).context(format!( "Invalid NL80211_FREQUENCY_ATTR_MAX_TX_POWER value: {:?}", payload ))?) } NL80211_FREQUENCY_ATTR_DFS_STATE => Self::DfsState( parse_u32(payload) .context(format!( "Invalid NL80211_FREQUENCY_ATTR_MAX_TX_POWER value: {:?}", payload ))? .into(), ), NL80211_FREQUENCY_ATTR_DFS_TIME => { Self::DfsTime(parse_u32(payload).context(format!( "Invalid NL80211_FREQUENCY_ATTR_DFS_TIME value: {:?}", payload ))?) } NL80211_FREQUENCY_ATTR_NO_HT40_MINUS => Self::NoHt40Minus, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS => Self::NoHt40Plus, NL80211_FREQUENCY_ATTR_NO_80MHZ => Self::No80Mhz, NL80211_FREQUENCY_ATTR_NO_160MHZ => Self::No160Mhz, NL80211_FREQUENCY_ATTR_DFS_CAC_TIME => { Self::DfsCacTime(parse_u32(payload).context(format!( "Invalid NL80211_FREQUENCY_ATTR_DFS_CAC_TIME value: {:?}", payload ))?) } NL80211_FREQUENCY_ATTR_INDOOR_ONLY => Self::IndoorOnly, NL80211_FREQUENCY_ATTR_IR_CONCURRENT => Self::IrConcurrent, NL80211_FREQUENCY_ATTR_NO_20MHZ => Self::No20Mhz, NL80211_FREQUENCY_ATTR_NO_10MHZ => Self::No10Mhz, NL80211_FREQUENCY_ATTR_WMM => { let err_msg = format!( "Invalid NL80211_FREQUENCY_ATTR_WMM value {:?}", payload ); let mut nlas = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let nla = &nla.context(err_msg.clone())?; nlas.push( Nl80211WmmRuleAttrs::parse_with_param( nla, index as u16, ) .context(err_msg.clone())? .attributes, ); } Self::Wmm(nlas) } NL80211_FREQUENCY_ATTR_NO_HE => Self::NoHe, NL80211_FREQUENCY_ATTR_OFFSET => { Self::Offset(parse_u32(payload).context(format!( "Invalid NL80211_FREQUENCY_ATTR_OFFSET value {:?}", payload ))?) } NL80211_FREQUENCY_ATTR_1MHZ => Self::Allow1Mhz, NL80211_FREQUENCY_ATTR_2MHZ => Self::Allow2Mhz, NL80211_FREQUENCY_ATTR_4MHZ => Self::Allow4Mhz, NL80211_FREQUENCY_ATTR_8MHZ => Self::Allow8Mhz, NL80211_FREQUENCY_ATTR_16MHZ => Self::Allow16Mhz, NL80211_FREQUENCY_ATTR_NO_320MHZ => Self::No320Mhz, NL80211_FREQUENCY_ATTR_NO_EHT => Self::NoEht, NL80211_FREQUENCY_ATTR_PSD => { if payload.is_empty() { return Err( "Got empty NL80211_FREQUENCY_ATTR_PSD payload".into() ); } Self::Psd(payload[0] as i8) } NL80211_FREQUENCY_ATTR_DFS_CONCURRENT => Self::DfsConcurrent, NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT => Self::No6GhzVlpClient, NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT => Self::No6GhzAfcclient, NL80211_FREQUENCY_ATTR_CAN_MONITOR => Self::CanMonitor, _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } #[derive(Debug, PartialEq, Eq, Clone)] struct Nl80211RateAttrsList(Vec); impl std::ops::Deref for Nl80211RateAttrsList { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From<&Vec>> for Nl80211RateAttrsList { fn from(attributes: &Vec>) -> Self { Self( attributes .iter() .cloned() .enumerate() .map(|(index, attributes)| Nl80211RateAttrs { index: index as u16, attributes, }) .collect(), ) } } // `NL80211_BAND_ATTR_RATES` is a two levels array. // The second level is using index as NLA kind. #[derive(Debug, PartialEq, Eq, Clone)] struct Nl80211RateAttrs { index: u16, attributes: Vec, } impl Nla for Nl80211RateAttrs { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn kind(&self) -> u16 { self.index } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer); } } impl<'a, T> ParseableParametrized, u16> for Nl80211RateAttrs where T: AsRef<[u8]> + ?Sized, { fn parse_with_param( buf: &NlaBuffer<&'a T>, index: u16, ) -> Result { let payload = buf.value(); let err_msg = format!("Invalid NL80211_BAND_ATTR_RATES value {:?}", payload); let mut attributes = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; attributes.push(Nl80211Rate::parse(nla)?); } Ok(Self { index, attributes }) } } const NL80211_BITRATE_ATTR_RATE: u16 = 1; const NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: u16 = 2; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211Rate { /// Bitrate in units of 100 kbps. Rate(u32), /// Short preamble supported in 2.4 GHz band. Support2GhzShortpreamble, Other(DefaultNla), } impl Nla for Nl80211Rate { fn value_len(&self) -> usize { match self { Self::Rate(_) => 4, Self::Support2GhzShortpreamble => 0, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Rate(_) => NL80211_BITRATE_ATTR_RATE, Self::Support2GhzShortpreamble => { NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE } Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Rate(d) => write_u32(buffer, *d), Self::Support2GhzShortpreamble => (), Self::Other(ref attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211Rate { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_BITRATE_ATTR_RATE => { Self::Rate(parse_u32(payload).context(format!( "Invalid NL80211_BITRATE_ATTR_RATE value {:?}", payload ))?) } NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE => { Self::Support2GhzShortpreamble } _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } const NL80211_DFS_USABLE: u32 = 0; const NL80211_DFS_UNAVAILABLE: u32 = 1; const NL80211_DFS_AVAILABLE: u32 = 2; /// DFS states for channels #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211DfsState { /// The channel can be used, but channel availability check (CAC) must be /// performed before using it for AP or IBSS. Usable, /// A radar has been detected on this channel, it is therefore marked as /// not available. Unavailable, /// The channel has been CAC checked and is available. Available, /// Place holder for new state Other(u32), } impl From for Nl80211DfsState { fn from(d: u32) -> Self { match d { NL80211_DFS_USABLE => Self::Usable, NL80211_DFS_UNAVAILABLE => Self::Unavailable, NL80211_DFS_AVAILABLE => Self::Available, _ => Self::Other(d), } } } impl From<&Nl80211DfsState> for u32 { fn from(v: &Nl80211DfsState) -> Self { match v { Nl80211DfsState::Usable => NL80211_DFS_USABLE, Nl80211DfsState::Unavailable => NL80211_DFS_UNAVAILABLE, Nl80211DfsState::Available => NL80211_DFS_AVAILABLE, Nl80211DfsState::Other(d) => *d, } } } #[derive(Debug, PartialEq, Eq, Clone)] struct Nl80211WmmRuleAttrsList(Vec); impl std::ops::Deref for Nl80211WmmRuleAttrsList { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From<&Vec>> for Nl80211WmmRuleAttrsList { fn from(attributes: &Vec>) -> Self { Self( attributes .iter() .cloned() .enumerate() .map(|(index, attributes)| Nl80211WmmRuleAttrs { index: index as u16, attributes, }) .collect(), ) } } // `NL80211_FREQUENCY_ATTR_WMM` is a two levels array. // The second level is using index as NLA kind. #[derive(Debug, PartialEq, Eq, Clone)] struct Nl80211WmmRuleAttrs { index: u16, attributes: Vec, } impl Nla for Nl80211WmmRuleAttrs { fn value_len(&self) -> usize { self.attributes.as_slice().buffer_len() } fn kind(&self) -> u16 { self.index } fn emit_value(&self, buffer: &mut [u8]) { self.attributes.as_slice().emit(buffer); } } impl<'a, T> ParseableParametrized, u16> for Nl80211WmmRuleAttrs where T: AsRef<[u8]> + ?Sized, { fn parse_with_param( buf: &NlaBuffer<&'a T>, index: u16, ) -> Result { let payload = buf.value(); let err_msg = format!("Invalid NL80211_FREQUENCY_ATTR_WMM value {:?}", payload); let mut attributes = Vec::new(); for nla in NlasIterator::new(payload) { let nla = &nla.context(err_msg.clone())?; attributes.push(Nl80211WmmRule::parse(nla)?); } Ok(Self { index, attributes }) } } const NL80211_WMMR_CW_MIN: u16 = 1; const NL80211_WMMR_CW_MAX: u16 = 2; const NL80211_WMMR_AIFSN: u16 = 3; const NL80211_WMMR_TXOP: u16 = 4; /// DFS states for channels #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211WmmRule { /// Minimum contention window slot CwMin(u16), /// Maximum contention window slot CwMax(u16), /// Arbitration Inter Frame Space Aifsn(u8), /// Maximum allowed tx operation time Txop(u16), /// Place holder for new entry of `enum nl80211_wmm_rule` Other(DefaultNla), } impl Nla for Nl80211WmmRule { fn value_len(&self) -> usize { match self { Self::CwMin(_) | Self::CwMax(_) | Self::Txop(_) => 2, Self::Aifsn(_) => 1, Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::CwMin(_) => NL80211_WMMR_CW_MIN, Self::CwMax(_) => NL80211_WMMR_CW_MAX, Self::Aifsn(_) => NL80211_WMMR_AIFSN, Self::Txop(_) => NL80211_WMMR_TXOP, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::CwMin(d) | Self::CwMax(d) | Self::Txop(d) => { write_u16(buffer, *d) } Self::Aifsn(d) => buffer[0] = *d, Self::Other(ref attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211WmmRule { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_WMMR_CW_MIN => Self::CwMin(parse_u16(payload).context( format!("Invalid NL80211_WMMR_CW_MIN value {:?}", payload), )?), NL80211_WMMR_CW_MAX => Self::CwMax(parse_u16(payload).context( format!("Invalid NL80211_WMMR_CW_MAX value {:?}", payload), )?), NL80211_WMMR_AIFSN => Self::Aifsn(parse_u8(payload).context( format!("Invalid NL80211_WMMR_AIFSN value {:?}", payload), )?), NL80211_WMMR_TXOP => Self::Txop(parse_u16(payload).context( format!("Invalid NL80211_WMMR_CW_MAX value {:?}", payload), )?), _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } wl-nl80211-0.2.0/src/wiphy/cipher.rs000064400000000000000000000056421046102023000150260ustar 00000000000000// SPDX-License-Identifier: MIT const WLAN_CIPHER_SUITE_USE_GROUP: u32 = 0x000FAC << 8; const WLAN_CIPHER_SUITE_WEP40: u32 = 0x000FAC << 8 | 1; const WLAN_CIPHER_SUITE_TKIP: u32 = 0x000FAC << 8 | 2; const WLAN_CIPHER_SUITE_CCMP: u32 = 0x000FAC << 8 | 4; const WLAN_CIPHER_SUITE_WEP104: u32 = 0x000FAC << 8 | 5; const WLAN_CIPHER_SUITE_AES_CMAC: u32 = 0x000FAC << 8 | 6; const WLAN_CIPHER_SUITE_GCMP: u32 = 0x000FAC << 8 | 8; const WLAN_CIPHER_SUITE_GCMP_256: u32 = 0x000FAC << 8 | 9; const WLAN_CIPHER_SUITE_CCMP_256: u32 = 0x000FAC << 8 | 10; const WLAN_CIPHER_SUITE_BIP_GMAC_128: u32 = 0x000FAC << 8 | 11; const WLAN_CIPHER_SUITE_BIP_GMAC_256: u32 = 0x000FAC << 8 | 12; const WLAN_CIPHER_SUITE_BIP_CMAC_256: u32 = 0x000FAC << 8 | 13; const WLAN_CIPHER_SUITE_SMS4: u32 = 0x001472 << 8 | 1; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211CipherSuit { UseGroup, Wep40, Tkip, Ccmp, Wep104, AesCmac, Gcmp, Gcmp256, Ccmp256, BipGmac128, BipGmac256, BipCmac256, Sms4, Other(u32), } impl From for Nl80211CipherSuit { fn from(d: u32) -> Self { match d { WLAN_CIPHER_SUITE_USE_GROUP => Self::UseGroup, WLAN_CIPHER_SUITE_WEP40 => Self::Wep40, WLAN_CIPHER_SUITE_TKIP => Self::Tkip, WLAN_CIPHER_SUITE_CCMP => Self::Ccmp, WLAN_CIPHER_SUITE_WEP104 => Self::Wep104, WLAN_CIPHER_SUITE_AES_CMAC => Self::AesCmac, WLAN_CIPHER_SUITE_GCMP => Self::Gcmp, WLAN_CIPHER_SUITE_GCMP_256 => Self::Gcmp256, WLAN_CIPHER_SUITE_CCMP_256 => Self::Ccmp256, WLAN_CIPHER_SUITE_BIP_GMAC_128 => Self::BipGmac128, WLAN_CIPHER_SUITE_BIP_GMAC_256 => Self::BipGmac256, WLAN_CIPHER_SUITE_BIP_CMAC_256 => Self::BipCmac256, WLAN_CIPHER_SUITE_SMS4 => Self::Sms4, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211CipherSuit) -> u32 { match v { Nl80211CipherSuit::UseGroup => WLAN_CIPHER_SUITE_USE_GROUP, Nl80211CipherSuit::Wep40 => WLAN_CIPHER_SUITE_WEP40, Nl80211CipherSuit::Tkip => WLAN_CIPHER_SUITE_TKIP, Nl80211CipherSuit::Ccmp => WLAN_CIPHER_SUITE_CCMP, Nl80211CipherSuit::Wep104 => WLAN_CIPHER_SUITE_WEP104, Nl80211CipherSuit::AesCmac => WLAN_CIPHER_SUITE_AES_CMAC, Nl80211CipherSuit::Gcmp => WLAN_CIPHER_SUITE_GCMP, Nl80211CipherSuit::Gcmp256 => WLAN_CIPHER_SUITE_GCMP_256, Nl80211CipherSuit::Ccmp256 => WLAN_CIPHER_SUITE_CCMP_256, Nl80211CipherSuit::BipGmac128 => WLAN_CIPHER_SUITE_BIP_GMAC_128, Nl80211CipherSuit::BipGmac256 => WLAN_CIPHER_SUITE_BIP_GMAC_256, Nl80211CipherSuit::BipCmac256 => WLAN_CIPHER_SUITE_BIP_CMAC_256, Nl80211CipherSuit::Sms4 => WLAN_CIPHER_SUITE_SMS4, Nl80211CipherSuit::Other(d) => d, } } } wl-nl80211-0.2.0/src/wiphy/command.rs000064400000000000000000001023521046102023000151660ustar 00000000000000// SPDX-License-Identifier: MIT use anyhow::Context; use netlink_packet_utils::{ nla::{Nla, NlasIterator}, parsers::parse_u32, DecodeError, }; use crate::bytes::write_u32; pub(crate) struct Nl80211CommandNla { index: u16, cmd: Nl80211Command, } impl Nla for Nl80211CommandNla { fn value_len(&self) -> usize { 4 } fn emit_value(&self, buffer: &mut [u8]) { write_u32(buffer, self.cmd.into()) } fn kind(&self) -> u16 { self.index } } // NL80211_ATTR_SUPPORTED_COMMANDS is using index as NLA kind. pub(crate) struct Nl80211Commands(Vec); impl std::ops::Deref for Nl80211Commands { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl From<&Vec> for Nl80211Commands { fn from(cmds: &Vec) -> Self { let mut nlas = Vec::new(); for (i, cmd) in cmds.iter().enumerate() { let nla = Nl80211CommandNla { index: i as u16, cmd: *cmd, }; nlas.push(nla); } Nl80211Commands(nlas) } } impl From for Vec { fn from(cmds: Nl80211Commands) -> Self { let mut cmds = cmds; cmds.0.drain(..).map(|c| c.cmd).collect() } } impl Nl80211Commands { pub fn parse(payload: &[u8]) -> Result { let mut cmds: Vec = Vec::new(); for (index, nla) in NlasIterator::new(payload).enumerate() { let error_msg = format!("Invalid NL80211_ATTR_SUPPORTED_COMMANDS: {nla:?}"); let nla = &nla.context(error_msg.clone())?; let cmd = Nl80211Command::from(parse_u32(nla.value()).context( format!("Invalid NL80211_ATTR_SUPPORTED_COMMANDS: {nla:?}"), )?); cmds.push(Nl80211CommandNla { index: index as u16, cmd, }); } Ok(Self(cmds)) } } const NL80211_CMD_GET_WIPHY: u32 = 1; const NL80211_CMD_SET_WIPHY: u32 = 2; const NL80211_CMD_NEW_WIPHY: u32 = 3; const NL80211_CMD_DEL_WIPHY: u32 = 4; const NL80211_CMD_GET_INTERFACE: u32 = 5; const NL80211_CMD_SET_INTERFACE: u32 = 6; const NL80211_CMD_NEW_INTERFACE: u32 = 7; const NL80211_CMD_DEL_INTERFACE: u32 = 8; const NL80211_CMD_GET_KEY: u32 = 9; const NL80211_CMD_SET_KEY: u32 = 10; const NL80211_CMD_NEW_KEY: u32 = 11; const NL80211_CMD_DEL_KEY: u32 = 12; const NL80211_CMD_GET_BEACON: u32 = 13; const NL80211_CMD_SET_BEACON: u32 = 14; const NL80211_CMD_START_AP: u32 = 15; const NL80211_CMD_STOP_AP: u32 = 16; const NL80211_CMD_GET_STATION: u32 = 17; const NL80211_CMD_SET_STATION: u32 = 18; const NL80211_CMD_NEW_STATION: u32 = 19; const NL80211_CMD_DEL_STATION: u32 = 20; const NL80211_CMD_GET_MPATH: u32 = 21; const NL80211_CMD_SET_MPATH: u32 = 22; const NL80211_CMD_NEW_MPATH: u32 = 23; const NL80211_CMD_DEL_MPATH: u32 = 24; const NL80211_CMD_SET_BSS: u32 = 25; const NL80211_CMD_SET_REG: u32 = 26; const NL80211_CMD_REQ_SET_REG: u32 = 27; const NL80211_CMD_GET_MESH_CONFIG: u32 = 28; const NL80211_CMD_SET_MESH_CONFIG: u32 = 29; const NL80211_CMD_SET_MGMT_EXTRA_IE: u32 = 30; const NL80211_CMD_GET_REG: u32 = 31; const NL80211_CMD_GET_SCAN: u32 = 32; const NL80211_CMD_TRIGGER_SCAN: u32 = 33; const NL80211_CMD_NEW_SCAN_RESULTS: u32 = 34; const NL80211_CMD_SCAN_ABORTED: u32 = 35; const NL80211_CMD_REG_CHANGE: u32 = 36; const NL80211_CMD_AUTHENTICATE: u32 = 37; const NL80211_CMD_ASSOCIATE: u32 = 38; const NL80211_CMD_DEAUTHENTICATE: u32 = 39; const NL80211_CMD_DISASSOCIATE: u32 = 40; const NL80211_CMD_MICHAEL_MIC_FAILURE: u32 = 41; const NL80211_CMD_REG_BEACON_HINT: u32 = 42; const NL80211_CMD_JOIN_IBSS: u32 = 43; const NL80211_CMD_LEAVE_IBSS: u32 = 44; const NL80211_CMD_TESTMODE: u32 = 45; const NL80211_CMD_CONNECT: u32 = 46; const NL80211_CMD_ROAM: u32 = 47; const NL80211_CMD_DISCONNECT: u32 = 48; const NL80211_CMD_SET_WIPHY_NETNS: u32 = 49; const NL80211_CMD_GET_SURVEY: u32 = 50; const NL80211_CMD_NEW_SURVEY_RESULTS: u32 = 51; const NL80211_CMD_SET_PMKSA: u32 = 52; const NL80211_CMD_DEL_PMKSA: u32 = 53; const NL80211_CMD_FLUSH_PMKSA: u32 = 54; const NL80211_CMD_REMAIN_ON_CHANNEL: u32 = 55; const NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: u32 = 56; const NL80211_CMD_SET_TX_BITRATE_MASK: u32 = 57; const NL80211_CMD_REGISTER_FRAME: u32 = 58; const NL80211_CMD_FRAME: u32 = 59; const NL80211_CMD_FRAME_TX_STATUS: u32 = 60; const NL80211_CMD_SET_POWER_SAVE: u32 = 61; const NL80211_CMD_GET_POWER_SAVE: u32 = 62; const NL80211_CMD_SET_CQM: u32 = 63; const NL80211_CMD_NOTIFY_CQM: u32 = 64; const NL80211_CMD_SET_CHANNEL: u32 = 65; const NL80211_CMD_SET_WDS_PEER: u32 = 66; const NL80211_CMD_FRAME_WAIT_CANCEL: u32 = 67; const NL80211_CMD_JOIN_MESH: u32 = 68; const NL80211_CMD_LEAVE_MESH: u32 = 69; const NL80211_CMD_UNPROT_DEAUTHENTICATE: u32 = 70; const NL80211_CMD_UNPROT_DISASSOCIATE: u32 = 71; const NL80211_CMD_NEW_PEER_CANDIDATE: u32 = 72; const NL80211_CMD_GET_WOWLAN: u32 = 73; const NL80211_CMD_SET_WOWLAN: u32 = 74; const NL80211_CMD_START_SCHED_SCAN: u32 = 75; const NL80211_CMD_STOP_SCHED_SCAN: u32 = 76; const NL80211_CMD_SCHED_SCAN_RESULTS: u32 = 77; const NL80211_CMD_SCHED_SCAN_STOPPED: u32 = 78; const NL80211_CMD_SET_REKEY_OFFLOAD: u32 = 79; const NL80211_CMD_PMKSA_CANDIDATE: u32 = 80; const NL80211_CMD_TDLS_OPER: u32 = 81; const NL80211_CMD_TDLS_MGMT: u32 = 82; const NL80211_CMD_UNEXPECTED_FRAME: u32 = 83; const NL80211_CMD_PROBE_CLIENT: u32 = 84; const NL80211_CMD_REGISTER_BEACONS: u32 = 85; const NL80211_CMD_UNEXPECTED_4ADDR_FRAME: u32 = 86; const NL80211_CMD_SET_NOACK_MAP: u32 = 87; const NL80211_CMD_CH_SWITCH_NOTIFY: u32 = 88; const NL80211_CMD_START_P2P_DEVICE: u32 = 89; const NL80211_CMD_STOP_P2P_DEVICE: u32 = 90; const NL80211_CMD_CONN_FAILED: u32 = 91; const NL80211_CMD_SET_MCAST_RATE: u32 = 92; const NL80211_CMD_SET_MAC_ACL: u32 = 93; const NL80211_CMD_RADAR_DETECT: u32 = 94; const NL80211_CMD_GET_PROTOCOL_FEATURES: u32 = 95; const NL80211_CMD_UPDATE_FT_IES: u32 = 96; const NL80211_CMD_FT_EVENT: u32 = 97; const NL80211_CMD_CRIT_PROTOCOL_START: u32 = 98; const NL80211_CMD_CRIT_PROTOCOL_STOP: u32 = 99; const NL80211_CMD_GET_COALESCE: u32 = 100; const NL80211_CMD_SET_COALESCE: u32 = 101; const NL80211_CMD_CHANNEL_SWITCH: u32 = 102; const NL80211_CMD_VENDOR: u32 = 103; const NL80211_CMD_SET_QOS_MAP: u32 = 104; const NL80211_CMD_ADD_TX_TS: u32 = 105; const NL80211_CMD_DEL_TX_TS: u32 = 106; const NL80211_CMD_GET_MPP: u32 = 107; const NL80211_CMD_JOIN_OCB: u32 = 108; const NL80211_CMD_LEAVE_OCB: u32 = 109; const NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: u32 = 110; const NL80211_CMD_TDLS_CHANNEL_SWITCH: u32 = 111; const NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: u32 = 112; const NL80211_CMD_WIPHY_REG_CHANGE: u32 = 113; const NL80211_CMD_ABORT_SCAN: u32 = 114; const NL80211_CMD_START_NAN: u32 = 115; const NL80211_CMD_STOP_NAN: u32 = 116; const NL80211_CMD_ADD_NAN_FUNCTION: u32 = 117; const NL80211_CMD_DEL_NAN_FUNCTION: u32 = 118; const NL80211_CMD_CHANGE_NAN_CONFIG: u32 = 119; const NL80211_CMD_NAN_MATCH: u32 = 120; const NL80211_CMD_SET_MULTICAST_TO_UNICAST: u32 = 121; const NL80211_CMD_UPDATE_CONNECT_PARAMS: u32 = 122; const NL80211_CMD_SET_PMK: u32 = 123; const NL80211_CMD_DEL_PMK: u32 = 124; const NL80211_CMD_PORT_AUTHORIZED: u32 = 125; const NL80211_CMD_RELOAD_REGDB: u32 = 126; const NL80211_CMD_EXTERNAL_AUTH: u32 = 127; const NL80211_CMD_STA_OPMODE_CHANGED: u32 = 128; const NL80211_CMD_CONTROL_PORT_FRAME: u32 = 129; const NL80211_CMD_GET_FTM_RESPONDER_STATS: u32 = 130; const NL80211_CMD_PEER_MEASUREMENT_START: u32 = 131; const NL80211_CMD_PEER_MEASUREMENT_RESULT: u32 = 132; const NL80211_CMD_PEER_MEASUREMENT_COMPLETE: u32 = 133; const NL80211_CMD_NOTIFY_RADAR: u32 = 134; const NL80211_CMD_UPDATE_OWE_INFO: u32 = 135; const NL80211_CMD_PROBE_MESH_LINK: u32 = 136; const NL80211_CMD_SET_TID_CONFIG: u32 = 137; const NL80211_CMD_UNPROT_BEACON: u32 = 138; const NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: u32 = 139; const NL80211_CMD_SET_SAR_SPECS: u32 = 140; const NL80211_CMD_OBSS_COLOR_COLLISION: u32 = 141; const NL80211_CMD_COLOR_CHANGE_REQUEST: u32 = 142; const NL80211_CMD_COLOR_CHANGE_STARTED: u32 = 143; const NL80211_CMD_COLOR_CHANGE_ABORTED: u32 = 144; const NL80211_CMD_COLOR_CHANGE_COMPLETED: u32 = 145; const NL80211_CMD_SET_FILS_AAD: u32 = 146; const NL80211_CMD_ASSOC_COMEBACK: u32 = 147; const NL80211_CMD_ADD_LINK: u32 = 148; const NL80211_CMD_REMOVE_LINK: u32 = 149; const NL80211_CMD_ADD_LINK_STA: u32 = 150; const NL80211_CMD_MODIFY_LINK_STA: u32 = 151; const NL80211_CMD_REMOVE_LINK_STA: u32 = 152; const NL80211_CMD_SET_HW_TIMESTAMP: u32 = 153; const NL80211_CMD_LINKS_REMOVED: u32 = 154; const NL80211_CMD_SET_TID_TO_LINK_MAPPING: u32 = 155; const NL80211_CMD_NEW_BEACON: u32 = NL80211_CMD_START_AP; const NL80211_CMD_DEL_BEACON: u32 = NL80211_CMD_STOP_AP; const NL80211_CMD_REGISTER_ACTION: u32 = NL80211_CMD_REGISTER_FRAME; const NL80211_CMD_ACTION: u32 = NL80211_CMD_FRAME; const NL80211_CMD_ACTION_TX_STATUS: u32 = NL80211_CMD_FRAME_TX_STATUS; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211Command { GetWiphy, SetWiphy, NewWiphy, DelWiphy, GetInterface, SetInterface, NewInterface, DelInterface, GetKey, SetKey, NewKey, DelKey, GetBeacon, SetBeacon, StartAp, StopAp, GetStation, SetStation, NewStation, DelStation, GetMpath, SetMpath, NewMpath, DelMpath, SetBss, SetReg, ReqSetReg, GetMeshConfig, SetMeshConfig, SetMgmtExtraIe, GetReg, GetScan, TriggerScan, NewScanResults, ScanAborted, RegChange, Authenticate, Associate, Deauthenticate, Disassociate, MichaelMicFailure, RegBeaconHint, JoinIbss, LeaveIbss, Testmode, Connect, Roam, Disconnect, SetWiphyNetns, GetSurvey, NewSurveyResults, SetPmksa, DelPmksa, FlushPmksa, RemainOnChannel, CancelRemainOnChannel, SetTxBitrateMask, RegisterFrame, Frame, FrameTxStatus, SetPowerSave, GetPowerSave, SetCqm, NotifyCqm, SetChannel, SetWdsPeer, FrameWaitCancel, JoinMesh, LeaveMesh, UnprotDeauthenticate, UnprotDisassociate, NewPeerCandidate, GetWowlan, SetWowlan, StartSchedScan, StopSchedScan, SchedScanResults, SchedScanStopped, SetRekeyOffload, PmksaCandidate, TdlsOper, TdlsMgmt, UnexpectedFrame, ProbeClient, RegisterBeacons, Unexpected4addrFrame, SetNoackMap, ChSwitchNotify, StartP2PDevice, StopP2PDevice, ConnFailed, SetMcastRate, SetMacAcl, RadarDetect, GetProtocolFeatures, UpdateFtIes, FtEvent, CritProtocolStart, CritProtocolStop, GetCoalesce, SetCoalesce, ChannelSwitch, Vendor, SetQosMap, AddTxTs, DelTxTs, GetMpp, JoinOcb, LeaveOcb, ChSwitchStartedNotify, TdlsChannelSwitch, TdlsCancelChannelSwitch, WiphyRegChange, AbortScan, StartNan, StopNan, AddNanFunction, DelNanFunction, ChangeNanConfig, NanMatch, SetMulticastToUnicast, UpdateConnectParams, SetPmk, DelPmk, PortAuthorized, ReloadRegdb, ExternalAuth, StaOpmodeChanged, ControlPortFrame, GetFtmResponderStats, PeerMeasurementStart, PeerMeasurementResult, PeerMeasurementComplete, NotifyRadar, UpdateOweInfo, ProbeMeshLink, SetTidConfig, UnprotBeacon, ControlPortFrameTxStatus, SetSarSpecs, ObssColorCollision, ColorChangeRequest, ColorChangeStarted, ColorChangeAborted, ColorChangeCompleted, SetFilsAad, AssocComeback, AddLink, RemoveLink, AddLinkSta, ModifyLinkSta, RemoveLinkSta, SetHwTimestamp, LinksRemoved, SetTidToLinkMapping, Other(u32), // Below are aliases NewBeacon, DelBeacon, RegisterAction, Action, ActionTxStatus, } impl From for Nl80211Command { fn from(d: u32) -> Self { match d { NL80211_CMD_GET_WIPHY => Self::GetWiphy, NL80211_CMD_SET_WIPHY => Self::SetWiphy, NL80211_CMD_NEW_WIPHY => Self::NewWiphy, NL80211_CMD_DEL_WIPHY => Self::DelWiphy, NL80211_CMD_GET_INTERFACE => Self::GetInterface, NL80211_CMD_SET_INTERFACE => Self::SetInterface, NL80211_CMD_NEW_INTERFACE => Self::NewInterface, NL80211_CMD_DEL_INTERFACE => Self::DelInterface, NL80211_CMD_GET_KEY => Self::GetKey, NL80211_CMD_SET_KEY => Self::SetKey, NL80211_CMD_NEW_KEY => Self::NewKey, NL80211_CMD_DEL_KEY => Self::DelKey, NL80211_CMD_GET_BEACON => Self::GetBeacon, NL80211_CMD_SET_BEACON => Self::SetBeacon, NL80211_CMD_START_AP => Self::StartAp, NL80211_CMD_STOP_AP => Self::StopAp, NL80211_CMD_GET_STATION => Self::GetStation, NL80211_CMD_SET_STATION => Self::SetStation, NL80211_CMD_NEW_STATION => Self::NewStation, NL80211_CMD_DEL_STATION => Self::DelStation, NL80211_CMD_GET_MPATH => Self::GetMpath, NL80211_CMD_SET_MPATH => Self::SetMpath, NL80211_CMD_NEW_MPATH => Self::NewMpath, NL80211_CMD_DEL_MPATH => Self::DelMpath, NL80211_CMD_SET_BSS => Self::SetBss, NL80211_CMD_SET_REG => Self::SetReg, NL80211_CMD_REQ_SET_REG => Self::ReqSetReg, NL80211_CMD_GET_MESH_CONFIG => Self::GetMeshConfig, NL80211_CMD_SET_MESH_CONFIG => Self::SetMeshConfig, NL80211_CMD_SET_MGMT_EXTRA_IE => Self::SetMgmtExtraIe, NL80211_CMD_GET_REG => Self::GetReg, NL80211_CMD_GET_SCAN => Self::GetScan, NL80211_CMD_TRIGGER_SCAN => Self::TriggerScan, NL80211_CMD_NEW_SCAN_RESULTS => Self::NewScanResults, NL80211_CMD_SCAN_ABORTED => Self::ScanAborted, NL80211_CMD_REG_CHANGE => Self::RegChange, NL80211_CMD_AUTHENTICATE => Self::Authenticate, NL80211_CMD_ASSOCIATE => Self::Associate, NL80211_CMD_DEAUTHENTICATE => Self::Deauthenticate, NL80211_CMD_DISASSOCIATE => Self::Disassociate, NL80211_CMD_MICHAEL_MIC_FAILURE => Self::MichaelMicFailure, NL80211_CMD_REG_BEACON_HINT => Self::RegBeaconHint, NL80211_CMD_JOIN_IBSS => Self::JoinIbss, NL80211_CMD_LEAVE_IBSS => Self::LeaveIbss, NL80211_CMD_TESTMODE => Self::Testmode, NL80211_CMD_CONNECT => Self::Connect, NL80211_CMD_ROAM => Self::Roam, NL80211_CMD_DISCONNECT => Self::Disconnect, NL80211_CMD_SET_WIPHY_NETNS => Self::SetWiphyNetns, NL80211_CMD_GET_SURVEY => Self::GetSurvey, NL80211_CMD_NEW_SURVEY_RESULTS => Self::NewSurveyResults, NL80211_CMD_SET_PMKSA => Self::SetPmksa, NL80211_CMD_DEL_PMKSA => Self::DelPmksa, NL80211_CMD_FLUSH_PMKSA => Self::FlushPmksa, NL80211_CMD_REMAIN_ON_CHANNEL => Self::RemainOnChannel, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL => Self::CancelRemainOnChannel, NL80211_CMD_SET_TX_BITRATE_MASK => Self::SetTxBitrateMask, NL80211_CMD_REGISTER_FRAME => Self::RegisterFrame, NL80211_CMD_FRAME => Self::Frame, NL80211_CMD_FRAME_TX_STATUS => Self::FrameTxStatus, NL80211_CMD_SET_POWER_SAVE => Self::SetPowerSave, NL80211_CMD_GET_POWER_SAVE => Self::GetPowerSave, NL80211_CMD_SET_CQM => Self::SetCqm, NL80211_CMD_NOTIFY_CQM => Self::NotifyCqm, NL80211_CMD_SET_CHANNEL => Self::SetChannel, NL80211_CMD_SET_WDS_PEER => Self::SetWdsPeer, NL80211_CMD_FRAME_WAIT_CANCEL => Self::FrameWaitCancel, NL80211_CMD_JOIN_MESH => Self::JoinMesh, NL80211_CMD_LEAVE_MESH => Self::LeaveMesh, NL80211_CMD_UNPROT_DEAUTHENTICATE => Self::UnprotDeauthenticate, NL80211_CMD_UNPROT_DISASSOCIATE => Self::UnprotDisassociate, NL80211_CMD_NEW_PEER_CANDIDATE => Self::NewPeerCandidate, NL80211_CMD_GET_WOWLAN => Self::GetWowlan, NL80211_CMD_SET_WOWLAN => Self::SetWowlan, NL80211_CMD_START_SCHED_SCAN => Self::StartSchedScan, NL80211_CMD_STOP_SCHED_SCAN => Self::StopSchedScan, NL80211_CMD_SCHED_SCAN_RESULTS => Self::SchedScanResults, NL80211_CMD_SCHED_SCAN_STOPPED => Self::SchedScanStopped, NL80211_CMD_SET_REKEY_OFFLOAD => Self::SetRekeyOffload, NL80211_CMD_PMKSA_CANDIDATE => Self::PmksaCandidate, NL80211_CMD_TDLS_OPER => Self::TdlsOper, NL80211_CMD_TDLS_MGMT => Self::TdlsMgmt, NL80211_CMD_UNEXPECTED_FRAME => Self::UnexpectedFrame, NL80211_CMD_PROBE_CLIENT => Self::ProbeClient, NL80211_CMD_REGISTER_BEACONS => Self::RegisterBeacons, NL80211_CMD_UNEXPECTED_4ADDR_FRAME => Self::Unexpected4addrFrame, NL80211_CMD_SET_NOACK_MAP => Self::SetNoackMap, NL80211_CMD_CH_SWITCH_NOTIFY => Self::ChSwitchNotify, NL80211_CMD_START_P2P_DEVICE => Self::StartP2PDevice, NL80211_CMD_STOP_P2P_DEVICE => Self::StopP2PDevice, NL80211_CMD_CONN_FAILED => Self::ConnFailed, NL80211_CMD_SET_MCAST_RATE => Self::SetMcastRate, NL80211_CMD_SET_MAC_ACL => Self::SetMacAcl, NL80211_CMD_RADAR_DETECT => Self::RadarDetect, NL80211_CMD_GET_PROTOCOL_FEATURES => Self::GetProtocolFeatures, NL80211_CMD_UPDATE_FT_IES => Self::UpdateFtIes, NL80211_CMD_FT_EVENT => Self::FtEvent, NL80211_CMD_CRIT_PROTOCOL_START => Self::CritProtocolStart, NL80211_CMD_CRIT_PROTOCOL_STOP => Self::CritProtocolStop, NL80211_CMD_GET_COALESCE => Self::GetCoalesce, NL80211_CMD_SET_COALESCE => Self::SetCoalesce, NL80211_CMD_CHANNEL_SWITCH => Self::ChannelSwitch, NL80211_CMD_VENDOR => Self::Vendor, NL80211_CMD_SET_QOS_MAP => Self::SetQosMap, NL80211_CMD_ADD_TX_TS => Self::AddTxTs, NL80211_CMD_DEL_TX_TS => Self::DelTxTs, NL80211_CMD_GET_MPP => Self::GetMpp, NL80211_CMD_JOIN_OCB => Self::JoinOcb, NL80211_CMD_LEAVE_OCB => Self::LeaveOcb, NL80211_CMD_CH_SWITCH_STARTED_NOTIFY => Self::ChSwitchStartedNotify, NL80211_CMD_TDLS_CHANNEL_SWITCH => Self::TdlsChannelSwitch, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH => { Self::TdlsCancelChannelSwitch } NL80211_CMD_WIPHY_REG_CHANGE => Self::WiphyRegChange, NL80211_CMD_ABORT_SCAN => Self::AbortScan, NL80211_CMD_START_NAN => Self::StartNan, NL80211_CMD_STOP_NAN => Self::StopNan, NL80211_CMD_ADD_NAN_FUNCTION => Self::AddNanFunction, NL80211_CMD_DEL_NAN_FUNCTION => Self::DelNanFunction, NL80211_CMD_CHANGE_NAN_CONFIG => Self::ChangeNanConfig, NL80211_CMD_NAN_MATCH => Self::NanMatch, NL80211_CMD_SET_MULTICAST_TO_UNICAST => Self::SetMulticastToUnicast, NL80211_CMD_UPDATE_CONNECT_PARAMS => Self::UpdateConnectParams, NL80211_CMD_SET_PMK => Self::SetPmk, NL80211_CMD_DEL_PMK => Self::DelPmk, NL80211_CMD_PORT_AUTHORIZED => Self::PortAuthorized, NL80211_CMD_RELOAD_REGDB => Self::ReloadRegdb, NL80211_CMD_EXTERNAL_AUTH => Self::ExternalAuth, NL80211_CMD_STA_OPMODE_CHANGED => Self::StaOpmodeChanged, NL80211_CMD_CONTROL_PORT_FRAME => Self::ControlPortFrame, NL80211_CMD_GET_FTM_RESPONDER_STATS => Self::GetFtmResponderStats, NL80211_CMD_PEER_MEASUREMENT_START => Self::PeerMeasurementStart, NL80211_CMD_PEER_MEASUREMENT_RESULT => Self::PeerMeasurementResult, NL80211_CMD_PEER_MEASUREMENT_COMPLETE => { Self::PeerMeasurementComplete } NL80211_CMD_NOTIFY_RADAR => Self::NotifyRadar, NL80211_CMD_UPDATE_OWE_INFO => Self::UpdateOweInfo, NL80211_CMD_PROBE_MESH_LINK => Self::ProbeMeshLink, NL80211_CMD_SET_TID_CONFIG => Self::SetTidConfig, NL80211_CMD_UNPROT_BEACON => Self::UnprotBeacon, NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS => { Self::ControlPortFrameTxStatus } NL80211_CMD_SET_SAR_SPECS => Self::SetSarSpecs, NL80211_CMD_OBSS_COLOR_COLLISION => Self::ObssColorCollision, NL80211_CMD_COLOR_CHANGE_REQUEST => Self::ColorChangeRequest, NL80211_CMD_COLOR_CHANGE_STARTED => Self::ColorChangeStarted, NL80211_CMD_COLOR_CHANGE_ABORTED => Self::ColorChangeAborted, NL80211_CMD_COLOR_CHANGE_COMPLETED => Self::ColorChangeCompleted, NL80211_CMD_SET_FILS_AAD => Self::SetFilsAad, NL80211_CMD_ASSOC_COMEBACK => Self::AssocComeback, NL80211_CMD_ADD_LINK => Self::AddLink, NL80211_CMD_REMOVE_LINK => Self::RemoveLink, NL80211_CMD_ADD_LINK_STA => Self::AddLinkSta, NL80211_CMD_MODIFY_LINK_STA => Self::ModifyLinkSta, NL80211_CMD_REMOVE_LINK_STA => Self::RemoveLinkSta, NL80211_CMD_SET_HW_TIMESTAMP => Self::SetHwTimestamp, NL80211_CMD_LINKS_REMOVED => Self::LinksRemoved, NL80211_CMD_SET_TID_TO_LINK_MAPPING => Self::SetTidToLinkMapping, _ => Self::Other(d), } } } impl From for u32 { fn from(v: Nl80211Command) -> u32 { match v { Nl80211Command::GetWiphy => NL80211_CMD_GET_WIPHY, Nl80211Command::SetWiphy => NL80211_CMD_SET_WIPHY, Nl80211Command::NewWiphy => NL80211_CMD_NEW_WIPHY, Nl80211Command::DelWiphy => NL80211_CMD_DEL_WIPHY, Nl80211Command::GetInterface => NL80211_CMD_GET_INTERFACE, Nl80211Command::SetInterface => NL80211_CMD_SET_INTERFACE, Nl80211Command::NewInterface => NL80211_CMD_NEW_INTERFACE, Nl80211Command::DelInterface => NL80211_CMD_DEL_INTERFACE, Nl80211Command::GetKey => NL80211_CMD_GET_KEY, Nl80211Command::SetKey => NL80211_CMD_SET_KEY, Nl80211Command::NewKey => NL80211_CMD_NEW_KEY, Nl80211Command::DelKey => NL80211_CMD_DEL_KEY, Nl80211Command::GetBeacon => NL80211_CMD_GET_BEACON, Nl80211Command::SetBeacon => NL80211_CMD_SET_BEACON, Nl80211Command::StartAp => NL80211_CMD_START_AP, Nl80211Command::StopAp => NL80211_CMD_STOP_AP, Nl80211Command::GetStation => NL80211_CMD_GET_STATION, Nl80211Command::SetStation => NL80211_CMD_SET_STATION, Nl80211Command::NewStation => NL80211_CMD_NEW_STATION, Nl80211Command::DelStation => NL80211_CMD_DEL_STATION, Nl80211Command::GetMpath => NL80211_CMD_GET_MPATH, Nl80211Command::SetMpath => NL80211_CMD_SET_MPATH, Nl80211Command::NewMpath => NL80211_CMD_NEW_MPATH, Nl80211Command::DelMpath => NL80211_CMD_DEL_MPATH, Nl80211Command::SetBss => NL80211_CMD_SET_BSS, Nl80211Command::SetReg => NL80211_CMD_SET_REG, Nl80211Command::ReqSetReg => NL80211_CMD_REQ_SET_REG, Nl80211Command::GetMeshConfig => NL80211_CMD_GET_MESH_CONFIG, Nl80211Command::SetMeshConfig => NL80211_CMD_SET_MESH_CONFIG, Nl80211Command::SetMgmtExtraIe => NL80211_CMD_SET_MGMT_EXTRA_IE, Nl80211Command::GetReg => NL80211_CMD_GET_REG, Nl80211Command::GetScan => NL80211_CMD_GET_SCAN, Nl80211Command::TriggerScan => NL80211_CMD_TRIGGER_SCAN, Nl80211Command::NewScanResults => NL80211_CMD_NEW_SCAN_RESULTS, Nl80211Command::ScanAborted => NL80211_CMD_SCAN_ABORTED, Nl80211Command::RegChange => NL80211_CMD_REG_CHANGE, Nl80211Command::Authenticate => NL80211_CMD_AUTHENTICATE, Nl80211Command::Associate => NL80211_CMD_ASSOCIATE, Nl80211Command::Deauthenticate => NL80211_CMD_DEAUTHENTICATE, Nl80211Command::Disassociate => NL80211_CMD_DISASSOCIATE, Nl80211Command::MichaelMicFailure => { NL80211_CMD_MICHAEL_MIC_FAILURE } Nl80211Command::RegBeaconHint => NL80211_CMD_REG_BEACON_HINT, Nl80211Command::JoinIbss => NL80211_CMD_JOIN_IBSS, Nl80211Command::LeaveIbss => NL80211_CMD_LEAVE_IBSS, Nl80211Command::Testmode => NL80211_CMD_TESTMODE, Nl80211Command::Connect => NL80211_CMD_CONNECT, Nl80211Command::Roam => NL80211_CMD_ROAM, Nl80211Command::Disconnect => NL80211_CMD_DISCONNECT, Nl80211Command::SetWiphyNetns => NL80211_CMD_SET_WIPHY_NETNS, Nl80211Command::GetSurvey => NL80211_CMD_GET_SURVEY, Nl80211Command::NewSurveyResults => NL80211_CMD_NEW_SURVEY_RESULTS, Nl80211Command::SetPmksa => NL80211_CMD_SET_PMKSA, Nl80211Command::DelPmksa => NL80211_CMD_DEL_PMKSA, Nl80211Command::FlushPmksa => NL80211_CMD_FLUSH_PMKSA, Nl80211Command::RemainOnChannel => NL80211_CMD_REMAIN_ON_CHANNEL, Nl80211Command::CancelRemainOnChannel => { NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL } Nl80211Command::SetTxBitrateMask => NL80211_CMD_SET_TX_BITRATE_MASK, Nl80211Command::RegisterFrame => NL80211_CMD_REGISTER_FRAME, Nl80211Command::Frame => NL80211_CMD_FRAME, Nl80211Command::FrameTxStatus => NL80211_CMD_FRAME_TX_STATUS, Nl80211Command::SetPowerSave => NL80211_CMD_SET_POWER_SAVE, Nl80211Command::GetPowerSave => NL80211_CMD_GET_POWER_SAVE, Nl80211Command::SetCqm => NL80211_CMD_SET_CQM, Nl80211Command::NotifyCqm => NL80211_CMD_NOTIFY_CQM, Nl80211Command::SetChannel => NL80211_CMD_SET_CHANNEL, Nl80211Command::SetWdsPeer => NL80211_CMD_SET_WDS_PEER, Nl80211Command::FrameWaitCancel => NL80211_CMD_FRAME_WAIT_CANCEL, Nl80211Command::JoinMesh => NL80211_CMD_JOIN_MESH, Nl80211Command::LeaveMesh => NL80211_CMD_LEAVE_MESH, Nl80211Command::UnprotDeauthenticate => { NL80211_CMD_UNPROT_DEAUTHENTICATE } Nl80211Command::UnprotDisassociate => { NL80211_CMD_UNPROT_DISASSOCIATE } Nl80211Command::NewPeerCandidate => NL80211_CMD_NEW_PEER_CANDIDATE, Nl80211Command::GetWowlan => NL80211_CMD_GET_WOWLAN, Nl80211Command::SetWowlan => NL80211_CMD_SET_WOWLAN, Nl80211Command::StartSchedScan => NL80211_CMD_START_SCHED_SCAN, Nl80211Command::StopSchedScan => NL80211_CMD_STOP_SCHED_SCAN, Nl80211Command::SchedScanResults => NL80211_CMD_SCHED_SCAN_RESULTS, Nl80211Command::SchedScanStopped => NL80211_CMD_SCHED_SCAN_STOPPED, Nl80211Command::SetRekeyOffload => NL80211_CMD_SET_REKEY_OFFLOAD, Nl80211Command::PmksaCandidate => NL80211_CMD_PMKSA_CANDIDATE, Nl80211Command::TdlsOper => NL80211_CMD_TDLS_OPER, Nl80211Command::TdlsMgmt => NL80211_CMD_TDLS_MGMT, Nl80211Command::UnexpectedFrame => NL80211_CMD_UNEXPECTED_FRAME, Nl80211Command::ProbeClient => NL80211_CMD_PROBE_CLIENT, Nl80211Command::RegisterBeacons => NL80211_CMD_REGISTER_BEACONS, Nl80211Command::Unexpected4addrFrame => { NL80211_CMD_UNEXPECTED_4ADDR_FRAME } Nl80211Command::SetNoackMap => NL80211_CMD_SET_NOACK_MAP, Nl80211Command::ChSwitchNotify => NL80211_CMD_CH_SWITCH_NOTIFY, Nl80211Command::StartP2PDevice => NL80211_CMD_START_P2P_DEVICE, Nl80211Command::StopP2PDevice => NL80211_CMD_STOP_P2P_DEVICE, Nl80211Command::ConnFailed => NL80211_CMD_CONN_FAILED, Nl80211Command::SetMcastRate => NL80211_CMD_SET_MCAST_RATE, Nl80211Command::SetMacAcl => NL80211_CMD_SET_MAC_ACL, Nl80211Command::RadarDetect => NL80211_CMD_RADAR_DETECT, Nl80211Command::GetProtocolFeatures => { NL80211_CMD_GET_PROTOCOL_FEATURES } Nl80211Command::UpdateFtIes => NL80211_CMD_UPDATE_FT_IES, Nl80211Command::FtEvent => NL80211_CMD_FT_EVENT, Nl80211Command::CritProtocolStart => { NL80211_CMD_CRIT_PROTOCOL_START } Nl80211Command::CritProtocolStop => NL80211_CMD_CRIT_PROTOCOL_STOP, Nl80211Command::GetCoalesce => NL80211_CMD_GET_COALESCE, Nl80211Command::SetCoalesce => NL80211_CMD_SET_COALESCE, Nl80211Command::ChannelSwitch => NL80211_CMD_CHANNEL_SWITCH, Nl80211Command::Vendor => NL80211_CMD_VENDOR, Nl80211Command::SetQosMap => NL80211_CMD_SET_QOS_MAP, Nl80211Command::AddTxTs => NL80211_CMD_ADD_TX_TS, Nl80211Command::DelTxTs => NL80211_CMD_DEL_TX_TS, Nl80211Command::GetMpp => NL80211_CMD_GET_MPP, Nl80211Command::JoinOcb => NL80211_CMD_JOIN_OCB, Nl80211Command::LeaveOcb => NL80211_CMD_LEAVE_OCB, Nl80211Command::ChSwitchStartedNotify => { NL80211_CMD_CH_SWITCH_STARTED_NOTIFY } Nl80211Command::TdlsChannelSwitch => { NL80211_CMD_TDLS_CHANNEL_SWITCH } Nl80211Command::TdlsCancelChannelSwitch => { NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH } Nl80211Command::WiphyRegChange => NL80211_CMD_WIPHY_REG_CHANGE, Nl80211Command::AbortScan => NL80211_CMD_ABORT_SCAN, Nl80211Command::StartNan => NL80211_CMD_START_NAN, Nl80211Command::StopNan => NL80211_CMD_STOP_NAN, Nl80211Command::AddNanFunction => NL80211_CMD_ADD_NAN_FUNCTION, Nl80211Command::DelNanFunction => NL80211_CMD_DEL_NAN_FUNCTION, Nl80211Command::ChangeNanConfig => NL80211_CMD_CHANGE_NAN_CONFIG, Nl80211Command::NanMatch => NL80211_CMD_NAN_MATCH, Nl80211Command::SetMulticastToUnicast => { NL80211_CMD_SET_MULTICAST_TO_UNICAST } Nl80211Command::UpdateConnectParams => { NL80211_CMD_UPDATE_CONNECT_PARAMS } Nl80211Command::SetPmk => NL80211_CMD_SET_PMK, Nl80211Command::DelPmk => NL80211_CMD_DEL_PMK, Nl80211Command::PortAuthorized => NL80211_CMD_PORT_AUTHORIZED, Nl80211Command::ReloadRegdb => NL80211_CMD_RELOAD_REGDB, Nl80211Command::ExternalAuth => NL80211_CMD_EXTERNAL_AUTH, Nl80211Command::StaOpmodeChanged => NL80211_CMD_STA_OPMODE_CHANGED, Nl80211Command::ControlPortFrame => NL80211_CMD_CONTROL_PORT_FRAME, Nl80211Command::GetFtmResponderStats => { NL80211_CMD_GET_FTM_RESPONDER_STATS } Nl80211Command::PeerMeasurementStart => { NL80211_CMD_PEER_MEASUREMENT_START } Nl80211Command::PeerMeasurementResult => { NL80211_CMD_PEER_MEASUREMENT_RESULT } Nl80211Command::PeerMeasurementComplete => { NL80211_CMD_PEER_MEASUREMENT_COMPLETE } Nl80211Command::NotifyRadar => NL80211_CMD_NOTIFY_RADAR, Nl80211Command::UpdateOweInfo => NL80211_CMD_UPDATE_OWE_INFO, Nl80211Command::ProbeMeshLink => NL80211_CMD_PROBE_MESH_LINK, Nl80211Command::SetTidConfig => NL80211_CMD_SET_TID_CONFIG, Nl80211Command::UnprotBeacon => NL80211_CMD_UNPROT_BEACON, Nl80211Command::ControlPortFrameTxStatus => { NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS } Nl80211Command::SetSarSpecs => NL80211_CMD_SET_SAR_SPECS, Nl80211Command::ObssColorCollision => { NL80211_CMD_OBSS_COLOR_COLLISION } Nl80211Command::ColorChangeRequest => { NL80211_CMD_COLOR_CHANGE_REQUEST } Nl80211Command::ColorChangeStarted => { NL80211_CMD_COLOR_CHANGE_STARTED } Nl80211Command::ColorChangeAborted => { NL80211_CMD_COLOR_CHANGE_ABORTED } Nl80211Command::ColorChangeCompleted => { NL80211_CMD_COLOR_CHANGE_COMPLETED } Nl80211Command::SetFilsAad => NL80211_CMD_SET_FILS_AAD, Nl80211Command::AssocComeback => NL80211_CMD_ASSOC_COMEBACK, Nl80211Command::AddLink => NL80211_CMD_ADD_LINK, Nl80211Command::RemoveLink => NL80211_CMD_REMOVE_LINK, Nl80211Command::AddLinkSta => NL80211_CMD_ADD_LINK_STA, Nl80211Command::ModifyLinkSta => NL80211_CMD_MODIFY_LINK_STA, Nl80211Command::RemoveLinkSta => NL80211_CMD_REMOVE_LINK_STA, Nl80211Command::SetHwTimestamp => NL80211_CMD_SET_HW_TIMESTAMP, Nl80211Command::LinksRemoved => NL80211_CMD_LINKS_REMOVED, Nl80211Command::SetTidToLinkMapping => { NL80211_CMD_SET_TID_TO_LINK_MAPPING } Nl80211Command::Other(d) => d, Nl80211Command::NewBeacon => NL80211_CMD_NEW_BEACON, Nl80211Command::DelBeacon => NL80211_CMD_DEL_BEACON, Nl80211Command::RegisterAction => NL80211_CMD_REGISTER_ACTION, Nl80211Command::Action => NL80211_CMD_ACTION, Nl80211Command::ActionTxStatus => NL80211_CMD_ACTION_TX_STATUS, } } } wl-nl80211-0.2.0/src/wiphy/get.rs000064400000000000000000000012531046102023000143250ustar 00000000000000// SPDX-License-Identifier: MIT use futures::TryStream; use netlink_packet_generic::GenlMessage; use crate::{nl80211_execute, Nl80211Error, Nl80211Handle, Nl80211Message}; pub struct Nl80211WiphyGetRequest { handle: Nl80211Handle, } impl Nl80211WiphyGetRequest { pub(crate) fn new(handle: Nl80211Handle) -> Self { Nl80211WiphyGetRequest { handle } } pub async fn execute( self, ) -> impl TryStream, Error = Nl80211Error> { let Nl80211WiphyGetRequest { mut handle } = self; let nl80211_msg = Nl80211Message::new_wiphy_get(); nl80211_execute(&mut handle, nl80211_msg).await } } wl-nl80211-0.2.0/src/wiphy/handle.rs000064400000000000000000000007061046102023000150030ustar 00000000000000// SPDX-License-Identifier: MIT use crate::{Nl80211Handle, Nl80211WiphyGetRequest}; #[derive(Debug)] pub struct Nl80211WiphyHandle(Nl80211Handle); impl Nl80211WiphyHandle { pub fn new(handle: Nl80211Handle) -> Self { Nl80211WiphyHandle(handle) } /// Retrieve the wireless interfaces /// (equivalent to `iw phy`) pub fn get(&mut self) -> Nl80211WiphyGetRequest { Nl80211WiphyGetRequest::new(self.0.clone()) } } wl-nl80211-0.2.0/src/wiphy/ifmode.rs000064400000000000000000000067661046102023000150270ustar 00000000000000// SPDX-License-Identifier: MIT use netlink_packet_utils::{ nla::{Nla, NlaBuffer}, DecodeError, Parseable, }; const NL80211_IFTYPE_ADHOC: u16 = 1; const NL80211_IFTYPE_STATION: u16 = 2; const NL80211_IFTYPE_AP: u16 = 3; const NL80211_IFTYPE_AP_VLAN: u16 = 4; const NL80211_IFTYPE_WDS: u16 = 5; const NL80211_IFTYPE_MONITOR: u16 = 6; const NL80211_IFTYPE_MESH_POINT: u16 = 7; const NL80211_IFTYPE_P2P_CLIENT: u16 = 8; const NL80211_IFTYPE_P2P_GO: u16 = 9; const NL80211_IFTYPE_P2P_DEVICE: u16 = 10; const NL80211_IFTYPE_OCB: u16 = 11; const NL80211_IFTYPE_NAN: u16 = 12; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Nl80211IfMode { Adhoc, Station, Ap, ApVlan, Wds, Monitor, MeshPoint, P2pClient, P2pGo, P2pDevice, Ocb, Nan, Other(u16), } impl From for Nl80211IfMode { fn from(d: u16) -> Self { match d { NL80211_IFTYPE_ADHOC => Self::Adhoc, NL80211_IFTYPE_STATION => Self::Station, NL80211_IFTYPE_AP => Self::Ap, NL80211_IFTYPE_AP_VLAN => Self::ApVlan, NL80211_IFTYPE_WDS => Self::Wds, NL80211_IFTYPE_MONITOR => Self::Monitor, NL80211_IFTYPE_MESH_POINT => Self::MeshPoint, NL80211_IFTYPE_P2P_CLIENT => Self::P2pClient, NL80211_IFTYPE_P2P_GO => Self::P2pGo, NL80211_IFTYPE_P2P_DEVICE => Self::P2pDevice, NL80211_IFTYPE_OCB => Self::Ocb, NL80211_IFTYPE_NAN => Self::Nan, _ => Self::Other(d), } } } impl From for u16 { fn from(v: Nl80211IfMode) -> u16 { match v { Nl80211IfMode::Adhoc => NL80211_IFTYPE_ADHOC, Nl80211IfMode::Station => NL80211_IFTYPE_STATION, Nl80211IfMode::Ap => NL80211_IFTYPE_AP, Nl80211IfMode::ApVlan => NL80211_IFTYPE_AP_VLAN, Nl80211IfMode::Wds => NL80211_IFTYPE_WDS, Nl80211IfMode::Monitor => NL80211_IFTYPE_MONITOR, Nl80211IfMode::MeshPoint => NL80211_IFTYPE_MESH_POINT, Nl80211IfMode::P2pClient => NL80211_IFTYPE_P2P_CLIENT, Nl80211IfMode::P2pGo => NL80211_IFTYPE_P2P_GO, Nl80211IfMode::P2pDevice => NL80211_IFTYPE_P2P_DEVICE, Nl80211IfMode::Ocb => NL80211_IFTYPE_OCB, Nl80211IfMode::Nan => NL80211_IFTYPE_NAN, Nl80211IfMode::Other(d) => d, } } } impl Nla for Nl80211IfMode { fn value_len(&self) -> usize { 0 } fn kind(&self) -> u16 { match self { Nl80211IfMode::Adhoc => NL80211_IFTYPE_ADHOC, Nl80211IfMode::Station => NL80211_IFTYPE_STATION, Nl80211IfMode::Ap => NL80211_IFTYPE_AP, Nl80211IfMode::ApVlan => NL80211_IFTYPE_AP_VLAN, Nl80211IfMode::Wds => NL80211_IFTYPE_WDS, Nl80211IfMode::Monitor => NL80211_IFTYPE_MONITOR, Nl80211IfMode::MeshPoint => NL80211_IFTYPE_MESH_POINT, Nl80211IfMode::P2pClient => NL80211_IFTYPE_P2P_CLIENT, Nl80211IfMode::P2pGo => NL80211_IFTYPE_P2P_GO, Nl80211IfMode::P2pDevice => NL80211_IFTYPE_P2P_DEVICE, Nl80211IfMode::Ocb => NL80211_IFTYPE_OCB, Nl80211IfMode::Nan => NL80211_IFTYPE_NAN, Nl80211IfMode::Other(d) => *d, } } fn emit_value(&self, _buffer: &mut [u8]) {} } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211IfMode { fn parse(buf: &NlaBuffer<&'a T>) -> Result { Ok(buf.kind().into()) } } wl-nl80211-0.2.0/src/wiphy/mod.rs000064400000000000000000000011701046102023000143230ustar 00000000000000// SPDX-License-Identifier: MIT mod band; mod cipher; mod command; mod get; mod handle; mod ifmode; mod wowlan; pub use self::band::{ Nl80211Band, Nl80211BandInfo, Nl80211BandType, Nl80211BandTypes, Nl80211Frequency, Nl80211FrequencyInfo, }; pub use self::cipher::Nl80211CipherSuit; pub use self::command::Nl80211Command; pub use self::get::Nl80211WiphyGetRequest; pub use self::handle::Nl80211WiphyHandle; pub use self::ifmode::Nl80211IfMode; pub use self::wowlan::{ Nl80211WowlanTcpTrigerSupport, Nl80211WowlanTrigerPatternSupport, Nl80211WowlanTrigersSupport, }; pub(crate) use self::command::Nl80211Commands; wl-nl80211-0.2.0/src/wiphy/wowlan.rs000064400000000000000000000333511046102023000150610ustar 00000000000000// SPDX-License-Identifier: MIT // Most documentation comments are copied and modified from linux kernel // include/uapi/linux/nl80211.h which is holding these license disclaimer: /* * 802.11 netlink interface public header * * Copyright 2006-2010 Johannes Berg * Copyright 2008 Michael Wu * Copyright 2008 Luis Carlos Cobo * Copyright 2008 Michael Buesch * Copyright 2008, 2009 Luis R. Rodriguez * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH * Copyright (C) 2018-2024 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::parse_u32, DecodeError, Emitable, Parseable, }; use crate::bytes::write_u32; const NL80211_WOWLAN_TRIG_ANY: u16 = 1; const NL80211_WOWLAN_TRIG_DISCONNECT: u16 = 2; const NL80211_WOWLAN_TRIG_MAGIC_PKT: u16 = 3; const NL80211_WOWLAN_TRIG_PKT_PATTERN: u16 = 4; const NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: u16 = 5; const NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: u16 = 6; const NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: u16 = 7; const NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: u16 = 8; const NL80211_WOWLAN_TRIG_RFKILL_RELEASE: u16 = 9; // const NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: u16 = 10; // const NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: u16 = 11; // const NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: u16 = 12; // const NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: u16 = 13; const NL80211_WOWLAN_TRIG_TCP_CONNECTION: u16 = 14; // const NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH: u16 = 15; // const NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: u16 = 16; // const NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: u16 = 17; const NL80211_WOWLAN_TRIG_NET_DETECT: u16 = 18; // const NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: u16 = 19; // const NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC: u16 = 20; /// Supported WoWLAN trigger #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211WowlanTrigersSupport { /// Wake up on any activity, do not really put the chip into a special /// state -- works best with chips that have support for low-power /// operation already. /// Note that this mode is incompatible with all of the others, if /// any others are even supported by the device. Any, /// Wake up on disconnect, the way disconnect is detected is /// implementation-specific. Disconnect, /// Wake up on magic packet (6x 0xff, followed by 16 repetitions of MAC /// addr, anywhere in payload). MagicPkt, /// Wake up on the specified packet patterns. /// The matching is done on the MSDU, i.e. as though the packet was an /// 802.3 packet, so the pattern matching is done after the packet is /// converted to the MSDU. PktPattern(Nl80211WowlanTrigerPatternSupport), /// Not a real trigger, and cannot be used when setting, used only to /// indicate that GTK rekeying is supported by the device. GtkRekeySupported, /// wake up on GTK rekey failure (if done by the device). GtkRekeyFailure, /// wake up on EAP Identity Request packet. EapIdentRequest, /// wake up on 4-way handshake. FourWayHandshake, /// wake up when rfkill is released (on devices that have rfkill in the /// device). RfkillRelease, /// The number of match sets supported by driver for waking up when a /// configured network is detected. NetDetect(u32), /// TCP connection wake. TcpConnection(Vec), Other(DefaultNla), } impl Nla for Nl80211WowlanTrigersSupport { fn value_len(&self) -> usize { match self { Self::Any | Self::Disconnect | Self::MagicPkt | Self::GtkRekeySupported | Self::GtkRekeyFailure | Self::EapIdentRequest | Self::FourWayHandshake | Self::RfkillRelease => 0, Self::PktPattern(_) => Nl80211WowlanTrigerPatternSupport::LENGTH, Self::NetDetect(_) => 4, Self::TcpConnection(s) => s.as_slice().buffer_len(), Self::Other(attr) => attr.value_len(), } } fn kind(&self) -> u16 { match self { Self::Any => NL80211_WOWLAN_TRIG_ANY, Self::Disconnect => NL80211_WOWLAN_TRIG_DISCONNECT, Self::MagicPkt => NL80211_WOWLAN_TRIG_MAGIC_PKT, Self::GtkRekeySupported => NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED, Self::GtkRekeyFailure => NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE, Self::EapIdentRequest => NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST, Self::FourWayHandshake => NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE, Self::RfkillRelease => NL80211_WOWLAN_TRIG_RFKILL_RELEASE, Self::PktPattern(_) => NL80211_WOWLAN_TRIG_PKT_PATTERN, Self::NetDetect(_) => NL80211_WOWLAN_TRIG_NET_DETECT, Self::TcpConnection(_) => NL80211_WOWLAN_TRIG_TCP_CONNECTION, Self::Other(attr) => attr.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::Any | Self::Disconnect | Self::MagicPkt | Self::GtkRekeySupported | Self::GtkRekeyFailure | Self::EapIdentRequest | Self::FourWayHandshake | Self::RfkillRelease => (), Self::PktPattern(s) => s.emit(buffer), Self::NetDetect(d) => write_u32(buffer, *d), Self::TcpConnection(s) => s.as_slice().emit(buffer), Self::Other(attr) => attr.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211WowlanTrigersSupport { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_WOWLAN_TRIG_ANY => Self::Any, NL80211_WOWLAN_TRIG_DISCONNECT => Self::Disconnect, NL80211_WOWLAN_TRIG_MAGIC_PKT => Self::MagicPkt, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED => Self::GtkRekeySupported, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE => Self::GtkRekeyFailure, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST => Self::EapIdentRequest, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE => Self::FourWayHandshake, NL80211_WOWLAN_TRIG_RFKILL_RELEASE => Self::RfkillRelease, NL80211_WOWLAN_TRIG_PKT_PATTERN => Self::PktPattern( Nl80211WowlanTrigerPatternSupport::parse(payload)?, ), NL80211_WOWLAN_TRIG_NET_DETECT => { Self::NetDetect(parse_u32(payload).context(format!( "Invalid NL80211_WOWLAN_TRIG_NET_DETECT \ {payload:?}" ))?) } NL80211_WOWLAN_TRIG_TCP_CONNECTION => { let mut nlas = Vec::new(); for nla in NlasIterator::new(payload) { let err_msg = format!( "Invalid NL80211_WOWLAN_TRIG_TCP_CONNECTION value {:?}", nla ); let nla = &nla.context(err_msg.clone())?; nlas.push(Nl80211WowlanTcpTrigerSupport::parse(nla)?); } Self::TcpConnection(nlas) } _ => Self::Other(DefaultNla::parse(buf).context( "invalid NLA for NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED ", )?), }) } } /// Support status of WoWLAN trigger pattern #[derive(Debug, PartialEq, Eq, Clone)] pub struct Nl80211WowlanTrigerPatternSupport { pub max_patterns: u32, pub min_pattern_len: u32, pub max_pattern_len: u32, pub max_pkt_offset: u32, } impl Nl80211WowlanTrigerPatternSupport { const LENGTH: usize = 16; pub fn parse(payload: &[u8]) -> Result { if payload.len() < Self::LENGTH { Err(format!( "Invalid NL80211_WOWLAN_TRIG_PKT_PATTERN \ for support query, expecting length {} but got {}: \ {payload:?}", Self::LENGTH, payload.len() ) .into()) } else { Ok(Self { max_patterns: parse_u32(&payload[..4])?, min_pattern_len: parse_u32(&payload[4..8])?, max_pattern_len: parse_u32(&payload[8..12])?, max_pkt_offset: parse_u32(&payload[12..16])?, }) } } } impl Emitable for Nl80211WowlanTrigerPatternSupport { fn buffer_len(&self) -> usize { Self::LENGTH } fn emit(&self, buffer: &mut [u8]) { write_u32(&mut buffer[0..4], self.max_patterns); write_u32(&mut buffer[4..8], self.min_pattern_len); write_u32(&mut buffer[8..12], self.max_pattern_len); write_u32(&mut buffer[12..16], self.max_pkt_offset); } } const NL80211_WOWLAN_TCP_SRC_IPV4: u16 = 1; const NL80211_WOWLAN_TCP_DST_IPV4: u16 = 2; const NL80211_WOWLAN_TCP_DST_MAC: u16 = 3; const NL80211_WOWLAN_TCP_SRC_PORT: u16 = 4; const NL80211_WOWLAN_TCP_DST_PORT: u16 = 5; const NL80211_WOWLAN_TCP_DATA_PAYLOAD: u16 = 6; const NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: u16 = 7; const NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: u16 = 8; const NL80211_WOWLAN_TCP_DATA_INTERVAL: u16 = 9; const NL80211_WOWLAN_TCP_WAKE_PAYLOAD: u16 = 10; const NL80211_WOWLAN_TCP_WAKE_MASK: u16 = 11; /// Supported WoWLAN TCP connection trigger #[derive(Debug, PartialEq, Eq, Clone)] pub enum Nl80211WowlanTcpTrigerSupport { SrcIpv4, DstIpv4, DstMac, SrcPort, DstPort, DataPayload(u32), DataPayloadSeq, DataPayloadToken, DataInterval(u32), WakePayload(u32), WakeMask, Other(DefaultNla), } impl Nla for Nl80211WowlanTcpTrigerSupport { fn value_len(&self) -> usize { match self { Self::SrcIpv4 | Self::DstIpv4 | Self::DstMac | Self::SrcPort | Self::DstPort | Self::DataPayloadSeq | Self::DataPayloadToken | Self::WakeMask => 0, Self::DataPayload(_) | Self::DataInterval(_) | Self::WakePayload(_) => 4, Self::Other(v) => v.value_len(), } } fn kind(&self) -> u16 { match self { Self::SrcIpv4 => NL80211_WOWLAN_TCP_SRC_IPV4, Self::DstIpv4 => NL80211_WOWLAN_TCP_DST_IPV4, Self::DstMac => NL80211_WOWLAN_TCP_DST_MAC, Self::SrcPort => NL80211_WOWLAN_TCP_SRC_PORT, Self::DstPort => NL80211_WOWLAN_TCP_DST_PORT, Self::DataPayload(_) => NL80211_WOWLAN_TCP_DATA_PAYLOAD, Self::DataPayloadSeq => NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, Self::DataPayloadToken => NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, Self::DataInterval(_) => NL80211_WOWLAN_TCP_DATA_INTERVAL, Self::WakePayload(_) => NL80211_WOWLAN_TCP_WAKE_PAYLOAD, Self::WakeMask => NL80211_WOWLAN_TCP_WAKE_MASK, Self::Other(v) => v.kind(), } } fn emit_value(&self, buffer: &mut [u8]) { match self { Self::SrcIpv4 | Self::DstIpv4 | Self::DstMac | Self::SrcPort | Self::DstPort | Self::DataPayloadSeq | Self::DataPayloadToken | Self::WakeMask => (), Self::DataPayload(d) | Self::DataInterval(d) | Self::WakePayload(d) => write_u32(buffer, *d), Self::Other(v) => v.emit(buffer), } } } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Nl80211WowlanTcpTrigerSupport { fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NL80211_WOWLAN_TCP_SRC_IPV4 => Self::SrcIpv4, NL80211_WOWLAN_TCP_DST_IPV4 => Self::DstIpv4, NL80211_WOWLAN_TCP_DST_MAC => Self::DstMac, NL80211_WOWLAN_TCP_SRC_PORT => Self::SrcPort, NL80211_WOWLAN_TCP_DST_PORT => Self::DstPort, NL80211_WOWLAN_TCP_DATA_PAYLOAD => { Self::DataPayload(parse_u32(payload).context(format!( "Invalid NL80211_WOWLAN_TCP_DATA_PAYLOAD {payload:?}" ))?) } NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ => Self::DataPayloadSeq, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN => Self::DataPayloadToken, NL80211_WOWLAN_TCP_DATA_INTERVAL => { Self::DataInterval(parse_u32(payload).context(format!( "Invalid NL80211_WOWLAN_TCP_DATA_INTERVAL {payload:?}" ))?) } NL80211_WOWLAN_TCP_WAKE_PAYLOAD => { Self::WakePayload(parse_u32(payload).context(format!( "Invalid NL80211_WOWLAN_TCP_WAKE_PAYLOAD {payload:?}" ))?) } NL80211_WOWLAN_TCP_WAKE_MASK => Self::WakeMask, _ => Self::Other( DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, ), }) } } wl-nl80211-0.2.0/tools/make_release.sh000075500000000000000000000044021046102023000153640ustar 00000000000000#!/bin/bash -ex # SPDX-License-Identifier: MIT MAIN_BRANCH_NAME="main" UPSTERAM_GIT="https://github.com/rust-netlink/wl-nl80211.git" TMP_CHANGELOG_FILE=$(mktemp) EDITOR="${EDITOR:-vim}" if ! command -v jq &> /dev/null then echo "Please install jq to proceed" exit 1 fi if ! command -v cargo set-version &> /dev/null then echo 'Please install cargo-edit via `cargo install cargo-edit` to proceed' exit 1 fi CHANGLOG_FORMAT=" ### Breaking changes\n\ - N/A\n\ \n\ ### New features\n\ - N/A\n\ \n\ ### Bug fixes" function cleanup { rm -f $TMP_CHANGELOG_FILE } trap cleanup ERR EXIT CODE_BASE_DIR=$(readlink -f "$(dirname -- "$0")/.."); cd $CODE_BASE_DIR; CUR_VERSION=$(cargo metadata --no-deps --format-version 1 | \ jq '.packages[0].version' --raw-output) CUR_MAJOR_VERSION=$(echo $CUR_VERSION|cut -f1 -d.) CUR_MINOR_VERSION=$(echo $CUR_VERSION|cut -f2 -d.) CUR_MICRO_VERSION=$(echo $CUR_VERSION|cut -f3 -d.) # TODO: Be smart on bumping major, micro or minor version by checking API # stability NEXT_VERSION="${CUR_MAJOR_VERSION}.$((CUR_MINOR_VERSION + 1)).0"; git branch new_release || true git checkout new_release git fetch upstream || (git remote add upstream $UPSTERAM_GIT; \ git fetch upstream) git reset --hard upstream/$MAIN_BRANCH_NAME echo "Checking 'cargo publish --dry-run'" cargo set-version $NEXT_VERSION cargo publish --dry-run --allow-dirty echo "# Changelog" > $TMP_CHANGELOG_FILE echo "## [$NEXT_VERSION] - $(date +%F)" >> $TMP_CHANGELOG_FILE echo -e $CHANGLOG_FORMAT >> $TMP_CHANGELOG_FILE git log --oneline --format=" - %s. (%h)" \ v${CUR_VERSION}..upstream/$MAIN_BRANCH_NAME -- | \ grep -v -E '^ - test:' | \ grep -v -E '^ - Bump version' | \ grep -v -E 'cargo clippy' >> $TMP_CHANGELOG_FILE echo "" >> $TMP_CHANGELOG_FILE $EDITOR $TMP_CHANGELOG_FILE if [ $(wc -l < $TMP_CHANGELOG_FILE) -lt 2 ];then echo "No CHANGELOG addition, exiting" git checkout CHANGELOG exit 1 fi CHANGELOG_STR=$(sed -n '3,$p' $TMP_CHANGELOG_FILE|tr '#' '=') sed -n '2,$p' CHANGELOG >> $TMP_CHANGELOG_FILE mv $TMP_CHANGELOG_FILE $CODE_BASE_DIR/CHANGELOG git commit --signoff -a -m "New release ${NEXT_VERSION}" \ -m "$CHANGELOG_STR" git push origin +new_release echo "Please visit github to create pull request for this breach"