[
  {
    "path": ".github/workflows/clippy-rustfmt.yml",
    "content": "name: Rustfmt and clippy check\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n  push:\n    branches:\n      - master\n\njobs:\n  rustfmt_clippy:\n    strategy:\n      fail-fast: true\n\n    name: Rustfmt and clippy check\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Install Rust Nightly\n        uses: actions-rs/toolchain@v1\n        with:\n            toolchain: nightly\n            override: true\n            components: rustfmt, clippy\n\n      - name: rustfmt\n        run: cargo fmt --all -- --check\n\n      - name: clippy-tokio-socket\n        run: cargo clippy --workspace\n\n      - name: clippy-smol-socket\n        run: cargo clippy --no-default-features --features smol_socket --workspace\n"
  },
  {
    "path": ".github/workflows/license.yml",
    "content": "name: license\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n  push:\n    branches:\n      - master\n\njobs:\n  check-license:\n    name: Check License\n    runs-on: ubuntu-latest\n    timeout-minutes: 3\n\n    steps:\n      - uses: actions/checkout@v3\n      - name: Check License Header\n        uses: apache/skywalking-eyes@v0.3.0\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n  push:\n    branches:\n      - master\n\njobs:\n  ci:\n    name: CI (stable)\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Install Rust Stable\n        uses: actions-rs/toolchain@v1\n        with:\n            toolchain: stable\n            override: true\n\n      - name: test (netlink-sys)\n        run: |\n          cargo test -p netlink-sys\n          cargo test -p netlink-sys --features tokio_socket\n\n      - name: test (netlink-packet-audit)\n        run: cargo test -p netlink-packet-audit\n\n      - name: test (netlink-packet-core)\n        run: cargo test -p netlink-packet-core\n\n      - name: test (netlink-packet-generic)\n        run: cargo test -p netlink-packet-generic\n\n      - name: test (netlink-packet-netfilter)\n        run: cargo test -p netlink-packet-netfilter\n\n      - name: test (netlink-packet-route)\n        run: |\n          cargo test -p netlink-packet-route\n          cargo test -p netlink-packet-route --features rich_nlas\n\n      - name: test (netlink-packet-sock-diag)\n        run: cargo test -p netlink-packet-sock-diag\n\n      - name: test (netlink-packet-utils)\n        run: cargo test -p netlink-packet-utils\n\n      - name: test (netlink-packet-wireguard)\n        run: cargo test -p netlink-packet-wireguard\n\n      - name: test (netlink-proto)\n        run: cargo test -p netlink-proto\n\n      - name: test (rtnetlink)\n        env:\n          # Needed for the `link::test::create_get_delete_w` test to pass.\n          CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER: \"sudo -E\"\n        run: cargo test -p rtnetlink\n\n      - name: test (audit)\n        run: cargo test -p audit\n\n      - name: test (genetlink)\n        run: cargo test -p genetlink --features tokio_socket\n\n      - name: test (ethtool)\n        run: cargo test -p ethtool\n\n      - name: test (mptcp-pm)\n        env:\n          # Needed root permission to modify MPTCP\n          CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER: \"sudo -E\"\n        run: cargo test -p mptcp-pm\n"
  },
  {
    "path": ".gitignore",
    "content": "**/target\n**/*.rs.bk\nCargo.lock\n.idea"
  },
  {
    "path": ".licenserc.yaml",
    "content": "header:\n  license:\n    content: |\n      SPDX-License-Identifier: MIT\n  paths-ignore:\n    - 'target'\n    - '**/*.toml'\n    - '**/*.lock'\n    - '**/*.yml'\n    - '**/*.md'\n    - 'CHANGELOG'\n    - 'LICENSE-MIT'\n    - '.gitignore'\n\n  comment: on-failure\n"
  },
  {
    "path": "CHANGELOG",
    "content": "# Changelog\n## On-going\n### Versioning\n### Breaking Changes\n### New Features\n### Bug fixes\n\n## [20220715] 2022-07-15\n### Versioning\n * rtnetlink 0.10.1 -> 0.11.0\n * netlink-packet-route 0.12.0 -> 0.13.0\n\n### Breaking Changes\n * netlink-packet-route: `rtnl::link::nlas::InfoData::Bond` changed from\n   `Vec<u8>` to `Vec<InfoBond>`. (99b5765)\n\n### New Features\n * Add support bond. (99b5765)\n\n### Bug fixes\n * Fix the flag of link deletion. (9dccf92)\n\n## [20220624] 2022-06-24\n### Versioning\n * audit 0.7.0 -> 0.7.1\n * ethtool 0.2.2 -> 0.2.3\n * genetlink 0.2.2 -> 0.2.3\n * mptcp-pm 0.1.0 -> 0.1.1\n * netlink-packet-audit 0.4.1 -> 0.4.2\n * netlink-packet-wireguard 0.2.1 -> 0.2.2\n * rtnetlink 0.10.0 -> 0.10.1\n\n### Breaking Changes\n * netlink-proto: removed `netlink-proto::ErrorKind`. (3d799df)\n\n### New Features\n * N/A\n\n### Bug fixes\n * N/A\n\n## [20220623] 2022-06-23\n### Versioning\n * audit 0.6.0 -> 0.7.0\n * genetlink 0.2.1 -> 0.2.2\n * mptcp-pm NULL -> 0.1.0\n * netlink-packet-generic 0.2.0 -> 0.3.1\n * netlink-packet-audit 0.4.0 -> 0.4.1\n * netlink-packet-route 0.11.0 -> 0.12.0\n * netlink-proto 0.9.2 -> 0.9.3\n * netlink-sys 0.8.2 -> 0.8.3\n * rtnetlink 0.9.1 -> 0.10.0\n\n### Breaking Changes\n * audit: removed `audit::proto::ErrorKind`. (3d799df)\n * netlink-packet-route: changed from `AfSpecBridge::VlanInfo(Vec<u8>)` to\n   `AfSpecBridge::VlanInfo(BridgeVlanInfo)`. (f21ddb2)\n * netlink-packet-route: changed from `Nla::AfSpecBridge(Vec<u8>)` to\n   `Nla::AfSpecBridge(Vec<AfSpecBridge>)`. (f21ddb2)\n * netlink-packet-route: removed `InfoBridge::Flags` and `InfoBridge::VlanInfo`\n   as they should in `Nla::AfSpecBridge`. (b688737)\n * netlink-packet-route: changed `NextHop.gateway` to\n   `NextHop.nlas`. (f6b3b9a)\n * rtnetlink: Removed `rtnetlink::proto::ErrorKind`. (3d799df)\n\n### New Features\n * New crate mptcp-pm for MPTCP path manager. (1903b39)\n * netlink-packet-route: Add tc filter support. (2c41fb0)\n * netlink-packet-route: Add tc qdisc support. (921a936)\n * rtnetlink: Add tc filter support. (2c41fb0)\n * rtnetlink: Add tc qdisc support. (921a936)\n\n### Bug fixes\n * netlink-packet-audit: Simplfied codec error handling.\n   (33cc558, 0027b82, 9cdc870)\n * netlink-packet-route: Fixed tc buffer error. (d2a5109)\n * netlink-proto: fix netlink_proto::Error recursive problem. (3d799df)\n * netlink-proto: Simplfied codec error handling. (0027b82, 9cdc870)\n\n## [20220220] 2022-02-20\n\n### Versioning\n\n* netlink-packet-netfilter NULL -> 0.1.0\n* netlink-sys 0.8.1 -> 0.8.2\n* netlink-packet-core 0.4.1 -> 0.4.2\n* netlink-packet-utils 0.5.0 -> 0.5.1\n* netlink-packet-route 0.10.0 -> 0.11.0\n* netlink-packet-sock-diag 0.3.0 -> 0.3.1\n* netlink-packet-wireguard 0.2.0 -> 0.2.1\n* netlink-proto 0.9.1 -> 0.9.2\n* ethtool 0.2.1 -> 0.2.2\n* rtnetlink 0.9.0 -> 0.9.1\n\n### New Features\n\n* **new crate netlink-packet-netfilter!** Thank you @dzamlo :) (https://github.com/little-dude/netlink/pull/235)\n* netlink-packet-utils: speed up computation of netlink attributes paddins (https://github.com/little-dude/netlink/pull/229)\n* netlink-packet-route: support additional MPLS attributes (https://github.com/little-dude/netlink/pull/233)\n\n### Bug fixes\n\n* netlink-packet-sys, netlink-packet-sock-diag, netlink-packet-route, netlink-packet-wireguard, ethtool, netlink-packet-core: clippy fixes (https://github.com/little-dude/netlink/pull/238)\n* netlink-packet-route: fix encoding of link info attribute (https://github.com/little-dude/netlink/pull/239)\n\n## [20220212] 2022-02-12\n\n### Versioning\n\n* netlink-packet-wireguard 0.1.1 -> 0.2\n\n### Breaking changes\n\n* netlink-packet-wireguard (https://github.com/little-dude/netlink/pull/225):\n  * In `netlink_packet_wireguard::nlas::device`: `WgDeviceAttrs::Peers(Vec<Vec<WgPeerAttrs>>)` is now `WgDeviceAttrs::Peers(Vec<WgPeer>>)`\n  * In `netlink_packet_wireguard::nlas::peer`: `WgDeviceAttrs::AllowedIps(Vec<Vec<WgAllowedIpAttrs>>)` is now `WgDeviceAttrs::AllowedIps(Vec<WgAllowedIp>>)`\n\n### New Features\n\nNone\n\n### Bug fixes\n\n* netlink-packet-wireguard (https://github.com/little-dude/netlink/pull/225): various serialization fixes\n\n## [20211229] 2022-01-15\n\n### Versioning\n\n* ethtool 0.2.0 -> 0.2.1 (0.2.0 yanked)\n* genetlink 0.2.0 -> 0.2.1 (0.2.0 yanked)\n* netlink-packet-wireguard -> 0.1.1 (0.1.0 yanked)\n\n### Breaking changes\n\nNone\n\n### New Features\n\nNone\n\n### Bug fixes\n\nFix dependencies in the netlink generic crates. See: https://github.com/little-dude/netlink/pull/223/files\n\n\n## [20211229] 2021-12-29\n\n### Versioning\n\n * audit 0.4.0 -> 0.6.0 (botched 0.5.0 release)\n * ethtool 0.1.0 -> 0.2.0\n * genetlink 0.1.0 -> 0.2.0\n * netlink-packet-audit 0.2.2 -> 0.4.0 (botched 0.4.0 release)\n * netlink-packet-core 0.2.4 -> 0.4.1 (botched 0.3.0 release, 0.4.0 was published with downgraded dependencies to break cycles)\n * netlink-packet-generic 0.1.0 -> 0.2.0\n * netlink-packet-route 0.8.0 -> 0.10.0 (botched 0.9.0 release)\n * netlink-packet-sock-diag 0.1.0 -> 0.3.0 (botched 0.2.0 release)\n * netlink-packet-utils 0.4.1 -> 0.5\n * netlink-packet-wireguard NULL -> 0.1.0\n * netlink-proto 0.7.0 -> 0.9.1 (botched 0.8.0 release, 0.9.0 was published with downgraded dev-dependences to break cycles)\n * netlink-sys 0.7.0 -> 0.8.1 (0.8.0 was published with downgraded dev-dependencies to break cycles)\n * rtnetlink 0.8.1 -> 0.9.0\n\n### Breaking Changes\n\n- `netlink-packet-route`:\n  - add `InfoBridge::VlanInfo` (https://github.com/little-dude/netlink/pull/212 https://github.com/little-dude/netlink/pull/213)\n- `rtnetlink`:\n  - add `LinkGetRequest::match_name` to filter links by name more efficiently, and remove `LinkGetRequest::set_name_filter` (https://github.com/little-dude/netlink/pull/208)\n- refactor `netlink_packet_core::traits::NetlinkSerializable` and `netlink_packet_core::trait::NetlinkDeserializable` such that they are not generic (https://github.com/little-dude/netlink/pull/195/, specifically https://github.com/little-dude/netlink/pull/195/commits/94c263282d9a34d01422513de6a7f683ac08addc)\n- `netlink-proto`: Add new type parameter for `Connection` which represents the socket (https://github.com/little-dude/netlink/pull/195, specifically 944307ce292682283891f41db8a0ec4706419664)\n\n### New Features\n\n- new `netlink-packet-wireguard` crate for the wireguard netlink protocol (https://github.com/little-dude/netlink/pull/191)\n- new `rich_nlas` feature for `netlink-packet-route` that enables parsing more message types (https://github.com/little-dude/netlink/pull/199 https://github.com/little-dude/netlink/pull/205)\n- `rtnetlink`:\n  - add `NeighbourAddRequest::add_bridge` helper to create a bridge interface (https://github.com/little-dude/netlink/pull/203)\n  - allow the requests to be built with the `NLM_F_REPLACE` flag to optimize \"create or update\" operations (https://github.com/little-dude/netlink/pull/202)\n  - add helper to create macvlan links (https://github.com/little-dude/netlink/pull/194)\n- `netlink-packet-utils`: add `parse_ip` function\n\n### Bug fixes\n\n- fix UB in unsafe code (https://github.com/little-dude/netlink/pull/195/ specifically 7e6cfd743bf822e917e260eb24fbf5b2c541922e)\n- fix `netlink_sys::SmolSocket::recv` error handling (https://github.com/little-dude/netlink/pull/195/ specifically 1cd3e0fbb8d77d6b9c4fe43b8c4aa745fa6ba66c)\n- various fixes in the `netlink-proto` encoder (https://github.com/little-dude/netlink/pull/168)\n\n## [20210927] 2021-09-27\n### Versioning\n * audit 0.4.0\n * ethtool NULL -> 0.1.0\n * genetlink NULL -> 0.1.0\n * netlink-packet-audit 0.2.2\n * netlink-packet-core 0.2.4\n * netlink-packet-generic NULL -> 0.1.0\n * netlink-packet-route 0.7.0 -> 0.8.0\n * netlink-packet-sock-diag 0.1.0\n * netlink-packet-utils 0.4.1\n * netlink-proto 0.7.0\n * netlink-sys 0.7.0\n * rtnetlink 0.8.0 -> 0.8.1\n\n### Breaking Changes\n * `netlink_packet_route::rtnl::link::nlas::Nla::PropList` changed from\n `PropList(Vec<u8>)` to `PropList(Vec<Prop>)` (b4b3c46)\n\n### New Features\n * ethtool: New crate for ethtool netlink protocol (7998f8c, 2b79197, bc43fd6,\n   2ec5f17, cb8738b)\n * genetlink: New create for higher level abstraction of generic netlink\n   protocol (89ee697)\n * netlink-packet-generic: New crate for generic netlink protocol (89ee697)\n * netlink-packet-route: Add support of property addition and deletion (cc073b3)\n * rtnetlink: Add support of preferred source address (720e764)\n\n### Bug fixes\n * netlink-packet-route: vlan: Fix endianness when creating VLAN (b0fd2ea)\n * rtnetlink: drop byteordered dependency (8bca238)\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\n\nmembers = [\n    \"netlink-sys\",\n    \"netlink-packet-core\",\n    \"netlink-packet-utils\",\n    \"netlink-packet-generic\",\n    \"netlink-packet-route\",\n    \"netlink-packet-route/fuzz\",\n    \"netlink-packet-audit\",\n    \"netlink-packet-audit/fuzz\",\n    \"netlink-packet-sock-diag\",\n    \"netlink-packet-netfilter\",\n    \"netlink-packet-wireguard\",\n    \"netlink-proto\",\n    \"ethtool\",\n    \"genetlink\",\n    \"rtnetlink\",\n    \"audit\",\n    \"mptcp-pm\",\n]\n\n# omit fuzz projects\ndefault-members = [\n    \"netlink-sys\",\n    \"netlink-packet-core\",\n    \"netlink-packet-utils\",\n    \"netlink-packet-generic\",\n    \"netlink-packet-route\",\n    \"netlink-packet-audit\",\n    \"netlink-packet-sock-diag\",\n    \"netlink-packet-netfilter\",\n    \"netlink-packet-wireguard\",\n    \"netlink-proto\",\n    \"ethtool\",\n    \"genetlink\",\n    \"rtnetlink\",\n    \"audit\",\n    \"mptcp-pm\",\n]\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Permission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nDistributions of all or part of the Software intended to be used by the\nrecipients as they would use the unmodified Software, containing modifications\nthat substantially alter, remove, or disable functionality of the Software,\noutside of the documented configuration mechanisms provided by the Software,\nshall be modified such that the Original Author's bug reporting email addresses\nand urls are either replaced with the contact information of the parties\nresponsible for the changes, or removed entirely.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE. \n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/little-dude/netlink.svg?branch=master)](https://travis-ci.org/little-dude/netlink)\n\n# This repository has been deprecated. Subsequent development will take place [@rust-netlink](https://github.com/rust-netlink).\n\n# Netlink\n\nThis project aims at providing building blocks for [netlink][man-netlink] (see `man 7 netlink`).\n\n## Organization\n\n- the [`netlink_sys`](./netlink-sys) crate provides netlink sockets. Integration with [`mio`][mio] and [`tokio`][tokio]\n  is optional.\n- Each netlink protocol has a `netlink-packet-<protocol_name>` crate that provides the packets for this protocol:\n    - [`netlink-packet-route`](./netlink-packet-route) provides messages for the [route protocol][man-rtnetlink]\n    - [`netlink-packet-audit`](./netlink-packet-audit) provides messages for the [audit][man-audit] protocol\n    - [`netlink-packet-sock-diag`](./netlink-packet-sock-diag) provides messages for the [sock-diag][man-sock-diag]\n      protocol\n    - [`netlink-packet-generic`](./netlink-packet-generic) provides message for the [generic netlink][man-genl]\n      protocol\n    - [`netlink-packet-netfilter`](./netlink-packet-netfilter) provides message for the `NETLINK_NETFILTER`\n      protocol\n- the [`netlink-packet-core`](./netlink-packet-core) is the glue for all the other `netlink-packet-*` crates. It\n  provides a `NetlinkMessage<T>` type that represent any netlink message for any sub-protocol.\n- the [`netlink_proto`](./netlink-proto) crate is an asynchronous implementation of the netlink protocol. It only\n  depends on `netlink-packet-core` for the `NetlinkMessage` type and `netlink-sys` for the socket.\n- the [`rtnetlink`](./rtnetlink) crate provides higher level abstraction for the [route protocol][man-rtnetlink]\n- the [`audit`](./audit) crate provides higher level abstractions for the audit protocol.\n- the [`genetlink`](./genetlink) crate provide higher level abstraction for the\n  [generic netlink protocol][man-genl]\n- the [`ethtool`](./ethtool) crate provide higher level abstraction for\n  [ethtool netlink protocol][ethtool-kernel-doc]\n\n\n## Altnernatives\n\n- https://github.com/jbaublitz/neli: the main alternative to these crates, as it is actively developed.\n- Other but less actively developed alternatives:\n  - https://github.com/achanda/netlink\n  - https://github.com/polachok/pnetlink\n  - https://github.com/crhino/netlink-rs\n  - https://github.com/carrotsrc/rsnl\n  - https://github.com/TaborKelly/nl-utils\n\n## Credits\n\nMy main resource so far has been the source code of [`pyroute2`][pyroute2] (python) and [`netlink`][netlink-go] (golang)\na lot. These two projects are great, and very nicely written. As someone who does not read C fluently, and that does not\nknow much about netlink, they have been invaluable.\n\nI'd also like to praise [`libnl`][libnl] for its documentation. It helped me a lot in understanding the protocol basics.\n\nThe whole packet parsing logic is inspired by @whitequark excellent blog posts ([part 1][whitequark-1], [part\n2][whitequark-2] and [part 3][whitequark-3], although I've only really used the concepts described in the first blog\npost).\n\nThanks also to the people behind [tokio](tokio.rs) for the amazing\ntool they are building, and the support they provide.\n\n[man-netlink]: https://www.man7.org/linux/man-pages/man7/netlink.7.html\n[man-audit]: https://man7.org/linux/man-pages/man3/audit_open.3.html\n[man-sock-diag]: https://www.man7.org/linux/man-pages/man7/sock_diag.7.html\n[man-rtnetlink]: https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html\n[man-genl]: https://www.man7.org/linux/man-pages/man8/genl.8.html\n[generic-netlink-lwn]: https://lwn.net/Articles/208755/\n[mio]: https://github.com/tokio-rs/mio\n[tokio]: https://github.com/tokio-rs/tokio\n[route-proto-doc]: https://www.infradead.org/~tgr/libnl/doc/route.html\n[netlink-go]: https://github.com/vishvananda/netlink\n[pyroute2]: https://github.com/svinota/pyroute2/tree/master/pyroute2/netlink\n[libnl]: https://www.infradead.org/~tgr/libnl\n[whitequark-1]: https://lab.whitequark.org/notes/2016-12-13/abstracting-over-mutability-in-rust\n[whitequark-2]: https://lab.whitequark.org/notes/2016-12-17/owning-collections-in-heap-less-rust\n[whitequark-3]: https://lab.whitequark.org/notes/2017-01-16/abstracting-over-mutability-in-rust-macros\n[ethtool-kernel-doc]: https://www.kernel.org/doc/html/latest/networking/ethtool-netlink.html\n"
  },
  {
    "path": "RELEASE_PROCESS.md",
    "content": "# Release process\n\n## Summary\n\n- bump the versions in the Cargo.toml using `git blame` and `git log`,\n  starting from the `netlink-packet-*` and `netlink-sys` crates\n- Update the `CHANGELOG` file with version changes, new features, bug fixes\n  and breaking changes\n- Check that `cargo test` still works once your done\n- Create pull request for the changes for CHANGELOG and version dumping.\n- Create new tag via command `git tag --sign $(date +%Y%m%d)`\n- Publish the tag to github via command `git push --tags upstream`\n- Create new release page at [github webpage][github_new_release]\n- Publish the crates via command `cargo publish` in changed crate folders\n\n## Detailed process\n\n### Crate groups\n\nFirst, distinguish three groups of crates:\n\n- `netlink-packet-*` crates\n- `netlink-sys`\n- `netlink-proto`, `audit` and `rtnetlink`, which depend on the two other groups\n\nUsually start by bumping the versions of the first group of crates,\nthen `netlink-sys`, and then the last group of crates.\n\n### Dependency graph\n\nHere are the dependency tree for each group.\n\n```\nnetlink-packet-utils v0.4.0\n\nnetlink-packet-core v0.2.4\n└── netlink-packet-utils v0.4.0\n[dev-dependencies]\n└── netlink-packet-route v0.7.0\n    ├── netlink-packet-core v0.2.4\n    └── netlink-packet-utils v0.4.0\n\nnetlink-packet-route v0.7.0\n├── netlink-packet-core v0.2.4\n│   └── netlink-packet-utils v0.4.0\n└── netlink-packet-utils v0.4.0\n[dev-dependencies]\n└── netlink-sys v0.6.0\n\nnetlink-packet-audit v0.2.2\n├── netlink-packet-core v0.2.4\n│   └── netlink-packet-utils v0.4.0\n└── netlink-packet-utils v0.4.0\n\nnetlink-packet-sock-diag v0.1.0\n├── netlink-packet-core v0.2.4\n│   └── netlink-packet-utils v0.4.0\n└── netlink-packet-utils v0.4.0\n[dev-dependencies]\n└── netlink-sys v0.6.0\n```\n\nThen `netlink-sys`:\n\n```\nnetlink-sys v0.6.0\n[dev-dependencies]\n└── netlink-packet-audit v0.2.2\n    ├── netlink-packet-core v0.2.4\n    │   └── netlink-packet-utils v0.4.0\n    └── netlink-packet-utils v0.4.0\n```\n\nFinally, `netlink-proto`, `audit` and `rtnetlink`, which use both the\n`netlink-packet-*` crates and `netlink-sys`:\n\n```\nnetlink-proto v0.6.0\n├── netlink-packet-core v0.2.4\n│   └── netlink-packet-utils v0.4.0\n└── netlink-sys v0.6.0\n[dev-dependencies]\n├── netlink-packet-audit v0.2.2\n└── netlink-packet-route v0.7.0\n\naudit v0.3.1\n├── netlink-packet-audit v0.2.2\n│   ├── netlink-packet-core v0.2.4\n│   │   └── netlink-packet-utils v0.4.0\n│   └── netlink-packet-utils v0.4.0\n└── netlink-proto v0.6.0\n    ├── netlink-packet-core v0.2.4\n    └── netlink-sys v0.6.0\n\nrtnetlink v0.7.0\n├── netlink-packet-route v0.7.0\n│   ├── netlink-packet-core v0.2.4\n│   │   └── netlink-packet-utils v0.4.0\n│   └── netlink-packet-utils v0.4.0\n└── netlink-proto v0.6.0\n    ├── netlink-packet-core v0.2.4\n    └── netlink-sys v0.6.0\n```\n\n### Version bump\n\nFor each crate, look at when was the last time the version was\nchanged. For instance for `rtnetlink`:\n\n```\n$ git blame rtnetlink/Cargo.toml  | grep \"version = \"\n88dde610 rtnetlink/Cargo.toml   (little-dude    2021-01-20 20:09:23 +0100  3) version = \"0.7.0\"\n2f721807 rtnetlink/Cargo.toml   (Stefan Bühler  2021-06-06 14:20:15 +0200 26) netlink-proto = { default-features = false, version = \"0.6\" }\n83da33e2 rtnetlink/Cargo.toml   (gabrik         2021-01-22 16:22:16 +0100 29) tokio = { version = \"1.0.1\", features = [\"rt\"], optional = true}\n83da33e2 rtnetlink/Cargo.toml   (gabrik         2021-01-22 16:22:16 +0100 30) async-std = { version = \"1.9.0\", features = [\"unstable\"], optional = true}\nef3a79a8 rtnetlink/Cargo.toml   (Tim Zhang      2021-01-15 19:31:38 +0800 35) tokio = { version = \"1.0.1\", features = [\"macros\", \"rt\", \"rt-multi-thread\"] }\n83da33e2 rtnetlink/Cargo.toml   (gabrik         2021-01-22 16:22:16 +0100 36) async-std = { version = \"1.9.0\", features = [\"attributes\"]}\n\n$ git log  --oneline 88dde610.. rtnetlink/\n2f72180 Cargo.toml: move path specs to workspace [patch.crates-io] section\n1e8bc53 CI: Fix rtnetlink example\ncae6e09 Merge pull request #97 from SkamDart/SkamDart/ip-monitor\n35b6cb9 use `unwrap()` instead of `.is_ok()` so that the error is printed\n2f0877a (origin/release) rustfmt, clippy\n5c39136 Merge pull request #130 from benjumanji/wireguard-type\naf1ee71 Merge pull request #137 from little-dude/rtnetlink-macros\n83da33e added features and examples to rtnetlink\n079b5f3 (origin/rtnetlink-macros) rtnetlink: use macros in response handling\nb681f35 Add basic test for bringing up interface\n5201dcd ip monitor clone\n```\n\nBased on the changes, decide whether bumping the patch or minor\nversion. For crates that like `rtnetlink`, usually just bump the\nminor version. For `netlink-packet-*` and `netlink-sys`, try to bump\nit only if really necessary, because bumping it means bumping all the\ncrates that depend on it.\n\nOnce we have bumped all the version locally, push to a `release`\nbranch to have CI running. If CI passes, just go with `cargo publish`,\nagain starting from the `netlink-packet-*` and `netlink-sys`\ncrates. `--dry-run` is nice but it doesn't really work. For instance\nif `netlink-packet-utils` is bumped from 0.x to 0.x+1,\nthen `cargo publish --dry-run` will not work for `netlink-packet-core`,\nbecause the crate depends on `netlink-packet-utils` 0.x+1, which hasn't be\npublished yet.\n\n[github_new_release]: https://github.com/little-dude/netlink/releases/new\n"
  },
  {
    "path": "audit/Cargo.toml",
    "content": "[package]\nname = \"audit\"\nversion = \"0.7.1\"\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"ip\", \"linux\", \"audit\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"linux audit via netlink\"\n\n[dependencies]\nfutures = \"0.3.11\"\nthiserror = \"1\"\nnetlink-packet-audit = { version = \"0.4.1\", path = \"../netlink-packet-audit\" }\nnetlink-proto = { default-features = false, version = \"0.10.0\", path = \"../netlink-proto\" }\n\n[features]\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-proto/tokio_socket\"]\nsmol_socket = [\"netlink-proto/smol_socket\"]\n\n[dev-dependencies]\ntokio = { version = \"1.0.1\", default-features = false, features = [\"macros\", \"rt-multi-thread\"] }\nasync-std = { version = \"1.9.0\", features = [\"attributes\"] }\nenv_logger = \"0.8.2\"\n\n[[example]]\nname = \"events_async\"\nrequired-features = [\"smol_socket\"]\n"
  },
  {
    "path": "audit/examples/add_rules.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! In this example, we create two rules which is equivalent to the following commands:\n//!\n//! auditctl -w /etc/passwd -p rwxa -k my_key\n//! auditctl -a always,exit -F arch=b64 -S personality -F key=bypass\n\nuse audit::{\n    new_connection,\n    packet::{\n        constants::AUDIT_ARCH_X86_64,\n        RuleAction,\n        RuleField,\n        RuleFieldFlags,\n        RuleFlags,\n        RuleMessage,\n        RuleSyscalls,\n    },\n    Error,\n    Handle,\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, handle, _) = new_connection().map_err(|e| format!(\"{}\", e))?;\n    tokio::spawn(connection);\n    add_rules(handle).await.map_err(|e| format!(\"{}\", e))\n}\n\nasync fn add_rules(mut handle: Handle) -> Result<(), Error> {\n    let etc_passwd_rule = RuleMessage {\n        flags: RuleFlags::FilterExit,\n        action: RuleAction::Always,\n        fields: vec![\n            (\n                RuleField::Watch(\"/etc/passwd\".into()),\n                RuleFieldFlags::Equal,\n            ),\n            (RuleField::Perm(15), RuleFieldFlags::Equal),\n            (RuleField::Filterkey(\"my_key\".into()), RuleFieldFlags::Equal),\n        ],\n        syscalls: RuleSyscalls::new_maxed(),\n    };\n    handle.add_rule(etc_passwd_rule).await?;\n\n    let mut syscalls = RuleSyscalls::new_zeroed();\n    syscalls.set(135);\n    let personality_syscall_rule = RuleMessage {\n        flags: RuleFlags::FilterExit,\n        action: RuleAction::Always,\n        fields: vec![\n            (RuleField::Arch(AUDIT_ARCH_X86_64), RuleFieldFlags::Equal),\n            (RuleField::Filterkey(\"bypass\".into()), RuleFieldFlags::Equal),\n        ],\n        syscalls,\n    };\n    handle.add_rule(personality_syscall_rule).await?;\n    Ok(())\n}\n"
  },
  {
    "path": "audit/examples/dump_audit_rules.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! In this example, we create a netlink connection, and send a request to retrieve the list of\n//! rules. We receive a stream of rule messages that we just prints to the terminal.\nuse audit::{new_connection, Error, Handle};\nuse futures::stream::TryStreamExt;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, handle, _) = new_connection().map_err(|e| format!(\"{}\", e))?;\n    tokio::spawn(connection);\n    list_rules(handle).await.map_err(|e| format!(\"{}\", e))\n}\n\nasync fn list_rules(mut handle: Handle) -> Result<(), Error> {\n    let mut rules = handle.list_rules();\n    while let Some(rule) = rules.try_next().await? {\n        println!(\"{:?}\", rule);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "audit/examples/events.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This example opens a netlink socket, enables audit events, and prints the events that are being\n//! received.\n\nuse audit::new_connection;\nuse futures::stream::StreamExt;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, mut handle, mut messages) = new_connection().map_err(|e| format!(\"{}\", e))?;\n\n    tokio::spawn(connection);\n    handle.enable_events().await.map_err(|e| format!(\"{}\", e))?;\n\n    env_logger::init();\n    while let Some((msg, _)) = messages.next().await {\n        println!(\"{:?}\", msg);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "audit/examples/events_async.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This example opens a netlink socket, enables audit events, and prints the events that are being\n//! received.\n\nuse audit::new_connection;\nuse futures::stream::StreamExt;\n\n#[async_std::main]\nasync fn main() -> Result<(), String> {\n    let (connection, mut handle, mut messages) = new_connection().map_err(|e| format!(\"{}\", e))?;\n\n    async_std::task::spawn(connection);\n\n    handle.enable_events().await.map_err(|e| format!(\"{}\", e))?;\n\n    env_logger::init();\n    while let Some((msg, _)) = messages.next().await {\n        println!(\"{:?}\", msg);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "audit/src/errors.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse thiserror::Error;\n\nuse crate::packet::{AuditMessage, ErrorMessage, NetlinkMessage};\n\n#[derive(Clone, Eq, PartialEq, Debug, Error)]\npub enum Error {\n    #[error(\"Received an unexpected message {0:?}\")]\n    UnexpectedMessage(NetlinkMessage<AuditMessage>),\n\n    #[error(\"Received a netlink error message {0:?}\")]\n    NetlinkError(ErrorMessage),\n\n    #[error(\"Request failed\")]\n    RequestFailed,\n}\n"
  },
  {
    "path": "audit/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::process;\n\nuse futures::{\n    future::{self, Either},\n    stream::{Stream, StreamExt, TryStream},\n    FutureExt,\n};\nuse netlink_proto::{sys::SocketAddr, ConnectionHandle};\n\nuse crate::packet::{\n    rules::RuleMessage,\n    AuditMessage,\n    NetlinkMessage,\n    NetlinkPayload,\n    StatusMessage,\n    NLM_F_ACK,\n    NLM_F_CREATE,\n    NLM_F_DUMP,\n    NLM_F_EXCL,\n    NLM_F_NONREC,\n    NLM_F_REQUEST,\n};\n\n// ==========================================\n// mask values\n// ==========================================\npub const AUDIT_STATUS_ENABLED: u32 = 1;\npub const AUDIT_STATUS_FAILURE: u32 = 2;\npub const AUDIT_STATUS_PID: u32 = 4;\npub const AUDIT_STATUS_RATE_LIMIT: u32 = 8;\npub const AUDIT_STATUS_BACKLOG_LIMIT: u32 = 16;\npub const AUDIT_STATUS_BACKLOG_WAIT_TIME: u32 = 32;\npub const AUDIT_STATUS_LOST: u32 = 64;\npub const AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT: u32 = 1;\npub const AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME: u32 = 2;\npub const AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH: u32 = 4;\npub const AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND: u32 = 8;\npub const AUDIT_FEATURE_BITMAP_SESSIONID_FILTER: u32 = 16;\npub const AUDIT_FEATURE_BITMAP_LOST_RESET: u32 = 32;\npub const AUDIT_FEATURE_BITMAP_FILTER_FS: u32 = 64;\npub const AUDIT_FEATURE_BITMAP_ALL: u32 = 127;\npub const AUDIT_VERSION_LATEST: u32 = 127;\npub const AUDIT_VERSION_BACKLOG_LIMIT: u32 = 1;\npub const AUDIT_VERSION_BACKLOG_WAIT_TIME: u32 = 2;\n\nuse crate::Error;\n\n/// A handle to the netlink connection, used to send and receive netlink messsage\n#[derive(Clone, Debug)]\npub struct Handle(ConnectionHandle<AuditMessage>);\n\nimpl Handle {\n    pub(crate) fn new(conn: ConnectionHandle<AuditMessage>) -> Self {\n        Handle(conn)\n    }\n\n    /// Send a netlink message, and get the reponse as a stream of messages.\n    pub fn request(\n        &mut self,\n        message: NetlinkMessage<AuditMessage>,\n    ) -> Result<impl Stream<Item = NetlinkMessage<AuditMessage>>, Error> {\n        self.0\n            .request(message, SocketAddr::new(0, 0))\n            .map_err(|_| Error::RequestFailed)\n    }\n\n    /// Send a netlink message that expects an acknowledgement. The returned future resolved when\n    /// that ACK is received. If anything else is received, the future resolves into an error.\n    async fn acked_request(&mut self, message: NetlinkMessage<AuditMessage>) -> Result<(), Error> {\n        let mut response = self.request(message)?;\n        if let Some(message) = response.next().await {\n            let (header, payload) = message.into_parts();\n            // NetlinkError and AuditMessage are forwarded to the\n            // handle. Ack is signaled by the stream finishing.\n            if let NetlinkPayload::Error(err_msg) = payload {\n                Err(Error::NetlinkError(err_msg))\n            } else {\n                Err(Error::UnexpectedMessage(NetlinkMessage::new(\n                    header, payload,\n                )))\n            }\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Add the given rule\n    pub async fn add_rule(&mut self, rule: RuleMessage) -> Result<(), Error> {\n        let mut req = NetlinkMessage::from(AuditMessage::AddRule(rule));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;\n        self.acked_request(req).await\n    }\n\n    /// Deletes a given rule\n    pub async fn del_rule(&mut self, rule: RuleMessage) -> Result<(), Error> {\n        let mut req = NetlinkMessage::from(AuditMessage::DelRule(rule));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_NONREC;\n        self.acked_request(req).await\n    }\n\n    /// List the current rules\n    pub fn list_rules(&mut self) -> impl TryStream<Ok = RuleMessage, Error = Error> {\n        let mut req = NetlinkMessage::from(AuditMessage::ListRules(None));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match self.request(req) {\n            Ok(response) => Either::Left(response.map(move |msg| {\n                let (header, payload) = msg.into_parts();\n                match payload {\n                    NetlinkPayload::InnerMessage(AuditMessage::ListRules(Some(rule_msg))) => {\n                        Ok(rule_msg)\n                    }\n                    NetlinkPayload::Error(err_msg) => Err(Error::NetlinkError(err_msg)),\n                    _ => Err(Error::UnexpectedMessage(NetlinkMessage::new(\n                        header, payload,\n                    ))),\n                }\n            })),\n            Err(e) => Either::Right(future::err::<RuleMessage, Error>(e).into_stream()),\n        }\n    }\n\n    /// Enable receiving audit events\n    pub async fn enable_events(&mut self) -> Result<(), Error> {\n        let mut status = StatusMessage::new();\n        status.enabled = 1;\n        status.pid = process::id();\n        status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n        let mut req = NetlinkMessage::from(AuditMessage::SetStatus(status));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n        self.acked_request(req).await\n    }\n\n    /// Get current audit status\n    pub async fn get_status(&mut self) -> Result<StatusMessage, Error> {\n        let mut req = NetlinkMessage::from(AuditMessage::GetStatus(None));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n        let mut request = self.request(req)?;\n\n        let response = request.next().await.ok_or(Error::RequestFailed)?;\n\n        match response.into_parts() {\n            (_, NetlinkPayload::InnerMessage(AuditMessage::GetStatus(Some(status)))) => Ok(status),\n            (header, payload) => Err(Error::UnexpectedMessage(NetlinkMessage::new(\n                header, payload,\n            ))),\n        }\n    }\n}\n"
  },
  {
    "path": "audit/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use crate::handle::*;\n\nmod errors;\npub use crate::errors::*;\n\npub use netlink_packet_audit as packet;\npub mod proto {\n    pub use netlink_proto::{Connection, ConnectionHandle, Error};\n}\npub use netlink_proto::sys;\n\nuse std::io;\n\nuse futures::channel::mpsc::UnboundedReceiver;\n\n#[allow(clippy::type_complexity)]\n#[cfg(feature = \"tokio_socket\")]\npub fn new_connection() -> io::Result<(\n    proto::Connection<packet::AuditMessage, sys::TokioSocket, packet::NetlinkAuditCodec>,\n    Handle,\n    UnboundedReceiver<(\n        packet::NetlinkMessage<packet::AuditMessage>,\n        sys::SocketAddr,\n    )>,\n)> {\n    new_connection_with_socket()\n}\n\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<S>() -> io::Result<(\n    proto::Connection<packet::AuditMessage, S, packet::NetlinkAuditCodec>,\n    Handle,\n    UnboundedReceiver<(\n        packet::NetlinkMessage<packet::AuditMessage>,\n        sys::SocketAddr,\n    )>,\n)>\nwhere\n    S: sys::AsyncSocket,\n{\n    let (conn, handle, messages) =\n        netlink_proto::new_connection_with_codec(sys::protocols::NETLINK_AUDIT)?;\n    Ok((conn, Handle::new(handle), messages))\n}\n"
  },
  {
    "path": "ethtool/Cargo.toml",
    "content": "[package]\nname = \"ethtool\"\nversion = \"0.2.3\"\nauthors = [\"Gris Ge <fge@redhat.com>\"]\nlicense = \"MIT\"\nedition = \"2018\"\ndescription = \"Linux Ethtool Communication Library\"\nkeywords = [\"network\"]\ncategories = [\"network-programming\", \"os\"]\nreadme = \"../README.md\"\n\n[lib]\nname = \"ethtool\"\npath = \"src/lib.rs\"\ncrate-type = [\"lib\"]\n\n[features]\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-proto/tokio_socket\", \"tokio\"]\nsmol_socket = [\"netlink-proto/smol_socket\", \"async-std\"]\n\n[dependencies]\nanyhow = \"1.0.44\"\nasync-std = { version = \"1.9.0\", optional = true}\nbyteorder = \"1.4.3\"\nfutures = \"0.3.17\"\nlog = \"0.4.14\"\ngenetlink = { default-features = false, version = \"0.2.1\", path = \"../genetlink\" }\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-generic = { version = \"0.3.1\", path = \"../netlink-packet-generic\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nnetlink-proto = { default-features = false, version = \"0.10\", path = \"../netlink-proto\" }\nnetlink-sys = { version = \"0.8.3\", path = \"../netlink-sys\" }\nthiserror = \"1.0.29\"\ntokio = { version = \"1.0.1\", features = [\"rt\"], optional = true}\n\n[dev-dependencies]\ntokio = { version = \"1.11.0\", features = [\"macros\", \"rt\", \"rt-multi-thread\"] }\nenv_logger = \"0.9.0\"\n\n[[example]]\nname = \"dump_pause\"\nrequired-features = [\"tokio_socket\"]\n"
  },
  {
    "path": "ethtool/examples/dump_coalesce.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n// Once we find a way to load netsimdev kernel module in CI, we can convert this\n// to a test\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_coalesce(None));\n}\n\nasync fn get_coalesce(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut coalesce_handle = handle.coalesce().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = coalesce_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n}\n"
  },
  {
    "path": "ethtool/examples/dump_features.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n// Once we find a way to load netsimdev kernel module in CI, we can convert this\n// to a test\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_feature(None));\n}\n\nasync fn get_feature(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut feature_handle = handle.feature().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = feature_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n}\n"
  },
  {
    "path": "ethtool/examples/dump_link_mode.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n// Once we find a way to load netsimdev kernel module in CI, we can convert this\n// to a test\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_link_mode(None));\n}\n\nasync fn get_link_mode(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut link_mode_handle = handle.link_mode().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = link_mode_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n}\n"
  },
  {
    "path": "ethtool/examples/dump_pause.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n// Once we find a way to load netsimdev kernel module in CI, we can convert this\n// to a test\nfn main() {\n    env_logger::init();\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_pause(None));\n}\n\nasync fn get_pause(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut pause_handle = handle.pause().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = pause_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    println!(\"{:?}\", msgs);\n}\n"
  },
  {
    "path": "ethtool/examples/dump_rings.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n// Once we find a way to load netsimdev kernel module in CI, we can convert this\n// to a test\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_ring(None));\n}\n\nasync fn get_ring(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut ring_handle = handle.ring().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = ring_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n}\n"
  },
  {
    "path": "ethtool/src/coalesce/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::{parse_u32, parse_u8},\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nuse crate::{EthtoolAttr, EthtoolHeader};\n\nconst ETHTOOL_A_COALESCE_HEADER: u16 = 1;\nconst ETHTOOL_A_COALESCE_RX_USECS: u16 = 2;\nconst ETHTOOL_A_COALESCE_RX_MAX_FRAMES: u16 = 3;\nconst ETHTOOL_A_COALESCE_RX_USECS_IRQ: u16 = 4;\nconst ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ: u16 = 5;\nconst ETHTOOL_A_COALESCE_TX_USECS: u16 = 6;\nconst ETHTOOL_A_COALESCE_TX_MAX_FRAMES: u16 = 7;\nconst ETHTOOL_A_COALESCE_TX_USECS_IRQ: u16 = 8;\nconst ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ: u16 = 9;\nconst ETHTOOL_A_COALESCE_STATS_BLOCK_USECS: u16 = 10;\nconst ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX: u16 = 11;\nconst ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX: u16 = 12;\nconst ETHTOOL_A_COALESCE_PKT_RATE_LOW: u16 = 13;\nconst ETHTOOL_A_COALESCE_RX_USECS_LOW: u16 = 14;\nconst ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW: u16 = 15;\nconst ETHTOOL_A_COALESCE_TX_USECS_LOW: u16 = 16;\nconst ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW: u16 = 17;\nconst ETHTOOL_A_COALESCE_PKT_RATE_HIGH: u16 = 18;\nconst ETHTOOL_A_COALESCE_RX_USECS_HIGH: u16 = 19;\nconst ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH: u16 = 20;\nconst ETHTOOL_A_COALESCE_TX_USECS_HIGH: u16 = 21;\nconst ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH: u16 = 22;\nconst ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL: u16 = 23;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolCoalesceAttr {\n    Header(Vec<EthtoolHeader>),\n    RxUsecs(u32),\n    RxMaxFrames(u32),\n    RxUsecsIrq(u32),\n    RxMaxFramesIrq(u32),\n    TxUsecs(u32),\n    TxMaxFrames(u32),\n    TxUsecsIrq(u32),\n    TxMaxFramesIrq(u32),\n    StatsBlockUsecs(u32),\n    UseAdaptiveRx(bool),\n    UseAdaptiveTx(bool),\n    PktRateLow(u32),\n    RxUsecsLow(u32),\n    RxMaxFramesLow(u32),\n    TxUsecsLow(u32),\n    TxMaxFramesLow(u32),\n    PktRateHigh(u32),\n    RxUsecsHigh(u32),\n    RxMaxFramesHigh(u32),\n    TxUsecsHigh(u32),\n    TxMaxFramesHigh(u32),\n    RateSampleInterval(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolCoalesceAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Header(hdrs) => hdrs.as_slice().buffer_len(),\n            Self::RxUsecs(_)\n            | Self::RxMaxFrames(_)\n            | Self::RxUsecsIrq(_)\n            | Self::RxMaxFramesIrq(_)\n            | Self::TxUsecs(_)\n            | Self::TxMaxFrames(_)\n            | Self::TxUsecsIrq(_)\n            | Self::TxMaxFramesIrq(_)\n            | Self::StatsBlockUsecs(_)\n            | Self::PktRateLow(_)\n            | Self::RxUsecsLow(_)\n            | Self::RxMaxFramesLow(_)\n            | Self::TxUsecsLow(_)\n            | Self::TxMaxFramesLow(_)\n            | Self::PktRateHigh(_)\n            | Self::RxUsecsHigh(_)\n            | Self::RxMaxFramesHigh(_)\n            | Self::TxUsecsHigh(_)\n            | Self::TxMaxFramesHigh(_)\n            | Self::RateSampleInterval(_) => 4,\n            Self::UseAdaptiveRx(_) | Self::UseAdaptiveTx(_) => 1,\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Header(_) => ETHTOOL_A_COALESCE_HEADER | NLA_F_NESTED,\n            Self::RxUsecs(_) => ETHTOOL_A_COALESCE_RX_USECS,\n            Self::RxMaxFrames(_) => ETHTOOL_A_COALESCE_RX_MAX_FRAMES,\n            Self::RxUsecsIrq(_) => ETHTOOL_A_COALESCE_RX_USECS_IRQ,\n            Self::RxMaxFramesIrq(_) => ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ,\n            Self::TxUsecs(_) => ETHTOOL_A_COALESCE_TX_USECS,\n            Self::TxMaxFrames(_) => ETHTOOL_A_COALESCE_TX_MAX_FRAMES,\n            Self::TxUsecsIrq(_) => ETHTOOL_A_COALESCE_TX_USECS_IRQ,\n            Self::TxMaxFramesIrq(_) => ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ,\n            Self::StatsBlockUsecs(_) => ETHTOOL_A_COALESCE_STATS_BLOCK_USECS,\n            Self::UseAdaptiveRx(_) => ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX,\n            Self::UseAdaptiveTx(_) => ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX,\n            Self::PktRateLow(_) => ETHTOOL_A_COALESCE_PKT_RATE_LOW,\n            Self::RxUsecsLow(_) => ETHTOOL_A_COALESCE_RX_USECS_LOW,\n            Self::RxMaxFramesLow(_) => ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW,\n            Self::TxUsecsLow(_) => ETHTOOL_A_COALESCE_TX_USECS_LOW,\n            Self::TxMaxFramesLow(_) => ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW,\n            Self::PktRateHigh(_) => ETHTOOL_A_COALESCE_PKT_RATE_HIGH,\n            Self::RxUsecsHigh(_) => ETHTOOL_A_COALESCE_RX_USECS_HIGH,\n            Self::RxMaxFramesHigh(_) => ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH,\n            Self::TxUsecsHigh(_) => ETHTOOL_A_COALESCE_TX_USECS_HIGH,\n            Self::TxMaxFramesHigh(_) => ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH,\n            Self::RateSampleInterval(_) => ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Header(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::Other(ref attr) => attr.emit(buffer),\n            Self::RxUsecs(d)\n            | Self::RxMaxFrames(d)\n            | Self::RxUsecsIrq(d)\n            | Self::RxMaxFramesIrq(d)\n            | Self::TxUsecs(d)\n            | Self::TxMaxFrames(d)\n            | Self::TxUsecsIrq(d)\n            | Self::TxMaxFramesIrq(d)\n            | Self::StatsBlockUsecs(d)\n            | Self::PktRateLow(d)\n            | Self::RxUsecsLow(d)\n            | Self::RxMaxFramesLow(d)\n            | Self::TxUsecsLow(d)\n            | Self::TxMaxFramesLow(d)\n            | Self::PktRateHigh(d)\n            | Self::RxUsecsHigh(d)\n            | Self::RxMaxFramesHigh(d)\n            | Self::TxUsecsHigh(d)\n            | Self::TxMaxFramesHigh(d)\n            | Self::RateSampleInterval(d) => NativeEndian::write_u32(buffer, *d),\n            Self::UseAdaptiveRx(d) | Self::UseAdaptiveTx(d) => buffer[0] = if *d { 1 } else { 0 },\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolCoalesceAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_COALESCE_HEADER => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse coalesce header attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolHeader::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Header(nlas)\n            }\n            ETHTOOL_A_COALESCE_RX_USECS => Self::RxUsecs(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_USECS value\")?,\n            ),\n            ETHTOOL_A_COALESCE_RX_MAX_FRAMES => Self::RxMaxFrames(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_MAX_FRAMES value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_USECS_IRQ => Self::RxUsecsIrq(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_USECS_IRQ value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ => Self::RxMaxFramesIrq(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_USECS => Self::TxUsecs(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_USECS value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_MAX_FRAMES => Self::TxMaxFrames(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_MAX_FRAMES value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_USECS_IRQ => Self::TxUsecsIrq(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_USECS_IRQ value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ => Self::TxMaxFramesIrq(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_STATS_BLOCK_USECS => Self::StatsBlockUsecs(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_STATS_BLOCK_USECS value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX => Self::UseAdaptiveRx(\n                parse_u8(payload).context(\"Invalid ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX value\")? == 1,\n            ),\n\n            ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX => Self::UseAdaptiveTx(\n                parse_u8(payload).context(\"Invalid ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX value\")? == 1,\n            ),\n\n            ETHTOOL_A_COALESCE_PKT_RATE_LOW => Self::PktRateLow(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_PKT_RATE_LOW value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_USECS_LOW => Self::RxUsecsLow(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_USECS_LOW value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW => Self::RxMaxFramesLow(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_USECS_LOW => Self::TxUsecsLow(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_USECS_LOW value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW => Self::TxMaxFramesLow(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_PKT_RATE_HIGH => Self::PktRateHigh(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_PKT_RATE_HIGH value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_USECS_HIGH => Self::RxUsecsHigh(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_RX_USECS_HIGH value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH => Self::RxMaxFramesHigh(\n                parse_u32(payload)\n                    .context(\"Invalid ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_USECS_HIGH => Self::TxUsecsHigh(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_COALESCE_TX_USECS_HIGH value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH => Self::TxMaxFramesHigh(\n                parse_u32(payload)\n                    .context(\"Invalid ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH value\")?,\n            ),\n\n            ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL => Self::RateSampleInterval(\n                parse_u32(payload)\n                    .context(\"Invalid ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL value\")?,\n            ),\n\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\npub(crate) fn parse_coalesce_nlas(buffer: &[u8]) -> Result<Vec<EthtoolAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\n            \"Failed to parse ethtool coalesce message attribute {:?}\",\n            nla\n        );\n        let nla = &nla.context(error_msg.clone())?;\n        let parsed = EthtoolCoalesceAttr::parse(nla).context(error_msg)?;\n        nlas.push(EthtoolAttr::Coalesce(parsed));\n    }\n    Ok(nlas)\n}\n"
  },
  {
    "path": "ethtool/src/coalesce/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};\n\npub struct EthtoolCoalesceGetRequest {\n    handle: EthtoolHandle,\n    iface_name: Option<String>,\n}\n\nimpl EthtoolCoalesceGetRequest {\n    pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {\n        EthtoolCoalesceGetRequest {\n            handle,\n            iface_name: iface_name.map(|i| i.to_string()),\n        }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n        let EthtoolCoalesceGetRequest {\n            mut handle,\n            iface_name,\n        } = self;\n\n        let ethtool_msg = EthtoolMessage::new_coalesce_get(iface_name.as_deref());\n        ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await\n    }\n}\n"
  },
  {
    "path": "ethtool/src/coalesce/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{EthtoolCoalesceGetRequest, EthtoolHandle};\n\npub struct EthtoolCoalesceHandle(EthtoolHandle);\n\nimpl EthtoolCoalesceHandle {\n    pub fn new(handle: EthtoolHandle) -> Self {\n        EthtoolCoalesceHandle(handle)\n    }\n\n    /// Retrieve the ethtool coalesces of a interface (equivalent to `ethtool -c eth1`)\n    pub fn get(&mut self, iface_name: Option<&str>) -> EthtoolCoalesceGetRequest {\n        EthtoolCoalesceGetRequest::new(self.0.clone(), iface_name)\n    }\n}\n"
  },
  {
    "path": "ethtool/src/coalesce/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub(crate) use attr::parse_coalesce_nlas;\n\npub use attr::EthtoolCoalesceAttr;\npub use get::EthtoolCoalesceGetRequest;\npub use handle::EthtoolCoalesceHandle;\n"
  },
  {
    "path": "ethtool/src/connection.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::io;\n\nuse futures::channel::mpsc::UnboundedReceiver;\nuse genetlink::message::RawGenlMessage;\nuse netlink_packet_core::NetlinkMessage;\nuse netlink_proto::Connection;\nuse netlink_sys::{AsyncSocket, SocketAddr};\n\nuse crate::EthtoolHandle;\n\n#[cfg(feature = \"tokio_socket\")]\n#[allow(clippy::type_complexity)]\npub fn new_connection() -> io::Result<(\n    Connection<RawGenlMessage>,\n    EthtoolHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)> {\n    new_connection_with_socket()\n}\n\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<S>() -> io::Result<(\n    Connection<RawGenlMessage, S>,\n    EthtoolHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)>\nwhere\n    S: AsyncSocket,\n{\n    let (conn, handle, messages) = genetlink::new_connection_with_socket()?;\n    Ok((conn, EthtoolHandle::new(handle), messages))\n}\n"
  },
  {
    "path": "ethtool/src/error.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse thiserror::Error;\n\nuse netlink_packet_core::{ErrorMessage, NetlinkMessage};\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::EthtoolMessage;\n\n#[derive(Clone, Eq, PartialEq, Debug, Error)]\npub enum EthtoolError {\n    #[error(\"Received an unexpected message {0:?}\")]\n    UnexpectedMessage(NetlinkMessage<GenlMessage<EthtoolMessage>>),\n\n    #[error(\"Received a netlink error message {0}\")]\n    NetlinkError(ErrorMessage),\n\n    #[error(\"A netlink request failed\")]\n    RequestFailed(String),\n\n    #[error(\"A bug in this crate\")]\n    Bug(String),\n}\n"
  },
  {
    "path": "ethtool/src/feature/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse log::warn;\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::{parse_string, parse_u32},\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nuse crate::{EthtoolAttr, EthtoolHeader};\n\nconst ETHTOOL_A_FEATURES_HEADER: u16 = 1;\nconst ETHTOOL_A_FEATURES_HW: u16 = 2; // User changable features\nconst ETHTOOL_A_FEATURES_WANTED: u16 = 3; // User requested fatures\nconst ETHTOOL_A_FEATURES_ACTIVE: u16 = 4; // Active features\nconst ETHTOOL_A_FEATURES_NOCHANGE: u16 = 5;\n\nconst ETHTOOL_A_BITSET_BITS: u16 = 3;\n\nconst ETHTOOL_A_BITSET_BITS_BIT: u16 = 1;\n\nconst ETHTOOL_A_BITSET_BIT_INDEX: u16 = 1;\nconst ETHTOOL_A_BITSET_BIT_NAME: u16 = 2;\nconst ETHTOOL_A_BITSET_BIT_VALUE: u16 = 3;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct EthtoolFeatureBit {\n    pub index: u32,\n    pub name: String,\n    pub value: bool,\n}\n\nimpl EthtoolFeatureBit {\n    fn new(has_mask: bool) -> Self {\n        Self {\n            index: 0,\n            name: \"\".into(),\n            value: !has_mask,\n        }\n    }\n}\n\nfn feature_bits_len(_feature_bits: &[EthtoolFeatureBit]) -> usize {\n    todo!(\"Does not support changing ethtool feature yet\")\n}\n\nfn feature_bits_emit(_feature_bits: &[EthtoolFeatureBit], _buffer: &mut [u8]) {\n    todo!(\"Does not support changing ethtool feature yet\")\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolFeatureAttr {\n    Header(Vec<EthtoolHeader>),\n    Hw(Vec<EthtoolFeatureBit>),\n    Wanted(Vec<EthtoolFeatureBit>),\n    Active(Vec<EthtoolFeatureBit>),\n    NoChange(Vec<EthtoolFeatureBit>),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolFeatureAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Header(hdrs) => hdrs.as_slice().buffer_len(),\n            Self::Hw(feature_bits)\n            | Self::Wanted(feature_bits)\n            | Self::Active(feature_bits)\n            | Self::NoChange(feature_bits) => feature_bits_len(feature_bits.as_slice()),\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Header(_) => ETHTOOL_A_FEATURES_HEADER | NLA_F_NESTED,\n            Self::Hw(_) => ETHTOOL_A_FEATURES_HW | NLA_F_NESTED,\n            Self::Wanted(_) => ETHTOOL_A_FEATURES_WANTED | NLA_F_NESTED,\n            Self::Active(_) => ETHTOOL_A_FEATURES_ACTIVE | NLA_F_NESTED,\n            Self::NoChange(_) => ETHTOOL_A_FEATURES_NOCHANGE | NLA_F_NESTED,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Header(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::Hw(feature_bits)\n            | Self::Wanted(feature_bits)\n            | Self::Active(feature_bits)\n            | Self::NoChange(feature_bits) => feature_bits_emit(feature_bits.as_slice(), buffer),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolFeatureAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_FEATURES_HEADER => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse feature header attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolHeader::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Header(nlas)\n            }\n            ETHTOOL_A_FEATURES_HW => {\n                Self::Hw(parse_bitset_bits_nlas(\n                    payload, true, /* ETHTOOL_A_FEATURES_HW is using mask */\n                )?)\n            }\n            ETHTOOL_A_FEATURES_WANTED => {\n                Self::Wanted(parse_bitset_bits_nlas(\n                    payload, false, /* ETHTOOL_A_FEATURES_WANTED does not use mask */\n                )?)\n            }\n            ETHTOOL_A_FEATURES_ACTIVE => {\n                Self::Active(parse_bitset_bits_nlas(\n                    payload, false, /* ETHTOOL_A_FEATURES_ACTIVE does not use mask */\n                )?)\n            }\n            ETHTOOL_A_FEATURES_NOCHANGE => {\n                Self::NoChange(parse_bitset_bits_nlas(\n                    payload, false, /* ETHTOOL_A_FEATURES_NOCHANGE does not use mask */\n                )?)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\nfn parse_bitset_bits_nlas(\n    raw: &[u8],\n    has_mask: bool,\n) -> Result<Vec<EthtoolFeatureBit>, DecodeError> {\n    let error_msg = \"failed to parse feature bit sets\";\n    for nla in NlasIterator::new(raw) {\n        let nla = &nla.context(error_msg)?;\n        if nla.kind() == ETHTOOL_A_BITSET_BITS {\n            return parse_bitset_bits_nla(nla.value(), has_mask);\n        }\n    }\n    Err(\"No ETHTOOL_A_BITSET_BITS NLA found\".into())\n}\n\nfn parse_bitset_bits_nla(\n    raw: &[u8],\n    has_mask: bool,\n) -> Result<Vec<EthtoolFeatureBit>, DecodeError> {\n    let mut feature_bits = Vec::new();\n    let error_msg = \"Failed to parse ETHTOOL_A_BITSET_BITS attributes\";\n    for bit_nla in NlasIterator::new(raw) {\n        let bit_nla = &bit_nla.context(error_msg)?;\n        match bit_nla.kind() {\n            ETHTOOL_A_BITSET_BITS_BIT => {\n                let error_msg = \"Failed to parse ETHTOOL_A_BITSET_BITS_BIT attributes\";\n                let nlas = NlasIterator::new(bit_nla.value());\n                let mut cur_bit_info = EthtoolFeatureBit::new(has_mask);\n                for nla in nlas {\n                    let nla = &nla.context(error_msg)?;\n                    let payload = nla.value();\n                    match nla.kind() {\n                        ETHTOOL_A_BITSET_BIT_INDEX => {\n                            if cur_bit_info.index != 0 && !&cur_bit_info.name.is_empty() {\n                                feature_bits.push(cur_bit_info);\n                                cur_bit_info = EthtoolFeatureBit::new(has_mask);\n                            }\n                            cur_bit_info.index = parse_u32(payload)\n                                .context(\"Invald ETHTOOL_A_BITSET_BIT_INDEX value\")?;\n                        }\n                        ETHTOOL_A_BITSET_BIT_NAME => {\n                            cur_bit_info.name = parse_string(payload)\n                                .context(\"Invald ETHTOOL_A_BITSET_BIT_NAME value\")?;\n                        }\n                        ETHTOOL_A_BITSET_BIT_VALUE => {\n                            cur_bit_info.value = true;\n                        }\n                        _ => {\n                            warn!(\n                                \"Unknown ETHTOOL_A_BITSET_BITS_BIT {} {:?}\",\n                                nla.kind(),\n                                nla.value(),\n                            );\n                        }\n                    }\n                }\n                if cur_bit_info.index != 0 && !&cur_bit_info.name.is_empty() {\n                    feature_bits.push(cur_bit_info);\n                }\n            }\n            _ => {\n                warn!(\n                    \"Unknown ETHTOOL_A_BITSET_BITS kind {}, {:?}\",\n                    bit_nla.kind(),\n                    bit_nla.value()\n                );\n            }\n        };\n    }\n    Ok(feature_bits)\n}\n\npub(crate) fn parse_feature_nlas(buffer: &[u8]) -> Result<Vec<EthtoolAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\n            \"Failed to parse ethtool feature message attribute {:?}\",\n            nla\n        );\n        let nla = &nla.context(error_msg.clone())?;\n        let parsed = EthtoolFeatureAttr::parse(nla).context(error_msg)?;\n        nlas.push(EthtoolAttr::Feature(parsed));\n    }\n    Ok(nlas)\n}\n"
  },
  {
    "path": "ethtool/src/feature/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};\n\npub struct EthtoolFeatureGetRequest {\n    handle: EthtoolHandle,\n    iface_name: Option<String>,\n}\n\nimpl EthtoolFeatureGetRequest {\n    pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {\n        EthtoolFeatureGetRequest {\n            handle,\n            iface_name: iface_name.map(|i| i.to_string()),\n        }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n        let EthtoolFeatureGetRequest {\n            mut handle,\n            iface_name,\n        } = self;\n\n        let ethtool_msg = EthtoolMessage::new_feature_get(iface_name.as_deref());\n        ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await\n    }\n}\n"
  },
  {
    "path": "ethtool/src/feature/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{EthtoolFeatureGetRequest, EthtoolHandle};\n\npub struct EthtoolFeatureHandle(EthtoolHandle);\n\nimpl EthtoolFeatureHandle {\n    pub fn new(handle: EthtoolHandle) -> Self {\n        EthtoolFeatureHandle(handle)\n    }\n\n    /// Retrieve the ethtool features of a interface (equivalent to `ethtool -k eth1`)\n    pub fn get(&mut self, iface_name: Option<&str>) -> EthtoolFeatureGetRequest {\n        EthtoolFeatureGetRequest::new(self.0.clone(), iface_name)\n    }\n}\n"
  },
  {
    "path": "ethtool/src/feature/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub(crate) use attr::parse_feature_nlas;\npub use attr::{EthtoolFeatureAttr, EthtoolFeatureBit};\npub use get::EthtoolFeatureGetRequest;\npub use handle::EthtoolFeatureHandle;\n"
  },
  {
    "path": "ethtool/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{future::Either, FutureExt, Stream, StreamExt, TryStream};\nuse genetlink::GenetlinkHandle;\nuse netlink_packet_core::{NetlinkMessage, NLM_F_ACK, NLM_F_DUMP, NLM_F_REQUEST};\nuse netlink_packet_generic::GenlMessage;\nuse netlink_packet_utils::DecodeError;\n\nuse crate::{\n    try_ethtool,\n    EthtoolCoalesceHandle,\n    EthtoolError,\n    EthtoolFeatureHandle,\n    EthtoolLinkModeHandle,\n    EthtoolMessage,\n    EthtoolPauseHandle,\n    EthtoolRingHandle,\n};\n\n#[derive(Clone, Debug)]\npub struct EthtoolHandle {\n    pub handle: GenetlinkHandle,\n}\n\nimpl EthtoolHandle {\n    pub(crate) fn new(handle: GenetlinkHandle) -> Self {\n        EthtoolHandle { handle }\n    }\n\n    pub fn pause(&mut self) -> EthtoolPauseHandle {\n        EthtoolPauseHandle::new(self.clone())\n    }\n\n    pub fn feature(&mut self) -> EthtoolFeatureHandle {\n        EthtoolFeatureHandle::new(self.clone())\n    }\n\n    pub fn link_mode(&mut self) -> EthtoolLinkModeHandle {\n        EthtoolLinkModeHandle::new(self.clone())\n    }\n\n    pub fn ring(&mut self) -> EthtoolRingHandle {\n        EthtoolRingHandle::new(self.clone())\n    }\n\n    pub fn coalesce(&mut self) -> EthtoolCoalesceHandle {\n        EthtoolCoalesceHandle::new(self.clone())\n    }\n\n    pub async fn request(\n        &mut self,\n        message: NetlinkMessage<GenlMessage<EthtoolMessage>>,\n    ) -> Result<\n        impl Stream<Item = Result<NetlinkMessage<GenlMessage<EthtoolMessage>>, DecodeError>>,\n        EthtoolError,\n    > {\n        self.handle\n            .request(message)\n            .await\n            .map_err(|e| EthtoolError::RequestFailed(format!(\"BUG: Request failed with {}\", e)))\n    }\n}\n\npub(crate) async fn ethtool_execute(\n    handle: &mut EthtoolHandle,\n    is_dump: bool,\n    ethtool_msg: EthtoolMessage,\n) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n    let nl_header_flags = if is_dump {\n        // The NLM_F_ACK is required due to bug of kernel:\n        //  https://bugzilla.redhat.com/show_bug.cgi?id=1953847\n        // without `NLM_F_MULTI`, rust-netlink will not parse\n        // multiple netlink message in single socket reply.\n        // Using NLM_F_ACK will force rust-netlink to parse all till\n        // acked at the end.\n        NLM_F_DUMP | NLM_F_REQUEST | NLM_F_ACK\n    } else {\n        NLM_F_REQUEST\n    };\n\n    let mut nl_msg = NetlinkMessage::from(GenlMessage::from_payload(ethtool_msg));\n\n    nl_msg.header.flags = nl_header_flags;\n\n    match handle.request(nl_msg).await {\n        Ok(response) => Either::Left(response.map(move |msg| Ok(try_ethtool!(msg)))),\n        Err(e) => Either::Right(\n            futures::future::err::<GenlMessage<EthtoolMessage>, EthtoolError>(e).into_stream(),\n        ),\n    }\n}\n"
  },
  {
    "path": "ethtool/src/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::ffi::CString;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer},\n    parsers::{parse_string, parse_u32},\n    DecodeError,\n    Parseable,\n};\n\nconst ALTIFNAMSIZ: usize = 128;\nconst ETHTOOL_A_HEADER_DEV_INDEX: u16 = 1;\nconst ETHTOOL_A_HEADER_DEV_NAME: u16 = 2;\nconst ETHTOOL_A_HEADER_FLAGS: u16 = 3;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolHeader {\n    DevIndex(u32),\n    DevName(String),\n    Flags(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolHeader {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::DevIndex(_) | Self::Flags(_) => 4,\n            Self::DevName(s) => {\n                if s.len() + 1 > ALTIFNAMSIZ {\n                    ALTIFNAMSIZ\n                } else {\n                    s.len() + 1\n                }\n            }\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::DevIndex(_) => ETHTOOL_A_HEADER_DEV_INDEX,\n            Self::DevName(_) => ETHTOOL_A_HEADER_DEV_NAME,\n            Self::Flags(_) => ETHTOOL_A_HEADER_FLAGS,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::DevIndex(value) | Self::Flags(value) => NativeEndian::write_u32(buffer, *value),\n            Self::DevName(s) => str_to_zero_ended_u8_array(s, buffer, ALTIFNAMSIZ),\n            Self::Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolHeader {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_HEADER_DEV_INDEX => Self::DevIndex(\n                parse_u32(payload).context(\"invalid ETHTOOL_A_HEADER_DEV_INDEX value\")?,\n            ),\n            ETHTOOL_A_HEADER_FLAGS => {\n                Self::Flags(parse_u32(payload).context(\"invalid ETHTOOL_A_HEADER_FLAGS value\")?)\n            }\n            ETHTOOL_A_HEADER_DEV_NAME => Self::DevName(\n                parse_string(payload).context(\"invalid ETHTOOL_A_HEADER_DEV_NAME value\")?,\n            ),\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\nfn str_to_zero_ended_u8_array(src_str: &str, buffer: &mut [u8], max_size: usize) {\n    if let Ok(src_cstring) = CString::new(src_str.as_bytes()) {\n        let src_null_ended_str = src_cstring.into_bytes_with_nul();\n        if src_null_ended_str.len() > max_size {\n            buffer[..max_size].clone_from_slice(&src_null_ended_str[..max_size])\n        } else {\n            buffer[..src_null_ended_str.len()].clone_from_slice(&src_null_ended_str)\n        }\n    }\n}\n"
  },
  {
    "path": "ethtool/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod coalesce;\nmod connection;\nmod error;\nmod feature;\nmod handle;\nmod header;\nmod link_mode;\nmod macros;\nmod message;\nmod pause;\nmod ring;\n\npub use coalesce::{EthtoolCoalesceAttr, EthtoolCoalesceGetRequest, EthtoolCoalesceHandle};\n#[cfg(feature = \"tokio_socket\")]\npub use connection::new_connection;\npub use connection::new_connection_with_socket;\npub use error::EthtoolError;\npub use feature::{\n    EthtoolFeatureAttr,\n    EthtoolFeatureBit,\n    EthtoolFeatureGetRequest,\n    EthtoolFeatureHandle,\n};\npub use handle::EthtoolHandle;\npub use header::EthtoolHeader;\npub use link_mode::{\n    EthtoolLinkModeAttr,\n    EthtoolLinkModeDuplex,\n    EthtoolLinkModeGetRequest,\n    EthtoolLinkModeHandle,\n};\npub use message::{EthtoolAttr, EthtoolCmd, EthtoolMessage};\npub use pause::{\n    EthtoolPauseAttr,\n    EthtoolPauseGetRequest,\n    EthtoolPauseHandle,\n    EthtoolPauseStatAttr,\n};\npub use ring::{EthtoolRingAttr, EthtoolRingGetRequest, EthtoolRingHandle};\n\npub(crate) use handle::ethtool_execute;\n"
  },
  {
    "path": "ethtool/src/link_mode/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse log::warn;\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::{parse_string, parse_u32, parse_u8},\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nuse crate::{EthtoolAttr, EthtoolHeader};\n\nconst ETHTOOL_A_LINKMODES_HEADER: u16 = 1;\nconst ETHTOOL_A_LINKMODES_AUTONEG: u16 = 2;\nconst ETHTOOL_A_LINKMODES_OURS: u16 = 3;\nconst ETHTOOL_A_LINKMODES_PEER: u16 = 4;\nconst ETHTOOL_A_LINKMODES_SPEED: u16 = 5;\nconst ETHTOOL_A_LINKMODES_DUPLEX: u16 = 6;\nconst ETHTOOL_A_LINKMODES_SUBORDINATE_CFG: u16 = 7;\nconst ETHTOOL_A_LINKMODES_SUBORDINATE_STATE: u16 = 8;\nconst ETHTOOL_A_LINKMODES_LANES: u16 = 9;\n\nconst ETHTOOL_A_BITSET_BITS: u16 = 3;\n\nconst ETHTOOL_A_BITSET_BITS_BIT: u16 = 1;\n\nconst ETHTOOL_A_BITSET_BIT_INDEX: u16 = 1;\nconst ETHTOOL_A_BITSET_BIT_NAME: u16 = 2;\nconst ETHTOOL_A_BITSET_BIT_VALUE: u16 = 3;\n\nconst DUPLEX_HALF: u8 = 0x00;\nconst DUPLEX_FULL: u8 = 0x01;\nconst DUPLEX_UNKNOWN: u8 = 0xff;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolLinkModeDuplex {\n    Half,\n    Full,\n    Unknown,\n    Other(u8),\n}\n\nimpl From<u8> for EthtoolLinkModeDuplex {\n    fn from(d: u8) -> Self {\n        match d {\n            DUPLEX_HALF => Self::Half,\n            DUPLEX_FULL => Self::Full,\n            DUPLEX_UNKNOWN => Self::Unknown,\n            _ => Self::Other(d),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolLinkModeAttr {\n    Header(Vec<EthtoolHeader>),\n    Autoneg(bool),\n    Ours(Vec<String>),\n    Peer(Vec<String>),\n    Speed(u32),\n    Duplex(EthtoolLinkModeDuplex),\n    ControllerSubordinateCfg(u8),\n    ControllerSubordinateState(u8),\n    Lanes(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolLinkModeAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Header(hdrs) => hdrs.as_slice().buffer_len(),\n            Self::Autoneg(_)\n            | Self::Duplex(_)\n            | Self::ControllerSubordinateCfg(_)\n            | Self::ControllerSubordinateState(_) => 1,\n            Self::Ours(_) => {\n                todo!(\"Does not support changing ethtool link mode yet\")\n            }\n            Self::Peer(_) => {\n                todo!(\"Does not support changing ethtool link mode yet\")\n            }\n            Self::Speed(_) | Self::Lanes(_) => 4,\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Header(_) => ETHTOOL_A_LINKMODES_HEADER | NLA_F_NESTED,\n            Self::Autoneg(_) => ETHTOOL_A_LINKMODES_AUTONEG,\n            Self::Ours(_) => ETHTOOL_A_LINKMODES_OURS,\n            Self::Peer(_) => ETHTOOL_A_LINKMODES_PEER,\n            Self::Speed(_) => ETHTOOL_A_LINKMODES_SPEED,\n            Self::Duplex(_) => ETHTOOL_A_LINKMODES_DUPLEX,\n            Self::ControllerSubordinateCfg(_) => ETHTOOL_A_LINKMODES_SUBORDINATE_CFG,\n            Self::ControllerSubordinateState(_) => ETHTOOL_A_LINKMODES_SUBORDINATE_STATE,\n            Self::Lanes(_) => ETHTOOL_A_LINKMODES_LANES,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Header(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::Other(ref attr) => attr.emit(buffer),\n            _ => todo!(\"Does not support changing ethtool link mode yet\"),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolLinkModeAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_LINKMODES_HEADER => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse link_mode header attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolHeader::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Header(nlas)\n            }\n            ETHTOOL_A_LINKMODES_AUTONEG => Self::Autoneg(\n                parse_u8(payload).context(\"Invalid ETHTOOL_A_LINKMODES_AUTONEG value\")? == 1,\n            ),\n\n            ETHTOOL_A_LINKMODES_OURS => Self::Ours(parse_bitset_bits_nlas(payload)?),\n            ETHTOOL_A_LINKMODES_PEER => Self::Peer(parse_bitset_bits_nlas(payload)?),\n            ETHTOOL_A_LINKMODES_SPEED => {\n                Self::Speed(parse_u32(payload).context(\"Invalid ETHTOOL_A_LINKMODES_SPEED value\")?)\n            }\n            ETHTOOL_A_LINKMODES_DUPLEX => Self::Duplex(\n                parse_u8(payload)\n                    .context(\"Invalid ETHTOOL_A_LINKMODES_DUPLEX value\")?\n                    .into(),\n            ),\n            ETHTOOL_A_LINKMODES_SUBORDINATE_CFG => Self::ControllerSubordinateCfg(\n                parse_u8(payload).context(\"Invalid ETHTOOL_A_LINKMODES_SUBORDINATE_CFG value\")?,\n            ),\n            ETHTOOL_A_LINKMODES_SUBORDINATE_STATE => Self::ControllerSubordinateState(\n                parse_u8(payload).context(\"Invalid ETHTOOL_A_LINKMODES_SUBORDINATE_STATE value\")?,\n            ),\n            ETHTOOL_A_LINKMODES_LANES => {\n                Self::Lanes(parse_u32(payload).context(\"Invalid ETHTOOL_A_LINKMODES_LANES value\")?)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\nfn parse_bitset_bits_nlas(raw: &[u8]) -> Result<Vec<String>, DecodeError> {\n    let error_msg = \"failed to parse mode bit sets\";\n    for nla in NlasIterator::new(raw) {\n        let nla = &nla.context(error_msg)?;\n        if nla.kind() == ETHTOOL_A_BITSET_BITS {\n            return parse_bitset_bits_nla(nla.value());\n        }\n    }\n    Err(\"No ETHTOOL_A_BITSET_BITS NLA found\".into())\n}\n\nfn parse_bitset_bits_nla(raw: &[u8]) -> Result<Vec<String>, DecodeError> {\n    let mut modes = Vec::new();\n    let error_msg = \"Failed to parse ETHTOOL_A_BITSET_BITS attributes\";\n    for bit_nla in NlasIterator::new(raw) {\n        let bit_nla = &bit_nla.context(error_msg)?;\n        match bit_nla.kind() {\n            ETHTOOL_A_BITSET_BITS_BIT => {\n                let error_msg = \"Failed to parse ETHTOOL_A_BITSET_BITS_BIT attributes\";\n                let nlas = NlasIterator::new(bit_nla.value());\n                for nla in nlas {\n                    let nla = &nla.context(error_msg)?;\n                    let payload = nla.value();\n                    match nla.kind() {\n                        ETHTOOL_A_BITSET_BIT_INDEX | ETHTOOL_A_BITSET_BIT_VALUE => {\n                            // ignored\n                        }\n                        ETHTOOL_A_BITSET_BIT_NAME => {\n                            modes.push(\n                                parse_string(payload)\n                                    .context(\"Invald ETHTOOL_A_BITSET_BIT_NAME value\")?,\n                            );\n                        }\n                        _ => {\n                            warn!(\n                                \"Unknown ETHTOOL_A_BITSET_BITS_BIT {} {:?}\",\n                                nla.kind(),\n                                nla.value(),\n                            );\n                        }\n                    }\n                }\n            }\n            _ => {\n                warn!(\n                    \"Unknown ETHTOOL_A_BITSET_BITS kind {}, {:?}\",\n                    bit_nla.kind(),\n                    bit_nla.value()\n                );\n            }\n        };\n    }\n    Ok(modes)\n}\n\npub(crate) fn parse_link_mode_nlas(buffer: &[u8]) -> Result<Vec<EthtoolAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\n            \"Failed to parse ethtool link_mode message attribute {:?}\",\n            nla\n        );\n        let nla = &nla.context(error_msg.clone())?;\n        let parsed = EthtoolLinkModeAttr::parse(nla).context(error_msg)?;\n        nlas.push(EthtoolAttr::LinkMode(parsed));\n    }\n    Ok(nlas)\n}\n"
  },
  {
    "path": "ethtool/src/link_mode/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};\n\npub struct EthtoolLinkModeGetRequest {\n    handle: EthtoolHandle,\n    iface_name: Option<String>,\n}\n\nimpl EthtoolLinkModeGetRequest {\n    pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {\n        EthtoolLinkModeGetRequest {\n            handle,\n            iface_name: iface_name.map(|i| i.to_string()),\n        }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n        let EthtoolLinkModeGetRequest {\n            mut handle,\n            iface_name,\n        } = self;\n\n        let ethtool_msg = EthtoolMessage::new_link_mode_get(iface_name.as_deref());\n        ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await\n    }\n}\n"
  },
  {
    "path": "ethtool/src/link_mode/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{EthtoolHandle, EthtoolLinkModeGetRequest};\n\npub struct EthtoolLinkModeHandle(EthtoolHandle);\n\nimpl EthtoolLinkModeHandle {\n    pub fn new(handle: EthtoolHandle) -> Self {\n        EthtoolLinkModeHandle(handle)\n    }\n\n    /// Retrieve the ethtool link_modes(duplex, link speed and etc) of a interface\n    pub fn get(&mut self, iface_name: Option<&str>) -> EthtoolLinkModeGetRequest {\n        EthtoolLinkModeGetRequest::new(self.0.clone(), iface_name)\n    }\n}\n"
  },
  {
    "path": "ethtool/src/link_mode/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub(crate) use attr::parse_link_mode_nlas;\npub use attr::{EthtoolLinkModeAttr, EthtoolLinkModeDuplex};\npub use get::EthtoolLinkModeGetRequest;\npub use handle::EthtoolLinkModeHandle;\n"
  },
  {
    "path": "ethtool/src/macros.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_export]\nmacro_rules! try_ethtool {\n    ($msg: expr) => {{\n        use netlink_packet_core::{NetlinkMessage, NetlinkPayload};\n        use $crate::EthtoolError;\n\n        match $msg {\n            Ok(msg) => {\n                let (header, payload) = msg.into_parts();\n                match payload {\n                    NetlinkPayload::InnerMessage(msg) => msg,\n                    NetlinkPayload::Error(err) => return Err(EthtoolError::NetlinkError(err)),\n                    _ => {\n                        return Err(EthtoolError::UnexpectedMessage(NetlinkMessage::new(\n                            header, payload,\n                        )))\n                    }\n                }\n            }\n            Err(e) => return Err(EthtoolError::Bug(format!(\"BUG: decode error {:?}\", e))),\n        }\n    }};\n}\n"
  },
  {
    "path": "ethtool/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_generic::{GenlFamily, GenlHeader};\nuse netlink_packet_utils::{nla::Nla, Emitable, ParseableParametrized};\n\nuse crate::{\n    coalesce::{parse_coalesce_nlas, EthtoolCoalesceAttr},\n    feature::{parse_feature_nlas, EthtoolFeatureAttr},\n    link_mode::{parse_link_mode_nlas, EthtoolLinkModeAttr},\n    pause::{parse_pause_nlas, EthtoolPauseAttr},\n    ring::{parse_ring_nlas, EthtoolRingAttr},\n    EthtoolHeader,\n};\n\nconst ETHTOOL_MSG_PAUSE_GET: u8 = 21;\nconst ETHTOOL_MSG_PAUSE_GET_REPLY: u8 = 22;\nconst ETHTOOL_MSG_FEATURES_GET: u8 = 11;\nconst ETHTOOL_MSG_FEATURES_GET_REPLY: u8 = 11;\nconst ETHTOOL_MSG_LINKMODES_GET: u8 = 4;\nconst ETHTOOL_MSG_LINKMODES_GET_REPLY: u8 = 4;\nconst ETHTOOL_MSG_RINGS_GET: u8 = 15;\nconst ETHTOOL_MSG_RINGS_GET_REPLY: u8 = 16;\nconst ETHTOOL_MSG_COALESCE_GET: u8 = 19;\nconst ETHTOOL_MSG_COALESCE_GET_REPLY: u8 = 20;\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum EthtoolCmd {\n    PauseGet,\n    PauseGetReply,\n    FeatureGet,\n    FeatureGetReply,\n    LinkModeGet,\n    LinkModeGetReply,\n    RingGet,\n    RingGetReply,\n    CoalesceGet,\n    CoalesceGetReply,\n}\n\nimpl From<EthtoolCmd> for u8 {\n    fn from(cmd: EthtoolCmd) -> Self {\n        match cmd {\n            EthtoolCmd::PauseGet => ETHTOOL_MSG_PAUSE_GET,\n            EthtoolCmd::PauseGetReply => ETHTOOL_MSG_PAUSE_GET_REPLY,\n            EthtoolCmd::FeatureGet => ETHTOOL_MSG_FEATURES_GET,\n            EthtoolCmd::FeatureGetReply => ETHTOOL_MSG_FEATURES_GET_REPLY,\n            EthtoolCmd::LinkModeGet => ETHTOOL_MSG_LINKMODES_GET,\n            EthtoolCmd::LinkModeGetReply => ETHTOOL_MSG_LINKMODES_GET_REPLY,\n            EthtoolCmd::RingGet => ETHTOOL_MSG_RINGS_GET,\n            EthtoolCmd::RingGetReply => ETHTOOL_MSG_RINGS_GET_REPLY,\n            EthtoolCmd::CoalesceGet => ETHTOOL_MSG_COALESCE_GET,\n            EthtoolCmd::CoalesceGetReply => ETHTOOL_MSG_COALESCE_GET_REPLY,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolAttr {\n    Pause(EthtoolPauseAttr),\n    Feature(EthtoolFeatureAttr),\n    LinkMode(EthtoolLinkModeAttr),\n    Ring(EthtoolRingAttr),\n    Coalesce(EthtoolCoalesceAttr),\n}\n\nimpl Nla for EthtoolAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Pause(attr) => attr.value_len(),\n            Self::Feature(attr) => attr.value_len(),\n            Self::LinkMode(attr) => attr.value_len(),\n            Self::Ring(attr) => attr.value_len(),\n            Self::Coalesce(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Pause(attr) => attr.kind(),\n            Self::Feature(attr) => attr.kind(),\n            Self::LinkMode(attr) => attr.kind(),\n            Self::Ring(attr) => attr.kind(),\n            Self::Coalesce(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Pause(attr) => attr.emit_value(buffer),\n            Self::Feature(attr) => attr.emit_value(buffer),\n            Self::LinkMode(attr) => attr.emit_value(buffer),\n            Self::Ring(attr) => attr.emit_value(buffer),\n            Self::Coalesce(attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct EthtoolMessage {\n    pub cmd: EthtoolCmd,\n    pub nlas: Vec<EthtoolAttr>,\n}\n\nimpl GenlFamily for EthtoolMessage {\n    fn family_name() -> &'static str {\n        \"ethtool\"\n    }\n\n    fn version(&self) -> u8 {\n        1\n    }\n\n    fn command(&self) -> u8 {\n        self.cmd.into()\n    }\n}\n\nimpl EthtoolMessage {\n    pub fn new_pause_get(iface_name: Option<&str>) -> Self {\n        let nlas = match iface_name {\n            Some(s) => vec![EthtoolAttr::Pause(EthtoolPauseAttr::Header(vec![\n                EthtoolHeader::DevName(s.to_string()),\n            ]))],\n            None => vec![EthtoolAttr::Pause(EthtoolPauseAttr::Header(vec![]))],\n        };\n        EthtoolMessage {\n            cmd: EthtoolCmd::PauseGet,\n            nlas,\n        }\n    }\n\n    pub fn new_feature_get(iface_name: Option<&str>) -> Self {\n        let nlas = match iface_name {\n            Some(s) => vec![EthtoolAttr::Feature(EthtoolFeatureAttr::Header(vec![\n                EthtoolHeader::DevName(s.to_string()),\n            ]))],\n            None => vec![EthtoolAttr::Feature(EthtoolFeatureAttr::Header(vec![]))],\n        };\n        EthtoolMessage {\n            cmd: EthtoolCmd::FeatureGet,\n            nlas,\n        }\n    }\n\n    pub fn new_link_mode_get(iface_name: Option<&str>) -> Self {\n        let nlas = match iface_name {\n            Some(s) => vec![EthtoolAttr::LinkMode(EthtoolLinkModeAttr::Header(vec![\n                EthtoolHeader::DevName(s.to_string()),\n            ]))],\n            None => vec![EthtoolAttr::LinkMode(EthtoolLinkModeAttr::Header(vec![]))],\n        };\n        EthtoolMessage {\n            cmd: EthtoolCmd::LinkModeGet,\n            nlas,\n        }\n    }\n\n    pub fn new_ring_get(iface_name: Option<&str>) -> Self {\n        let nlas = match iface_name {\n            Some(s) => vec![EthtoolAttr::Ring(EthtoolRingAttr::Header(vec![\n                EthtoolHeader::DevName(s.to_string()),\n            ]))],\n            None => vec![EthtoolAttr::Ring(EthtoolRingAttr::Header(vec![]))],\n        };\n        EthtoolMessage {\n            cmd: EthtoolCmd::RingGet,\n            nlas,\n        }\n    }\n\n    pub fn new_coalesce_get(iface_name: Option<&str>) -> Self {\n        let nlas = match iface_name {\n            Some(s) => vec![EthtoolAttr::Coalesce(EthtoolCoalesceAttr::Header(vec![\n                EthtoolHeader::DevName(s.to_string()),\n            ]))],\n            None => vec![EthtoolAttr::Coalesce(EthtoolCoalesceAttr::Header(vec![]))],\n        };\n        EthtoolMessage {\n            cmd: EthtoolCmd::CoalesceGet,\n            nlas,\n        }\n    }\n}\n\nimpl Emitable for EthtoolMessage {\n    fn buffer_len(&self) -> usize {\n        self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.nlas.as_slice().emit(buffer)\n    }\n}\n\nimpl ParseableParametrized<[u8], GenlHeader> for EthtoolMessage {\n    fn parse_with_param(buffer: &[u8], header: GenlHeader) -> Result<Self, DecodeError> {\n        Ok(match header.cmd {\n            ETHTOOL_MSG_PAUSE_GET_REPLY => Self {\n                cmd: EthtoolCmd::PauseGetReply,\n                nlas: parse_pause_nlas(buffer)?,\n            },\n            ETHTOOL_MSG_FEATURES_GET_REPLY => Self {\n                cmd: EthtoolCmd::FeatureGetReply,\n                nlas: parse_feature_nlas(buffer)?,\n            },\n            ETHTOOL_MSG_LINKMODES_GET_REPLY => Self {\n                cmd: EthtoolCmd::LinkModeGetReply,\n                nlas: parse_link_mode_nlas(buffer)?,\n            },\n            ETHTOOL_MSG_RINGS_GET_REPLY => Self {\n                cmd: EthtoolCmd::RingGetReply,\n                nlas: parse_ring_nlas(buffer)?,\n            },\n            ETHTOOL_MSG_COALESCE_GET_REPLY => Self {\n                cmd: EthtoolCmd::CoalesceGetReply,\n                nlas: parse_coalesce_nlas(buffer)?,\n            },\n            cmd => {\n                return Err(DecodeError::from(format!(\n                    \"Unsupported ethtool reply command: {}\",\n                    cmd\n                )))\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "ethtool/src/pause/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::{parse_u64, parse_u8},\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nuse crate::{EthtoolAttr, EthtoolHeader};\n\nconst ETHTOOL_A_PAUSE_HEADER: u16 = 1;\nconst ETHTOOL_A_PAUSE_AUTONEG: u16 = 2;\nconst ETHTOOL_A_PAUSE_RX: u16 = 3;\nconst ETHTOOL_A_PAUSE_TX: u16 = 4;\nconst ETHTOOL_A_PAUSE_STATS: u16 = 5;\n\nconst ETHTOOL_A_PAUSE_STAT_TX_FRAMES: u16 = 2;\nconst ETHTOOL_A_PAUSE_STAT_RX_FRAMES: u16 = 3;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolPauseStatAttr {\n    Rx(u64),\n    Tx(u64),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolPauseStatAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Rx(_) | Self::Tx(_) => 8,\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Rx(_) => ETHTOOL_A_PAUSE_STAT_RX_FRAMES,\n            Self::Tx(_) => ETHTOOL_A_PAUSE_STAT_RX_FRAMES,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Rx(value) | Self::Tx(value) => NativeEndian::write_u64(buffer, *value),\n            Self::Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolPauseStatAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_PAUSE_STAT_TX_FRAMES => Self::Tx(\n                parse_u64(payload).context(\"invalid ETHTOOL_A_PAUSE_STAT_TX_FRAMES value\")?,\n            ),\n            ETHTOOL_A_PAUSE_STAT_RX_FRAMES => Self::Rx(\n                parse_u64(payload).context(\"invalid ETHTOOL_A_PAUSE_STAT_RX_FRAMES value\")?,\n            ),\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolPauseAttr {\n    Header(Vec<EthtoolHeader>),\n    AutoNeg(bool),\n    Rx(bool),\n    Tx(bool),\n    Stats(Vec<EthtoolPauseStatAttr>),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolPauseAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Header(hdrs) => hdrs.as_slice().buffer_len(),\n            Self::AutoNeg(_) | Self::Rx(_) | Self::Tx(_) => 1,\n            Self::Stats(ref nlas) => nlas.as_slice().buffer_len(),\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Header(_) => ETHTOOL_A_PAUSE_HEADER | NLA_F_NESTED,\n            Self::AutoNeg(_) => ETHTOOL_A_PAUSE_AUTONEG,\n            Self::Rx(_) => ETHTOOL_A_PAUSE_RX,\n            Self::Tx(_) => ETHTOOL_A_PAUSE_TX,\n            Self::Stats(_) => ETHTOOL_A_PAUSE_STATS | NLA_F_NESTED,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Header(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::AutoNeg(value) | Self::Rx(value) | Self::Tx(value) => buffer[0] = *value as u8,\n            Self::Stats(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolPauseAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_PAUSE_HEADER => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse pause header attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolHeader::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Header(nlas)\n            }\n            ETHTOOL_A_PAUSE_AUTONEG => Self::AutoNeg(\n                parse_u8(payload).context(\"invalid ETHTOOL_A_PAUSE_AUTONEG value\")? == 1,\n            ),\n            ETHTOOL_A_PAUSE_RX => {\n                Self::Rx(parse_u8(payload).context(\"invalid ETHTOOL_A_PAUSE_RX value\")? == 1)\n            }\n            ETHTOOL_A_PAUSE_TX => {\n                Self::Tx(parse_u8(payload).context(\"invalid ETHTOOL_A_PAUSE_TX value\")? == 1)\n            }\n            ETHTOOL_A_PAUSE_STATS => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse pause stats attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolPauseStatAttr::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Stats(nlas)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\npub(crate) fn parse_pause_nlas(buffer: &[u8]) -> Result<Vec<EthtoolAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\"Failed to parse ethtool pause message attribute {:?}\", nla);\n        let nla = &nla.context(error_msg.clone())?;\n        let parsed = EthtoolPauseAttr::parse(nla).context(error_msg)?;\n        nlas.push(EthtoolAttr::Pause(parsed));\n    }\n    Ok(nlas)\n}\n"
  },
  {
    "path": "ethtool/src/pause/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};\n\npub struct EthtoolPauseGetRequest {\n    handle: EthtoolHandle,\n    iface_name: Option<String>,\n}\n\nimpl EthtoolPauseGetRequest {\n    pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {\n        EthtoolPauseGetRequest {\n            handle,\n            iface_name: iface_name.map(|i| i.to_string()),\n        }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n        let EthtoolPauseGetRequest {\n            mut handle,\n            iface_name,\n        } = self;\n\n        let ethtool_msg = EthtoolMessage::new_pause_get(iface_name.as_deref());\n        ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await\n    }\n}\n"
  },
  {
    "path": "ethtool/src/pause/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{EthtoolHandle, EthtoolPauseGetRequest};\n\npub struct EthtoolPauseHandle(EthtoolHandle);\n\nimpl EthtoolPauseHandle {\n    pub fn new(handle: EthtoolHandle) -> Self {\n        EthtoolPauseHandle(handle)\n    }\n\n    /// Retrieve the pause setting of a interface (equivalent to `ethtool -a eth1`)\n    pub fn get(&mut self, iface_name: Option<&str>) -> EthtoolPauseGetRequest {\n        EthtoolPauseGetRequest::new(self.0.clone(), iface_name)\n    }\n}\n"
  },
  {
    "path": "ethtool/src/pause/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub(crate) use attr::parse_pause_nlas;\npub use attr::{EthtoolPauseAttr, EthtoolPauseStatAttr};\npub use get::EthtoolPauseGetRequest;\npub use handle::EthtoolPauseHandle;\n"
  },
  {
    "path": "ethtool/src/ring/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::parse_u32,\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nuse crate::{EthtoolAttr, EthtoolHeader};\n\nconst ETHTOOL_A_RINGS_HEADER: u16 = 1;\nconst ETHTOOL_A_RINGS_RX_MAX: u16 = 2;\nconst ETHTOOL_A_RINGS_RX_MINI_MAX: u16 = 3;\nconst ETHTOOL_A_RINGS_RX_JUMBO_MAX: u16 = 4;\nconst ETHTOOL_A_RINGS_TX_MAX: u16 = 5;\nconst ETHTOOL_A_RINGS_RX: u16 = 6;\nconst ETHTOOL_A_RINGS_RX_MINI: u16 = 7;\nconst ETHTOOL_A_RINGS_RX_JUMBO: u16 = 8;\nconst ETHTOOL_A_RINGS_TX: u16 = 9;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum EthtoolRingAttr {\n    Header(Vec<EthtoolHeader>),\n    RxMax(u32),\n    RxMiniMax(u32),\n    RxJumboMax(u32),\n    TxMax(u32),\n    Rx(u32),\n    RxMini(u32),\n    RxJumbo(u32),\n    Tx(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for EthtoolRingAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Header(hdrs) => hdrs.as_slice().buffer_len(),\n            Self::RxMax(_)\n            | Self::RxMiniMax(_)\n            | Self::RxJumboMax(_)\n            | Self::TxMax(_)\n            | Self::Rx(_)\n            | Self::RxMini(_)\n            | Self::RxJumbo(_)\n            | Self::Tx(_) => 4,\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Header(_) => ETHTOOL_A_RINGS_HEADER | NLA_F_NESTED,\n            Self::RxMax(_) => ETHTOOL_A_RINGS_RX_MAX,\n            Self::RxMiniMax(_) => ETHTOOL_A_RINGS_RX_MINI_MAX,\n            Self::RxJumboMax(_) => ETHTOOL_A_RINGS_RX_JUMBO_MAX,\n            Self::TxMax(_) => ETHTOOL_A_RINGS_TX_MAX,\n            Self::Rx(_) => ETHTOOL_A_RINGS_RX,\n            Self::RxMini(_) => ETHTOOL_A_RINGS_RX_MINI,\n            Self::RxJumbo(_) => ETHTOOL_A_RINGS_RX_JUMBO,\n            Self::Tx(_) => ETHTOOL_A_RINGS_TX,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Header(ref nlas) => nlas.as_slice().emit(buffer),\n            Self::RxMax(d)\n            | Self::RxMiniMax(d)\n            | Self::RxJumboMax(d)\n            | Self::TxMax(d)\n            | Self::Rx(d)\n            | Self::RxMini(d)\n            | Self::RxJumbo(d)\n            | Self::Tx(d) => NativeEndian::write_u32(buffer, *d),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for EthtoolRingAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            ETHTOOL_A_RINGS_HEADER => {\n                let mut nlas = Vec::new();\n                let error_msg = \"failed to parse ring header attributes\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = EthtoolHeader::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                Self::Header(nlas)\n            }\n            ETHTOOL_A_RINGS_RX_MAX => {\n                Self::RxMax(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX_MAX value\")?)\n            }\n\n            ETHTOOL_A_RINGS_RX_MINI_MAX => Self::RxMiniMax(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX_MINI_MAX value\")?,\n            ),\n            ETHTOOL_A_RINGS_RX_JUMBO_MAX => Self::RxJumboMax(\n                parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX_JUMBO_MAX value\")?,\n            ),\n            ETHTOOL_A_RINGS_TX_MAX => {\n                Self::TxMax(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_TX_MAX value\")?)\n            }\n            ETHTOOL_A_RINGS_RX => {\n                Self::Rx(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX value\")?)\n            }\n            ETHTOOL_A_RINGS_RX_MINI => {\n                Self::RxMini(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX_MINI value\")?)\n            }\n            ETHTOOL_A_RINGS_RX_JUMBO => {\n                Self::RxJumbo(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_RX_JUMBO value\")?)\n            }\n            ETHTOOL_A_RINGS_TX => {\n                Self::Tx(parse_u32(payload).context(\"Invalid ETHTOOL_A_RINGS_TX value\")?)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n\npub(crate) fn parse_ring_nlas(buffer: &[u8]) -> Result<Vec<EthtoolAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\"Failed to parse ethtool ring message attribute {:?}\", nla);\n        let nla = &nla.context(error_msg.clone())?;\n        let parsed = EthtoolRingAttr::parse(nla).context(error_msg)?;\n        nlas.push(EthtoolAttr::Ring(parsed));\n    }\n    Ok(nlas)\n}\n"
  },
  {
    "path": "ethtool/src/ring/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{ethtool_execute, EthtoolError, EthtoolHandle, EthtoolMessage};\n\npub struct EthtoolRingGetRequest {\n    handle: EthtoolHandle,\n    iface_name: Option<String>,\n}\n\nimpl EthtoolRingGetRequest {\n    pub(crate) fn new(handle: EthtoolHandle, iface_name: Option<&str>) -> Self {\n        EthtoolRingGetRequest {\n            handle,\n            iface_name: iface_name.map(|i| i.to_string()),\n        }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<EthtoolMessage>, Error = EthtoolError> {\n        let EthtoolRingGetRequest {\n            mut handle,\n            iface_name,\n        } = self;\n\n        let ethtool_msg = EthtoolMessage::new_ring_get(iface_name.as_deref());\n        ethtool_execute(&mut handle, iface_name.is_none(), ethtool_msg).await\n    }\n}\n"
  },
  {
    "path": "ethtool/src/ring/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{EthtoolHandle, EthtoolRingGetRequest};\n\npub struct EthtoolRingHandle(EthtoolHandle);\n\nimpl EthtoolRingHandle {\n    pub fn new(handle: EthtoolHandle) -> Self {\n        EthtoolRingHandle(handle)\n    }\n\n    /// Retrieve the ethtool rings of a interface (equivalent to `ethtool -g eth1`)\n    pub fn get(&mut self, iface_name: Option<&str>) -> EthtoolRingGetRequest {\n        EthtoolRingGetRequest::new(self.0.clone(), iface_name)\n    }\n}\n"
  },
  {
    "path": "ethtool/src/ring/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub(crate) use attr::parse_ring_nlas;\n\npub use attr::EthtoolRingAttr;\npub use get::EthtoolRingGetRequest;\npub use handle::EthtoolRingHandle;\n"
  },
  {
    "path": "ethtool/tests/dump_link_modes.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n#[test]\n// CI container normally have a veth for external communication which support link modes of ethtool.\nfn test_dump_link_modes() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(dump_link_modes());\n}\n\nasync fn dump_link_modes() {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut link_modes_handle = handle.link_mode().get(None).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = link_modes_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    let ethtool_msg = &msgs[0].payload;\n    println!(\"ethtool_msg {:?}\", &ethtool_msg);\n\n    assert!(ethtool_msg.cmd == ethtool::EthtoolCmd::LinkModeGetReply);\n    assert!(ethtool_msg.nlas.len() > 1);\n}\n"
  },
  {
    "path": "ethtool/tests/get_features_lo.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\n#[test]\nfn test_get_features_of_loopback() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_feature(Some(\"lo\")));\n}\n\nasync fn get_feature(iface_name: Option<&str>) {\n    let (connection, mut handle, _) = ethtool::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut feature_handle = handle.feature().get(iface_name).execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = feature_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(msgs.len() == 1);\n    let ethtool_msg = &msgs[0].payload;\n\n    assert!(ethtool_msg.cmd == ethtool::EthtoolCmd::FeatureGetReply);\n    assert!(ethtool_msg.nlas.len() > 1);\n    assert!(\n        ethtool_msg.nlas[0]\n            == ethtool::EthtoolAttr::Feature(ethtool::EthtoolFeatureAttr::Header(vec![\n                ethtool::EthtoolHeader::DevIndex(1),\n                ethtool::EthtoolHeader::DevName(\"lo\".into())\n            ]))\n    );\n}\n"
  },
  {
    "path": "genetlink/Cargo.toml",
    "content": "[package]\nname = \"genetlink\"\nversion = \"0.2.3\"\nauthors = [\"Leo <leo881003@gmail.com>\"]\nedition = \"2018\"\nhomepage = \"https://github.com/little-dude/netlink\"\nrepository = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\ndescription = \"communicate with generic netlink\"\n\n[features]\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-proto/tokio_socket\", \"tokio\"]\nsmol_socket = [\"netlink-proto/smol_socket\",\"async-std\"]\n\n[dependencies]\nfutures = \"0.3.16\"\nnetlink-proto = { default-features = false, version = \"0.10\" , path = \"../netlink-proto\" }\nnetlink-packet-generic = { version = \"0.3.1\", path = \"../netlink-packet-generic\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\ntokio = { version = \"1.9.0\", features = [\"rt\"], optional = true }\nasync-std = { version = \"1.9.0\", optional = true }\nthiserror = \"1.0.26\"\n\n[dev-dependencies]\nanyhow = \"1.0.42\"\ntokio = { version = \"1.9.0\", features = [\"rt\", \"rt-multi-thread\", \"macros\"] }\n\n[[example]]\nname = \"list_genetlink_family\"\nrequired-features = [\"tokio_socket\"]\n\n[[example]]\nname = \"dump_family_policy\"\nrequired-features = [\"tokio_socket\"]\n"
  },
  {
    "path": "genetlink/examples/dump_family_policy.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::env::args;\n\nuse anyhow::{bail, Error};\nuse futures::StreamExt;\nuse genetlink::new_connection;\nuse netlink_packet_core::{\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\nuse netlink_packet_generic::{\n    ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},\n    GenlMessage,\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), Error> {\n    let argv: Vec<_> = args().collect();\n\n    if argv.len() < 2 {\n        eprintln!(\"Usage: dump_family_policy <family name>\");\n        bail!(\"Required arguments not given\");\n    }\n\n    let nlmsg = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_DUMP,\n            ..Default::default()\n        },\n        payload: GenlMessage::from_payload(GenlCtrl {\n            cmd: GenlCtrlCmd::GetPolicy,\n            nlas: vec![GenlCtrlAttrs::FamilyName(argv[1].to_owned())],\n        })\n        .into(),\n    };\n    let (conn, mut handle, _) = new_connection()?;\n    tokio::spawn(conn);\n\n    let mut responses = handle.request(nlmsg).await?;\n\n    while let Some(result) = responses.next().await {\n        let resp = result?;\n        match resp.payload {\n            NetlinkPayload::InnerMessage(genlmsg) => {\n                if genlmsg.payload.cmd == GenlCtrlCmd::GetPolicy {\n                    println!(\"<<< {:?}\", genlmsg);\n                }\n            }\n            NetlinkPayload::Error(err) => {\n                eprintln!(\"Received a netlink error message: {:?}\", err);\n                bail!(err);\n            }\n            _ => {}\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "genetlink/examples/list_genetlink_family.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Example of listing generic families based on `netlink_proto`\n//!\n//! This example's functionality is same as the identical name example in `netlink_packet_generic`.\n//! But this example shows you the usage of this crate to run generic netlink protocol asynchronously.\n\nuse anyhow::{bail, Error};\nuse futures::StreamExt;\nuse genetlink::new_connection;\nuse netlink_packet_core::{\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\nuse netlink_packet_generic::{\n    ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},\n    GenlMessage,\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), Error> {\n    let nlmsg = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_DUMP,\n            ..Default::default()\n        },\n        payload: GenlMessage::from_payload(GenlCtrl {\n            cmd: GenlCtrlCmd::GetFamily,\n            nlas: vec![],\n        })\n        .into(),\n    };\n    let (conn, mut handle, _) = new_connection()?;\n    tokio::spawn(conn);\n\n    let mut responses = handle.request(nlmsg).await?;\n\n    while let Some(result) = responses.next().await {\n        let resp = result?;\n        match resp.payload {\n            NetlinkPayload::InnerMessage(genlmsg) => {\n                if genlmsg.payload.cmd == GenlCtrlCmd::NewFamily {\n                    print_entry(genlmsg.payload.nlas);\n                }\n            }\n            NetlinkPayload::Error(err) => {\n                eprintln!(\"Received a netlink error message: {:?}\", err);\n                bail!(err);\n            }\n            _ => {}\n        }\n    }\n\n    Ok(())\n}\n\nfn print_entry(entry: Vec<GenlCtrlAttrs>) {\n    let family_id = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::FamilyId(id) = nla {\n                Some(*id)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find FamilyId attribute\");\n    let family_name = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::FamilyName(name) = nla {\n                Some(name.as_str())\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find FamilyName attribute\");\n    let version = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::Version(ver) = nla {\n                Some(*ver)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find Version attribute\");\n    let hdrsize = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::HdrSize(hdr) = nla {\n                Some(*hdr)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find HdrSize attribute\");\n\n    if hdrsize == 0 {\n        println!(\"0x{:04x} {} [Version {}]\", family_id, family_name, version);\n    } else {\n        println!(\n            \"0x{:04x} {} [Version {}] [Header {} bytes]\",\n            family_id, family_name, version, hdrsize\n        );\n    }\n}\n"
  },
  {
    "path": "genetlink/src/connection.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{message::RawGenlMessage, GenetlinkHandle};\nuse futures::channel::mpsc::UnboundedReceiver;\nuse netlink_packet_core::NetlinkMessage;\nuse netlink_proto::{\n    self,\n    sys::{protocols::NETLINK_GENERIC, AsyncSocket, SocketAddr},\n    Connection,\n};\nuse std::io;\n\n/// Construct a generic netlink connection\n///\n/// The function would return a tuple containing three objects.\n/// - an async netlink connection\n/// - a connection handle to interact with the connection\n/// - a receiver of the unsolicited messages\n///\n/// The connection object is also a event loop which implements [`std::future::Future`].\n/// In most cases, users spawn it on an async runtime and use the handle to send\n/// messages. For detailed documentation, please refer to [`netlink_proto::new_connection`].\n///\n/// The [`GenetlinkHandle`] can send and receive any type of generic netlink message.\n/// And it can automatic resolve the generic family id before sending.\n#[cfg(feature = \"tokio_socket\")]\n#[allow(clippy::type_complexity)]\npub fn new_connection() -> io::Result<(\n    Connection<RawGenlMessage>,\n    GenetlinkHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)> {\n    new_connection_with_socket()\n}\n\n/// Variant of [`new_connection`] that allows specifying a socket type to use for async handling\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<S>() -> io::Result<(\n    Connection<RawGenlMessage, S>,\n    GenetlinkHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)>\nwhere\n    S: AsyncSocket,\n{\n    let (conn, handle, messages) = netlink_proto::new_connection_with_socket(NETLINK_GENERIC)?;\n    Ok((conn, GenetlinkHandle::new(handle), messages))\n}\n"
  },
  {
    "path": "genetlink/src/error.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::message::RawGenlMessage;\n\n/// Error type of genetlink\n#[derive(Debug, Error)]\npub enum GenetlinkError {\n    #[error(\"Failed to send netlink request\")]\n    ProtocolError(#[from] netlink_proto::Error<RawGenlMessage>),\n    #[error(\"Failed to decode generic packet\")]\n    DecodeError(#[from] netlink_packet_utils::DecodeError),\n    #[error(\"Netlink error message: {0}\")]\n    NetlinkError(std::io::Error),\n    #[error(\"Cannot find specified netlink attribute: {0}\")]\n    AttributeNotFound(String),\n    #[error(\"Desire netlink message type not received\")]\n    NoMessageReceived,\n}\n\n// Since `netlink_packet_core::error::ErrorMessage` doesn't impl `Error` trait,\n// it need to convert to `std::io::Error` here\nimpl From<netlink_packet_core::error::ErrorMessage> for GenetlinkError {\n    fn from(err_msg: netlink_packet_core::error::ErrorMessage) -> Self {\n        Self::NetlinkError(err_msg.to_io())\n    }\n}\n"
  },
  {
    "path": "genetlink/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    error::GenetlinkError,\n    message::{map_from_rawgenlmsg, map_to_rawgenlmsg, RawGenlMessage},\n    resolver::Resolver,\n};\nuse futures::{lock::Mutex, Stream, StreamExt};\nuse netlink_packet_core::{DecodeError, NetlinkMessage, NetlinkPayload};\nuse netlink_packet_generic::{GenlFamily, GenlHeader, GenlMessage};\nuse netlink_packet_utils::{Emitable, ParseableParametrized};\nuse netlink_proto::{sys::SocketAddr, ConnectionHandle};\nuse std::{fmt::Debug, sync::Arc};\n\n/// The generic netlink connection handle\n///\n/// The handle is used to send messages to the connection. It also resolves\n/// the family id automatically before sending messages.\n///\n/// # Family id resolving\n/// There is a resolver with cache inside each connection. When you send generic\n/// netlink message, the handle resolves and fills the family id into the message.\n///\n/// Since the resolver is created in [`new_connection()`](crate::new_connection),\n/// the cache state wouldn't share between different connections.\n///\n/// P.s. The cloned handles use the same connection with the original handle. So,\n/// they share the same cache state.\n///\n/// # Detailed process of sending generic messages\n/// 1. Check if the message's family id is resolved. If yes, jump to step 6.\n/// 2. Query the family id using the builtin resolver.\n/// 3. If the id is in the cache, returning the id in the cache and skip step 4.\n/// 4. The resolver sends `CTRL_CMD_GETFAMILY` request to get the id and records it in the cache.\n/// 5. fill the family id using [`GenlMessage::set_resolved_family_id()`].\n/// 6. Serialize the payload to [`RawGenlMessage`].\n/// 7. Send it through the connection.\n///     - The family id filled into `message_type` field in [`NetlinkMessage::finalize()`].\n/// 8. In the response stream, deserialize the payload back to [`GenlMessage<F>`].\n#[derive(Clone, Debug)]\npub struct GenetlinkHandle {\n    handle: ConnectionHandle<RawGenlMessage>,\n    resolver: Arc<Mutex<Resolver>>,\n}\n\nimpl GenetlinkHandle {\n    pub(crate) fn new(handle: ConnectionHandle<RawGenlMessage>) -> Self {\n        Self {\n            handle,\n            resolver: Arc::new(Mutex::new(Resolver::new())),\n        }\n    }\n\n    /// Resolve the family id of the given [`GenlFamily`].\n    pub async fn resolve_family_id<F>(&self) -> Result<u16, GenetlinkError>\n    where\n        F: GenlFamily,\n    {\n        self.resolver\n            .lock()\n            .await\n            .query_family_id(self, F::family_name())\n            .await\n    }\n\n    /// Clear the resolver's fanily id cache\n    pub async fn clear_family_id_cache(&self) {\n        self.resolver.lock().await.clear_cache();\n    }\n\n    /// Send the generic netlink message and get the response stream\n    ///\n    /// The function resolves the family id before sending the request. If the\n    /// resolving process is failed, the function would return an error.\n    pub async fn request<F>(\n        &mut self,\n        mut message: NetlinkMessage<GenlMessage<F>>,\n    ) -> Result<\n        impl Stream<Item = Result<NetlinkMessage<GenlMessage<F>>, DecodeError>>,\n        GenetlinkError,\n    >\n    where\n        F: GenlFamily + Emitable + ParseableParametrized<[u8], GenlHeader> + Debug,\n    {\n        self.resolve_message_family_id(&mut message).await?;\n        self.send_request(message)\n    }\n\n    /// Send the request without resolving family id\n    ///\n    /// This function is identical to [`request()`](Self::request) but it doesn't\n    /// resolve the family id for you.\n    pub fn send_request<F>(\n        &mut self,\n        message: NetlinkMessage<GenlMessage<F>>,\n    ) -> Result<\n        impl Stream<Item = Result<NetlinkMessage<GenlMessage<F>>, DecodeError>>,\n        GenetlinkError,\n    >\n    where\n        F: GenlFamily + Emitable + ParseableParametrized<[u8], GenlHeader> + Debug,\n    {\n        let raw_msg = map_to_rawgenlmsg(message);\n\n        let stream = self.handle.request(raw_msg, SocketAddr::new(0, 0))?;\n        Ok(stream.map(map_from_rawgenlmsg))\n    }\n\n    /// Send the generic netlink message without returning the response stream\n    pub async fn notify<F>(\n        &mut self,\n        mut message: NetlinkMessage<GenlMessage<F>>,\n    ) -> Result<(), GenetlinkError>\n    where\n        F: GenlFamily + Emitable + ParseableParametrized<[u8], GenlHeader> + Debug,\n    {\n        self.resolve_message_family_id(&mut message).await?;\n        self.send_notify(message)\n    }\n\n    /// Send the notify without resolving family id\n    pub fn send_notify<F>(\n        &mut self,\n        message: NetlinkMessage<GenlMessage<F>>,\n    ) -> Result<(), GenetlinkError>\n    where\n        F: GenlFamily + Emitable + ParseableParametrized<[u8], GenlHeader> + Debug,\n    {\n        let raw_msg = map_to_rawgenlmsg(message);\n\n        self.handle.notify(raw_msg, SocketAddr::new(0, 0))?;\n        Ok(())\n    }\n\n    async fn resolve_message_family_id<F>(\n        &mut self,\n        message: &mut NetlinkMessage<GenlMessage<F>>,\n    ) -> Result<(), GenetlinkError>\n    where\n        F: GenlFamily + Debug,\n    {\n        if let NetlinkPayload::InnerMessage(genlmsg) = &mut message.payload {\n            if genlmsg.family_id() == 0 {\n                // The family id is not resolved\n                // Resolve it before send it\n                let id = self.resolve_family_id::<F>().await?;\n                genlmsg.set_resolved_family_id(id);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "genetlink/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_use]\nextern crate thiserror;\n\nmod connection;\nmod error;\nmod handle;\npub mod message;\nmod resolver;\n\n#[cfg(feature = \"tokio_socket\")]\npub use connection::new_connection;\npub use connection::new_connection_with_socket;\npub use error::GenetlinkError;\npub use handle::GenetlinkHandle;\n"
  },
  {
    "path": "genetlink/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Raw generic netlink payload message\n//!\n//! # Design\n//! Since we use generic type to represent different generic family's message type,\n//! and it is not easy to create a underlying [`netlink_proto::new_connection()`]\n//! with trait object to multiplex different generic netlink family's message.\n//!\n//! Therefore, I decided to serialize the generic type payload into bytes before\n//! sending to the underlying connection. The [`RawGenlMessage`] is meant for this.\n//!\n//! This special message doesn't use generic type and its payload is `Vec<u8>`.\n//! Therefore, its type is easier to use.\n//!\n//! Another advantage is that it can let users know when the generic netlink payload\n//! fails to decode instead of just dropping the messages.\n//! (`netlink_proto` would drop messages if they fails to decode.)\n//! I think this can help developers debug their deserializing implementation.\nuse netlink_packet_core::{\n    DecodeError,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\nuse netlink_packet_generic::{GenlBuffer, GenlFamily, GenlHeader, GenlMessage};\nuse netlink_packet_utils::{Emitable, Parseable, ParseableParametrized};\nuse std::fmt::Debug;\n\n/// Message type to hold serialized generic netlink payload\n///\n/// **Note** This message type is not intend to be used by normal users, unless\n/// you need to use the `UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>`\n/// return by [`new_connection()`](crate::new_connection)\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct RawGenlMessage {\n    pub header: GenlHeader,\n    pub payload: Vec<u8>,\n    pub family_id: u16,\n}\n\nimpl RawGenlMessage {\n    /// Construct the message\n    pub fn new(header: GenlHeader, payload: Vec<u8>, family_id: u16) -> Self {\n        Self {\n            header,\n            payload,\n            family_id,\n        }\n    }\n\n    /// Consume this message and return its header and payload\n    pub fn into_parts(self) -> (GenlHeader, Vec<u8>) {\n        (self.header, self.payload)\n    }\n\n    /// Serialize the generic netlink payload into raw bytes\n    pub fn from_genlmsg<F>(genlmsg: GenlMessage<F>) -> Self\n    where\n        F: GenlFamily + Emitable + Debug,\n    {\n        let mut payload_buf = vec![0u8; genlmsg.payload.buffer_len()];\n        genlmsg.payload.emit(&mut payload_buf);\n\n        Self {\n            header: genlmsg.header,\n            payload: payload_buf,\n            family_id: genlmsg.family_id(),\n        }\n    }\n\n    /// Try to deserialize the generic netlink payload from raw bytes\n    pub fn parse_into_genlmsg<F>(&self) -> Result<GenlMessage<F>, DecodeError>\n    where\n        F: GenlFamily + ParseableParametrized<[u8], GenlHeader> + Debug,\n    {\n        let inner = F::parse_with_param(&self.payload, self.header)?;\n        Ok(GenlMessage::new(self.header, inner, self.family_id))\n    }\n}\n\nimpl Emitable for RawGenlMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.payload.len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n\n        let buffer = &mut buffer[self.header.buffer_len()..];\n        buffer.copy_from_slice(&self.payload);\n    }\n}\n\nimpl<'a, T> ParseableParametrized<GenlBuffer<&'a T>, u16> for RawGenlMessage\nwhere\n    T: AsRef<[u8]> + ?Sized,\n{\n    fn parse_with_param(buf: &GenlBuffer<&'a T>, message_type: u16) -> Result<Self, DecodeError> {\n        let header = GenlHeader::parse(buf)?;\n        let payload_buf = buf.payload();\n        Ok(RawGenlMessage::new(\n            header,\n            payload_buf.to_vec(),\n            message_type,\n        ))\n    }\n}\n\nimpl NetlinkSerializable for RawGenlMessage {\n    fn message_type(&self) -> u16 {\n        self.family_id\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl NetlinkDeserializable for RawGenlMessage {\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        let buffer = GenlBuffer::new_checked(payload)?;\n        RawGenlMessage::parse_with_param(&buffer, header.message_type)\n    }\n}\n\nimpl From<RawGenlMessage> for NetlinkPayload<RawGenlMessage> {\n    fn from(message: RawGenlMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n\n/// Helper function to map the [`NetlinkPayload`] types in [`NetlinkMessage`]\n/// and serialize the generic netlink payload into raw bytes.\npub fn map_to_rawgenlmsg<F>(\n    message: NetlinkMessage<GenlMessage<F>>,\n) -> NetlinkMessage<RawGenlMessage>\nwhere\n    F: GenlFamily + Emitable + Debug,\n{\n    let raw_payload = match message.payload {\n        NetlinkPayload::InnerMessage(genlmsg) => {\n            NetlinkPayload::InnerMessage(RawGenlMessage::from_genlmsg(genlmsg))\n        }\n        NetlinkPayload::Done => NetlinkPayload::Done,\n        NetlinkPayload::Error(i) => NetlinkPayload::Error(i),\n        NetlinkPayload::Ack(i) => NetlinkPayload::Ack(i),\n        NetlinkPayload::Noop => NetlinkPayload::Noop,\n        NetlinkPayload::Overrun(i) => NetlinkPayload::Overrun(i),\n    };\n    NetlinkMessage::new(message.header, raw_payload)\n}\n\n/// Helper function to map the [`NetlinkPayload`] types in [`NetlinkMessage`]\n/// and try to deserialize the generic netlink payload from raw bytes.\npub fn map_from_rawgenlmsg<F>(\n    raw_msg: NetlinkMessage<RawGenlMessage>,\n) -> Result<NetlinkMessage<GenlMessage<F>>, DecodeError>\nwhere\n    F: GenlFamily + ParseableParametrized<[u8], GenlHeader> + Debug,\n{\n    let payload = match raw_msg.payload {\n        NetlinkPayload::InnerMessage(raw_genlmsg) => {\n            NetlinkPayload::InnerMessage(raw_genlmsg.parse_into_genlmsg()?)\n        }\n        NetlinkPayload::Done => NetlinkPayload::Done,\n        NetlinkPayload::Error(i) => NetlinkPayload::Error(i),\n        NetlinkPayload::Ack(i) => NetlinkPayload::Ack(i),\n        NetlinkPayload::Noop => NetlinkPayload::Noop,\n        NetlinkPayload::Overrun(i) => NetlinkPayload::Overrun(i),\n    };\n    Ok(NetlinkMessage::new(raw_msg.header, payload))\n}\n"
  },
  {
    "path": "genetlink/src/resolver.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{error::GenetlinkError, GenetlinkHandle};\nuse futures::{future::Either, StreamExt};\nuse netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_REQUEST};\nuse netlink_packet_generic::{\n    ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},\n    GenlMessage,\n};\nuse std::{collections::HashMap, future::Future};\n\n#[derive(Clone, Debug, Default)]\npub struct Resolver {\n    cache: HashMap<&'static str, u16>,\n}\n\nimpl Resolver {\n    pub fn new() -> Self {\n        Self {\n            cache: HashMap::new(),\n        }\n    }\n\n    pub fn get_cache_by_name(&self, family_name: &str) -> Option<u16> {\n        self.cache.get(family_name).copied()\n    }\n\n    pub fn query_family_id(\n        &mut self,\n        handle: &GenetlinkHandle,\n        family_name: &'static str,\n    ) -> impl Future<Output = Result<u16, GenetlinkError>> + '_ {\n        if let Some(id) = self.get_cache_by_name(family_name) {\n            Either::Left(futures::future::ready(Ok(id)))\n        } else {\n            let mut handle = handle.clone();\n            Either::Right(async move {\n                let mut genlmsg: GenlMessage<GenlCtrl> = GenlMessage::from_payload(GenlCtrl {\n                    cmd: GenlCtrlCmd::GetFamily,\n                    nlas: vec![GenlCtrlAttrs::FamilyName(family_name.to_owned())],\n                });\n                genlmsg.finalize();\n                // We don't have to set family id here, since nlctrl has static family id (0x10)\n                let mut nlmsg = NetlinkMessage::from(genlmsg);\n                nlmsg.header.flags = NLM_F_REQUEST;\n                nlmsg.finalize();\n\n                let mut res = handle.send_request(nlmsg)?;\n\n                while let Some(result) = res.next().await {\n                    let rx_packet = result?;\n                    match rx_packet.payload {\n                        NetlinkPayload::InnerMessage(genlmsg) => {\n                            let family_id = genlmsg\n                                .payload\n                                .nlas\n                                .iter()\n                                .find_map(|nla| {\n                                    if let GenlCtrlAttrs::FamilyId(id) = nla {\n                                        Some(*id)\n                                    } else {\n                                        None\n                                    }\n                                })\n                                .ok_or_else(|| {\n                                    GenetlinkError::AttributeNotFound(\n                                        \"CTRL_ATTR_FAMILY_ID\".to_owned(),\n                                    )\n                                })?;\n\n                            self.cache.insert(family_name, family_id);\n                            return Ok(family_id);\n                        }\n                        NetlinkPayload::Error(e) => return Err(e.into()),\n                        _ => (),\n                    }\n                }\n\n                Err(GenetlinkError::NoMessageReceived)\n            })\n        }\n    }\n\n    pub fn clear_cache(&mut self) {\n        self.cache.clear();\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::new_connection;\n    use std::io::ErrorKind;\n\n    #[tokio::test]\n    async fn test_resolver_nlctrl() {\n        let (conn, handle, _) = new_connection().unwrap();\n        tokio::spawn(conn);\n\n        let mut resolver = Resolver::new();\n        // nlctrl should always be 0x10\n        let nlctrl_fid = resolver.query_family_id(&handle, \"nlctrl\").await.unwrap();\n        assert_eq!(nlctrl_fid, 0x10);\n    }\n\n    const TEST_FAMILIES: &[&str] = &[\n        \"devlink\",\n        \"ethtool\",\n        \"acpi_event\",\n        \"tcp_metrics\",\n        \"TASKSTATS\",\n        \"nl80211\",\n    ];\n\n    #[tokio::test]\n    async fn test_resolver_cache() {\n        let (conn, handle, _) = new_connection().unwrap();\n        tokio::spawn(conn);\n\n        let mut resolver = Resolver::new();\n\n        // Test if family id cached\n        for name in TEST_FAMILIES.iter().copied() {\n            let id = resolver\n                .query_family_id(&handle, name)\n                .await\n                .or_else(|e| {\n                    if let GenetlinkError::NetlinkError(io_err) = &e {\n                        if io_err.kind() == ErrorKind::NotFound {\n                            // Ignore non exist entries\n                            Ok(0)\n                        } else {\n                            Err(e)\n                        }\n                    } else {\n                        Err(e)\n                    }\n                })\n                .unwrap();\n            if id == 0 {\n                eprintln!(\n                    \"Generic family \\\"{}\\\" not exist or not loaded in this environment. Ignored.\",\n                    name\n                );\n                continue;\n            }\n\n            let cache = resolver.get_cache_by_name(name).unwrap();\n            assert_eq!(id, cache);\n            eprintln!(\"{:?}\", (name, cache));\n        }\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/Cargo.toml",
    "content": "[package]\nname = \"mptcp-pm\"\nversion = \"0.1.1\"\nauthors = [\"Gris Ge <fge@redhat.com>\"]\nlicense = \"MIT\"\nedition = \"2018\"\ndescription = \"Linux kernel MPTCP path manager netlink Library\"\nkeywords = [\"network\"]\ncategories = [\"network-programming\", \"os\"]\nreadme = \"../README.md\"\n\n[lib]\nname = \"mptcp_pm\"\npath = \"src/lib.rs\"\ncrate-type = [\"lib\"]\n\n[features]\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-proto/tokio_socket\", \"tokio\"]\nsmol_socket = [\"netlink-proto/smol_socket\", \"async-std\"]\n\n[dependencies]\nanyhow = \"1.0.44\"\nasync-std = { version = \"1.9.0\", optional = true}\nbyteorder = \"1.4.3\"\nfutures = \"0.3.17\"\nlog = \"0.4.14\"\nthiserror = \"1.0.29\"\ntokio = { version = \"1.0.1\", features = [\"rt\"], optional = true}\ngenetlink = { default-features = false, version = \"0.2.1\", path = \"../genetlink\" }\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-generic = { version = \"0.3.1\", path = \"../netlink-packet-generic\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nnetlink-proto = { default-features = false, version = \"0.10\", path = \"../netlink-proto\" }\nnetlink-sys = { version = \"0.8.3\", path = \"../netlink-sys\" }\n\n[dev-dependencies]\ntokio = { version = \"1.11.0\", features = [\"macros\", \"rt\", \"rt-multi-thread\"] }\nenv_logger = \"0.9.0\"\n"
  },
  {
    "path": "mptcp-pm/examples/dump_mptcp.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\nfn main() {\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(get_addresses());\n}\n\nasync fn get_addresses() {\n    let (connection, handle, _) = mptcp_pm::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut address_handle = handle.address().get().execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = address_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n\n    let mut limits_handle = handle.limits().get().execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = limits_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(!msgs.is_empty());\n    for msg in msgs {\n        println!(\"{:?}\", msg);\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/address/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::net::{IpAddr, Ipv4Addr, Ipv6Addr};\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer},\n    parsers::{parse_i32, parse_ip, parse_u16, parse_u32, parse_u8},\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nconst MPTCP_PM_ADDR_ATTR_FAMILY: u16 = 1;\nconst MPTCP_PM_ADDR_ATTR_ID: u16 = 2;\nconst MPTCP_PM_ADDR_ATTR_ADDR4: u16 = 3;\nconst MPTCP_PM_ADDR_ATTR_ADDR6: u16 = 4;\nconst MPTCP_PM_ADDR_ATTR_PORT: u16 = 5;\nconst MPTCP_PM_ADDR_ATTR_FLAGS: u16 = 6;\nconst MPTCP_PM_ADDR_ATTR_IF_IDX: u16 = 7;\n\nconst MPTCP_PM_ADDR_FLAG_SIGNAL: u32 = 1 << 0;\nconst MPTCP_PM_ADDR_FLAG_SUBFLOW: u32 = 1 << 1;\nconst MPTCP_PM_ADDR_FLAG_BACKUP: u32 = 1 << 2;\nconst MPTCP_PM_ADDR_FLAG_FULLMESH: u32 = 1 << 3;\nconst MPTCP_PM_ADDR_FLAG_IMPLICIT: u32 = 1 << 4;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum MptcpPathManagerAddressAttrFlag {\n    Signal,\n    Subflow,\n    Backup,\n    Fullmesh,\n    Implicit,\n    Other(u32),\n}\n\nfn u32_to_vec_flags(value: u32) -> Vec<MptcpPathManagerAddressAttrFlag> {\n    let mut ret = Vec::new();\n    let mut found = 0u32;\n    if (value & MPTCP_PM_ADDR_FLAG_SIGNAL) > 0 {\n        found += MPTCP_PM_ADDR_FLAG_SIGNAL;\n        ret.push(MptcpPathManagerAddressAttrFlag::Signal);\n    }\n    if (value & MPTCP_PM_ADDR_FLAG_SUBFLOW) > 0 {\n        found += MPTCP_PM_ADDR_FLAG_SUBFLOW;\n        ret.push(MptcpPathManagerAddressAttrFlag::Subflow);\n    }\n    if (value & MPTCP_PM_ADDR_FLAG_BACKUP) > 0 {\n        found += MPTCP_PM_ADDR_FLAG_BACKUP;\n        ret.push(MptcpPathManagerAddressAttrFlag::Backup);\n    }\n    if (value & MPTCP_PM_ADDR_FLAG_FULLMESH) > 0 {\n        found += MPTCP_PM_ADDR_FLAG_FULLMESH;\n        ret.push(MptcpPathManagerAddressAttrFlag::Fullmesh);\n    }\n    if (value & MPTCP_PM_ADDR_FLAG_IMPLICIT) > 0 {\n        found += MPTCP_PM_ADDR_FLAG_IMPLICIT;\n        ret.push(MptcpPathManagerAddressAttrFlag::Implicit);\n    }\n    if (value - found) > 0 {\n        ret.push(MptcpPathManagerAddressAttrFlag::Other(value - found));\n    }\n    ret\n}\n\nimpl From<&MptcpPathManagerAddressAttrFlag> for u32 {\n    fn from(v: &MptcpPathManagerAddressAttrFlag) -> u32 {\n        match v {\n            MptcpPathManagerAddressAttrFlag::Signal => MPTCP_PM_ADDR_FLAG_SIGNAL,\n            MptcpPathManagerAddressAttrFlag::Subflow => MPTCP_PM_ADDR_FLAG_SUBFLOW,\n            MptcpPathManagerAddressAttrFlag::Backup => MPTCP_PM_ADDR_FLAG_BACKUP,\n            MptcpPathManagerAddressAttrFlag::Fullmesh => MPTCP_PM_ADDR_FLAG_FULLMESH,\n            MptcpPathManagerAddressAttrFlag::Implicit => MPTCP_PM_ADDR_FLAG_IMPLICIT,\n            MptcpPathManagerAddressAttrFlag::Other(d) => *d,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum MptcpPathManagerAddressAttr {\n    Family(u16),\n    Id(u8),\n    Addr4(Ipv4Addr),\n    Addr6(Ipv6Addr),\n    Port(u16),\n    Flags(Vec<MptcpPathManagerAddressAttrFlag>),\n    IfIndex(i32),\n    Other(DefaultNla),\n}\n\nimpl Nla for MptcpPathManagerAddressAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Family(_) | Self::Port(_) => 2,\n            Self::Addr4(_) | Self::Flags(_) | Self::IfIndex(_) => 4,\n            Self::Id(_) => 1,\n            Self::Addr6(_) => 16,\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Family(_) => MPTCP_PM_ADDR_ATTR_FAMILY,\n            Self::Id(_) => MPTCP_PM_ADDR_ATTR_ID,\n            Self::Addr4(_) => MPTCP_PM_ADDR_ATTR_ADDR4,\n            Self::Addr6(_) => MPTCP_PM_ADDR_ATTR_ADDR6,\n            Self::Port(_) => MPTCP_PM_ADDR_ATTR_PORT,\n            Self::Flags(_) => MPTCP_PM_ADDR_ATTR_FLAGS,\n            Self::IfIndex(_) => MPTCP_PM_ADDR_ATTR_IF_IDX,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Family(d) | Self::Port(d) => NativeEndian::write_u16(buffer, *d),\n            Self::Addr4(i) => buffer.copy_from_slice(&i.octets()),\n            Self::Addr6(i) => buffer.copy_from_slice(&i.octets()),\n            Self::Id(d) => buffer[0] = *d,\n            Self::Flags(flags) => {\n                let mut value = 0u32;\n                for flag in flags {\n                    value += u32::from(flag);\n                }\n                NativeEndian::write_u32(buffer, value)\n            }\n            Self::IfIndex(d) => NativeEndian::write_i32(buffer, *d),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for MptcpPathManagerAddressAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            MPTCP_PM_ADDR_ATTR_FAMILY => {\n                let err_msg = format!(\"Invalid MPTCP_PM_ADDR_ATTR_FAMILY value {:?}\", payload);\n                Self::Family(parse_u16(payload).context(err_msg)?)\n            }\n            MPTCP_PM_ADDR_ATTR_ID => {\n                Self::Id(parse_u8(payload).context(\"Invalid MPTCP_PM_ADDR_ATTR_ID value\")?)\n            }\n            MPTCP_PM_ADDR_ATTR_ADDR4 | MPTCP_PM_ADDR_ATTR_ADDR6 => {\n                match parse_ip(payload)\n                    .context(\"Invalid MPTCP_PM_ADDR_ATTR_ADDR4/MPTCP_PM_ADDR_ATTR_ADDR6 value\")?\n                {\n                    IpAddr::V4(i) => Self::Addr4(i),\n                    IpAddr::V6(i) => Self::Addr6(i),\n                }\n            }\n            MPTCP_PM_ADDR_ATTR_PORT => {\n                Self::Port(parse_u16(payload).context(\"Invalid MPTCP_PM_ADDR_ATTR_PORT value\")?)\n            }\n            MPTCP_PM_ADDR_ATTR_FLAGS => Self::Flags(u32_to_vec_flags(\n                parse_u32(payload).context(\"Invalid MPTCP_PM_ADDR_ATTR_FLAGS value\")?,\n            )),\n            MPTCP_PM_ADDR_ATTR_IF_IDX => Self::IfIndex(\n                parse_i32(payload).context(\"Invalid MPTCP_PM_ADDR_ATTR_IF_IDX value\")?,\n            ),\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/address/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{\n    mptcp_execute,\n    MptcpPathManagerError,\n    MptcpPathManagerHandle,\n    MptcpPathManagerMessage,\n};\n\npub struct MptcpPathManagerAddressGetRequest {\n    handle: MptcpPathManagerHandle,\n}\n\nimpl MptcpPathManagerAddressGetRequest {\n    pub(crate) fn new(handle: MptcpPathManagerHandle) -> Self {\n        MptcpPathManagerAddressGetRequest { handle }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<MptcpPathManagerMessage>, Error = MptcpPathManagerError>\n    {\n        let MptcpPathManagerAddressGetRequest { mut handle } = self;\n\n        let mptcp_msg = MptcpPathManagerMessage::new_address_get();\n        mptcp_execute(&mut handle, mptcp_msg).await\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/address/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{MptcpPathManagerAddressGetRequest, MptcpPathManagerHandle};\n\npub struct MptcpPathManagerAddressHandle(MptcpPathManagerHandle);\n\nimpl MptcpPathManagerAddressHandle {\n    pub fn new(handle: MptcpPathManagerHandle) -> Self {\n        MptcpPathManagerAddressHandle(handle)\n    }\n\n    /// Retrieve the multipath-TCP  addresses\n    /// (equivalent to `ip mptcp endpoint show`)\n    pub fn get(&mut self) -> MptcpPathManagerAddressGetRequest {\n        MptcpPathManagerAddressGetRequest::new(self.0.clone())\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/address/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub use attr::{MptcpPathManagerAddressAttr, MptcpPathManagerAddressAttrFlag};\npub use get::MptcpPathManagerAddressGetRequest;\npub use handle::MptcpPathManagerAddressHandle;\n"
  },
  {
    "path": "mptcp-pm/src/connection.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::io;\n\nuse futures::channel::mpsc::UnboundedReceiver;\nuse genetlink::message::RawGenlMessage;\nuse netlink_packet_core::NetlinkMessage;\nuse netlink_proto::Connection;\nuse netlink_sys::{AsyncSocket, SocketAddr};\n\nuse crate::MptcpPathManagerHandle;\n\n#[cfg(feature = \"tokio_socket\")]\n#[allow(clippy::type_complexity)]\npub fn new_connection() -> io::Result<(\n    Connection<RawGenlMessage>,\n    MptcpPathManagerHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)> {\n    new_connection_with_socket()\n}\n\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<S>() -> io::Result<(\n    Connection<RawGenlMessage, S>,\n    MptcpPathManagerHandle,\n    UnboundedReceiver<(NetlinkMessage<RawGenlMessage>, SocketAddr)>,\n)>\nwhere\n    S: AsyncSocket,\n{\n    let (conn, handle, messages) = genetlink::new_connection_with_socket()?;\n    Ok((conn, MptcpPathManagerHandle::new(handle), messages))\n}\n"
  },
  {
    "path": "mptcp-pm/src/error.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse thiserror::Error;\n\nuse netlink_packet_core::{ErrorMessage, NetlinkMessage};\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::MptcpPathManagerMessage;\n\n#[derive(Clone, Eq, PartialEq, Debug, Error)]\npub enum MptcpPathManagerError {\n    #[error(\"Received an unexpected message {0:?}\")]\n    UnexpectedMessage(NetlinkMessage<GenlMessage<MptcpPathManagerMessage>>),\n\n    #[error(\"Received a netlink error message {0}\")]\n    NetlinkError(ErrorMessage),\n\n    #[error(\"A netlink request failed\")]\n    RequestFailed(String),\n\n    #[error(\"A bug in this crate\")]\n    Bug(String),\n}\n"
  },
  {
    "path": "mptcp-pm/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{future::Either, FutureExt, Stream, StreamExt, TryStream};\nuse genetlink::GenetlinkHandle;\nuse netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};\nuse netlink_packet_generic::GenlMessage;\nuse netlink_packet_utils::DecodeError;\n\nuse crate::{\n    try_mptcp,\n    MptcpPathManagerAddressHandle,\n    MptcpPathManagerCmd,\n    MptcpPathManagerError,\n    MptcpPathManagerLimitsHandle,\n    MptcpPathManagerMessage,\n};\n\n#[derive(Clone, Debug)]\npub struct MptcpPathManagerHandle {\n    pub handle: GenetlinkHandle,\n}\n\nimpl MptcpPathManagerHandle {\n    pub(crate) fn new(handle: GenetlinkHandle) -> Self {\n        MptcpPathManagerHandle { handle }\n    }\n\n    // equivalent to `ip mptcp endpoint` command\n    // Instead of using `endpoint`, we are aligning with kernel netlink name\n    // `address` here.\n    pub fn address(&self) -> MptcpPathManagerAddressHandle {\n        MptcpPathManagerAddressHandle::new(self.clone())\n    }\n\n    // equivalent to `ip mptcp limits` command\n    pub fn limits(&self) -> MptcpPathManagerLimitsHandle {\n        MptcpPathManagerLimitsHandle::new(self.clone())\n    }\n\n    pub async fn request(\n        &mut self,\n        message: NetlinkMessage<GenlMessage<MptcpPathManagerMessage>>,\n    ) -> Result<\n        impl Stream<Item = Result<NetlinkMessage<GenlMessage<MptcpPathManagerMessage>>, DecodeError>>,\n        MptcpPathManagerError,\n    > {\n        self.handle.request(message).await.map_err(|e| {\n            MptcpPathManagerError::RequestFailed(format!(\"BUG: Request failed with {}\", e))\n        })\n    }\n}\n\npub(crate) async fn mptcp_execute(\n    handle: &mut MptcpPathManagerHandle,\n    mptcp_msg: MptcpPathManagerMessage,\n) -> impl TryStream<Ok = GenlMessage<MptcpPathManagerMessage>, Error = MptcpPathManagerError> {\n    let nl_header_flags = match mptcp_msg.cmd {\n        MptcpPathManagerCmd::AddressGet => NLM_F_REQUEST | NLM_F_DUMP,\n        MptcpPathManagerCmd::LimitsGet => NLM_F_REQUEST,\n    };\n\n    let mut nl_msg = NetlinkMessage::from(GenlMessage::from_payload(mptcp_msg));\n\n    nl_msg.header.flags = nl_header_flags;\n\n    match handle.request(nl_msg).await {\n        Ok(response) => Either::Left(response.map(move |msg| Ok(try_mptcp!(msg)))),\n        Err(e) => Either::Right(\n            futures::future::err::<GenlMessage<MptcpPathManagerMessage>, MptcpPathManagerError>(e)\n                .into_stream(),\n        ),\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod address;\nmod connection;\nmod error;\nmod handle;\nmod limits;\nmod macros;\nmod message;\n\npub use address::{\n    MptcpPathManagerAddressAttr,\n    MptcpPathManagerAddressAttrFlag,\n    MptcpPathManagerAddressGetRequest,\n    MptcpPathManagerAddressHandle,\n};\n#[cfg(feature = \"tokio_socket\")]\npub use connection::new_connection;\npub use connection::new_connection_with_socket;\npub use error::MptcpPathManagerError;\npub use handle::MptcpPathManagerHandle;\npub use limits::{\n    MptcpPathManagerLimitsAttr,\n    MptcpPathManagerLimitsGetRequest,\n    MptcpPathManagerLimitsHandle,\n};\npub use message::{MptcpPathManagerAttr, MptcpPathManagerCmd, MptcpPathManagerMessage};\n\npub(crate) use handle::mptcp_execute;\n"
  },
  {
    "path": "mptcp-pm/src/limits/attr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlaBuffer},\n    parsers::parse_u32,\n    DecodeError,\n    Emitable,\n    Parseable,\n};\n\nconst MPTCP_PM_ATTR_RCV_ADD_ADDRS: u16 = 2;\nconst MPTCP_PM_ATTR_SUBFLOWS: u16 = 3;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum MptcpPathManagerLimitsAttr {\n    RcvAddAddrs(u32),\n    Subflows(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for MptcpPathManagerLimitsAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Other(attr) => attr.value_len(),\n            _ => 4,\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::RcvAddAddrs(_) => MPTCP_PM_ATTR_RCV_ADD_ADDRS,\n            Self::Subflows(_) => MPTCP_PM_ATTR_SUBFLOWS,\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::RcvAddAddrs(d) | Self::Subflows(d) => NativeEndian::write_u32(buffer, *d),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for MptcpPathManagerLimitsAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            MPTCP_PM_ATTR_RCV_ADD_ADDRS => Self::RcvAddAddrs(\n                parse_u32(payload).context(\"Invalid MPTCP_PM_ATTR_RCV_ADD_ADDRS value\")?,\n            ),\n            MPTCP_PM_ATTR_SUBFLOWS => {\n                Self::Subflows(parse_u32(payload).context(\"Invalid MPTCP_PM_ATTR_SUBFLOWS value\")?)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/limits/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStream;\nuse netlink_packet_generic::GenlMessage;\n\nuse crate::{\n    mptcp_execute,\n    MptcpPathManagerError,\n    MptcpPathManagerHandle,\n    MptcpPathManagerMessage,\n};\n\npub struct MptcpPathManagerLimitsGetRequest {\n    handle: MptcpPathManagerHandle,\n}\n\nimpl MptcpPathManagerLimitsGetRequest {\n    pub(crate) fn new(handle: MptcpPathManagerHandle) -> Self {\n        MptcpPathManagerLimitsGetRequest { handle }\n    }\n\n    pub async fn execute(\n        self,\n    ) -> impl TryStream<Ok = GenlMessage<MptcpPathManagerMessage>, Error = MptcpPathManagerError>\n    {\n        let MptcpPathManagerLimitsGetRequest { mut handle } = self;\n\n        let mptcp_msg = MptcpPathManagerMessage::new_limits_get();\n        mptcp_execute(&mut handle, mptcp_msg).await\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/limits/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{MptcpPathManagerHandle, MptcpPathManagerLimitsGetRequest};\n\npub struct MptcpPathManagerLimitsHandle(MptcpPathManagerHandle);\n\nimpl MptcpPathManagerLimitsHandle {\n    pub fn new(handle: MptcpPathManagerHandle) -> Self {\n        MptcpPathManagerLimitsHandle(handle)\n    }\n\n    /// Retrieve the multipath-TCP  addresses\n    /// (equivalent to `ip mptcp endpoint show`)\n    pub fn get(&mut self) -> MptcpPathManagerLimitsGetRequest {\n        MptcpPathManagerLimitsGetRequest::new(self.0.clone())\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/src/limits/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod attr;\nmod get;\nmod handle;\n\npub use attr::MptcpPathManagerLimitsAttr;\npub use get::MptcpPathManagerLimitsGetRequest;\npub use handle::MptcpPathManagerLimitsHandle;\n"
  },
  {
    "path": "mptcp-pm/src/macros.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_export]\nmacro_rules! try_mptcp {\n    ($msg: expr) => {{\n        use netlink_packet_core::{NetlinkMessage, NetlinkPayload};\n        use $crate::MptcpPathManagerError;\n\n        match $msg {\n            Ok(msg) => {\n                let (header, payload) = msg.into_parts();\n                match payload {\n                    NetlinkPayload::InnerMessage(msg) => msg,\n                    NetlinkPayload::Error(err) => {\n                        return Err(MptcpPathManagerError::NetlinkError(err))\n                    }\n                    _ => {\n                        return Err(MptcpPathManagerError::UnexpectedMessage(\n                            NetlinkMessage::new(header, payload),\n                        ))\n                    }\n                }\n            }\n            Err(e) => {\n                return Err(MptcpPathManagerError::Bug(format!(\n                    \"BUG: decode error {:?}\",\n                    e\n                )))\n            }\n        }\n    }};\n}\n"
  },
  {
    "path": "mptcp-pm/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_generic::{GenlFamily, GenlHeader};\nuse netlink_packet_utils::{\n    nla::{DefaultNla, Nla, NlasIterator},\n    Emitable,\n    Parseable,\n    ParseableParametrized,\n};\n\nuse crate::{address::MptcpPathManagerAddressAttr, limits::MptcpPathManagerLimitsAttr};\n\nconst MPTCP_PM_CMD_GET_ADDR: u8 = 3;\nconst MPTCP_PM_CMD_GET_LIMITS: u8 = 6;\n\nconst MPTCP_PM_ATTR_ADDR: u16 = 1;\nconst MPTCP_PM_ATTR_RCV_ADD_ADDRS: u16 = 2;\nconst MPTCP_PM_ATTR_SUBFLOWS: u16 = 3;\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub enum MptcpPathManagerCmd {\n    AddressGet,\n    LimitsGet,\n}\n\nimpl From<MptcpPathManagerCmd> for u8 {\n    fn from(cmd: MptcpPathManagerCmd) -> Self {\n        match cmd {\n            MptcpPathManagerCmd::AddressGet => MPTCP_PM_CMD_GET_ADDR,\n            MptcpPathManagerCmd::LimitsGet => MPTCP_PM_CMD_GET_LIMITS,\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum MptcpPathManagerAttr {\n    Address(MptcpPathManagerAddressAttr),\n    Limits(MptcpPathManagerLimitsAttr),\n    Other(DefaultNla),\n}\n\nimpl Nla for MptcpPathManagerAttr {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Address(attr) => attr.value_len(),\n            Self::Limits(attr) => attr.value_len(),\n            Self::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Address(attr) => attr.kind(),\n            Self::Limits(attr) => attr.kind(),\n            Self::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Address(attr) => attr.emit_value(buffer),\n            Self::Limits(attr) => attr.emit_value(buffer),\n            Self::Other(ref attr) => attr.emit(buffer),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct MptcpPathManagerMessage {\n    pub cmd: MptcpPathManagerCmd,\n    pub nlas: Vec<MptcpPathManagerAttr>,\n}\n\nimpl GenlFamily for MptcpPathManagerMessage {\n    fn family_name() -> &'static str {\n        \"mptcp_pm\"\n    }\n\n    fn version(&self) -> u8 {\n        1\n    }\n\n    fn command(&self) -> u8 {\n        self.cmd.into()\n    }\n}\n\nimpl MptcpPathManagerMessage {\n    pub fn new_address_get() -> Self {\n        MptcpPathManagerMessage {\n            cmd: MptcpPathManagerCmd::AddressGet,\n            nlas: vec![],\n        }\n    }\n\n    pub fn new_limits_get() -> Self {\n        MptcpPathManagerMessage {\n            cmd: MptcpPathManagerCmd::LimitsGet,\n            nlas: vec![],\n        }\n    }\n}\n\nimpl Emitable for MptcpPathManagerMessage {\n    fn buffer_len(&self) -> usize {\n        self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.nlas.as_slice().emit(buffer)\n    }\n}\n\nfn parse_nlas(buffer: &[u8]) -> Result<Vec<MptcpPathManagerAttr>, DecodeError> {\n    let mut nlas = Vec::new();\n    for nla in NlasIterator::new(buffer) {\n        let error_msg = format!(\"Failed to parse mptcp address message attribute {:?}\", nla);\n        let nla = &nla.context(error_msg)?;\n        match nla.kind() {\n            MPTCP_PM_ATTR_ADDR => {\n                for addr_nla in NlasIterator::new(nla.value()) {\n                    let error_msg = format!(\"Failed to parse MPTCP_PM_ATTR_ADDR {:?}\", addr_nla);\n                    let addr_nla = &addr_nla.context(error_msg)?;\n\n                    nlas.push(MptcpPathManagerAttr::Address(\n                        MptcpPathManagerAddressAttr::parse(addr_nla)\n                            .context(\"Failed to parse MPTCP_PM_ATTR_ADDR\")?,\n                    ))\n                }\n            }\n            MPTCP_PM_ATTR_RCV_ADD_ADDRS => nlas.push(MptcpPathManagerAttr::Limits(\n                MptcpPathManagerLimitsAttr::parse(nla)\n                    .context(\"Failed to parse MPTCP_PM_ATTR_RCV_ADD_ADDRS\")?,\n            )),\n            MPTCP_PM_ATTR_SUBFLOWS => nlas.push(MptcpPathManagerAttr::Limits(\n                MptcpPathManagerLimitsAttr::parse(nla)\n                    .context(\"Failed to parse MPTCP_PM_ATTR_RCV_ADD_ADDRS\")?,\n            )),\n            _ => nlas.push(MptcpPathManagerAttr::Other(\n                DefaultNla::parse(nla).context(\"invalid NLA (unknown kind)\")?,\n            )),\n        }\n    }\n    Ok(nlas)\n}\n\nimpl ParseableParametrized<[u8], GenlHeader> for MptcpPathManagerMessage {\n    fn parse_with_param(buffer: &[u8], header: GenlHeader) -> Result<Self, DecodeError> {\n        Ok(match header.cmd {\n            MPTCP_PM_CMD_GET_ADDR => Self {\n                cmd: MptcpPathManagerCmd::AddressGet,\n                nlas: parse_nlas(buffer)?,\n            },\n            MPTCP_PM_CMD_GET_LIMITS => Self {\n                cmd: MptcpPathManagerCmd::LimitsGet,\n                nlas: parse_nlas(buffer)?,\n            },\n            cmd => {\n                return Err(DecodeError::from(format!(\n                    \"Unsupported mptcp reply command: {}\",\n                    cmd\n                )))\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "mptcp-pm/tests/dump_mptcp.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse std::process::Command;\n\nuse mptcp_pm::{MptcpPathManagerAttr, MptcpPathManagerLimitsAttr};\n\n#[test]\nfn test_mptcp_empty_addresses_and_limits() {\n    Command::new(\"sysctl\")\n        .arg(\"-w\")\n        .arg(\"net.mptcp.enabled=1\")\n        .spawn()\n        .unwrap();\n    // OK to fail as Github CI has no ip-mptcp\n    Command::new(\"ip\")\n        .arg(\"mptcp\")\n        .arg(\"endpoint\")\n        .arg(\"flush\")\n        .spawn()\n        .ok();\n    // OK to fail as Github CI has no ip-mptcp\n    Command::new(\"ip\")\n        .arg(\"mptcp\")\n        .arg(\"limits\")\n        .arg(\"set\")\n        .arg(\"subflows\")\n        .arg(\"0\")\n        .arg(\"add_addr_accepted\")\n        .arg(\"0\")\n        .spawn()\n        .ok();\n\n    let rt = tokio::runtime::Builder::new_current_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n    rt.block_on(assert_empty_addresses_and_limits());\n}\n\nasync fn assert_empty_addresses_and_limits() {\n    let (connection, handle, _) = mptcp_pm::new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let mut address_handle = handle.address().get().execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = address_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert!(msgs.is_empty());\n    let mut limits_handle = handle.limits().get().execute().await;\n\n    let mut msgs = Vec::new();\n    while let Some(msg) = limits_handle.try_next().await.unwrap() {\n        msgs.push(msg);\n    }\n    assert_eq!(msgs.len(), 1);\n    let mptcp_nlas = &msgs[0].payload.nlas;\n    assert_eq!(\n        mptcp_nlas[0],\n        MptcpPathManagerAttr::Limits(MptcpPathManagerLimitsAttr::RcvAddAddrs(0))\n    );\n    assert_eq!(\n        mptcp_nlas[1],\n        MptcpPathManagerAttr::Limits(MptcpPathManagerLimitsAttr::Subflows(0))\n    );\n}\n"
  },
  {
    "path": "netlink-packet-audit/Cargo.toml",
    "content": "[package]\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-packet-audit\"\nversion = \"0.4.2\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink packet types\"\n\n[dependencies]\nanyhow = \"1.0.31\"\nbytes = \"1.0\"\nbyteorder = \"1.3.2\"\nlog = \"0.4.8\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nnetlink-proto = { default-features = false, version = \"0.10\", path = \"../netlink-proto\" }\n\n[dev-dependencies]\nlazy_static = \"1.4.0\"\n"
  },
  {
    "path": "netlink-packet-audit/fuzz/.gitignore",
    "content": "\ntarget\ncorpus\nartifacts\n"
  },
  {
    "path": "netlink-packet-audit/fuzz/Cargo.toml",
    "content": "[package]\nname = \"netlink-packet-audit-fuzz\"\nversion = \"0.0.1\"\nauthors = [\"Automatically generated\"]\npublish = false\nedition = \"2018\"\n\n[package.metadata]\ncargo-fuzz = true\n\n[dependencies]\nnetlink-packet-audit = { version = \"0.4.1\", path = \"../../netlink-packet-audit\" }\nnetlink-packet-core = { version = \"0.4.2\", path = \"../../netlink-packet-core\" }\nlibfuzzer-sys = { git = \"https://github.com/rust-fuzz/libfuzzer-sys.git\" }\n\n[[bin]]\nname = \"netlink-audit\"\npath = \"fuzz_targets/netlink.rs\"\n"
  },
  {
    "path": "netlink-packet-audit/fuzz/fuzz_targets/netlink.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#![no_main]\n\nuse libfuzzer_sys::fuzz_target;\nuse netlink_packet_audit::{AuditMessage, NetlinkMessage};\n\nfuzz_target!(|data: &[u8]| {\n    let _ = NetlinkMessage::<AuditMessage>::deserialize(data);\n});\n"
  },
  {
    "path": "netlink-packet-audit/src/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    rules::{RuleBuffer, RuleMessage},\n    traits::{Parseable, ParseableParametrized},\n    AuditMessage,\n    DecodeError,\n    StatusMessage,\n    StatusMessageBuffer,\n};\nuse anyhow::Context;\n\npub struct AuditBuffer<T> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> AuditBuffer<T> {\n    pub fn new(buffer: T) -> AuditBuffer<T> {\n        AuditBuffer { buffer }\n    }\n\n    pub fn length(&self) -> usize {\n        self.buffer.as_ref().len()\n    }\n\n    pub fn new_checked(buffer: T) -> Result<AuditBuffer<T>, DecodeError> {\n        Ok(Self::new(buffer))\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> AuditBuffer<&'a T> {\n    pub fn inner(&self) -> &'a [u8] {\n        self.buffer.as_ref()\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> AuditBuffer<&'a mut T> {\n    pub fn inner_mut(&mut self) -> &mut [u8] {\n        self.buffer.as_mut()\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<AuditBuffer<&'a T>, u16> for AuditMessage {\n    fn parse_with_param(buf: &AuditBuffer<&'a T>, message_type: u16) -> Result<Self, DecodeError> {\n        use self::AuditMessage::*;\n        let message = match message_type {\n            AUDIT_GET if buf.length() == 0 => GetStatus(None),\n            AUDIT_GET => {\n                let err = \"failed to parse AUDIT_GET message\";\n                let buf = StatusMessageBuffer::new(buf.inner());\n                GetStatus(Some(StatusMessage::parse(&buf).context(err)?))\n            }\n            AUDIT_SET => {\n                let err = \"failed to parse AUDIT_SET message\";\n                let buf = StatusMessageBuffer::new(buf.inner());\n                SetStatus(StatusMessage::parse(&buf).context(err)?)\n            }\n            AUDIT_ADD_RULE => {\n                let err = \"failed to parse AUDIT_ADD_RULE message\";\n                let buf = RuleBuffer::new_checked(buf.inner()).context(err)?;\n                AddRule(RuleMessage::parse(&buf).context(err)?)\n            }\n            AUDIT_DEL_RULE => {\n                let err = \"failed to parse AUDIT_DEL_RULE message\";\n                let buf = RuleBuffer::new_checked(buf.inner()).context(err)?;\n                DelRule(RuleMessage::parse(&buf).context(err)?)\n            }\n            AUDIT_LIST_RULES if buf.length() == 0 => ListRules(None),\n            AUDIT_LIST_RULES => {\n                let err = \"failed to parse AUDIT_LIST_RULES message\";\n                let buf = RuleBuffer::new_checked(buf.inner()).context(err)?;\n                ListRules(Some(RuleMessage::parse(&buf).context(err)?))\n            }\n            i if (AUDIT_EVENT_MESSAGE_MIN..AUDIT_EVENT_MESSAGE_MAX).contains(&i) => {\n                let data = String::from_utf8(buf.inner().to_vec())\n                    .context(\"failed to parse audit event data as a valid string\")?;\n                Event((i, data))\n            }\n            i => {\n                let data = String::from_utf8(buf.inner().to_vec())\n                    .context(\"failed to parse audit event data as a valid string\")?;\n                Other((i, data))\n            }\n        };\n        Ok(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/codec.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{fmt::Debug, io};\n\nuse bytes::BytesMut;\nuse netlink_packet_core::{\n    NetlinkBuffer,\n    NetlinkDeserializable,\n    NetlinkMessage,\n    NetlinkSerializable,\n};\npub(crate) use netlink_proto::{NetlinkCodec, NetlinkMessageCodec};\n\n/// audit specific implementation of [`NetlinkMessageCodec`] due to the\n/// protocol violations in messages generated by kernal audit.\n///\n/// Among the known bugs in kernel audit messages:\n/// - `nlmsg_len` sometimes contains the padding too (it shouldn't)\n/// - `nlmsg_len` sometimes doesn't contain the header (it really should)\n///\n/// See also:\n/// - https://blog.des.no/2020/08/netlink-auditing-and-counting-bytes/\n/// - https://github.com/torvalds/linux/blob/b5013d084e03e82ceeab4db8ae8ceeaebe76b0eb/kernel/audit.c#L2386\n/// - https://github.com/mozilla/libaudit-go/issues/24\n/// - https://github.com/linux-audit/audit-userspace/issues/78\npub struct NetlinkAuditCodec {\n    // we don't need an instance of this, just the type\n    _private: (),\n}\n\nimpl NetlinkMessageCodec for NetlinkAuditCodec {\n    fn decode<T>(src: &mut BytesMut) -> io::Result<Option<NetlinkMessage<T>>>\n    where\n        T: NetlinkDeserializable + Debug,\n    {\n        debug!(\"NetlinkAuditCodec: decoding next message\");\n\n        loop {\n            // If there's nothing to read, return Ok(None)\n            if src.is_empty() {\n                trace!(\"buffer is empty\");\n                return Ok(None);\n            }\n\n            // This is a bit hacky because we don't want to keep `src`\n            // borrowed, since we need to mutate it later.\n            let src_len = src.len();\n            let len = match NetlinkBuffer::new_checked(src.as_mut()) {\n                Ok(mut buf) => {\n                    if (src_len as isize - buf.length() as isize) <= 16 {\n                        // The audit messages are sometimes truncated,\n                        // because the length specified in the header,\n                        // does not take the header itself into\n                        // account. To workaround this, we tweak the\n                        // length. We've noticed two occurences of\n                        // truncated packets:\n                        //\n                        // - the length of the header is not included (see also:\n                        //   https://github.com/mozilla/libaudit-go/issues/24)\n                        // - some rule message have some padding for alignment (see\n                        //   https://github.com/linux-audit/audit-userspace/issues/78) which is not\n                        //   taken into account in the buffer length.\n                        //\n                        // How do we know that's the right length? Due to an implementation detail and to\n                        // the fact that netlink is a datagram protocol.\n                        //\n                        // - our implementation of Stream always calls the codec with at most 1 message in\n                        //   the buffer, so we know the extra bytes do not belong to another message.\n                        // - because netlink is a datagram protocol, we receive entire messages, so we know\n                        //   that if those extra bytes do not belong to another message, they belong to\n                        //   this one.\n                        warn!(\"found what looks like a truncated audit packet\");\n                        // also write correct length to buffer so parsing does not fail:\n                        warn!(\n                            \"setting packet length to {} instead of {}\",\n                            src_len,\n                            buf.length()\n                        );\n                        buf.set_length(src_len as u32);\n                        src_len\n                    } else {\n                        buf.length() as usize\n                    }\n                }\n                Err(e) => {\n                    // We either received a truncated packet, or the\n                    // packet if malformed (invalid length field). In\n                    // both case, we can't decode the datagram, and we\n                    // cannot find the start of the next one (if\n                    // any). The only solution is to clear the buffer\n                    // and potentially lose some datagrams.\n                    error!(\n                        \"failed to decode datagram, clearing buffer: {:?}: {:#x?}.\",\n                        e,\n                        src.as_ref()\n                    );\n                    src.clear();\n                    return Ok(None);\n                }\n            };\n\n            let bytes = src.split_to(len);\n\n            let parsed = NetlinkMessage::<T>::deserialize(&bytes);\n            match parsed {\n                Ok(packet) => {\n                    trace!(\"<<< {:?}\", packet);\n                    return Ok(Some(packet));\n                }\n                Err(e) => {\n                    error!(\"failed to decode packet {:#x?}: {}\", &bytes, e);\n                    // continue looping, there may be more datagrams in the buffer\n                }\n            }\n        }\n    }\n\n    fn encode<T>(msg: NetlinkMessage<T>, buf: &mut BytesMut) -> io::Result<()>\n    where\n        T: Debug + NetlinkSerializable,\n    {\n        NetlinkCodec::encode(msg, buf)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub use netlink_packet_core::constants::*;\n\n// ==========================================\n// 1000 - 1099 are for commanding the audit system\n// ==========================================\n\n/// Get status\npub const AUDIT_GET: u16 = 1000;\n/// Set status (enable/disable/auditd)\npub const AUDIT_SET: u16 = 1001;\n/// List syscall rules -- deprecated\npub const AUDIT_LIST: u16 = 1002;\n/// Add syscall rule -- deprecated\npub const AUDIT_ADD: u16 = 1003;\n/// Delete syscall rule -- deprecated\npub const AUDIT_DEL: u16 = 1004;\n/// Message from userspace -- deprecated\npub const AUDIT_USER: u16 = 1005;\n/// Define the login id and information\npub const AUDIT_LOGIN: u16 = 1006;\n/// Insert file/dir watch entry\npub const AUDIT_WATCH_INS: u16 = 1007;\n/// Remove file/dir watch entry\npub const AUDIT_WATCH_REM: u16 = 1008;\n/// List all file/dir watches\npub const AUDIT_WATCH_LIST: u16 = 1009;\n/// Get info about sender of signal to auditd\npub const AUDIT_SIGNAL_INFO: u16 = 1010;\n/// Add syscall filtering rule\npub const AUDIT_ADD_RULE: u16 = 1011;\n/// Delete syscall filtering rule\npub const AUDIT_DEL_RULE: u16 = 1012;\n/// List syscall filtering rules\npub const AUDIT_LIST_RULES: u16 = 1013;\n/// Trim junk from watched tree\npub const AUDIT_TRIM: u16 = 1014;\n/// Append to watched tree\npub const AUDIT_MAKE_EQUIV: u16 = 1015;\n/// Get TTY auditing status\npub const AUDIT_TTY_GET: u16 = 1016;\n/// Set TTY auditing status\npub const AUDIT_TTY_SET: u16 = 1017;\n/// Turn an audit feature on or off\npub const AUDIT_SET_FEATURE: u16 = 1018;\n/// Get which features are enabled\npub const AUDIT_GET_FEATURE: u16 = 1019;\n\n// ==========================================\n// 1100 - 1199 user space trusted application messages\n// ==========================================\n\n/// Userspace messages mostly uninteresting to kernel\npub const AUDIT_FIRST_USER_MSG: u16 = 1100;\n/// We filter this differently\npub const AUDIT_USER_AVC: u16 = 1107;\n/// Non-ICANON TTY input meaning\npub const AUDIT_USER_TTY: u16 = 1124;\npub const AUDIT_LAST_USER_MSG: u16 = 1199;\n\n/// More user space messages;\npub const AUDIT_FIRST_USER_MSG2: u16 = 2100;\npub const AUDIT_LAST_USER_MSG2: u16 = 2999;\n\n// ==========================================\n// 1200 - 1299 messages internal to the audit daemon\n// ==========================================\n\n/// Daemon startup record\npub const AUDIT_DAEMON_START: u16 = 1200;\n/// Daemon normal stop record\npub const AUDIT_DAEMON_END: u16 = 1201;\n/// Daemon error stop record\npub const AUDIT_DAEMON_ABORT: u16 = 1202;\n/// Daemon config change\npub const AUDIT_DAEMON_CONFIG: u16 = 1203;\n\n// ==========================================\n// 1300 - 1399 audit event messages\n// ==========================================\n\npub const AUDIT_EVENT_MESSAGE_MIN: u16 = 1300;\npub const AUDIT_EVENT_MESSAGE_MAX: u16 = 1399;\n/// Syscall event\npub const AUDIT_SYSCALL: u16 = 1300;\n/// Filename path information\npub const AUDIT_PATH: u16 = 1302;\n/// IPC record\npub const AUDIT_IPC: u16 = 1303;\n/// sys_socketcall arguments\npub const AUDIT_SOCKETCALL: u16 = 1304;\n/// Audit system configuration change\npub const AUDIT_CONFIG_CHANGE: u16 = 1305;\n/// sockaddr copied as syscall arg\npub const AUDIT_SOCKADDR: u16 = 1306;\n/// Current working directory\npub const AUDIT_CWD: u16 = 1307;\n/// execve arguments\npub const AUDIT_EXECVE: u16 = 1309;\n/// IPC new permissions record type\npub const AUDIT_IPC_SET_PERM: u16 = 1311;\n/// POSIX MQ open record type\npub const AUDIT_MQ_OPEN: u16 = 1312;\n/// POSIX MQ send/receive record type\npub const AUDIT_MQ_SENDRECV: u16 = 1313;\n/// POSIX MQ notify record type\npub const AUDIT_MQ_NOTIFY: u16 = 1314;\n/// POSIX MQ get/set attribute record type\npub const AUDIT_MQ_GETSETATTR: u16 = 1315;\n/// For use by 3rd party modules\npub const AUDIT_KERNEL_OTHER: u16 = 1316;\n/// audit record for pipe/socketpair\npub const AUDIT_FD_PAIR: u16 = 1317;\n/// ptrace target\npub const AUDIT_OBJ_PID: u16 = 1318;\n/// Input on an administrative TTY\npub const AUDIT_TTY: u16 = 1319;\n/// End of multi-record event\npub const AUDIT_EOE: u16 = 1320;\n/// Information about fcaps increasing perms\npub const AUDIT_BPRM_FCAPS: u16 = 1321;\n/// Record showing argument to sys_capset\npub const AUDIT_CAPSET: u16 = 1322;\n/// Record showing descriptor and flags in mmap\npub const AUDIT_MMAP: u16 = 1323;\n/// Packets traversing netfilter chains\npub const AUDIT_NETFILTER_PKT: u16 = 1324;\n/// Netfilter chain modifications\npub const AUDIT_NETFILTER_CFG: u16 = 1325;\n/// Secure Computing event\npub const AUDIT_SECCOMP: u16 = 1326;\n/// Proctitle emit event\npub const AUDIT_PROCTITLE: u16 = 1327;\n/// audit log listing feature changes\npub const AUDIT_FEATURE_CHANGE: u16 = 1328;\n/// Replace auditd if this packet unanswerd\npub const AUDIT_REPLACE: u16 = 1329;\n/// Kernel Module events\npub const AUDIT_KERN_MODULE: u16 = 1330;\n/// Fanotify access decision\npub const AUDIT_FANOTIFY: u16 = 1331;\n\n// ==========================================\n// 1400 - 1499 SE Linux use\n// ==========================================\n\n/// SE Linux avc denial or grant\npub const AUDIT_AVC: u16 = 1400;\n/// Internal SE Linux Errors\npub const AUDIT_SELINUX_ERR: u16 = 1401;\n/// dentry, vfsmount pair from avc\npub const AUDIT_AVC_PATH: u16 = 1402;\n/// Policy file load\npub const AUDIT_MAC_POLICY_LOAD: u16 = 1403;\n/// Changed enforcing,permissive,off\npub const AUDIT_MAC_STATUS: u16 = 1404;\n/// Changes to booleans\npub const AUDIT_MAC_CONFIG_CHANGE: u16 = 1405;\n/// NetLabel: allow unlabeled traffic\npub const AUDIT_MAC_UNLBL_ALLOW: u16 = 1406;\n/// NetLabel: add CIPSOv4 DOI entry\npub const AUDIT_MAC_CIPSOV4_ADD: u16 = 1407;\n/// NetLabel: del CIPSOv4 DOI entry\npub const AUDIT_MAC_CIPSOV4_DEL: u16 = 1408;\n/// NetLabel: add LSM domain mapping\npub const AUDIT_MAC_MAP_ADD: u16 = 1409;\n/// NetLabel: del LSM domain mapping\npub const AUDIT_MAC_MAP_DEL: u16 = 1410;\n/// Not used\npub const AUDIT_MAC_IPSEC_ADDSA: u16 = 1411;\n/// Not used\npub const AUDIT_MAC_IPSEC_DELSA: u16 = 1412;\n/// Not used\npub const AUDIT_MAC_IPSEC_ADDSPD: u16 = 1413;\n/// Not used\npub const AUDIT_MAC_IPSEC_DELSPD: u16 = 1414;\n/// Audit an IPSec event\npub const AUDIT_MAC_IPSEC_EVENT: u16 = 1415;\n/// NetLabel: add a static label\npub const AUDIT_MAC_UNLBL_STCADD: u16 = 1416;\n/// NetLabel: del a static label\npub const AUDIT_MAC_UNLBL_STCDEL: u16 = 1417;\n/// NetLabel: add CALIPSO DOI entry\npub const AUDIT_MAC_CALIPSO_ADD: u16 = 1418;\n/// NetLabel: del CALIPSO DOI entry\npub const AUDIT_MAC_CALIPSO_DEL: u16 = 1419;\n\n// ==========================================\n// 1700 - 1799 kernel anomaly records\n// ==========================================\n\npub const AUDIT_FIRST_KERN_ANOM_MSG: u16 = 1700;\npub const AUDIT_LAST_KERN_ANOM_MSG: u16 = 1799;\n/// Device changed promiscuous mode\npub const AUDIT_ANOM_PROMISCUOUS: u16 = 1700;\n/// Process ended abnormally\npub const AUDIT_ANOM_ABEND: u16 = 1701;\n/// Suspicious use of file links\npub const AUDIT_ANOM_LINK: u16 = 1702;\n\n// ==========================================\n// 1800 - 1899 kernel integrity events\n// ==========================================\n\n/// Data integrity verification\npub const AUDIT_INTEGRITY_DATA: u16 = 1800;\n/// Metadata integrity verification\npub const AUDIT_INTEGRITY_METADATA: u16 = 1801;\n/// Integrity enable status\npub const AUDIT_INTEGRITY_STATUS: u16 = 1802;\n/// Integrity HASH type\npub const AUDIT_INTEGRITY_HASH: u16 = 1803;\n/// PCR invalidation msgs\npub const AUDIT_INTEGRITY_PCR: u16 = 1804;\n/// policy rule\npub const AUDIT_INTEGRITY_RULE: u16 = 1805;\n\n// 2000 is for otherwise unclassified kernel audit messages (legacy)\npub const AUDIT_KERNEL: u16 = 2000;\n\n// rule flags\n\n/// Apply rule to user-generated messages\npub const AUDIT_FILTER_USER: u32 = 0;\n/// Apply rule at task creation (not syscall)\npub const AUDIT_FILTER_TASK: u32 = 1;\n/// Apply rule at syscall entry\npub const AUDIT_FILTER_ENTRY: u32 = 2;\n/// Apply rule to file system watches\npub const AUDIT_FILTER_WATCH: u32 = 3;\n/// Apply rule at syscall exit\npub const AUDIT_FILTER_EXIT: u32 = 4;\n/// Apply rule at audit_log_start\npub const AUDIT_FILTER_TYPE: u32 = 5;\n\npub const AUDIT_FILTER_FS: u32 = 6;\n\n/// Mask to get actual filter\npub const AUDIT_NR_FILTERS: u32 = 7;\npub const AUDIT_FILTER_PREPEND: u32 = 16;\n/// Filter is unset\npub const AUDIT_FILTER_UNSET: u32 = 128;\n\n// Rule actions\n\n/// Do not build context if rule matches\npub const AUDIT_NEVER: u32 = 0;\n/// Build context if rule matches\npub const AUDIT_POSSIBLE: u32 = 1;\n/// Generate audit record if rule matches\npub const AUDIT_ALWAYS: u32 = 2;\n\npub const AUDIT_MAX_FIELDS: usize = 64;\npub const AUDIT_MAX_KEY_LEN: usize = 256;\npub const AUDIT_BITMASK_SIZE: usize = 64;\n\npub const AUDIT_SYSCALL_CLASSES: u32 = 16;\npub const AUDIT_CLASS_DIR_WRITE: u32 = 0;\npub const AUDIT_CLASS_DIR_WRITE_32: u32 = 1;\npub const AUDIT_CLASS_CHATTR: u32 = 2;\npub const AUDIT_CLASS_CHATTR_32: u32 = 3;\npub const AUDIT_CLASS_READ: u32 = 4;\npub const AUDIT_CLASS_READ_32: u32 = 5;\npub const AUDIT_CLASS_WRITE: u32 = 6;\npub const AUDIT_CLASS_WRITE_32: u32 = 7;\npub const AUDIT_CLASS_SIGNAL: u32 = 8;\npub const AUDIT_CLASS_SIGNAL_32: u32 = 9;\npub const AUDIT_UNUSED_BITS: u32 = 134216704;\n\n// Field Comparing Constants\npub const AUDIT_COMPARE_UID_TO_OBJ_UID: u32 = 1;\npub const AUDIT_COMPARE_GID_TO_OBJ_GID: u32 = 2;\npub const AUDIT_COMPARE_EUID_TO_OBJ_UID: u32 = 3;\npub const AUDIT_COMPARE_EGID_TO_OBJ_GID: u32 = 4;\npub const AUDIT_COMPARE_AUID_TO_OBJ_UID: u32 = 5;\npub const AUDIT_COMPARE_SUID_TO_OBJ_UID: u32 = 6;\npub const AUDIT_COMPARE_SGID_TO_OBJ_GID: u32 = 7;\npub const AUDIT_COMPARE_FSUID_TO_OBJ_UID: u32 = 8;\npub const AUDIT_COMPARE_FSGID_TO_OBJ_GID: u32 = 9;\npub const AUDIT_COMPARE_UID_TO_AUID: u32 = 10;\npub const AUDIT_COMPARE_UID_TO_EUID: u32 = 11;\npub const AUDIT_COMPARE_UID_TO_FSUID: u32 = 12;\npub const AUDIT_COMPARE_UID_TO_SUID: u32 = 13;\npub const AUDIT_COMPARE_AUID_TO_FSUID: u32 = 14;\npub const AUDIT_COMPARE_AUID_TO_SUID: u32 = 15;\npub const AUDIT_COMPARE_AUID_TO_EUID: u32 = 16;\npub const AUDIT_COMPARE_EUID_TO_SUID: u32 = 17;\npub const AUDIT_COMPARE_EUID_TO_FSUID: u32 = 18;\npub const AUDIT_COMPARE_SUID_TO_FSUID: u32 = 19;\npub const AUDIT_COMPARE_GID_TO_EGID: u32 = 20;\npub const AUDIT_COMPARE_GID_TO_FSGID: u32 = 21;\npub const AUDIT_COMPARE_GID_TO_SGID: u32 = 22;\npub const AUDIT_COMPARE_EGID_TO_FSGID: u32 = 23;\npub const AUDIT_COMPARE_EGID_TO_SGID: u32 = 24;\npub const AUDIT_COMPARE_SGID_TO_FSGID: u32 = 25;\npub const AUDIT_MAX_FIELD_COMPARE: u32 = 25;\n\n// =======================================================================\n// rule fields\n// =======================================================================\npub const AUDIT_PID: u32 = 0;\npub const AUDIT_UID: u32 = 1;\npub const AUDIT_EUID: u32 = 2;\npub const AUDIT_SUID: u32 = 3;\npub const AUDIT_FSUID: u32 = 4;\npub const AUDIT_GID: u32 = 5;\npub const AUDIT_EGID: u32 = 6;\npub const AUDIT_SGID: u32 = 7;\npub const AUDIT_FSGID: u32 = 8;\npub const AUDIT_LOGINUID: u32 = 9;\npub const AUDIT_PERS: u32 = 10;\npub const AUDIT_ARCH: u32 = 11;\npub const AUDIT_MSGTYPE: u32 = 12;\npub const AUDIT_SUBJ_USER: u32 = 13;\npub const AUDIT_SUBJ_ROLE: u32 = 14;\npub const AUDIT_SUBJ_TYPE: u32 = 15;\npub const AUDIT_SUBJ_SEN: u32 = 16;\npub const AUDIT_SUBJ_CLR: u32 = 17;\npub const AUDIT_PPID: u32 = 18;\npub const AUDIT_OBJ_USER: u32 = 19;\npub const AUDIT_OBJ_ROLE: u32 = 20;\npub const AUDIT_OBJ_TYPE: u32 = 21;\npub const AUDIT_OBJ_LEV_LOW: u32 = 22;\npub const AUDIT_OBJ_LEV_HIGH: u32 = 23;\npub const AUDIT_LOGINUID_SET: u32 = 24;\npub const AUDIT_SESSIONID: u32 = 25;\npub const AUDIT_FSTYPE: u32 = 26;\npub const AUDIT_DEVMAJOR: u32 = 100;\npub const AUDIT_DEVMINOR: u32 = 101;\npub const AUDIT_INODE: u32 = 102;\npub const AUDIT_EXIT: u32 = 103;\npub const AUDIT_SUCCESS: u32 = 104;\npub const AUDIT_WATCH: u32 = 105;\npub const AUDIT_PERM: u32 = 106;\npub const AUDIT_DIR: u32 = 107;\npub const AUDIT_FILETYPE: u32 = 108;\npub const AUDIT_OBJ_UID: u32 = 109;\npub const AUDIT_OBJ_GID: u32 = 110;\npub const AUDIT_FIELD_COMPARE: u32 = 111;\npub const AUDIT_EXE: u32 = 112;\npub const AUDIT_ARG0: u32 = 200;\npub const AUDIT_ARG1: u32 = 201;\npub const AUDIT_ARG2: u32 = 202;\npub const AUDIT_ARG3: u32 = 203;\npub const AUDIT_FILTERKEY: u32 = 210;\n\npub const AUDIT_BIT_MASK: u32 = 0x0800_0000;\npub const AUDIT_LESS_THAN: u32 = 0x1000_0000;\npub const AUDIT_GREATER_THAN: u32 = 0x2000_0000;\npub const AUDIT_NOT_EQUAL: u32 = 0x3000_0000;\npub const AUDIT_EQUAL: u32 = 0x4000_0000;\npub const AUDIT_BIT_TEST: u32 = AUDIT_BIT_MASK | AUDIT_EQUAL;\npub const AUDIT_LESS_THAN_OR_EQUAL: u32 = AUDIT_LESS_THAN | AUDIT_EQUAL;\npub const AUDIT_GREATER_THAN_OR_EQUAL: u32 = AUDIT_GREATER_THAN | AUDIT_EQUAL;\npub const AUDIT_OPERATORS: u32 = AUDIT_EQUAL | AUDIT_NOT_EQUAL | AUDIT_BIT_MASK;\n\n// ============================================\n// failure to log actions\n// ============================================\npub const AUDIT_FAIL_SILENT: u32 = 0;\npub const AUDIT_FAIL_PRINTK: u32 = 1;\npub const AUDIT_FAIL_PANIC: u32 = 2;\n\npub const AUDIT_PERM_EXEC: u32 = 1;\npub const AUDIT_PERM_WRITE: u32 = 2;\npub const AUDIT_PERM_READ: u32 = 4;\npub const AUDIT_PERM_ATTR: u32 = 8;\npub const AUDIT_MESSAGE_TEXT_MAX: u32 = 8560;\npub const AUDIT_FEATURE_VERSION: u32 = 1;\npub const AUDIT_FEATURE_ONLY_UNSET_LOGINUID: u32 = 0;\npub const AUDIT_FEATURE_LOGINUID_IMMUTABLE: u32 = 1;\npub const AUDIT_LAST_FEATURE: u32 = 1;\n\n/// Unused multicast group for audit\npub const AUDIT_NLGRP_NONE: u32 = 0;\n/// Multicast group to listen for audit events\npub const AUDIT_NLGRP_READLOG: u32 = 1;\n\npub const __AUDIT_ARCH_CONVENTION_MASK: u32 = 0x3000_0000;\npub const __AUDIT_ARCH_CONVENTION_MIPS64_N32: u32 = 0x2000_0000;\npub const __AUDIT_ARCH_64BIT: u32 = 0x0800_0000;\npub const __AUDIT_ARCH_LE: u32 = 0x4000_0000;\npub const AUDIT_ARCH_AARCH64: u32 = 0xC000_00B7;\npub const AUDIT_ARCH_ALPHA: u32 = 0xC000_9026;\npub const AUDIT_ARCH_ARM: u32 = 0x4000_0028;\npub const AUDIT_ARCH_ARMEB: u32 = 0x28;\npub const AUDIT_ARCH_CRIS: u32 = 0x4000_004C;\npub const AUDIT_ARCH_FRV: u32 = 0x5441;\npub const AUDIT_ARCH_I386: u32 = 0x4000_0003;\npub const AUDIT_ARCH_IA64: u32 = 0xC000_0032;\npub const AUDIT_ARCH_M32R: u32 = 0x58;\npub const AUDIT_ARCH_M68K: u32 = 0x04;\npub const AUDIT_ARCH_MICROBLAZE: u32 = 0xBD;\npub const AUDIT_ARCH_MIPS: u32 = 0x08;\npub const AUDIT_ARCH_MIPSEL: u32 = 0x4000_0008;\npub const AUDIT_ARCH_MIPS64: u32 = 0x8000_0008;\npub const AUDIT_ARCH_MIPS64N32: u32 = 0xA000_0008;\npub const AUDIT_ARCH_MIPSEL64: u32 = 0xC000_0008;\npub const AUDIT_ARCH_MIPSEL64N32: u32 = 0xE000_0008;\npub const AUDIT_ARCH_OPENRISC: u32 = 92;\npub const AUDIT_ARCH_PARISC: u32 = 15;\npub const AUDIT_ARCH_PARISC64: u32 = 0x8000_000F;\npub const AUDIT_ARCH_PPC: u32 = 20;\npub const AUDIT_ARCH_PPC64: u32 = 0x8000_0015;\npub const AUDIT_ARCH_PPC64LE: u32 = 0xC000_0015;\npub const AUDIT_ARCH_S390: u32 = 22;\npub const AUDIT_ARCH_S390X: u32 = 0x8000_0016;\npub const AUDIT_ARCH_SH: u32 = 42;\npub const AUDIT_ARCH_SHEL: u32 = 0x4000_002A;\npub const AUDIT_ARCH_SH64: u32 = 0x8000_002A;\npub const AUDIT_ARCH_SHEL64: u32 = 0xC000_002A;\npub const AUDIT_ARCH_SPARC: u32 = 2;\npub const AUDIT_ARCH_SPARC64: u32 = 0x8000_002B;\npub const AUDIT_ARCH_TILEGX: u32 = 0xC000_00BF;\npub const AUDIT_ARCH_TILEGX32: u32 = 0x4000_00BF;\npub const AUDIT_ARCH_TILEPRO: u32 = 0x4000_00BC;\npub const AUDIT_ARCH_X86_64: u32 = 0xC000_003E;\n"
  },
  {
    "path": "netlink-packet-audit/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_use]\nextern crate log;\n\npub(crate) extern crate netlink_packet_utils as utils;\npub use self::utils::{traits, DecodeError};\npub use netlink_packet_core::{\n    ErrorMessage,\n    NetlinkBuffer,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n};\npub(crate) use netlink_packet_core::{NetlinkDeserializable, NetlinkSerializable};\n\nuse core::ops::Range;\n/// Represent a multi-bytes field with a fixed size in a packet\npub(crate) type Field = Range<usize>;\n\nmod codec;\npub use codec::NetlinkAuditCodec;\n\npub mod status;\npub use self::status::*;\n\npub mod rules;\npub use self::rules::*;\n\nmod message;\npub use self::message::*;\n\nmod buffer;\npub use self::buffer::*;\n\npub mod constants;\npub use self::constants::*;\n\n#[cfg(test)]\n#[macro_use]\nextern crate lazy_static;\n"
  },
  {
    "path": "netlink-packet-audit/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    rules::RuleMessage,\n    traits::{Emitable, ParseableParametrized},\n    AuditBuffer,\n    DecodeError,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n    StatusMessage,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum AuditMessage {\n    GetStatus(Option<StatusMessage>),\n    SetStatus(StatusMessage),\n    AddRule(RuleMessage),\n    DelRule(RuleMessage),\n    ListRules(Option<RuleMessage>),\n    /// Event message (message types 1300 through 1399). This includes the following message types\n    /// (this list is non-exhaustive, and not really kept up to date): `AUDIT_SYSCALL`,\n    /// `AUDIT_PATH`, `AUDIT_IPC`, `AUDIT_SOCKETCALL`, `AUDIT_CONFIG_CHANGE`, `AUDIT_SOCKADDR`,\n    /// `AUDIT_CWD`, `AUDIT_EXECVE`, `AUDIT_IPC_SET_PERM`, `AUDIT_MQ_OPEN`, `AUDIT_MQ_SENDRECV`,\n    /// `AUDIT_MQ_NOTIFY`, `AUDIT_MQ_GETSETATTR`, `AUDIT_KERNEL_OTHER`, `AUDIT_FD_PAIR`,\n    /// `AUDIT_OBJ_PID`, `AUDIT_TTY`, `AUDIT_EOE`, `AUDIT_BPRM_FCAPS`, `AUDIT_CAPSET`,\n    /// `AUDIT_MMAP`, `AUDIT_NETFILTER_PKT`, `AUDIT_NETFILTER_CFG`, `AUDIT_SECCOMP`,\n    /// `AUDIT_PROCTITLE`, `AUDIT_FEATURE_CHANGE`, `AUDIT_REPLACE`, `AUDIT_KERN_MODULE`,\n    /// `AUDIT_FANOTIFY`.\n    ///\n    /// The first element of the tuple is the message type, and the second is the event data.\n    Event((u16, String)),\n    /// All the other events are parsed as such as they can be parsed also.\n    Other((u16, String)),\n}\n\nimpl AuditMessage {\n    pub fn is_event(&self) -> bool {\n        matches!(self, AuditMessage::Event(_))\n    }\n\n    pub fn is_get_status(&self) -> bool {\n        matches!(self, AuditMessage::GetStatus(_))\n    }\n\n    pub fn is_set_status(&self) -> bool {\n        matches!(self, AuditMessage::GetStatus(_))\n    }\n\n    pub fn is_add_rule(&self) -> bool {\n        matches!(self, AuditMessage::AddRule(_))\n    }\n\n    pub fn is_del_rule(&self) -> bool {\n        matches!(self, AuditMessage::DelRule(_))\n    }\n\n    pub fn is_list_rules(&self) -> bool {\n        matches!(self, AuditMessage::ListRules(_))\n    }\n\n    pub fn message_type(&self) -> u16 {\n        use self::AuditMessage::*;\n\n        match self {\n            GetStatus(_) => AUDIT_GET,\n            SetStatus(_) => AUDIT_SET,\n            ListRules(_) => AUDIT_LIST_RULES,\n            AddRule(_) => AUDIT_ADD_RULE,\n            DelRule(_) => AUDIT_DEL_RULE,\n            Event((message_type, _)) => *message_type,\n            Other((message_type, _)) => *message_type,\n        }\n    }\n}\n\nimpl Emitable for AuditMessage {\n    fn buffer_len(&self) -> usize {\n        use self::AuditMessage::*;\n\n        match self {\n            GetStatus(Some(ref msg)) => msg.buffer_len(),\n            SetStatus(ref msg) => msg.buffer_len(),\n            AddRule(ref msg) => msg.buffer_len(),\n            DelRule(ref msg) => msg.buffer_len(),\n            ListRules(Some(ref msg)) => msg.buffer_len(),\n            GetStatus(None) | ListRules(None) => 0,\n            Event((_, ref data)) => data.len(),\n            Other((_, ref data)) => data.len(),\n        }\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        use self::AuditMessage::*;\n\n        match self {\n            GetStatus(Some(ref msg)) => msg.emit(buffer),\n            SetStatus(ref msg) => msg.emit(buffer),\n            AddRule(ref msg) => msg.emit(buffer),\n            DelRule(ref msg) => msg.emit(buffer),\n            ListRules(Some(ref msg)) => msg.emit(buffer),\n            ListRules(None) | GetStatus(None) => {}\n            Event((_, ref data)) => buffer.copy_from_slice(data.as_bytes()),\n            Other((_, ref data)) => buffer.copy_from_slice(data.as_bytes()),\n        }\n    }\n}\n\nimpl NetlinkSerializable for AuditMessage {\n    fn message_type(&self) -> u16 {\n        self.message_type()\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl NetlinkDeserializable for AuditMessage {\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        match AuditBuffer::new_checked(payload) {\n            Err(e) => Err(e),\n            Ok(buffer) => match AuditMessage::parse_with_param(&buffer, header.message_type) {\n                Err(e) => Err(e),\n                Ok(message) => Ok(message),\n            },\n        }\n    }\n}\n\nimpl From<AuditMessage> for NetlinkPayload<AuditMessage> {\n    fn from(message: AuditMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/action.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\n\n#[derive(Copy, Debug, PartialEq, Eq, Clone)]\npub enum RuleAction {\n    Never,\n    Possible,\n    Always,\n    Unknown(u32),\n}\n\nimpl From<u32> for RuleAction {\n    fn from(value: u32) -> Self {\n        use self::RuleAction::*;\n        match value {\n            AUDIT_NEVER => Never,\n            AUDIT_POSSIBLE => Possible,\n            AUDIT_ALWAYS => Always,\n            _ => Unknown(value),\n        }\n    }\n}\n\nimpl From<RuleAction> for u32 {\n    fn from(value: RuleAction) -> Self {\n        use self::RuleAction::*;\n        match value {\n            Never => AUDIT_NEVER,\n            Possible => AUDIT_POSSIBLE,\n            Always => AUDIT_ALWAYS,\n            Unknown(value) => value,\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{constants::*, rules::*, traits::Parseable, DecodeError, Field};\n\n// FIXME: when const fn are stable, use them, instead of defining a macro\n// const fn u32_array(start: usize, len: usize) -> Field {\n//     start..(start + 4 * len)\n// }\nmacro_rules! u32_array {\n    ($start:expr, $len:expr) => {\n        $start..($start + 4 * $len)\n    };\n}\n\nconst FLAGS: Field = 0..4;\nconst ACTION: Field = 4..8;\nconst FIELD_COUNT: Field = 8..12;\nconst SYSCALLS: Field = u32_array!(FIELD_COUNT.end, AUDIT_BITMASK_SIZE);\nconst FIELDS: Field = u32_array!(SYSCALLS.end, AUDIT_MAX_FIELDS);\nconst VALUES: Field = u32_array!(FIELDS.end, AUDIT_MAX_FIELDS);\nconst FIELD_FLAGS: Field = u32_array!(VALUES.end, AUDIT_MAX_FIELDS);\nconst BUFLEN: Field = FIELD_FLAGS.end..FIELD_FLAGS.end + 4;\n\npub(crate) const RULE_BUF_MIN_LEN: usize = BUFLEN.end;\n\n#[allow(non_snake_case)]\nfn BUF(len: usize) -> Field {\n    BUFLEN.end..(BUFLEN.end + len)\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct RuleBuffer<T> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> RuleBuffer<T> {\n    pub fn new(buffer: T) -> RuleBuffer<T> {\n        RuleBuffer { buffer }\n    }\n\n    pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {\n        let packet = Self::new(buffer);\n        packet.check_len()?;\n        Ok(packet)\n    }\n\n    pub(crate) fn check_len(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < BUFLEN.end {\n            Err(format!(\n                \"buffer size is {}, whereas a rule buffer is at least {} long\",\n                len, BUFLEN.end\n            )\n            .into())\n        } else if len < BUFLEN.end + self.buflen() as usize {\n            Err(format!(\n                \"buffer length is {}, but it should be {} (header) + {} (length field)\",\n                len,\n                BUFLEN.end,\n                self.buflen()\n            )\n            .into())\n        } else {\n            Ok(())\n        }\n    }\n\n    pub fn flags(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[FLAGS])\n    }\n\n    pub fn action(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[ACTION])\n    }\n\n    pub fn field_count(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[FIELD_COUNT])\n    }\n\n    pub fn buflen(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[BUFLEN])\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> RuleBuffer<&'a T> {\n    pub fn syscalls(&self) -> &'a [u8] {\n        &self.buffer.as_ref()[SYSCALLS]\n    }\n\n    pub fn fields(&self) -> &'a [u8] {\n        &self.buffer.as_ref()[FIELDS]\n    }\n\n    pub fn values(&self) -> &'a [u8] {\n        &self.buffer.as_ref()[VALUES]\n    }\n\n    pub fn field_flags(&self) -> &'a [u8] {\n        &self.buffer.as_ref()[FIELD_FLAGS]\n    }\n\n    pub fn buf(&self) -> &'a [u8] {\n        let field = BUF(self.buflen() as usize);\n        &self.buffer.as_ref()[field.start..field.end]\n    }\n}\n\nimpl<T: AsRef<[u8]> + AsMut<[u8]>> RuleBuffer<T> {\n    pub fn set_flags(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[FLAGS], value)\n    }\n\n    pub fn set_action(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[ACTION], value)\n    }\n\n    pub fn set_field_count(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[FIELD_COUNT], value)\n    }\n\n    pub fn set_buflen(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[BUFLEN], value)\n    }\n\n    pub fn syscalls_mut(&mut self) -> &mut [u8] {\n        &mut self.buffer.as_mut()[SYSCALLS]\n    }\n\n    pub fn fields_mut(&mut self) -> &mut [u8] {\n        &mut self.buffer.as_mut()[FIELDS]\n    }\n\n    pub fn set_field(&mut self, position: usize, value: u32) {\n        let offset = FIELDS.start + (position * 4);\n        assert!(position <= FIELDS.end - 4);\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[offset..offset + 4], value)\n    }\n\n    pub fn values_mut(&mut self) -> &mut [u8] {\n        &mut self.buffer.as_mut()[VALUES]\n    }\n\n    pub fn set_value(&mut self, position: usize, value: u32) {\n        let offset = VALUES.start + (position * 4);\n        assert!(position <= VALUES.end - 4);\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[offset..offset + 4], value)\n    }\n\n    pub fn field_flags_mut(&mut self) -> &mut [u8] {\n        &mut self.buffer.as_mut()[FIELD_FLAGS]\n    }\n\n    pub fn set_field_flags(&mut self, position: usize, value: u32) {\n        let offset = FIELD_FLAGS.start + (position * 4);\n        assert!(position <= FIELD_FLAGS.end - 4);\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[offset..offset + 4], value)\n    }\n\n    pub fn buf_mut(&mut self) -> &mut [u8] {\n        let field = BUF(self.buflen() as usize);\n        &mut self.buffer.as_mut()[field.start..field.end]\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RuleBuffer<&'a T>> for RuleMessage {\n    fn parse(buf: &RuleBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::RuleField::*;\n\n        buf.check_len().context(\"invalid rule message buffer\")?;\n        let mut rule = RuleMessage::new();\n        rule.flags = buf.flags().into();\n        rule.action = buf.action().into();\n        rule.syscalls = RuleSyscalls::from_slice(buf.syscalls())?;\n\n        let mut offset = 0;\n\n        let fields = buf.fields().chunks(4).map(NativeEndian::read_u32);\n        let values = buf.values().chunks(4).map(NativeEndian::read_u32);\n        let field_flags = buf\n            .field_flags()\n            .chunks(4)\n            .map(|chunk| RuleFieldFlags::from(NativeEndian::read_u32(chunk)));\n        for (field, value, flags) in fields\n            .zip(values.zip(field_flags))\n            .map(|(field, (value, flags))| (field, value, flags))\n            .take(buf.field_count() as usize)\n        {\n            let field = match field {\n                AUDIT_PID => Pid(value),\n                AUDIT_UID => Uid(value),\n                AUDIT_EUID => Euid(value),\n                AUDIT_SUID => Suid(value),\n                AUDIT_FSUID => Fsuid(value),\n                AUDIT_GID => Gid(value),\n                AUDIT_EGID => Egid(value),\n                AUDIT_SGID => Sgid(value),\n                AUDIT_FSGID => Fsgid(value),\n                AUDIT_LOGINUID => Loginuid(value),\n                AUDIT_PERS => Pers(value),\n                AUDIT_ARCH => Arch(value),\n                AUDIT_MSGTYPE => Msgtype(value),\n                AUDIT_PPID => Ppid(value),\n                AUDIT_LOGINUID_SET => LoginuidSet(value),\n                AUDIT_SESSIONID => Sessionid(value),\n                AUDIT_FSTYPE => Fstype(value),\n                AUDIT_DEVMAJOR => Devmajor(value),\n                AUDIT_DEVMINOR => Devminor(value),\n                AUDIT_INODE => Inode(value),\n                AUDIT_EXIT => Exit(value),\n                AUDIT_SUCCESS => Success(value),\n                AUDIT_PERM => Perm(value),\n                AUDIT_FILETYPE => Filetype(value),\n                AUDIT_OBJ_UID => ObjUid(value),\n                AUDIT_OBJ_GID => ObjGid(value),\n                AUDIT_FIELD_COMPARE => FieldCompare(value),\n                AUDIT_EXE => Exe(value),\n                AUDIT_ARG0 => Arg0(value),\n                AUDIT_ARG1 => Arg1(value),\n                AUDIT_ARG2 => Arg2(value),\n                AUDIT_ARG3 => Arg3(value),\n                _ => {\n                    // For all the other fields, the value is a string\n                    let str_end = offset + value as usize;\n                    if str_end > buf.buf().len() {\n                        return Err(format!(\n                            \"failed to decode field. type={} (value should be a string?)\",\n                            field\n                        )\n                        .into());\n                    }\n                    let s: String = String::from_utf8_lossy(&buf.buf()[offset..str_end]).into();\n                    offset = str_end;\n                    match field {\n                        AUDIT_WATCH => Watch(s),\n                        AUDIT_DIR => Dir(s),\n                        AUDIT_FILTERKEY => Filterkey(s),\n                        AUDIT_SUBJ_USER => SubjUser(s),\n                        AUDIT_SUBJ_ROLE => SubjRole(s),\n                        AUDIT_SUBJ_TYPE => SubjType(s),\n                        AUDIT_SUBJ_SEN => SubjSen(s),\n                        AUDIT_SUBJ_CLR => SubjClr(s),\n                        AUDIT_OBJ_USER => ObjUser(s),\n                        AUDIT_OBJ_ROLE => ObjRole(s),\n                        AUDIT_OBJ_TYPE => ObjType(s),\n                        AUDIT_OBJ_LEV_LOW => ObjLevLow(s),\n                        AUDIT_OBJ_LEV_HIGH => ObjLevHigh(s),\n                        _ => {\n                            return Err(format!(\n                                \"failed to decode field (unknown type) type={}, value={}\",\n                                field, s\n                            )\n                            .into());\n                        }\n                    }\n                }\n            };\n            rule.fields.push((field, flags));\n        }\n        Ok(rule)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/field.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum RuleField {\n    Pid(u32),\n    Uid(u32),\n    Euid(u32),\n    Suid(u32),\n    Fsuid(u32),\n    Gid(u32),\n    Egid(u32),\n    Sgid(u32),\n    Fsgid(u32),\n    Loginuid(u32),\n    Pers(u32),\n    Arch(u32),\n    Msgtype(u32),\n    Ppid(u32),\n    LoginuidSet(u32),\n    Sessionid(u32),\n    Fstype(u32),\n    Devmajor(u32),\n    Devminor(u32),\n    Inode(u32),\n    Exit(u32),\n    Success(u32),\n    Perm(u32),\n    Filetype(u32),\n    ObjUid(u32),\n    ObjGid(u32),\n    FieldCompare(u32),\n    Exe(u32),\n    Arg0(u32),\n    Arg1(u32),\n    Arg2(u32),\n    Arg3(u32),\n\n    Watch(String),\n    Dir(String),\n    Filterkey(String),\n\n    SubjUser(String),\n    SubjRole(String),\n    SubjType(String),\n    SubjSen(String),\n    SubjClr(String),\n\n    ObjUser(String),\n    ObjRole(String),\n    ObjType(String),\n    ObjLevLow(String),\n    ObjLevHigh(String),\n}\n\n#[derive(Copy, Debug, PartialEq, Eq, Clone)]\npub enum RuleFieldFlags {\n    BitMask,\n    BitTest,\n    LessThan,\n    GreaterThan,\n    NotEqual,\n    Equal,\n    LessThanOrEqual,\n    GreaterThanOrEqual,\n    None,\n    Unknown(u32),\n}\n\nimpl From<u32> for RuleFieldFlags {\n    fn from(value: u32) -> Self {\n        use self::RuleFieldFlags::*;\n        match value {\n            AUDIT_BIT_MASK => BitMask,\n            AUDIT_BIT_TEST => BitTest,\n            AUDIT_LESS_THAN => LessThan,\n            AUDIT_GREATER_THAN => GreaterThan,\n            AUDIT_NOT_EQUAL => NotEqual,\n            AUDIT_EQUAL => Equal,\n            AUDIT_LESS_THAN_OR_EQUAL => LessThanOrEqual,\n            AUDIT_GREATER_THAN_OR_EQUAL => GreaterThanOrEqual,\n            0 => None,\n            _ => Unknown(value),\n        }\n    }\n}\n\nimpl From<RuleFieldFlags> for u32 {\n    fn from(value: RuleFieldFlags) -> Self {\n        use self::RuleFieldFlags::*;\n        match value {\n            BitMask => AUDIT_BIT_MASK,\n            BitTest => AUDIT_BIT_TEST,\n            LessThan => AUDIT_LESS_THAN,\n            GreaterThan => AUDIT_GREATER_THAN,\n            NotEqual => AUDIT_NOT_EQUAL,\n            Equal => AUDIT_EQUAL,\n            LessThanOrEqual => AUDIT_LESS_THAN_OR_EQUAL,\n            GreaterThanOrEqual => AUDIT_GREATER_THAN_OR_EQUAL,\n            None => 0,\n            Unknown(value) => value,\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/flags.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\n\n#[derive(Copy, Debug, PartialEq, Eq, Clone)]\npub enum RuleFlags {\n    FilterUser,\n    FilterTask,\n    FilterEntry,\n    FilterWatch,\n    FilterExit,\n    FilterType,\n    FilterFs,\n    NrFilters,\n    FilterPrepend,\n    Unset,\n    Unknown(u32),\n}\n\nimpl From<u32> for RuleFlags {\n    fn from(value: u32) -> Self {\n        use self::RuleFlags::*;\n        match value {\n            AUDIT_FILTER_USER => FilterUser,\n            AUDIT_FILTER_TASK => FilterTask,\n            AUDIT_FILTER_ENTRY => FilterEntry,\n            AUDIT_FILTER_WATCH => FilterWatch,\n            AUDIT_FILTER_EXIT => FilterExit,\n            AUDIT_FILTER_TYPE => FilterType,\n            AUDIT_FILTER_FS => FilterFs,\n            AUDIT_NR_FILTERS => NrFilters,\n            AUDIT_FILTER_PREPEND => FilterPrepend,\n            AUDIT_FILTER_UNSET => Unset,\n            _ => Unknown(value),\n        }\n    }\n}\n\nimpl From<RuleFlags> for u32 {\n    fn from(value: RuleFlags) -> Self {\n        use self::RuleFlags::*;\n        match value {\n            FilterUser => AUDIT_FILTER_USER,\n            FilterTask => AUDIT_FILTER_TASK,\n            FilterEntry => AUDIT_FILTER_ENTRY,\n            FilterWatch => AUDIT_FILTER_WATCH,\n            FilterExit => AUDIT_FILTER_EXIT,\n            FilterType => AUDIT_FILTER_TYPE,\n            FilterFs => AUDIT_FILTER_FS,\n            NrFilters => AUDIT_NR_FILTERS,\n            FilterPrepend => AUDIT_FILTER_PREPEND,\n            Unset => AUDIT_FILTER_UNSET,\n            Unknown(value) => value,\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod action;\npub use self::action::*;\n\nmod field;\npub use self::field::*;\n\nmod flags;\npub use self::flags::*;\n\nmod syscalls;\npub use self::syscalls::*;\n\nmod buffer;\npub use self::buffer::*;\n\nmod rule;\npub use self::rule::*;\n\n#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/rule.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::AUDIT_MAX_FIELDS,\n    rules::{\n        RuleAction,\n        RuleBuffer,\n        RuleField,\n        RuleFieldFlags,\n        RuleFlags,\n        RuleSyscalls,\n        RULE_BUF_MIN_LEN,\n    },\n    traits::Emitable,\n};\n\nuse crate::constants::*;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct RuleMessage {\n    pub flags: RuleFlags,\n    pub action: RuleAction,\n    pub fields: Vec<(RuleField, RuleFieldFlags)>,\n    pub syscalls: RuleSyscalls,\n}\n\nimpl Default for RuleMessage {\n    fn default() -> Self {\n        RuleMessage::new()\n    }\n}\n\nimpl RuleMessage {\n    pub fn new() -> Self {\n        RuleMessage {\n            flags: RuleFlags::from(0),\n            action: RuleAction::from(0),\n            fields: Vec::with_capacity(AUDIT_MAX_FIELDS),\n            syscalls: RuleSyscalls::new_zeroed(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn compute_string_values_length(&self) -> usize {\n        use self::RuleField::*;\n        let mut len = 0;\n        for (field, _) in self.fields.iter() {\n            match field {\n                Watch(ref s)\n                    | Dir(ref s)\n                    | Filterkey(ref s)\n                    | SubjUser(ref s)\n                    | SubjRole(ref s)\n                    | SubjType(ref s)\n                    | SubjSen(ref s)\n                    | SubjClr(ref s)\n                    | ObjUser(ref s)\n                    | ObjRole(ref s)\n                    | ObjType(ref s)\n                    | ObjLevLow(ref s)\n                    | ObjLevHigh(ref s)\n                    => len += s.len(),\n                _ => {}\n            }\n        }\n        len\n    }\n}\n\nfn set_str_field<T>(rule_buffer: &mut RuleBuffer<T>, position: usize, buflen: &mut usize, s: &str)\nwhere\n    T: AsRef<[u8]> + AsMut<[u8]>,\n{\n    // append the string to the strings buffer\n    rule_buffer.buf_mut()[*buflen..*buflen + s.len()].copy_from_slice(s.as_bytes());\n    // set the field's value to the string length\n    rule_buffer.set_value(position, s.len() as u32);\n    *buflen += s.len();\n}\n\nimpl Emitable for RuleMessage {\n    fn buffer_len(&self) -> usize {\n        RULE_BUF_MIN_LEN + self.compute_string_values_length()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        use self::RuleField::*;\n        let mut rule_buffer = RuleBuffer::new(buffer);\n\n        rule_buffer.set_flags(self.flags.into());\n        rule_buffer.set_action(self.action.into());\n        rule_buffer.set_field_count(self.fields.len() as u32);\n        {\n            let syscalls = rule_buffer.syscalls_mut();\n            for (i, word) in self.syscalls.0.iter().enumerate() {\n                NativeEndian::write_u32(&mut syscalls[i * 4..i * 4 + 4], *word);\n            }\n        }\n        rule_buffer.set_buflen(self.compute_string_values_length() as u32);\n\n        let mut buflen = 0;\n\n        for (i, (field, flags)) in self.fields.iter().enumerate() {\n            rule_buffer.set_field_flags(i, (*flags).into());\n            match field {\n                Watch(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_WATCH);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                Dir(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_DIR);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                Filterkey(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_FILTERKEY);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                SubjUser(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_SUBJ_USER);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                SubjRole(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_SUBJ_ROLE);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                SubjType(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_SUBJ_TYPE);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                SubjSen(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_SUBJ_SEN);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                SubjClr(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_SUBJ_CLR);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                ObjUser(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_USER);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                ObjRole(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_ROLE);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                ObjType(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_TYPE);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                ObjLevLow(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_LEV_LOW);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                ObjLevHigh(ref s) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_LEV_HIGH);\n                    set_str_field(&mut rule_buffer, i, &mut buflen, s);\n                }\n                Pid(val) => {\n                    rule_buffer.set_field(i, AUDIT_PID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Uid(val) => {\n                    rule_buffer.set_field(i, AUDIT_UID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Euid(val) => {\n                    rule_buffer.set_field(i, AUDIT_EUID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Suid(val) => {\n                    rule_buffer.set_field(i, AUDIT_SUID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Fsuid(val) => {\n                    rule_buffer.set_field(i, AUDIT_FSUID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Gid(val) => {\n                    rule_buffer.set_field(i, AUDIT_GID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Egid(val) => {\n                    rule_buffer.set_field(i, AUDIT_EGID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Sgid(val) => {\n                    rule_buffer.set_field(i, AUDIT_SGID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Fsgid(val) => {\n                    rule_buffer.set_field(i, AUDIT_FSGID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Loginuid(val) => {\n                    rule_buffer.set_field(i, AUDIT_LOGINUID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Pers(val) => {\n                    rule_buffer.set_field(i, AUDIT_PERS);\n                    rule_buffer.set_value(i, *val);\n                }\n                Arch(val) => {\n                    rule_buffer.set_field(i, AUDIT_ARCH);\n                    rule_buffer.set_value(i, *val);\n                }\n                Msgtype(val) => {\n                    rule_buffer.set_field(i, AUDIT_MSGTYPE);\n                    rule_buffer.set_value(i, *val);\n                }\n                Ppid(val) => {\n                    rule_buffer.set_field(i, AUDIT_PPID);\n                    rule_buffer.set_value(i, *val);\n                }\n                LoginuidSet(val) => {\n                    rule_buffer.set_field(i, AUDIT_LOGINUID_SET);\n                    rule_buffer.set_value(i, *val);\n                }\n                Sessionid(val) => {\n                    rule_buffer.set_field(i, AUDIT_SESSIONID);\n                    rule_buffer.set_value(i, *val);\n                }\n                Fstype(val) => {\n                    rule_buffer.set_field(i, AUDIT_FSTYPE);\n                    rule_buffer.set_value(i, *val);\n                }\n                Devmajor(val) => {\n                    rule_buffer.set_field(i, AUDIT_DEVMAJOR);\n                    rule_buffer.set_value(i, *val);\n                }\n                Devminor(val) => {\n                    rule_buffer.set_field(i, AUDIT_DEVMINOR);\n                    rule_buffer.set_value(i, *val);\n                }\n                Inode(val) => {\n                    rule_buffer.set_field(i, AUDIT_INODE);\n                    rule_buffer.set_value(i, *val);\n                }\n                Exit(val) => {\n                    rule_buffer.set_field(i, AUDIT_EXIT);\n                    rule_buffer.set_value(i, *val);\n                }\n                Success(val) => {\n                    rule_buffer.set_field(i, AUDIT_SUCCESS);\n                    rule_buffer.set_value(i, *val);\n                }\n                Perm(val) => {\n                    rule_buffer.set_field(i, AUDIT_PERM);\n                    rule_buffer.set_value(i, *val);\n                }\n                Filetype(val) => {\n                    rule_buffer.set_field(i, AUDIT_FILETYPE);\n                    rule_buffer.set_value(i, *val);\n                }\n                ObjUid(val) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_UID);\n                    rule_buffer.set_value(i, *val);\n                }\n                ObjGid(val) => {\n                    rule_buffer.set_field(i, AUDIT_OBJ_GID);\n                    rule_buffer.set_value(i, *val);\n                }\n                FieldCompare(val) => {\n                    rule_buffer.set_field(i, AUDIT_FIELD_COMPARE);\n                    rule_buffer.set_value(i, *val);\n                }\n                Exe(val) => {\n                    rule_buffer.set_field(i, AUDIT_EXE);\n                    rule_buffer.set_value(i, *val);\n                }\n                Arg0(val) => {\n                    rule_buffer.set_field(i, AUDIT_ARG0);\n                    rule_buffer.set_value(i, *val);\n                }\n                Arg1(val) => {\n                    rule_buffer.set_field(i, AUDIT_ARG1);\n                    rule_buffer.set_value(i, *val);\n                }\n                Arg2(val) => {\n                    rule_buffer.set_field(i, AUDIT_ARG2);\n                    rule_buffer.set_value(i, *val);\n                }\n                Arg3(val) => {\n                    rule_buffer.set_field(i, AUDIT_ARG3);\n                    rule_buffer.set_value(i, *val);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/syscalls.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{constants::*, DecodeError};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct RuleSyscalls(pub(crate) Vec<u32>);\n\nconst BITMASK_BYTE_LEN: usize = AUDIT_BITMASK_SIZE * 4;\nconst BITMASK_BIT_LEN: u32 = AUDIT_BITMASK_SIZE as u32 * 32;\n\n// FIXME: I'm not 100% sure this implementation is correct wrt to endianness.\nimpl RuleSyscalls {\n    // FIXME: this should be a TryFrom when it stabilized...\n    pub fn from_slice(slice: &[u8]) -> Result<Self, DecodeError> {\n        if slice.len() != BITMASK_BYTE_LEN {\n            return Err(DecodeError::from(format!(\n                \"invalid bitmask size: expected {} bytes got {}\",\n                BITMASK_BYTE_LEN,\n                slice.len()\n            )));\n        }\n        let mut mask = RuleSyscalls::new_zeroed();\n        let mut word = 0;\n        while word < AUDIT_BITMASK_SIZE {\n            mask.0[word] = NativeEndian::read_u32(&slice[word * 4..word * 4 + 4]);\n            word += 1;\n        }\n        Ok(mask)\n    }\n\n    pub fn new_zeroed() -> Self {\n        RuleSyscalls(vec![0; AUDIT_BITMASK_SIZE])\n    }\n\n    pub fn new_maxed() -> Self {\n        RuleSyscalls(vec![0xffff_ffff; AUDIT_BITMASK_SIZE])\n    }\n\n    /// Unset all the bits\n    pub fn unset_all(&mut self) -> &mut Self {\n        self.0 = vec![0; AUDIT_BITMASK_SIZE];\n        self\n    }\n\n    /// Return `true` if all the syscalls are set, `false` otherwise\n    pub fn is_all(&self) -> bool {\n        for i in 0..AUDIT_BITMASK_SIZE {\n            if self.0[i] != 0xffff_ffff {\n                return false;\n            }\n        }\n        true\n    }\n\n    /// Set all the bits\n    pub fn set_all(&mut self) -> &mut Self {\n        self.0 = vec![0xffff_ffff; AUDIT_BITMASK_SIZE];\n        self\n    }\n\n    /// Unset the bit corresponding to the given syscall\n    pub fn unset(&mut self, syscall: u32) -> &mut Self {\n        let (word, mask) = Self::syscall_coordinates(syscall);\n        self.0[word] &= !mask;\n        self\n    }\n\n    /// Set the bit corresponding to the given syscall\n    pub fn set(&mut self, syscall: u32) -> &mut Self {\n        let (word, mask) = Self::syscall_coordinates(syscall);\n        self.0[word] |= mask;\n        self\n    }\n\n    /// Check if the bit corresponding to the given syscall is set\n    pub fn has(&self, syscall: u32) -> bool {\n        let (word, mask) = Self::syscall_coordinates(syscall);\n        self.0[word] & mask == mask\n    }\n\n    fn syscall_coordinates(syscall: u32) -> (usize, u32) {\n        let word_index = syscall / 32;\n        let mask = 0x0000_0001 << (syscall - word_index * 32);\n        (word_index as usize, mask)\n    }\n}\n\n// FIXME: There is a LOT of copy paste for those iterator implementations... This feels wrong but I\n// could not figure out how to avoid it :(\n\npub struct RuleSyscallsIter<T> {\n    index: u32,\n    syscalls: T,\n}\n\nimpl IntoIterator for RuleSyscalls {\n    type Item = u32;\n    type IntoIter = RuleSyscallsIter<RuleSyscalls>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        RuleSyscallsIter {\n            index: 0,\n            syscalls: self,\n        }\n    }\n}\n\nimpl Iterator for RuleSyscallsIter<RuleSyscalls> {\n    type Item = u32;\n    fn next(&mut self) -> Option<Self::Item> {\n        while self.index < BITMASK_BIT_LEN {\n            let index = self.index;\n            self.index += 1;\n            if self.syscalls.has(index) {\n                return Some(index as u32);\n            }\n        }\n        None\n    }\n}\n\nimpl<'a> IntoIterator for &'a RuleSyscalls {\n    type Item = u32;\n    type IntoIter = RuleSyscallsIter<&'a RuleSyscalls>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        RuleSyscallsIter {\n            index: 0,\n            syscalls: self,\n        }\n    }\n}\n\nimpl<'a> Iterator for RuleSyscallsIter<&'a RuleSyscalls> {\n    type Item = u32;\n    fn next(&mut self) -> Option<Self::Item> {\n        while self.index < BITMASK_BIT_LEN {\n            let index = self.index;\n            self.index += 1;\n            if self.syscalls.has(index) {\n                return Some(index as u32);\n            }\n        }\n        None\n    }\n}\n\nimpl<'a> IntoIterator for &'a mut RuleSyscalls {\n    type Item = u32;\n    type IntoIter = RuleSyscallsIter<&'a mut RuleSyscalls>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        RuleSyscallsIter {\n            index: 0,\n            syscalls: self,\n        }\n    }\n}\n\nimpl<'a> Iterator for RuleSyscallsIter<&'a mut RuleSyscalls> {\n    type Item = u32;\n    fn next(&mut self) -> Option<Self::Item> {\n        while self.index < BITMASK_BIT_LEN {\n            let index = self.index;\n            self.index += 1;\n            if self.syscalls.has(index) {\n                return Some(index as u32);\n            }\n        }\n        None\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    #[test]\n    fn test_from_slice() {\n        let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];\n        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();\n        assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);\n\n        let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];\n        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();\n        assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);\n    }\n\n    #[test]\n    fn test_iter() {\n        let s: Vec<u8> = vec![0xff; BITMASK_BYTE_LEN];\n        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();\n        let mut iter = syscalls.into_iter();\n        for i in 0..BITMASK_BIT_LEN {\n            assert_eq!(i as u32, iter.next().unwrap());\n        }\n        assert!(iter.next().is_none());\n\n        let s: Vec<u8> = vec![0; BITMASK_BYTE_LEN];\n        let syscalls = RuleSyscalls::from_slice(&s[..]).unwrap();\n        let mut iter = syscalls.into_iter();\n        assert!(iter.next().is_none());\n    }\n\n    #[test]\n    fn test_set_unset() {\n        let mut syscalls = RuleSyscalls::new_zeroed();\n        for i in 0..BITMASK_BIT_LEN {\n            syscalls.set(i);\n        }\n        assert_eq!(syscalls.0, vec![0xffff_ffff; AUDIT_BITMASK_SIZE]);\n        for i in 0..BITMASK_BIT_LEN {\n            syscalls.unset(BITMASK_BIT_LEN - 1 - i);\n        }\n        assert_eq!(syscalls.0, vec![0; AUDIT_BITMASK_SIZE]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/rules/tests.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    rules::{\n        RuleAction,\n        RuleBuffer,\n        RuleField,\n        RuleFieldFlags,\n        RuleFlags,\n        RuleMessage,\n        RuleSyscalls,\n    },\n    traits::{Emitable, Parseable},\n};\n\nconst AUDIT_ARCH_X86_64: u32 = 0xC000_003E;\n\n#[test]\nfn parse_rule_1() {\n    let buf = RuleBuffer::new_checked(&M1_BYTES[..]).unwrap();\n    let parsed = RuleMessage::parse(&buf).unwrap();\n    assert_eq!(parsed, *M1);\n}\n\n#[test]\nfn emit_rule_1() {\n    assert_eq!(M1.buffer_len(), M1_BYTES.len());\n    let mut buf = vec![0; M1_BYTES.len()];\n    M1.emit(&mut buf[..]);\n    assert_eq!(&buf[..], &M1_BYTES[..]);\n}\n\n#[test]\nfn parse_rule_2() {\n    let buf = RuleBuffer::new_checked(&M2_BYTES[..]).unwrap();\n    let parsed = RuleMessage::parse(&buf).unwrap();\n    assert_eq!(parsed, *M2);\n}\n\n#[test]\nfn emit_rule_2() {\n    assert_eq!(M2.buffer_len(), M2_BYTES.len());\n    let mut buf = vec![0; M2_BYTES.len()];\n    M2.emit(&mut buf[..]);\n    assert_eq!(&buf[..], &M2_BYTES[..]);\n}\n\n#[test]\nfn parse_rule_3() {\n    let buf = RuleBuffer::new_checked(&M3_BYTES[..]).unwrap();\n    let parsed = RuleMessage::parse(&buf).unwrap();\n    assert_eq!(parsed, *M3);\n}\n\n#[test]\nfn emit_rule_3() {\n    assert_eq!(M3.buffer_len(), M3_BYTES.len());\n    let mut buf = vec![0; M3_BYTES.len()];\n    M3.emit(&mut buf[..]);\n    assert_eq!(&buf[..], &M3_BYTES[..]);\n}\n\nlazy_static! {\n    // -w /etc/passwd -p rwxa\n    static ref M1_BYTES: Vec<u8> = vec![\n        0x04, 0x00, 0x00, 0x00, // flags\n        0x02, 0x00, 0x00, 0x00, // actions\n        0x02, 0x00, 0x00, 0x00, // field count\n\n        // syscalls (64 u32)\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\n        // fields (AUDIT_MAX_FIELD=64, but only the first 8 bytes are being used here)\n        //\n        // 0x69 = AUDIT_WATCH => the value is a path, so the field value is the path length, and the string itself is at the end of the buffer.\n        0x69, 0x00, 0x00, 0x00,\n        // 0x6a = AUDIT_PERM\n        0x6a, 0x00, 0x00, 0x00,\n        // Unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // values (AUDIT_MAX_FIELD=64, but only the first 8 bytes are being used here)\n        0x0b, 0x00, 0x00, 0x00, // 11 = length of the string\n        0x0f, 0x00, 0x00, 0x00, // 15 (not sure how it's interpreted)\n        // Unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // fieldflags\n        0x00, 0x00, 0x00, 0x40, // equal\n        0x00, 0x00, 0x00, 0x40, // equal\n        // Unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        0x0b, 0x00, 0x00, 0x00, // total buf length = 11\n        // buf /etc/passwd\n        0x2f, 0x65, 0x74, 0x63, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x64];\n\n    static ref M1: RuleMessage = RuleMessage {\n        flags: RuleFlags::FilterExit,\n        action: RuleAction::Always,\n        fields: vec![\n            (\n                RuleField::Watch(\"/etc/passwd\".into()),\n                RuleFieldFlags::Equal,\n            ),\n            (RuleField::Perm(15), RuleFieldFlags::Equal),\n        ],\n        syscalls: RuleSyscalls::new_maxed(),\n    };\n\n    // -w /etc/passwd -p rwxa -k mykey\n    static ref M2_BYTES: Vec<u8> = vec![\n        0x04, 0x00, 0x00, 0x00, // flags\n        0x02, 0x00, 0x00, 0x00, // actions\n        0x03, 0x00, 0x00, 0x00, // fields count\n\n        // syscalls\n        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\n        // fields\n        0x69, 0x00, 0x00, 0x00, // AUDIT_WATCH\n        0x6a, 0x00, 0x00, 0x00, // AUDIT_PERM\n        0xd2, 0x00, 0x00, 0x00, // AUDIT_FILTERKEY\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // values\n        0x0b, 0x00, 0x00, 0x00, // length of the AUDIT_WATCH value (11)\n        0x0f, 0x00, 0x00, 0x00, // value of the AUDIT_PERM field (15)\n        0x05, 0x00, 0x00, 0x00, // length of the AUDIT_FILTERKEY field (5)\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // fieldflags\n        0x00, 0x00, 0x00, 0x40, // equal\n        0x00, 0x00, 0x00, 0x40, // equal\n        0x00, 0x00, 0x00, 0x40, // equal\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // string buffer\n        0x10, 0x00, 0x00, 0x00,  // buffer length = 16\n        0x2f, 0x65, 0x74, 0x63, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x64,  // value of AUDIT_WATCH (\"/etc/passwd\")\n        0x6d, 0x79, 0x6b, 0x65, 0x79 // value of AUDIT_FILTERKEY (\"mykey\")\n    ];\n\n    static ref M2: RuleMessage = RuleMessage {\n        flags: RuleFlags::FilterExit,\n        action: RuleAction::Always,\n        fields: vec![\n            (RuleField::Watch(\"/etc/passwd\".into()), RuleFieldFlags::Equal),\n            (RuleField::Perm(15), RuleFieldFlags::Equal),\n            (RuleField::Filterkey(\"mykey\".into()), RuleFieldFlags::Equal),\n        ],\n        syscalls: RuleSyscalls::new_maxed(),\n    };\n\n    // -a always,exit -F arch=b64 -S personality -F key=bypass\n    static ref M3_BYTES: Vec<u8> = vec![\n        0x04, 0x00, 0x00, 0x00, // flags\n        0x02, 0x00, 0x00, 0x00, // actions\n        0x02, 0x00, 0x00, 0x00, // field count\n\n        // syscalls (execve)\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // fields\n        0x0b, 0x00, 0x00, 0x00, // AUDIT_ARCH\n        0xd2, 0x00, 0x00, 0x00, // AUDIT_FILTERKEY\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // values\n        0x3e, 0x00, 0x00, 0xc0, // AUDIT_ARCH_X86_64\n        0x06, 0x00, 0x00, 0x00, // length of the string = 6\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        // fieldflags\n        0x00, 0x00, 0x00, 0x40, // equal\n        0x00, 0x00, 0x00, 0x40, // equal\n        // unused\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n        0x06, 0x00, 0x00, 0x00, // buffer totoal length (6)\n        0x62, 0x79, 0x70, 0x61, 0x73, 0x73 // bypass\n    ];\n\n    static ref M3: RuleMessage = {\n        let mut syscalls = RuleSyscalls::new_zeroed();\n        syscalls.set(135);\n        RuleMessage {\n            flags: RuleFlags::FilterExit,\n            action: RuleAction::Always,\n            fields: vec![\n                (RuleField::Arch(AUDIT_ARCH_X86_64), RuleFieldFlags::Equal),\n                (RuleField::Filterkey(\"bypass\".into()), RuleFieldFlags::Equal),\n            ],\n            syscalls,\n        }\n    };\n}\n"
  },
  {
    "path": "netlink-packet-audit/src/status.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n    Field,\n};\n\nconst MASK: Field = 0..4;\nconst ENABLED: Field = 4..8;\nconst FAILURE: Field = 8..12;\nconst PID: Field = 12..16;\nconst RATE_LIMITING: Field = 16..20;\nconst BACKLOG_LIMIT: Field = 20..24;\nconst LOST: Field = 24..28;\nconst BACKLOG: Field = 28..32;\nconst FEATURE_BITMAP: Field = 32..36;\nconst BACKLOG_WAIT_TIME: Field = 36..40;\npub const STATUS_MESSAGE_LEN: usize = BACKLOG_WAIT_TIME.end;\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct StatusMessage {\n    /// Bit mask for valid entries\n    pub mask: u32,\n    pub enabled: u32,\n    /// Failure-to-log action\n    pub failure: u32,\n    /// PID of auditd process\n    pub pid: u32,\n    /// Message rate limit (per second)\n    pub rate_limiting: u32,\n    /// Waiting messages limit\n    pub backlog_limit: u32,\n    /// Messages lost\n    pub lost: u32,\n    /// Messages waiting in queue\n    pub backlog: u32,\n    /// bitmap of kernel audit features\n    pub feature_bitmap: u32,\n    /// Message queue wait timeout\n    pub backlog_wait_time: u32,\n}\n\nimpl StatusMessage {\n    pub fn new() -> Self {\n        Default::default()\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct StatusMessageBuffer<T> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> StatusMessageBuffer<T> {\n    pub fn new(buffer: T) -> StatusMessageBuffer<T> {\n        StatusMessageBuffer { buffer }\n    }\n\n    pub fn new_checked(buffer: T) -> Result<StatusMessageBuffer<T>, DecodeError> {\n        let buf = Self::new(buffer);\n        buf.check_buffer_length()?;\n        Ok(buf)\n    }\n\n    fn check_buffer_length(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < STATUS_MESSAGE_LEN {\n            return Err(format!(\n                \"invalid StatusMessageBuffer buffer: length is {} instead of {}\",\n                len, STATUS_MESSAGE_LEN\n            )\n            .into());\n        }\n        Ok(())\n    }\n\n    pub fn into_inner(self) -> T {\n        self.buffer\n    }\n\n    pub fn mask(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[MASK])\n    }\n\n    pub fn enabled(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[ENABLED])\n    }\n\n    pub fn failure(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[FAILURE])\n    }\n\n    pub fn pid(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[PID])\n    }\n\n    pub fn rate_limiting(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[RATE_LIMITING])\n    }\n\n    pub fn backlog_limit(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[BACKLOG_LIMIT])\n    }\n\n    pub fn lost(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[LOST])\n    }\n\n    pub fn backlog(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[BACKLOG])\n    }\n\n    pub fn feature_bitmap(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[FEATURE_BITMAP])\n    }\n\n    pub fn backlog_wait_time(&self) -> u32 {\n        NativeEndian::read_u32(&self.buffer.as_ref()[BACKLOG_WAIT_TIME])\n    }\n}\n\nimpl<T: AsRef<[u8]> + AsMut<[u8]>> StatusMessageBuffer<T> {\n    pub fn set_mask(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[MASK], value)\n    }\n\n    pub fn set_enabled(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[ENABLED], value)\n    }\n\n    pub fn set_failure(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[FAILURE], value)\n    }\n\n    pub fn set_pid(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[PID], value)\n    }\n\n    pub fn set_rate_limiting(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[RATE_LIMITING], value)\n    }\n\n    pub fn set_backlog_limit(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[BACKLOG_LIMIT], value)\n    }\n\n    pub fn set_lost(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[LOST], value)\n    }\n\n    pub fn set_backlog(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[BACKLOG], value)\n    }\n\n    pub fn set_feature_bitmap(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[FEATURE_BITMAP], value)\n    }\n\n    pub fn set_backlog_wait_time(&mut self, value: u32) {\n        NativeEndian::write_u32(&mut self.buffer.as_mut()[BACKLOG_WAIT_TIME], value)\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<StatusMessageBuffer<T>> for StatusMessage {\n    fn parse(buf: &StatusMessageBuffer<T>) -> Result<Self, DecodeError> {\n        buf.check_buffer_length()?;\n        Ok(StatusMessage {\n            mask: buf.mask(),\n            enabled: buf.enabled(),\n            failure: buf.failure(),\n            pid: buf.pid(),\n            rate_limiting: buf.rate_limiting(),\n            backlog_limit: buf.backlog_limit(),\n            lost: buf.lost(),\n            backlog: buf.backlog(),\n            feature_bitmap: buf.feature_bitmap(),\n            backlog_wait_time: buf.backlog_wait_time(),\n        })\n    }\n}\n\nimpl Emitable for StatusMessage {\n    fn buffer_len(&self) -> usize {\n        STATUS_MESSAGE_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatusMessageBuffer::new(buffer);\n        buffer.set_mask(self.mask);\n        buffer.set_enabled(self.enabled);\n        buffer.set_failure(self.failure);\n        buffer.set_pid(self.pid);\n        buffer.set_rate_limiting(self.rate_limiting);\n        buffer.set_backlog_limit(self.backlog_limit);\n        buffer.set_lost(self.lost);\n        buffer.set_backlog(self.backlog);\n        buffer.set_feature_bitmap(self.feature_bitmap);\n        buffer.set_backlog_wait_time(self.backlog_wait_time);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/Cargo.toml",
    "content": "[package]\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-packet-core\"\nversion = \"0.4.2\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink packet types\"\n\n[dependencies]\nanyhow = \"1.0.31\"\nbyteorder = \"1.3.2\"\nlibc = \"0.2.66\"\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\n\n[dev-dependencies]\nnetlink-packet-route = { version = \"0.13.0\", path = \"../netlink-packet-route\" }\n"
  },
  {
    "path": "netlink-packet-core/examples/protocol.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{error::Error, fmt};\n\nuse netlink_packet_core::{\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\n\n// PingPongMessage represent the messages for the \"ping-pong\" netlink\n// protocol. There are only two types of messages.\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum PingPongMessage {\n    Ping(Vec<u8>),\n    Pong(Vec<u8>),\n}\n\n// The netlink header contains a \"message type\" field that identifies\n// the message it carries. Some values are reserved, and we\n// arbitrarily decided that \"ping\" type is 18 and \"pong\" type is 20.\npub const PING_MESSAGE: u16 = 18;\npub const PONG_MESSAGE: u16 = 20;\n\n// A custom error type for when deserialization fails. This is\n// required because `NetlinkDeserializable::Error` must implement\n// `std::error::Error`, so a simple `String` won't cut it.\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct DeserializeError(&'static str);\n\nimpl Error for DeserializeError {\n    fn description(&self) -> &str {\n        self.0\n    }\n    fn source(&self) -> Option<&(dyn Error + 'static)> {\n        None\n    }\n}\n\nimpl fmt::Display for DeserializeError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.0)\n    }\n}\n\n// NetlinkDeserializable implementation\nimpl NetlinkDeserializable for PingPongMessage {\n    type Error = DeserializeError;\n\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        match header.message_type {\n            PING_MESSAGE => Ok(PingPongMessage::Ping(payload.to_vec())),\n            PONG_MESSAGE => Ok(PingPongMessage::Pong(payload.to_vec())),\n            _ => Err(DeserializeError(\n                \"invalid ping-pong message: invalid message type\",\n            )),\n        }\n    }\n}\n\n// NetlinkSerializable implementation\nimpl NetlinkSerializable for PingPongMessage {\n    fn message_type(&self) -> u16 {\n        match self {\n            PingPongMessage::Ping(_) => PING_MESSAGE,\n            PingPongMessage::Pong(_) => PONG_MESSAGE,\n        }\n    }\n\n    fn buffer_len(&self) -> usize {\n        match self {\n            PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => vec.len(),\n        }\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        match self {\n            PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => {\n                buffer.copy_from_slice(&vec[..])\n            }\n        }\n    }\n}\n\n// It can be convenient to be able to create a NetlinkMessage directly\n// from a PingPongMessage. Since NetlinkMessage<T> already implements\n// From<NetlinkPayload<T>>, we just need to implement\n// From<NetlinkPayload<PingPongMessage>> for this to work.\nimpl From<PingPongMessage> for NetlinkPayload<PingPongMessage> {\n    fn from(message: PingPongMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n\nfn main() {\n    let ping_pong_message = PingPongMessage::Ping(vec![0, 1, 2, 3]);\n    let mut packet = NetlinkMessage::from(ping_pong_message);\n\n    // Before serializing the packet, it is very important to call\n    // finalize() to ensure the header of the message is consistent\n    // with its payload. Otherwise, a panic may occur when calling\n    // `serialize()`\n    packet.finalize();\n\n    // Prepare a buffer to serialize the packet. Note that we never\n    // set explicitely `packet.header.length` above. This was done\n    // automatically when we called `finalize()`\n    let mut buf = vec![0; packet.header.length as usize];\n    // Serialize the packet\n    packet.serialize(&mut buf[..]);\n\n    // Deserialize the packet\n    let deserialized_packet = NetlinkMessage::<PingPongMessage>::deserialize(&buf)\n        .expect(\"Failed to deserialize message\");\n\n    // Normally, the deserialized packet should be exactly the same\n    // than the serialized one.\n    assert_eq!(deserialized_packet, packet);\n\n    // This should print:\n    // NetlinkMessage { header: NetlinkHeader { length: 20, message_type: 18, flags: 0, sequence_number: 0, port_number: 0 }, payload: InnerMessage(Ping([0, 1, 2, 3])) }\n    println!(\"{:?}\", packet);\n}\n"
  },
  {
    "path": "netlink-packet-core/examples/rtnetlink.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::{NetlinkHeader, NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};\nuse netlink_packet_route::rtnl::{LinkMessage, RtnlMessage};\n\nfn main() {\n    // Create the netlink message, that contains the rtnetlink\n    // message\n    let mut packet = NetlinkMessage {\n        header: NetlinkHeader {\n            sequence_number: 1,\n            flags: NLM_F_DUMP | NLM_F_REQUEST,\n            ..Default::default()\n        },\n        payload: RtnlMessage::GetLink(LinkMessage::default()).into(),\n    };\n\n    // Set a few fields in the packet's header\n    packet.header.flags = NLM_F_DUMP | NLM_F_REQUEST;\n    packet.header.sequence_number = 1;\n\n    // Before serializing the packet, it is very important to call\n    // finalize() to ensure the header of the message is consistent\n    // with its payload. Otherwise, a panic may occur when calling\n    // `serialize()`\n    packet.finalize();\n\n    // Prepare a buffer to serialize the packet. Note that we never\n    // set explicitely `packet.header.length` above. This was done\n    // automatically when we called `finalize()`\n    let mut buf = vec![0; packet.header.length as usize];\n    // Serialize the packet\n    packet.serialize(&mut buf[..]);\n\n    // Deserialize the packet\n    let deserialized_packet =\n        NetlinkMessage::<RtnlMessage>::deserialize(&buf).expect(\"Failed to deserialize message\");\n\n    // Normally, the deserialized packet should be exactly the same\n    // than the serialized one.\n    assert_eq!(deserialized_packet, packet);\n\n    println!(\"{:?}\", packet);\n}\n"
  },
  {
    "path": "netlink-packet-core/src/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{DecodeError, Field, Rest};\n\nconst LENGTH: Field = 0..4;\nconst MESSAGE_TYPE: Field = 4..6;\nconst FLAGS: Field = 6..8;\nconst SEQUENCE_NUMBER: Field = 8..12;\nconst PORT_NUMBER: Field = 12..16;\nconst PAYLOAD: Rest = 16..;\n\n/// Length of a Netlink packet header\npub const NETLINK_HEADER_LEN: usize = PAYLOAD.start;\n\n// Prevent some doctest snippers to be formatted, since we cannot add\n// the attribute directly in the doctest\n#[rustfmt::skip]\n#[derive(Debug, PartialEq, Eq, Clone)]\n/// A raw Netlink buffer that provides getters and setter for the various header fields, and to\n/// retrieve the payloads.\n///\n/// # Example: reading a packet\n///\n/// ```rust\n/// use netlink_packet_core::{NetlinkBuffer, NLM_F_MATCH, NLM_F_REQUEST, NLM_F_ROOT};\n///\n/// const RTM_GETLINK: u16 = 18;\n///\n/// fn main() {\n///     // Artificially create an array of bytes that represents a netlink packet.\n///     // Normally, we would read it from a socket.\n///     let buffer = vec![\n///         0x28, 0x00, 0x00, 0x00, // length = 40\n///         0x12, 0x00, // message type = 18 (RTM_GETLINK)\n///         0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching\n///         0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540\n///         0x00, 0x00, 0x00, 0x00, // port id = 0\n///         // payload\n///         0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n///         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n///         0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];\n///\n///     // Wrap the storage into a NetlinkBuffer\n///     let packet = NetlinkBuffer::new_checked(&buffer[..]).unwrap();\n///\n///     // Check that the different accessor return the expected values\n///     assert_eq!(packet.length(), 40);\n///     assert_eq!(packet.message_type(), RTM_GETLINK);\n///     assert_eq!(packet.sequence_number(), 1526271540);\n///     assert_eq!(packet.port_number(), 0);\n///     assert_eq!(packet.payload_length(), 24);\n///     assert_eq!(packet.payload(), &buffer[16..]);\n///     assert_eq!(\n///         Into::<u16>::into(packet.flags()),\n///         NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH\n///     );\n/// }\n/// ```\n///\n/// # Example: writing a packet\n///\n/// ```rust\n/// use netlink_packet_core::{NetlinkBuffer, NLM_F_MATCH, NLM_F_REQUEST, NLM_F_ROOT};\n///\n/// const RTM_GETLINK: u16 = 18;\n///\n/// fn main() {\n///     // The packet we want to write.\n///     let expected_buffer = vec![\n///         0x28, 0x00, 0x00, 0x00, // length = 40\n///         0x12, 0x00, // message type = 18 (RTM_GETLINK)\n///         0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching\n///         0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540\n///         0x00, 0x00, 0x00, 0x00, // port id = 0\n///         // payload\n///         0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n///         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n///         0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];\n///\n///     // Create a storage that is big enough for our packet\n///     let mut buf = vec![0; 40];\n///     // the extra scope is to restrict the scope of the borrow\n///     {\n///         // Create a NetlinkBuffer.\n///         let mut packet = NetlinkBuffer::new(&mut buf);\n///         // Set the various fields\n///         packet.set_length(40);\n///         packet.set_message_type(RTM_GETLINK);\n///         packet.set_sequence_number(1526271540);\n///         packet.set_port_number(0);\n///         packet.set_flags(From::from(NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH));\n///         // we kind of cheat here to keep the example short\n///         packet.payload_mut().copy_from_slice(&expected_buffer[16..]);\n///     }\n///     // Check that the storage contains the expected values\n///     assert_eq!(&buf[..], &expected_buffer[..]);\n/// }\n/// ```\n///\n/// Note that in this second example we don't call\n/// [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked) because the length field is\n/// initialized to 0, so `new_checked()` would return an error.\npub struct NetlinkBuffer<T> {\n    pub buffer: T,\n}\n\n// Prevent some doc strings to be formatted, since we cannot add the\n// attribute directly in the doctest\n#[rustfmt::skip]\nimpl<T: AsRef<[u8]>> NetlinkBuffer<T> {\n    /// Create a new `NetlinkBuffer` that uses the given buffer as storage. Note that when calling\n    /// this method no check is performed, so trying to access fields may panic. If you're not sure\n    /// the given buffer contains a valid netlink packet, use\n    /// [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked) instead.\n    pub fn new(buffer: T) -> NetlinkBuffer<T> {\n        NetlinkBuffer { buffer }\n    }\n\n    // Prevent some doc strings to be formatted, since we cannot add\n    // the attribute directly in the doctest\n    #[rustfmt::skip]\n    /// Check the length of the given buffer and make sure it's big enough so that trying to access\n    /// packet fields won't panic. If the buffer is big enough, create a new `NewlinkBuffer` that\n    /// uses this buffer as storage.\n    ///\n    /// # Example\n    ///\n    /// With a buffer that does not even contain a full header:\n    ///\n    /// ```rust\n    /// use netlink_packet_core::NetlinkBuffer;\n    /// static BYTES: [u8; 4] = [0x28, 0x00, 0x00, 0x00];\n    /// assert!(NetlinkBuffer::new_checked(&BYTES[..]).is_err());\n    /// ```\n    ///\n    /// Here is a slightly more tricky error, where technically, the buffer is big enough to\n    /// contains a valid packet. Here, accessing the packet header fields would not panic but\n    /// accessing the payload would, so `new_checked` also checks the length field in the packet\n    /// header:\n    ///\n    /// ```rust\n    /// use netlink_packet_core::NetlinkBuffer;\n    /// // The buffer is 24 bytes long. It contains a valid header but a truncated payload\n    /// static BYTES: [u8; 24] = [\n    ///     // The length field says the buffer is 40 bytes long\n    ///     0x28, 0x00, 0x00, 0x00,\n    ///     0x12, 0x00, // message type\n    ///     0x01, 0x03, // flags\n    ///     0x34, 0x0e, 0xf9, 0x5a, // sequence number\n    ///     0x00, 0x00, 0x00, 0x00, // port id\n    ///     // payload\n    ///     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];\n    /// assert!(NetlinkBuffer::new_checked(&BYTES[..]).is_err());\n    /// ```\n    pub fn new_checked(buffer: T) -> Result<NetlinkBuffer<T>, DecodeError> {\n        let packet = Self::new(buffer);\n        packet.check_buffer_length()?;\n        Ok(packet)\n    }\n\n    fn check_buffer_length(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < PORT_NUMBER.end {\n            Err(format!(\n                \"invalid netlink buffer: length is {} but netlink packets are at least {} bytes\",\n                len, PORT_NUMBER.end\n            )\n            .into())\n        } else if len < self.length() as usize {\n            Err(format!(\n                \"invalid netlink buffer: length field says {} the buffer is {} bytes long\",\n                self.length(),\n                len\n            )\n            .into())\n        } else if (self.length() as usize) < PORT_NUMBER.end {\n            Err(format!(\n                \"invalid netlink buffer: length field says {} but netlink packets are at least {} bytes\",\n                self.length(),\n                len\n            ).into())\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Return the payload length.\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small or if the `length` field in the header is\n    /// set to a value that exceeds the storage length (see\n    /// [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn payload_length(&self) -> usize {\n        let total_length = self.length() as usize;\n        let payload_offset = PAYLOAD.start;\n        // This may panic!\n        total_length - payload_offset\n    }\n\n    /// Consume the packet, returning the underlying buffer.\n    pub fn into_inner(self) -> T {\n        self.buffer\n    }\n\n    /// Return the `length` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn length(&self) -> u32 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u32(&data[LENGTH])\n    }\n\n    /// Return the `type` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn message_type(&self) -> u16 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u16(&data[MESSAGE_TYPE])\n    }\n\n    /// Return the `flags` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn flags(&self) -> u16 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u16(&data[FLAGS])\n    }\n\n    /// Return the `sequence_number` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn sequence_number(&self) -> u32 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u32(&data[SEQUENCE_NUMBER])\n    }\n\n    /// Return the `port_number` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn port_number(&self) -> u32 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u32(&data[PORT_NUMBER])\n    }\n}\n\nimpl<T: AsRef<[u8]> + AsMut<[u8]>> NetlinkBuffer<T> {\n    /// Set the packet header `length` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn set_length(&mut self, value: u32) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u32(&mut data[LENGTH], value)\n    }\n\n    /// Set the packet header `message_type` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn set_message_type(&mut self, value: u16) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[MESSAGE_TYPE], value)\n    }\n\n    /// Set the packet header `flags` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn set_flags(&mut self, value: u16) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[FLAGS], value)\n    }\n\n    /// Set the packet header `sequence_number` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn set_sequence_number(&mut self, value: u32) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u32(&mut data[SEQUENCE_NUMBER], value)\n    }\n\n    /// Set the packet header `port_number` field\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small (see [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn set_port_number(&mut self, value: u32) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u32(&mut data[PORT_NUMBER], value)\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NetlinkBuffer<&'a T> {\n    /// Return a pointer to the packet payload.\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small or if the `length` field in the header is\n    /// set to a value that exceeds the storage length (see\n    /// [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn payload(&self) -> &'a [u8] {\n        let range = PAYLOAD.start..self.length() as usize;\n        let data = self.buffer.as_ref();\n        &data[range]\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> NetlinkBuffer<&'a mut T> {\n    /// Return a mutable pointer to the payload.\n    ///\n    /// # Panic\n    ///\n    /// This panic is the underlying storage is too small or if the `length` field in the header is\n    /// set to a value that exceeds the storage length (see\n    /// [`new_checked()`](struct.NetlinkBuffer.html#method.new_checked))\n    pub fn payload_mut(&mut self) -> &mut [u8] {\n        let range = PAYLOAD.start..self.length() as usize;\n        let data = self.buffer.as_mut();\n        &mut data[range]\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{\n        constants::{NLM_F_MATCH, NLM_F_REQUEST, NLM_F_ROOT},\n        NetlinkBuffer,\n    };\n\n    const RTM_GETLINK: u16 = 18;\n\n    // a packet captured with tcpdump that was sent when running `ip link show`\n    #[rustfmt::skip]\n    static IP_LINK_SHOW_PKT: [u8; 40] = [\n        0x28, 0x00, 0x00, 0x00, // length = 40\n        0x12, 0x00, // message type = 18 (RTM_GETLINK)\n        0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching\n        0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540\n        0x00, 0x00, 0x00, 0x00, // port id = 0\n        // payload\n        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];\n\n    #[test]\n    fn packet_read() {\n        let packet = NetlinkBuffer::new(&IP_LINK_SHOW_PKT[..]);\n        assert_eq!(packet.length(), 40);\n        assert_eq!(packet.message_type(), RTM_GETLINK);\n        assert_eq!(packet.sequence_number(), 1526271540);\n        assert_eq!(packet.port_number(), 0);\n        let flags = packet.flags();\n        assert!(flags & NLM_F_ROOT == NLM_F_ROOT);\n        assert!(flags & NLM_F_REQUEST == NLM_F_REQUEST);\n        assert!(flags & NLM_F_MATCH == NLM_F_MATCH);\n        assert_eq!(flags, NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);\n        assert_eq!(packet.payload_length(), 24);\n        assert_eq!(packet.payload(), &IP_LINK_SHOW_PKT[16..]);\n    }\n\n    #[test]\n    fn packet_build() {\n        let mut buf = vec![0; 40];\n        {\n            let mut packet = NetlinkBuffer::new(&mut buf);\n            packet.set_length(40);\n            packet.set_message_type(RTM_GETLINK);\n            packet.set_sequence_number(1526271540);\n            packet.set_port_number(0);\n            packet.set_flags(NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);\n            packet\n                .payload_mut()\n                .copy_from_slice(&IP_LINK_SHOW_PKT[16..]);\n        }\n        assert_eq!(&buf[..], &IP_LINK_SHOW_PKT[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n/// Must be set on all request messages (typically from user space to kernel space)\npub const NLM_F_REQUEST: u16 = 1;\n///  Indicates the message is part of a multipart message terminated by NLMSG_DONE\npub const NLM_F_MULTIPART: u16 = 2;\n/// Request for an acknowledgment on success. Typical direction of request is from user space\n/// (CPC) to kernel space (FEC).\npub const NLM_F_ACK: u16 = 4;\n/// Echo this request.  Typical direction of request is from user space (CPC) to kernel space\n/// (FEC).\npub const NLM_F_ECHO: u16 = 8;\n/// Dump was inconsistent due to sequence change\npub const NLM_F_DUMP_INTR: u16 = 16;\n/// Dump was filtered as requested\npub const NLM_F_DUMP_FILTERED: u16 = 32;\n/// Return the complete table instead of a single entry.\npub const NLM_F_ROOT: u16 = 256;\n/// Return all entries matching criteria passed in message content.\npub const NLM_F_MATCH: u16 = 512;\n/// Return an atomic snapshot of the table. Requires `CAP_NET_ADMIN` capability or a effective UID\n/// of 0.\npub const NLM_F_ATOMIC: u16 = 1024;\npub const NLM_F_DUMP: u16 = 768;\n/// Replace existing matching object.\npub const NLM_F_REPLACE: u16 = 256;\n/// Don't replace if the object already exists.\npub const NLM_F_EXCL: u16 = 512;\n/// Create object if it doesn't already exist.\npub const NLM_F_CREATE: u16 = 1024;\n/// Add to the end of the object list.\npub const NLM_F_APPEND: u16 = 2048;\n\n/// Do not delete recursively\npub const NLM_F_NONREC: u16 = 256;\n/// request was capped\npub const NLM_F_CAPPED: u16 = 256;\n/// extended ACK TVLs were included\npub const NLM_F_ACK_TLVS: u16 = 512;\n"
  },
  {
    "path": "netlink-packet-core/src/error.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{fmt, io, mem::size_of};\n\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{DecodeError, Emitable, Field, Parseable, Rest};\n\nconst CODE: Field = 0..4;\nconst PAYLOAD: Rest = 4..;\nconst ERROR_HEADER_LEN: usize = PAYLOAD.start;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct ErrorBuffer<T> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> ErrorBuffer<T> {\n    pub fn new(buffer: T) -> ErrorBuffer<T> {\n        ErrorBuffer { buffer }\n    }\n\n    /// Consume the packet, returning the underlying buffer.\n    pub fn into_inner(self) -> T {\n        self.buffer\n    }\n\n    pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {\n        let packet = Self::new(buffer);\n        packet.check_buffer_length()?;\n        Ok(packet)\n    }\n\n    fn check_buffer_length(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < ERROR_HEADER_LEN {\n            Err(format!(\n                \"invalid ErrorBuffer: length is {} but ErrorBuffer are at least {} bytes\",\n                len, ERROR_HEADER_LEN\n            )\n            .into())\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Return the error code\n    pub fn code(&self) -> i32 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_i32(&data[CODE])\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ErrorBuffer<&'a T> {\n    /// Return a pointer to the payload.\n    pub fn payload(&self) -> &'a [u8] {\n        let data = self.buffer.as_ref();\n        &data[PAYLOAD]\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> ErrorBuffer<&'a mut T> {\n    /// Return a mutable pointer to the payload.\n    pub fn payload_mut(&mut self) -> &mut [u8] {\n        let data = self.buffer.as_mut();\n        &mut data[PAYLOAD]\n    }\n}\n\nimpl<T: AsRef<[u8]> + AsMut<[u8]>> ErrorBuffer<T> {\n    /// set the error code field\n    pub fn set_code(&mut self, value: i32) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_i32(&mut data[CODE], value)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ErrorMessage {\n    pub code: i32,\n    pub header: Vec<u8>,\n}\n\npub type AckMessage = ErrorMessage;\n\nimpl Emitable for ErrorMessage {\n    fn buffer_len(&self) -> usize {\n        size_of::<i32>() + self.header.len()\n    }\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = ErrorBuffer::new(buffer);\n        buffer.set_code(self.code);\n        buffer.payload_mut().copy_from_slice(&self.header)\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + 'buffer> Parseable<ErrorBuffer<&'buffer T>> for ErrorMessage {\n    fn parse(buf: &ErrorBuffer<&'buffer T>) -> Result<ErrorMessage, DecodeError> {\n        // FIXME: The payload of an error is basically a truncated packet, which requires custom\n        // logic to parse correctly. For now we just return it as a Vec<u8>\n        // let header: NetlinkHeader = {\n        //     NetlinkBuffer::new_checked(self.payload())\n        //         .context(\"failed to parse netlink header\")?\n        //         .parse()\n        //         .context(\"failed to parse nelink header\")?\n        // };\n        Ok(ErrorMessage {\n            code: buf.code(),\n            header: buf.payload().to_vec(),\n        })\n    }\n}\n\nimpl ErrorMessage {\n    /// According to [`netlink(7)`](https://linux.die.net/man/7/netlink)\n    /// the `NLMSG_ERROR` return Negative errno or 0 for acknowledgements.\n    ///\n    /// convert into [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)\n    /// using the absolute value from errno code\n    pub fn to_io(&self) -> io::Error {\n        io::Error::from_raw_os_error(self.code.abs())\n    }\n}\n\nimpl fmt::Display for ErrorMessage {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(&self.to_io(), f)\n    }\n}\n\nimpl From<ErrorMessage> for io::Error {\n    fn from(e: ErrorMessage) -> io::Error {\n        e.to_io()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn into_io_error() {\n        let io_err = io::Error::from_raw_os_error(95);\n        let err_msg = ErrorMessage {\n            code: -95,\n            header: vec![],\n        };\n\n        let to_io: io::Error = err_msg.to_io();\n\n        assert_eq!(err_msg.to_string(), io_err.to_string());\n        assert_eq!(to_io.raw_os_error(), io_err.raw_os_error());\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/src/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{buffer::NETLINK_HEADER_LEN, DecodeError, Emitable, NetlinkBuffer, Parseable};\n\n/// A Netlink header representation. A netlink header has the following structure:\n///\n/// ```no_rust\n/// 0                8                16              24               32\n/// +----------------+----------------+----------------+----------------+\n/// |                 packet length (including header)                  |\n/// +----------------+----------------+----------------+----------------+\n/// |          message type           |              flags              |\n/// +----------------+----------------+----------------+----------------+\n/// |                           sequence number                         |\n/// +----------------+----------------+----------------+----------------+\n/// |                   port number (formerly known as PID)             |\n/// +----------------+----------------+----------------+----------------+\n/// ```\n#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]\npub struct NetlinkHeader {\n    /// Length of the netlink packet, including the header and the payload\n    pub length: u32,\n\n    /// NetlinkMessage type. The meaning of this field depends on the netlink protocol family in use.\n    pub message_type: u16,\n\n    /// Flags. It should be set to one of the `NLM_F_*` constants.\n    pub flags: u16,\n\n    /// Sequence number of the packet\n    pub sequence_number: u32,\n\n    /// Port number (usually set to the the process ID)\n    pub port_number: u32,\n}\n\nimpl Emitable for NetlinkHeader {\n    fn buffer_len(&self) -> usize {\n        NETLINK_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = NetlinkBuffer::new(buffer);\n        buffer.set_message_type(self.message_type);\n        buffer.set_length(self.length);\n        buffer.set_flags(self.flags);\n        buffer.set_sequence_number(self.sequence_number);\n        buffer.set_port_number(self.port_number);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NetlinkBuffer<&'a T>> for NetlinkHeader {\n    fn parse(buf: &NetlinkBuffer<&'a T>) -> Result<NetlinkHeader, DecodeError> {\n        Ok(NetlinkHeader {\n            length: buf.length(),\n            message_type: buf.message_type(),\n            flags: buf.flags(),\n            sequence_number: buf.sequence_number(),\n            port_number: buf.port_number(),\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::constants::*;\n\n    // a packet captured with tcpdump that was sent when running `ip link show`\n    #[rustfmt::skip]\n    static IP_LINK_SHOW_PKT: [u8; 40] = [\n        0x28, 0x00, 0x00, 0x00, // length = 40\n        0x12, 0x00, // message type = 18 (RTM_GETLINK)\n        0x01, 0x03, // flags = Request + Specify Tree Root + Return All Matching\n        0x34, 0x0e, 0xf9, 0x5a, // sequence number = 1526271540\n        0x00, 0x00, 0x00, 0x00, // port id = 0\n        // payload\n        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n        0x08, 0x00, 0x1d, 0x00, 0x01, 0x00, 0x00, 0x00];\n\n    const RTM_GETLINK: u16 = 18;\n\n    #[test]\n    fn repr_parse() {\n        let repr =\n            NetlinkHeader::parse(&NetlinkBuffer::new_checked(&IP_LINK_SHOW_PKT[..]).unwrap())\n                .unwrap();\n        assert_eq!(repr.length, 40);\n        assert_eq!(repr.message_type, RTM_GETLINK);\n        assert_eq!(repr.sequence_number, 1_526_271_540);\n        assert_eq!(repr.port_number, 0);\n        assert_eq!(repr.flags, NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH);\n    }\n\n    #[test]\n    fn repr_emit() {\n        let repr = NetlinkHeader {\n            length: 40,\n            message_type: RTM_GETLINK,\n            sequence_number: 1_526_271_540,\n            flags: NLM_F_ROOT | NLM_F_REQUEST | NLM_F_MATCH,\n            port_number: 0,\n        };\n        assert_eq!(repr.buffer_len(), 16);\n        let mut buf = vec![0; 16];\n        repr.emit(&mut buf[..]);\n        assert_eq!(&buf[..], &IP_LINK_SHOW_PKT[..16]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! `netlink-packet-core` provides a generic netlink message\n//! `NetlinkMessage<T>` that is independant of the sub-protocol. Such\n//! messages are not very useful by themselves, since they are just\n//! used to carry protocol-dependant messages. That is what the `T`\n//! represent: `T` is the `NetlinkMessage`'s protocol-dependant\n//! message. This can be any type that implements\n//! `NetlinkSerializable` and `NetlinkDeserializable`.\n//!\n//! For instance, the `netlink-packet-route` crate provides rtnetlink\n//! messages via `netlink_packet_route::RtnlMessage`, and\n//! `netlink-packet-audit` provides audit messages via\n//! `netlink_packet_audit::AuditMessage`.\n//!\n//! By itself, the `netlink-packet-core` crate is not very\n//! useful. However, it is used in `netlink-proto` to provide an\n//! asynchronous implementation of the netlink protocol for any\n//! sub-protocol. Thus, a crate that defines messages for a given\n//! netlink sub-protocol could integrate with `netlink-packet-core`\n//! and would get an asynchronous implementation for free. See the\n//! second example below for such an integration, via the\n//! `NetlinkSerializable` and `NetlinkDeserializable` traits.\n//!\n//! # Example: usage with `netlink-packet-route`\n//!\n//! This example shows how to serialize and deserialize netlink packet\n//! for the rtnetlink sub-protocol. It requires\n//! `netlink-packet-route`.\n//!\n//! ```rust\n//! use netlink_packet_core::{NetlinkHeader, NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};\n//! use netlink_packet_route::{LinkMessage, RtnlMessage};\n//!\n//! // Create the netlink message, that contains the rtnetlink\n//! // message\n//! let mut packet = NetlinkMessage {\n//!     header: NetlinkHeader {\n//!         sequence_number: 1,\n//!         flags: NLM_F_DUMP | NLM_F_REQUEST,\n//!         ..Default::default()\n//!     },\n//!     payload: RtnlMessage::GetLink(LinkMessage::default()).into(),\n//! };\n//!\n//! // Before serializing the packet, it is important to call\n//! // finalize() to ensure the header of the message is consistent\n//! // with its payload. Otherwise, a panic may occur when calling\n//! // serialize()\n//! packet.finalize();\n//!\n//! // Prepare a buffer to serialize the packet. Note that we never\n//! // set explicitely `packet.header.length` above. This was done\n//! // automatically when we called `finalize()`\n//! let mut buf = vec![0; packet.header.length as usize];\n//! // Serialize the packet\n//! packet.serialize(&mut buf[..]);\n//!\n//! // Deserialize the packet\n//! let deserialized_packet =\n//!     NetlinkMessage::<RtnlMessage>::deserialize(&buf).expect(\"Failed to deserialize message\");\n//!\n//! // Normally, the deserialized packet should be exactly the same\n//! // than the serialized one.\n//! assert_eq!(deserialized_packet, packet);\n//!\n//! println!(\"{:?}\", packet);\n//! ```\n//!\n//! # Example: adding messages for new netlink sub-protocol\n//!\n//! Let's assume we have a netlink protocol called \"ping pong\" that\n//! defines two types of messages: \"ping\" messages, which payload can\n//! be any sequence of bytes, and \"pong\" message, which payload is\n//! also a sequence of bytes.  The protocol works as follow: when an\n//! enpoint receives a \"ping\" message, it answers with a \"pong\", with\n//! the payload of the \"ping\" it's answering to.\n//!\n//! \"ping\" messages have type 18 and \"pong\" have type \"20\". Here is\n//! what a \"ping\" message that would look like if its payload is `[0,\n//! 1, 2, 3]`:\n//!\n//! ```no_rust\n//! 0                8                16              24               32\n//! +----------------+----------------+----------------+----------------+\n//! |                 packet length (including header) = 16 + 4 = 20    |\n//! +----------------+----------------+----------------+----------------+\n//! |     message type = 18 (ping)    |              flags              |\n//! +----------------+----------------+----------------+----------------+\n//! |                           sequence number                         |\n//! +----------------+----------------+----------------+----------------+\n//! |                            port number                            |\n//! +----------------+----------------+----------------+----------------+\n//! |       0        |         1      |         2      |        3       |\n//! +----------------+----------------+----------------+----------------+\n//! ```\n//!\n//! And the \"pong\" response would be:\n//!\n//! ```no_rust\n//! 0                8                16              24               32\n//! +----------------+----------------+----------------+----------------+\n//! |                 packet length (including header) = 16 + 4 = 20    |\n//! +----------------+----------------+----------------+----------------+\n//! |     message type = 20 (pong)    |              flags              |\n//! +----------------+----------------+----------------+----------------+\n//! |                           sequence number                         |\n//! +----------------+----------------+----------------+----------------+\n//! |                            port number                            |\n//! +----------------+----------------+----------------+----------------+\n//! |       0        |         1      |         2      |        3       |\n//! +----------------+----------------+----------------+----------------+\n//! ```\n//!\n//! Here is how we could implement the messages for such a protocol\n//! and integrate this implementation with `netlink-packet-core`:\n//!\n//! ```rust\n//! use netlink_packet_core::{\n//!     NetlinkDeserializable, NetlinkHeader, NetlinkMessage, NetlinkPayload, NetlinkSerializable,\n//! };\n//! use std::error::Error;\n//! use std::fmt;\n//!\n//! // PingPongMessage represent the messages for the \"ping-pong\" netlink\n//! // protocol. There are only two types of messages.\n//! #[derive(Debug, Clone, Eq, PartialEq)]\n//! pub enum PingPongMessage {\n//!     Ping(Vec<u8>),\n//!     Pong(Vec<u8>),\n//! }\n//!\n//! // The netlink header contains a \"message type\" field that identifies\n//! // the message it carries. Some values are reserved, and we\n//! // arbitrarily decided that \"ping\" type is 18 and \"pong\" type is 20.\n//! pub const PING_MESSAGE: u16 = 18;\n//! pub const PONG_MESSAGE: u16 = 20;\n//!\n//! // A custom error type for when deserialization fails. This is\n//! // required because `NetlinkDeserializable::Error` must implement\n//! // `std::error::Error`, so a simple `String` won't cut it.\n//! #[derive(Debug, Clone, Eq, PartialEq)]\n//! pub struct DeserializeError(&'static str);\n//!\n//! impl Error for DeserializeError {\n//!     fn description(&self) -> &str {\n//!         self.0\n//!     }\n//!     fn source(&self) -> Option<&(dyn Error + 'static)> {\n//!         None\n//!     }\n//! }\n//!\n//! impl fmt::Display for DeserializeError {\n//!     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n//!         write!(f, \"{}\", self.0)\n//!     }\n//! }\n//!\n//! // NetlinkDeserializable implementation\n//! impl NetlinkDeserializable for PingPongMessage {\n//!     type Error = DeserializeError;\n//!\n//!     fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n//!         match header.message_type {\n//!             PING_MESSAGE => Ok(PingPongMessage::Ping(payload.to_vec())),\n//!             PONG_MESSAGE => Ok(PingPongMessage::Pong(payload.to_vec())),\n//!             _ => Err(DeserializeError(\n//!                 \"invalid ping-pong message: invalid message type\",\n//!             )),\n//!         }\n//!     }\n//! }\n//!\n//! // NetlinkSerializable implementation\n//! impl NetlinkSerializable for PingPongMessage {\n//!     fn message_type(&self) -> u16 {\n//!         match self {\n//!             PingPongMessage::Ping(_) => PING_MESSAGE,\n//!             PingPongMessage::Pong(_) => PONG_MESSAGE,\n//!         }\n//!     }\n//!\n//!     fn buffer_len(&self) -> usize {\n//!         match self {\n//!             PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => vec.len(),\n//!         }\n//!     }\n//!\n//!     fn serialize(&self, buffer: &mut [u8]) {\n//!         match self {\n//!             PingPongMessage::Ping(vec) | PingPongMessage::Pong(vec) => {\n//!                 buffer.copy_from_slice(&vec[..])\n//!             }\n//!         }\n//!     }\n//! }\n//!\n//! // It can be convenient to be able to create a NetlinkMessage directly\n//! // from a PingPongMessage. Since NetlinkMessage<T> already implements\n//! // From<NetlinkPayload<T>>, we just need to implement\n//! // From<NetlinkPayload<PingPongMessage>> for this to work.\n//! impl From<PingPongMessage> for NetlinkPayload<PingPongMessage> {\n//!     fn from(message: PingPongMessage) -> Self {\n//!         NetlinkPayload::InnerMessage(message)\n//!     }\n//! }\n//!\n//! fn main() {\n//!     let ping_pong_message = PingPongMessage::Ping(vec![0, 1, 2, 3]);\n//!     let mut packet = NetlinkMessage::from(ping_pong_message);\n//!\n//!     // Before serializing the packet, it is very important to call\n//!     // finalize() to ensure the header of the message is consistent\n//!     // with its payload. Otherwise, a panic may occur when calling\n//!     // `serialize()`\n//!     packet.finalize();\n//!\n//!     // Prepare a buffer to serialize the packet. Note that we never\n//!     // set explicitely `packet.header.length` above. This was done\n//!     // automatically when we called `finalize()`\n//!     let mut buf = vec![0; packet.header.length as usize];\n//!     // Serialize the packet\n//!     packet.serialize(&mut buf[..]);\n//!\n//!     // Deserialize the packet\n//!     let deserialized_packet = NetlinkMessage::<PingPongMessage>::deserialize(&buf)\n//!         .expect(\"Failed to deserialize message\");\n//!\n//!     // Normally, the deserialized packet should be exactly the same\n//!     // than the serialized one.\n//!     assert_eq!(deserialized_packet, packet);\n//!\n//!     // This should print:\n//!     // NetlinkMessage { header: NetlinkHeader { length: 20, message_type: 18, flags: 0, sequence_number: 0, port_number: 0 }, payload: InnerMessage(Ping([0, 1, 2, 3])) }\n//!     println!(\"{:?}\", packet);\n//! }\n//! ```\n\nuse core::ops::{Range, RangeFrom};\n/// Represent a multi-bytes field with a fixed size in a packet\npub(crate) type Field = Range<usize>;\n/// Represent a field that starts at a given index in a packet\npub(crate) type Rest = RangeFrom<usize>;\n\npub mod error;\npub use self::error::*;\n\npub mod buffer;\npub use self::buffer::*;\n\npub mod header;\npub use self::header::*;\n\nmod traits;\npub use self::traits::*;\n\nmod payload;\npub use self::payload::*;\n\nmod message;\npub use self::message::*;\n\npub mod constants;\npub use self::constants::*;\n\npub use self::utils::errors::*;\npub(crate) use self::utils::traits::*;\npub(crate) use netlink_packet_utils as utils;\n"
  },
  {
    "path": "netlink-packet-core/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse std::fmt::Debug;\n\nuse crate::{\n    payload::{NLMSG_DONE, NLMSG_ERROR, NLMSG_NOOP, NLMSG_OVERRUN},\n    AckMessage,\n    DecodeError,\n    Emitable,\n    ErrorBuffer,\n    ErrorMessage,\n    NetlinkBuffer,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n    Parseable,\n};\n\n/// Represent a netlink message.\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct NetlinkMessage<I> {\n    /// Message header (this is common to all the netlink protocols)\n    pub header: NetlinkHeader,\n    /// Inner message, which depends on the netlink protocol being used.\n    pub payload: NetlinkPayload<I>,\n}\n\nimpl<I> NetlinkMessage<I> {\n    /// Create a new netlink message from the given header and payload\n    pub fn new(header: NetlinkHeader, payload: NetlinkPayload<I>) -> Self {\n        NetlinkMessage { header, payload }\n    }\n\n    /// Consume this message and return its header and payload\n    pub fn into_parts(self) -> (NetlinkHeader, NetlinkPayload<I>) {\n        (self.header, self.payload)\n    }\n}\n\nimpl<I> NetlinkMessage<I>\nwhere\n    I: NetlinkDeserializable,\n{\n    /// Parse the given buffer as a netlink message\n    pub fn deserialize(buffer: &[u8]) -> Result<Self, DecodeError> {\n        let netlink_buffer = NetlinkBuffer::new_checked(&buffer)?;\n        <Self as Parseable<NetlinkBuffer<&&[u8]>>>::parse(&netlink_buffer)\n    }\n}\n\nimpl<I> NetlinkMessage<I>\nwhere\n    I: NetlinkSerializable,\n{\n    /// Return the length of this message in bytes\n    pub fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    /// Serialize this message and write the serialized data into the\n    /// given buffer. `buffer` must big large enough for the whole\n    /// message to fit, otherwise, this method will panic. To know how\n    /// big the serialized message is, call `buffer_len()`.\n    ///\n    /// # Panic\n    ///\n    /// This method panics if the buffer is not big enough.\n    pub fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n\n    /// Ensure the header (`NetlinkHeader`) is consistent with the payload (`NetlinkPayload`):\n    ///\n    /// - compute the payload length and set the header's length field\n    /// - check the payload type and set the header's message type field accordingly\n    ///\n    /// If you are not 100% sure the header is correct, this method should be called before calling\n    /// [`Emitable::emit()`](trait.Emitable.html#tymethod.emit), as it could panic if the header is\n    /// inconsistent with the rest of the message.\n    pub fn finalize(&mut self) {\n        self.header.length = self.buffer_len() as u32;\n        self.header.message_type = self.payload.message_type();\n    }\n}\n\nimpl<'buffer, B, I> Parseable<NetlinkBuffer<&'buffer B>> for NetlinkMessage<I>\nwhere\n    B: AsRef<[u8]> + 'buffer,\n    I: NetlinkDeserializable,\n{\n    fn parse(buf: &NetlinkBuffer<&'buffer B>) -> Result<Self, DecodeError> {\n        use self::NetlinkPayload::*;\n\n        let header = <NetlinkHeader as Parseable<NetlinkBuffer<&'buffer B>>>::parse(buf)\n            .context(\"failed to parse netlink header\")?;\n\n        let bytes = buf.payload();\n        let payload = match header.message_type {\n            NLMSG_ERROR => {\n                let buf =\n                    ErrorBuffer::new_checked(&bytes).context(\"failed to parse NLMSG_ERROR\")?;\n                let msg = ErrorMessage::parse(&buf).context(\"failed to parse NLMSG_ERROR\")?;\n                if msg.code >= 0 {\n                    Ack(msg as AckMessage)\n                } else {\n                    Error(msg)\n                }\n            }\n            NLMSG_NOOP => Noop,\n            NLMSG_DONE => Done,\n            NLMSG_OVERRUN => Overrun(bytes.to_vec()),\n            message_type => {\n                let inner_msg = I::deserialize(&header, bytes).context(format!(\n                    \"Failed to parse message with type {}\",\n                    message_type\n                ))?;\n                InnerMessage(inner_msg)\n            }\n        };\n        Ok(NetlinkMessage { header, payload })\n    }\n}\n\nimpl<I> Emitable for NetlinkMessage<I>\nwhere\n    I: NetlinkSerializable,\n{\n    fn buffer_len(&self) -> usize {\n        use self::NetlinkPayload::*;\n\n        let payload_len = match self.payload {\n            Noop | Done => 0,\n            Overrun(ref bytes) => bytes.len(),\n            Error(ref msg) => msg.buffer_len(),\n            Ack(ref msg) => msg.buffer_len(),\n            InnerMessage(ref msg) => msg.buffer_len(),\n        };\n\n        self.header.buffer_len() + payload_len\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        use self::NetlinkPayload::*;\n\n        self.header.emit(buffer);\n\n        let buffer = &mut buffer[self.header.buffer_len()..self.header.length as usize];\n        match self.payload {\n            Noop | Done => {}\n            Overrun(ref bytes) => buffer.copy_from_slice(bytes),\n            Error(ref msg) => msg.emit(buffer),\n            Ack(ref msg) => msg.emit(buffer),\n            InnerMessage(ref msg) => msg.serialize(buffer),\n        }\n    }\n}\n\nimpl<T> From<T> for NetlinkMessage<T>\nwhere\n    T: Into<NetlinkPayload<T>>,\n{\n    fn from(inner_message: T) -> Self {\n        NetlinkMessage {\n            header: NetlinkHeader::default(),\n            payload: inner_message.into(),\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/src/payload.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::fmt::Debug;\n\nuse crate::{AckMessage, ErrorMessage, NetlinkSerializable};\n\n/// The message is ignored.\npub const NLMSG_NOOP: u16 = 1;\n/// The message signals an error and the payload contains a nlmsgerr structure. This can be looked\n/// at as a NACK and typically it is from FEC to CPC.\npub const NLMSG_ERROR: u16 = 2;\n/// The message terminates a multipart message.\n/// Data lost\npub const NLMSG_DONE: u16 = 3;\npub const NLMSG_OVERRUN: u16 = 4;\npub const NLMSG_ALIGNTO: u16 = 4;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum NetlinkPayload<I> {\n    Done,\n    Error(ErrorMessage),\n    Ack(AckMessage),\n    Noop,\n    Overrun(Vec<u8>),\n    InnerMessage(I),\n}\n\nimpl<I> NetlinkPayload<I>\nwhere\n    I: NetlinkSerializable,\n{\n    pub fn message_type(&self) -> u16 {\n        match self {\n            NetlinkPayload::Done => NLMSG_DONE,\n            NetlinkPayload::Error(_) | NetlinkPayload::Ack(_) => NLMSG_ERROR,\n            NetlinkPayload::Noop => NLMSG_NOOP,\n            NetlinkPayload::Overrun(_) => NLMSG_OVERRUN,\n            NetlinkPayload::InnerMessage(message) => message.message_type(),\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-core/src/traits.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::NetlinkHeader;\nuse std::error::Error;\n\n/// A `NetlinkDeserializable` type can be deserialized from a buffer\npub trait NetlinkDeserializable: Sized {\n    type Error: Error + Send + Sync + 'static;\n\n    /// Deserialize the given buffer into `Self`.\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error>;\n}\n\npub trait NetlinkSerializable {\n    fn message_type(&self) -> u16;\n\n    /// Return the length of the serialized data.\n    ///\n    /// Most netlink messages are encoded following a\n    /// [TLV](https://en.wikipedia.org/wiki/Type-length-value) scheme\n    /// and this library takes advantage of this by pre-allocating\n    /// buffers of the appropriate size when serializing messages,\n    /// which is why `buffer_len` is needed.\n    fn buffer_len(&self) -> usize;\n\n    /// Serialize this types and write the serialized data into the given buffer.\n    /// `buffer`'s length is exactly `InnerMessage::buffer_len()`.\n    /// It means that if `InnerMessage::buffer_len()` is buggy and does not return the appropriate length,\n    /// bad things can happen:\n    ///\n    /// - if `buffer_len()` returns a value _smaller than the actual data_, `emit()` may panics\n    /// - if `buffer_len()` returns a value _bigger than the actual data_, the buffer will contain garbage\n    ///\n    /// # Panic\n    ///\n    /// This method panics if the buffer is not big enough.\n    fn serialize(&self, buffer: &mut [u8]);\n}\n"
  },
  {
    "path": "netlink-packet-generic/Cargo.toml",
    "content": "[package]\nname = \"netlink-packet-generic\"\nversion = \"0.3.1\"\nauthors = [\"Leo <leo881003@gmail.com>\"]\nedition = \"2018\"\nhomepage = \"https://github.com/little-dude/netlink\"\nrepository = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\ndescription = \"generic netlink packet types\"\n\n[dependencies]\nanyhow = \"1.0.39\"\nlibc = \"0.2.86\"\nbyteorder = \"1.4.2\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\n\n[dev-dependencies]\nnetlink-sys = { path = \"../netlink-sys\", version = \"0.8.3\" }\n"
  },
  {
    "path": "netlink-packet-generic/examples/list_generic_family.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST};\nuse netlink_packet_generic::{\n    ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},\n    GenlMessage,\n};\nuse netlink_sys::{protocols::NETLINK_GENERIC, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_GENERIC).unwrap();\n    socket.bind_auto().unwrap();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut genlmsg = GenlMessage::from_payload(GenlCtrl {\n        cmd: GenlCtrlCmd::GetFamily,\n        nlas: vec![],\n    });\n    genlmsg.finalize();\n    let mut nlmsg = NetlinkMessage::from(genlmsg);\n    nlmsg.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n    nlmsg.finalize();\n\n    let mut txbuf = vec![0u8; nlmsg.buffer_len()];\n    nlmsg.serialize(&mut txbuf);\n\n    socket.send(&txbuf, 0).unwrap();\n\n    let mut rxbuf = vec![0u8; 4096];\n    let mut offset = 0;\n\n    'outer: loop {\n        let size = socket.recv(&mut rxbuf, 0).unwrap();\n\n        loop {\n            let buf = &rxbuf[offset..];\n            // Parse the message\n            let msg = <NetlinkMessage<GenlMessage<GenlCtrl>>>::deserialize(buf).unwrap();\n\n            match msg.payload {\n                NetlinkPayload::Done => break 'outer,\n                NetlinkPayload::InnerMessage(genlmsg) => {\n                    if GenlCtrlCmd::NewFamily == genlmsg.payload.cmd {\n                        print_entry(genlmsg.payload.nlas);\n                    }\n                }\n                NetlinkPayload::Error(err) => {\n                    eprintln!(\"Received a netlink error message: {:?}\", err);\n                    return;\n                }\n                _ => {}\n            }\n\n            offset += msg.header.length as usize;\n            if offset == size || msg.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n\nfn print_entry(entry: Vec<GenlCtrlAttrs>) {\n    let family_id = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::FamilyId(id) = nla {\n                Some(*id)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find FamilyId attribute\");\n    let family_name = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::FamilyName(name) = nla {\n                Some(name.as_str())\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find FamilyName attribute\");\n    let version = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::Version(ver) = nla {\n                Some(*ver)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find Version attribute\");\n    let hdrsize = entry\n        .iter()\n        .find_map(|nla| {\n            if let GenlCtrlAttrs::HdrSize(hdr) = nla {\n                Some(*hdr)\n            } else {\n                None\n            }\n        })\n        .expect(\"Cannot find HdrSize attribute\");\n\n    if hdrsize == 0 {\n        println!(\"0x{:04x} {} [Version {}]\", family_id, family_name, version);\n    } else {\n        println!(\n            \"0x{:04x} {} [Version {}] [Header {} bytes]\",\n            family_id, family_name, version, hdrsize\n        );\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Buffer definition of generic netlink packet\nuse crate::{constants::GENL_HDRLEN, header::GenlHeader, message::GenlMessage};\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_utils::{Parseable, ParseableParametrized};\nuse std::fmt::Debug;\n\nbuffer!(GenlBuffer(GENL_HDRLEN) {\n    cmd: (u8, 0),\n    version: (u8, 1),\n    payload: (slice, GENL_HDRLEN..),\n});\n\nimpl<F> ParseableParametrized<[u8], u16> for GenlMessage<F>\nwhere\n    F: ParseableParametrized<[u8], GenlHeader> + Debug,\n{\n    fn parse_with_param(buf: &[u8], message_type: u16) -> Result<Self, DecodeError> {\n        let buf = GenlBuffer::new_checked(buf)?;\n        Self::parse_with_param(&buf, message_type)\n    }\n}\n\nimpl<'a, F, T> ParseableParametrized<GenlBuffer<&'a T>, u16> for GenlMessage<F>\nwhere\n    F: ParseableParametrized<[u8], GenlHeader> + Debug,\n    T: AsRef<[u8]> + ?Sized,\n{\n    fn parse_with_param(buf: &GenlBuffer<&'a T>, message_type: u16) -> Result<Self, DecodeError> {\n        let header = GenlHeader::parse(buf)?;\n        let payload_buf = buf.payload();\n        Ok(GenlMessage::new(\n            header,\n            F::parse_with_param(payload_buf, header)?,\n            message_type,\n        ))\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Define constants related to generic netlink\npub const GENL_ID_CTRL: u16 = libc::GENL_ID_CTRL as u16;\npub const GENL_HDRLEN: usize = 4;\n\npub const CTRL_CMD_UNSPEC: u8 = libc::CTRL_CMD_UNSPEC as u8;\npub const CTRL_CMD_NEWFAMILY: u8 = libc::CTRL_CMD_NEWFAMILY as u8;\npub const CTRL_CMD_DELFAMILY: u8 = libc::CTRL_CMD_DELFAMILY as u8;\npub const CTRL_CMD_GETFAMILY: u8 = libc::CTRL_CMD_GETFAMILY as u8;\npub const CTRL_CMD_NEWOPS: u8 = libc::CTRL_CMD_NEWOPS as u8;\npub const CTRL_CMD_DELOPS: u8 = libc::CTRL_CMD_DELOPS as u8;\npub const CTRL_CMD_GETOPS: u8 = libc::CTRL_CMD_GETOPS as u8;\npub const CTRL_CMD_NEWMCAST_GRP: u8 = libc::CTRL_CMD_NEWMCAST_GRP as u8;\npub const CTRL_CMD_DELMCAST_GRP: u8 = libc::CTRL_CMD_DELMCAST_GRP as u8;\npub const CTRL_CMD_GETMCAST_GRP: u8 = libc::CTRL_CMD_GETMCAST_GRP as u8;\npub const CTRL_CMD_GETPOLICY: u8 = 10;\n\npub const CTRL_ATTR_UNSPEC: u16 = libc::CTRL_ATTR_UNSPEC as u16;\npub const CTRL_ATTR_FAMILY_ID: u16 = libc::CTRL_ATTR_FAMILY_ID as u16;\npub const CTRL_ATTR_FAMILY_NAME: u16 = libc::CTRL_ATTR_FAMILY_NAME as u16;\npub const CTRL_ATTR_VERSION: u16 = libc::CTRL_ATTR_VERSION as u16;\npub const CTRL_ATTR_HDRSIZE: u16 = libc::CTRL_ATTR_HDRSIZE as u16;\npub const CTRL_ATTR_MAXATTR: u16 = libc::CTRL_ATTR_MAXATTR as u16;\npub const CTRL_ATTR_OPS: u16 = libc::CTRL_ATTR_OPS as u16;\npub const CTRL_ATTR_MCAST_GROUPS: u16 = libc::CTRL_ATTR_MCAST_GROUPS as u16;\npub const CTRL_ATTR_POLICY: u16 = 8;\npub const CTRL_ATTR_OP_POLICY: u16 = 9;\npub const CTRL_ATTR_OP: u16 = 10;\n\npub const CTRL_ATTR_OP_UNSPEC: u16 = libc::CTRL_ATTR_OP_UNSPEC as u16;\npub const CTRL_ATTR_OP_ID: u16 = libc::CTRL_ATTR_OP_ID as u16;\npub const CTRL_ATTR_OP_FLAGS: u16 = libc::CTRL_ATTR_OP_FLAGS as u16;\n\npub const CTRL_ATTR_MCAST_GRP_UNSPEC: u16 = libc::CTRL_ATTR_MCAST_GRP_UNSPEC as u16;\npub const CTRL_ATTR_MCAST_GRP_NAME: u16 = libc::CTRL_ATTR_MCAST_GRP_NAME as u16;\npub const CTRL_ATTR_MCAST_GRP_ID: u16 = libc::CTRL_ATTR_MCAST_GRP_ID as u16;\n\npub const CTRL_ATTR_POLICY_UNSPEC: u16 = 0;\npub const CTRL_ATTR_POLICY_DO: u16 = 1;\npub const CTRL_ATTR_POLICY_DUMP: u16 = 2;\n\npub const NL_ATTR_TYPE_INVALID: u32 = 0;\npub const NL_ATTR_TYPE_FLAG: u32 = 1;\npub const NL_ATTR_TYPE_U8: u32 = 2;\npub const NL_ATTR_TYPE_U16: u32 = 3;\npub const NL_ATTR_TYPE_U32: u32 = 4;\npub const NL_ATTR_TYPE_U64: u32 = 5;\npub const NL_ATTR_TYPE_S8: u32 = 6;\npub const NL_ATTR_TYPE_S16: u32 = 7;\npub const NL_ATTR_TYPE_S32: u32 = 8;\npub const NL_ATTR_TYPE_S64: u32 = 9;\npub const NL_ATTR_TYPE_BINARY: u32 = 10;\npub const NL_ATTR_TYPE_STRING: u32 = 11;\npub const NL_ATTR_TYPE_NUL_STRING: u32 = 12;\npub const NL_ATTR_TYPE_NESTED: u32 = 13;\npub const NL_ATTR_TYPE_NESTED_ARRAY: u32 = 14;\npub const NL_ATTR_TYPE_BITFIELD32: u32 = 15;\n\npub const NL_POLICY_TYPE_ATTR_UNSPEC: u16 = 0;\npub const NL_POLICY_TYPE_ATTR_TYPE: u16 = 1;\npub const NL_POLICY_TYPE_ATTR_MIN_VALUE_S: u16 = 2;\npub const NL_POLICY_TYPE_ATTR_MAX_VALUE_S: u16 = 3;\npub const NL_POLICY_TYPE_ATTR_MIN_VALUE_U: u16 = 4;\npub const NL_POLICY_TYPE_ATTR_MAX_VALUE_U: u16 = 5;\npub const NL_POLICY_TYPE_ATTR_MIN_LENGTH: u16 = 6;\npub const NL_POLICY_TYPE_ATTR_MAX_LENGTH: u16 = 7;\npub const NL_POLICY_TYPE_ATTR_POLICY_IDX: u16 = 8;\npub const NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE: u16 = 9;\npub const NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: u16 = 10;\npub const NL_POLICY_TYPE_ATTR_PAD: u16 = 11;\npub const NL_POLICY_TYPE_ATTR_MASK: u16 = 12;\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Generic netlink controller implementation\n//!\n//! This module provides the definition of the controller packet.\n//! It also serves as an example for creating a generic family.\n\nuse self::nlas::*;\nuse crate::{constants::*, traits::*, GenlHeader};\nuse anyhow::Context;\nuse netlink_packet_utils::{nla::NlasIterator, traits::*, DecodeError};\nuse std::convert::{TryFrom, TryInto};\n\n/// Netlink attributes for this family\npub mod nlas;\n\n/// Command code definition of Netlink controller (nlctrl) family\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum GenlCtrlCmd {\n    /// Notify from event\n    NewFamily,\n    /// Notify from event\n    DelFamily,\n    /// Request to get family info\n    GetFamily,\n    /// Currently unused\n    NewOps,\n    /// Currently unused\n    DelOps,\n    /// Currently unused\n    GetOps,\n    /// Notify from event\n    NewMcastGrp,\n    /// Notify from event\n    DelMcastGrp,\n    /// Currently unused\n    GetMcastGrp,\n    /// Request to get family policy\n    GetPolicy,\n}\n\nimpl From<GenlCtrlCmd> for u8 {\n    fn from(cmd: GenlCtrlCmd) -> u8 {\n        use GenlCtrlCmd::*;\n        match cmd {\n            NewFamily => CTRL_CMD_NEWFAMILY,\n            DelFamily => CTRL_CMD_DELFAMILY,\n            GetFamily => CTRL_CMD_GETFAMILY,\n            NewOps => CTRL_CMD_NEWOPS,\n            DelOps => CTRL_CMD_DELOPS,\n            GetOps => CTRL_CMD_GETOPS,\n            NewMcastGrp => CTRL_CMD_NEWMCAST_GRP,\n            DelMcastGrp => CTRL_CMD_DELMCAST_GRP,\n            GetMcastGrp => CTRL_CMD_GETMCAST_GRP,\n            GetPolicy => CTRL_CMD_GETPOLICY,\n        }\n    }\n}\n\nimpl TryFrom<u8> for GenlCtrlCmd {\n    type Error = DecodeError;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        use GenlCtrlCmd::*;\n        Ok(match value {\n            CTRL_CMD_NEWFAMILY => NewFamily,\n            CTRL_CMD_DELFAMILY => DelFamily,\n            CTRL_CMD_GETFAMILY => GetFamily,\n            CTRL_CMD_NEWOPS => NewOps,\n            CTRL_CMD_DELOPS => DelOps,\n            CTRL_CMD_GETOPS => GetOps,\n            CTRL_CMD_NEWMCAST_GRP => NewMcastGrp,\n            CTRL_CMD_DELMCAST_GRP => DelMcastGrp,\n            CTRL_CMD_GETMCAST_GRP => GetMcastGrp,\n            CTRL_CMD_GETPOLICY => GetPolicy,\n            cmd => {\n                return Err(DecodeError::from(format!(\n                    \"Unknown control command: {}\",\n                    cmd\n                )))\n            }\n        })\n    }\n}\n\n/// Payload of generic netlink controller\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct GenlCtrl {\n    /// Command code of this message\n    pub cmd: GenlCtrlCmd,\n    /// Netlink attributes in this message\n    pub nlas: Vec<GenlCtrlAttrs>,\n}\n\nimpl GenlFamily for GenlCtrl {\n    fn family_name() -> &'static str {\n        \"nlctrl\"\n    }\n\n    fn family_id(&self) -> u16 {\n        GENL_ID_CTRL\n    }\n\n    fn command(&self) -> u8 {\n        self.cmd.into()\n    }\n\n    fn version(&self) -> u8 {\n        2\n    }\n}\n\nimpl Emitable for GenlCtrl {\n    fn emit(&self, buffer: &mut [u8]) {\n        self.nlas.as_slice().emit(buffer)\n    }\n\n    fn buffer_len(&self) -> usize {\n        self.nlas.as_slice().buffer_len()\n    }\n}\n\nimpl ParseableParametrized<[u8], GenlHeader> for GenlCtrl {\n    fn parse_with_param(buf: &[u8], header: GenlHeader) -> Result<Self, DecodeError> {\n        Ok(Self {\n            cmd: header.cmd.try_into()?,\n            nlas: parse_ctrlnlas(buf)?,\n        })\n    }\n}\n\nfn parse_ctrlnlas(buf: &[u8]) -> Result<Vec<GenlCtrlAttrs>, DecodeError> {\n    let nlas = NlasIterator::new(buf)\n        .map(|nla| nla.and_then(|nla| GenlCtrlAttrs::parse(&nla)))\n        .collect::<Result<Vec<_>, _>>()\n        .context(\"failed to parse control message attributes\")?;\n\n    Ok(nlas)\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/nlas/mcast.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::mem::size_of_val;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum McastGrpAttrs {\n    Name(String),\n    Id(u32),\n}\n\nimpl Nla for McastGrpAttrs {\n    fn value_len(&self) -> usize {\n        use McastGrpAttrs::*;\n        match self {\n            Name(s) => s.as_bytes().len() + 1,\n            Id(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use McastGrpAttrs::*;\n        match self {\n            Name(_) => CTRL_ATTR_MCAST_GRP_NAME,\n            Id(_) => CTRL_ATTR_MCAST_GRP_ID,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use McastGrpAttrs::*;\n        match self {\n            Name(s) => {\n                buffer[..s.len()].copy_from_slice(s.as_bytes());\n                buffer[s.len()] = 0;\n            }\n            Id(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for McastGrpAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            CTRL_ATTR_MCAST_GRP_NAME => {\n                Self::Name(parse_string(payload).context(\"invalid CTRL_ATTR_MCAST_GRP_NAME value\")?)\n            }\n            CTRL_ATTR_MCAST_GRP_ID => {\n                Self::Id(parse_u32(payload).context(\"invalid CTRL_ATTR_MCAST_GRP_ID value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"Unknown NLA type: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer, NlasIterator},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::mem::size_of_val;\n\nmod mcast;\nmod oppolicy;\nmod ops;\nmod policy;\n\npub use mcast::*;\npub use oppolicy::*;\npub use ops::*;\npub use policy::*;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum GenlCtrlAttrs {\n    FamilyId(u16),\n    FamilyName(String),\n    Version(u32),\n    HdrSize(u32),\n    MaxAttr(u32),\n    Ops(Vec<Vec<OpAttrs>>),\n    McastGroups(Vec<Vec<McastGrpAttrs>>),\n    Policy(PolicyAttr),\n    OpPolicy(OppolicyAttr),\n    Op(u32),\n}\n\nimpl Nla for GenlCtrlAttrs {\n    fn value_len(&self) -> usize {\n        use GenlCtrlAttrs::*;\n        match self {\n            FamilyId(v) => size_of_val(v),\n            FamilyName(s) => s.len() + 1,\n            Version(v) => size_of_val(v),\n            HdrSize(v) => size_of_val(v),\n            MaxAttr(v) => size_of_val(v),\n            Ops(nlas) => nlas.iter().map(|op| op.as_slice().buffer_len()).sum(),\n            McastGroups(nlas) => nlas.iter().map(|op| op.as_slice().buffer_len()).sum(),\n            Policy(nla) => nla.buffer_len(),\n            OpPolicy(nla) => nla.buffer_len(),\n            Op(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use GenlCtrlAttrs::*;\n        match self {\n            FamilyId(_) => CTRL_ATTR_FAMILY_ID,\n            FamilyName(_) => CTRL_ATTR_FAMILY_NAME,\n            Version(_) => CTRL_ATTR_VERSION,\n            HdrSize(_) => CTRL_ATTR_HDRSIZE,\n            MaxAttr(_) => CTRL_ATTR_MAXATTR,\n            Ops(_) => CTRL_ATTR_OPS,\n            McastGroups(_) => CTRL_ATTR_MCAST_GROUPS,\n            Policy(_) => CTRL_ATTR_POLICY,\n            OpPolicy(_) => CTRL_ATTR_OP_POLICY,\n            Op(_) => CTRL_ATTR_OP,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use GenlCtrlAttrs::*;\n        match self {\n            FamilyId(v) => NativeEndian::write_u16(buffer, *v),\n            FamilyName(s) => {\n                buffer[..s.len()].copy_from_slice(s.as_bytes());\n                buffer[s.len()] = 0;\n            }\n            Version(v) => NativeEndian::write_u32(buffer, *v),\n            HdrSize(v) => NativeEndian::write_u32(buffer, *v),\n            MaxAttr(v) => NativeEndian::write_u32(buffer, *v),\n            Ops(nlas) => {\n                let mut len = 0;\n                for op in nlas {\n                    op.as_slice().emit(&mut buffer[len..]);\n                    len += op.as_slice().buffer_len();\n                }\n            }\n            McastGroups(nlas) => {\n                let mut len = 0;\n                for op in nlas {\n                    op.as_slice().emit(&mut buffer[len..]);\n                    len += op.as_slice().buffer_len();\n                }\n            }\n            Policy(nla) => nla.emit_value(buffer),\n            OpPolicy(nla) => nla.emit_value(buffer),\n            Op(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for GenlCtrlAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            CTRL_ATTR_FAMILY_ID => {\n                Self::FamilyId(parse_u16(payload).context(\"invalid CTRL_ATTR_FAMILY_ID value\")?)\n            }\n            CTRL_ATTR_FAMILY_NAME => Self::FamilyName(\n                parse_string(payload).context(\"invalid CTRL_ATTR_FAMILY_NAME value\")?,\n            ),\n            CTRL_ATTR_VERSION => {\n                Self::Version(parse_u32(payload).context(\"invalid CTRL_ATTR_VERSION value\")?)\n            }\n            CTRL_ATTR_HDRSIZE => {\n                Self::HdrSize(parse_u32(payload).context(\"invalid CTRL_ATTR_HDRSIZE value\")?)\n            }\n            CTRL_ATTR_MAXATTR => {\n                Self::MaxAttr(parse_u32(payload).context(\"invalid CTRL_ATTR_MAXATTR value\")?)\n            }\n            CTRL_ATTR_OPS => {\n                let ops = NlasIterator::new(payload)\n                    .map(|nlas| {\n                        nlas.and_then(|nlas| {\n                            NlasIterator::new(nlas.value())\n                                .map(|nla| nla.and_then(|nla| OpAttrs::parse(&nla)))\n                                .collect::<Result<Vec<_>, _>>()\n                        })\n                    })\n                    .collect::<Result<Vec<Vec<_>>, _>>()\n                    .context(\"failed to parse CTRL_ATTR_OPS\")?;\n\n                Self::Ops(ops)\n            }\n            CTRL_ATTR_MCAST_GROUPS => {\n                let groups = NlasIterator::new(payload)\n                    .map(|nlas| {\n                        nlas.and_then(|nlas| {\n                            NlasIterator::new(nlas.value())\n                                .map(|nla| nla.and_then(|nla| McastGrpAttrs::parse(&nla)))\n                                .collect::<Result<Vec<_>, _>>()\n                        })\n                    })\n                    .collect::<Result<Vec<Vec<_>>, _>>()\n                    .context(\"failed to parse CTRL_ATTR_MCAST_GROUPS\")?;\n\n                Self::McastGroups(groups)\n            }\n            CTRL_ATTR_POLICY => Self::Policy(\n                PolicyAttr::parse(&NlaBuffer::new(payload))\n                    .context(\"failed to parse CTRL_ATTR_POLICY\")?,\n            ),\n            CTRL_ATTR_OP_POLICY => Self::OpPolicy(\n                OppolicyAttr::parse(&NlaBuffer::new(payload))\n                    .context(\"failed to parse CTRL_ATTR_OP_POLICY\")?,\n            ),\n            CTRL_ATTR_OP => Self::Op(parse_u32(payload)?),\n            kind => return Err(DecodeError::from(format!(\"Unknown NLA type: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/nlas/oppolicy.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer, NlasIterator},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::mem::size_of_val;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct OppolicyAttr {\n    pub cmd: u8,\n    pub policy_idx: Vec<OppolicyIndexAttr>,\n}\n\nimpl Nla for OppolicyAttr {\n    fn value_len(&self) -> usize {\n        self.policy_idx.as_slice().buffer_len()\n    }\n\n    fn kind(&self) -> u16 {\n        self.cmd as u16\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.policy_idx.as_slice().emit(buffer);\n    }\n\n    fn is_nested(&self) -> bool {\n        true\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for OppolicyAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        let policy_idx = NlasIterator::new(payload)\n            .map(|nla| nla.and_then(|nla| OppolicyIndexAttr::parse(&nla)))\n            .collect::<Result<Vec<_>, _>>()\n            .context(\"failed to parse OppolicyAttr\")?;\n\n        Ok(Self {\n            cmd: buf.kind() as u8,\n            policy_idx,\n        })\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum OppolicyIndexAttr {\n    Do(u32),\n    Dump(u32),\n}\n\nimpl Nla for OppolicyIndexAttr {\n    fn value_len(&self) -> usize {\n        use OppolicyIndexAttr::*;\n        match self {\n            Do(v) => size_of_val(v),\n            Dump(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use OppolicyIndexAttr::*;\n        match self {\n            Do(_) => CTRL_ATTR_POLICY_DO,\n            Dump(_) => CTRL_ATTR_POLICY_DUMP,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use OppolicyIndexAttr::*;\n        match self {\n            Do(v) => NativeEndian::write_u32(buffer, *v),\n            Dump(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for OppolicyIndexAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            CTRL_ATTR_POLICY_DO => {\n                Self::Do(parse_u32(payload).context(\"invalid CTRL_ATTR_POLICY_DO value\")?)\n            }\n            CTRL_ATTR_POLICY_DUMP => {\n                Self::Dump(parse_u32(payload).context(\"invalid CTRL_ATTR_POLICY_DUMP value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"Unknown NLA type: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/nlas/ops.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::mem::size_of_val;\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum OpAttrs {\n    Id(u32),\n    Flags(u32),\n}\n\nimpl Nla for OpAttrs {\n    fn value_len(&self) -> usize {\n        use OpAttrs::*;\n        match self {\n            Id(v) => size_of_val(v),\n            Flags(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use OpAttrs::*;\n        match self {\n            Id(_) => CTRL_ATTR_OP_ID,\n            Flags(_) => CTRL_ATTR_OP_FLAGS,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use OpAttrs::*;\n        match self {\n            Id(v) => NativeEndian::write_u32(buffer, *v),\n            Flags(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for OpAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            CTRL_ATTR_OP_ID => {\n                Self::Id(parse_u32(payload).context(\"invalid CTRL_ATTR_OP_ID value\")?)\n            }\n            CTRL_ATTR_OP_FLAGS => {\n                Self::Flags(parse_u32(payload).context(\"invalid CTRL_ATTR_OP_FLAGS value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"Unknown NLA type: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/ctrl/nlas/policy.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer, NlasIterator},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::{\n    convert::TryFrom,\n    mem::{size_of, size_of_val},\n};\n\n// PolicyAttr\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct PolicyAttr {\n    pub index: u16,\n    pub attr_policy: AttributePolicyAttr,\n}\n\nimpl Nla for PolicyAttr {\n    fn value_len(&self) -> usize {\n        self.attr_policy.buffer_len()\n    }\n\n    fn kind(&self) -> u16 {\n        self.index\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.attr_policy.emit(buffer);\n    }\n\n    fn is_nested(&self) -> bool {\n        true\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for PolicyAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n\n        Ok(Self {\n            index: buf.kind(),\n            attr_policy: AttributePolicyAttr::parse(&NlaBuffer::new(payload))\n                .context(\"failed to parse PolicyAttr\")?,\n        })\n    }\n}\n\n// AttributePolicyAttr\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct AttributePolicyAttr {\n    pub index: u16,\n    pub policies: Vec<NlPolicyTypeAttrs>,\n}\n\nimpl Nla for AttributePolicyAttr {\n    fn value_len(&self) -> usize {\n        self.policies.as_slice().buffer_len()\n    }\n\n    fn kind(&self) -> u16 {\n        self.index\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.policies.as_slice().emit(buffer);\n    }\n\n    fn is_nested(&self) -> bool {\n        true\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AttributePolicyAttr {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        let policies = NlasIterator::new(payload)\n            .map(|nla| nla.and_then(|nla| NlPolicyTypeAttrs::parse(&nla)))\n            .collect::<Result<Vec<_>, _>>()\n            .context(\"failed to parse AttributePolicyAttr\")?;\n\n        Ok(Self {\n            index: buf.kind(),\n            policies,\n        })\n    }\n}\n\n// PolicyTypeAttrs\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum NlPolicyTypeAttrs {\n    Type(NlaType),\n    MinValueSigned(i64),\n    MaxValueSigned(i64),\n    MaxValueUnsigned(u64),\n    MinValueUnsigned(u64),\n    MinLength(u32),\n    MaxLength(u32),\n    PolicyIdx(u32),\n    PolicyMaxType(u32),\n    Bitfield32Mask(u32),\n    Mask(u64),\n}\n\nimpl Nla for NlPolicyTypeAttrs {\n    fn value_len(&self) -> usize {\n        use NlPolicyTypeAttrs::*;\n        match self {\n            Type(v) => size_of_val(v),\n            MinValueSigned(v) => size_of_val(v),\n            MaxValueSigned(v) => size_of_val(v),\n            MaxValueUnsigned(v) => size_of_val(v),\n            MinValueUnsigned(v) => size_of_val(v),\n            MinLength(v) => size_of_val(v),\n            MaxLength(v) => size_of_val(v),\n            PolicyIdx(v) => size_of_val(v),\n            PolicyMaxType(v) => size_of_val(v),\n            Bitfield32Mask(v) => size_of_val(v),\n            Mask(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use NlPolicyTypeAttrs::*;\n        match self {\n            Type(_) => NL_POLICY_TYPE_ATTR_TYPE,\n            MinValueSigned(_) => NL_POLICY_TYPE_ATTR_MIN_VALUE_S,\n            MaxValueSigned(_) => NL_POLICY_TYPE_ATTR_MAX_VALUE_S,\n            MaxValueUnsigned(_) => NL_POLICY_TYPE_ATTR_MIN_VALUE_U,\n            MinValueUnsigned(_) => NL_POLICY_TYPE_ATTR_MAX_VALUE_U,\n            MinLength(_) => NL_POLICY_TYPE_ATTR_MIN_LENGTH,\n            MaxLength(_) => NL_POLICY_TYPE_ATTR_MAX_LENGTH,\n            PolicyIdx(_) => NL_POLICY_TYPE_ATTR_POLICY_IDX,\n            PolicyMaxType(_) => NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,\n            Bitfield32Mask(_) => NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,\n            Mask(_) => NL_POLICY_TYPE_ATTR_MASK,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use NlPolicyTypeAttrs::*;\n        match self {\n            Type(v) => NativeEndian::write_u32(buffer, u32::from(*v)),\n            MinValueSigned(v) => NativeEndian::write_i64(buffer, *v),\n            MaxValueSigned(v) => NativeEndian::write_i64(buffer, *v),\n            MaxValueUnsigned(v) => NativeEndian::write_u64(buffer, *v),\n            MinValueUnsigned(v) => NativeEndian::write_u64(buffer, *v),\n            MinLength(v) => NativeEndian::write_u32(buffer, *v),\n            MaxLength(v) => NativeEndian::write_u32(buffer, *v),\n            PolicyIdx(v) => NativeEndian::write_u32(buffer, *v),\n            PolicyMaxType(v) => NativeEndian::write_u32(buffer, *v),\n            Bitfield32Mask(v) => NativeEndian::write_u32(buffer, *v),\n            Mask(v) => NativeEndian::write_u64(buffer, *v),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for NlPolicyTypeAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            NL_POLICY_TYPE_ATTR_TYPE => {\n                let value = parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_TYPE value\")?;\n                Self::Type(NlaType::try_from(value)?)\n            }\n            NL_POLICY_TYPE_ATTR_MIN_VALUE_S => Self::MinValueSigned(\n                parse_i64(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MIN_VALUE_S value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MAX_VALUE_S => Self::MaxValueSigned(\n                parse_i64(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MAX_VALUE_S value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MIN_VALUE_U => Self::MinValueUnsigned(\n                parse_u64(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MIN_VALUE_U value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MAX_VALUE_U => Self::MaxValueUnsigned(\n                parse_u64(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MAX_VALUE_U value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MIN_LENGTH => Self::MinLength(\n                parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MIN_LENGTH value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MAX_LENGTH => Self::MaxLength(\n                parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MAX_LENGTH value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_POLICY_IDX => Self::PolicyIdx(\n                parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_POLICY_IDX value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE => Self::PolicyMaxType(\n                parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_BITFIELD32_MASK => Self::Bitfield32Mask(\n                parse_u32(payload).context(\"invalid NL_POLICY_TYPE_ATTR_BITFIELD32_MASK value\")?,\n            ),\n            NL_POLICY_TYPE_ATTR_MASK => {\n                Self::Mask(parse_u64(payload).context(\"invalid NL_POLICY_TYPE_ATTR_MASK value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"Unknown NLA type: {}\", kind))),\n        })\n    }\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\npub enum NlaType {\n    Flag,\n    U8,\n    U16,\n    U32,\n    U64,\n    S8,\n    S16,\n    S32,\n    S64,\n    Binary,\n    String,\n    NulString,\n    Nested,\n    NestedArray,\n    Bitfield32,\n}\n\nimpl From<NlaType> for u32 {\n    fn from(nlatype: NlaType) -> u32 {\n        match nlatype {\n            NlaType::Flag => NL_ATTR_TYPE_FLAG,\n            NlaType::U8 => NL_ATTR_TYPE_U8,\n            NlaType::U16 => NL_ATTR_TYPE_U16,\n            NlaType::U32 => NL_ATTR_TYPE_U32,\n            NlaType::U64 => NL_ATTR_TYPE_U64,\n            NlaType::S8 => NL_ATTR_TYPE_S8,\n            NlaType::S16 => NL_ATTR_TYPE_S16,\n            NlaType::S32 => NL_ATTR_TYPE_S32,\n            NlaType::S64 => NL_ATTR_TYPE_S64,\n            NlaType::Binary => NL_ATTR_TYPE_BINARY,\n            NlaType::String => NL_ATTR_TYPE_STRING,\n            NlaType::NulString => NL_ATTR_TYPE_NUL_STRING,\n            NlaType::Nested => NL_ATTR_TYPE_NESTED,\n            NlaType::NestedArray => NL_ATTR_TYPE_NESTED_ARRAY,\n            NlaType::Bitfield32 => NL_ATTR_TYPE_BITFIELD32,\n        }\n    }\n}\n\nimpl TryFrom<u32> for NlaType {\n    type Error = DecodeError;\n\n    fn try_from(value: u32) -> Result<Self, Self::Error> {\n        Ok(match value {\n            NL_ATTR_TYPE_FLAG => NlaType::Flag,\n            NL_ATTR_TYPE_U8 => NlaType::U8,\n            NL_ATTR_TYPE_U16 => NlaType::U16,\n            NL_ATTR_TYPE_U32 => NlaType::U32,\n            NL_ATTR_TYPE_U64 => NlaType::U64,\n            NL_ATTR_TYPE_S8 => NlaType::S8,\n            NL_ATTR_TYPE_S16 => NlaType::S16,\n            NL_ATTR_TYPE_S32 => NlaType::S32,\n            NL_ATTR_TYPE_S64 => NlaType::S64,\n            NL_ATTR_TYPE_BINARY => NlaType::Binary,\n            NL_ATTR_TYPE_STRING => NlaType::String,\n            NL_ATTR_TYPE_NUL_STRING => NlaType::NulString,\n            NL_ATTR_TYPE_NESTED => NlaType::Nested,\n            NL_ATTR_TYPE_NESTED_ARRAY => NlaType::NestedArray,\n            NL_ATTR_TYPE_BITFIELD32 => NlaType::Bitfield32,\n            _ => return Err(DecodeError::from(format!(\"invalid NLA type: {}\", value))),\n        })\n    }\n}\n\n// FIXME: Add this into netlink_packet_utils::parser\nfn parse_i64(payload: &[u8]) -> Result<i64, DecodeError> {\n    if payload.len() != size_of::<i64>() {\n        return Err(format!(\"invalid i64: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_i64(payload))\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! header definition of generic netlink packet\nuse crate::{buffer::GenlBuffer, constants::GENL_HDRLEN};\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_utils::{Emitable, Parseable};\n\n/// Generic Netlink header\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct GenlHeader {\n    pub cmd: u8,\n    pub version: u8,\n}\n\nimpl Emitable for GenlHeader {\n    fn buffer_len(&self) -> usize {\n        GENL_HDRLEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = GenlBuffer::new(buffer);\n        packet.set_cmd(self.cmd);\n        packet.set_version(self.version);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<GenlBuffer<T>> for GenlHeader {\n    fn parse(buf: &GenlBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            cmd: buf.cmd(),\n            version: buf.version(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This crate provides the packet of generic netlink family and its controller.\n//!\n//! The `[GenlMessage]` provides a generic netlink family message which is\n//! sub-protocol independant.\n//! You can wrap your message into the type, then it can be used in `netlink-proto` crate.\n//!\n//! # Implementing a generic netlink family\n//! A generic netlink family contains several commands, and a version number in\n//! the header.\n//!\n//! The payload usually consists of netlink attributes, carrying the messages to\n//! the peer. In order to help you to make your payload into a valid netlink\n//! packet, this crate requires the informations about the family id,\n//! and the informations in the generic header. So, you need to implement some\n//! traits on your types.\n//!\n//! All the things in the payload including all netlink attributes used\n//! and the optional header should be handled by your implementation.\n//!\n//! ## Serializaion / Deserialization\n//! To implement your generic netlink family, you should handle the payload\n//! serialization process including its specific header (if any) and the netlink\n//! attributes.\n//!\n//! To achieve this, you should implement [`netlink_packet_utils::Emitable`]\n//! trait for the payload type.\n//!\n//! For deserialization, [`netlink_packet_utils::ParseableParametrized<[u8], GenlHeader>`](netlink_packet_utils::ParseableParametrized)\n//! trait should be implemented. As mention above, to provide more scalability,\n//! we use the simplest buffer type: `[u8]` here. You can turn it into other\n//! buffer type easily during deserializing.\n//!\n//! ## `GenlFamily` trait\n//! The trait is aim to provide some necessary informations in order to build\n//! the packet headers of netlink (nlmsghdr) and generic netlink (genlmsghdr).\n//!\n//! ### `family_name()`\n//! The method let the resolver to obtain the name registered in the kernel.\n//!\n//! ### `family_id()`\n//! Few netlink family has static family ID (e.g. controller). The method is\n//! mainly used to let those family to return their familt ID.\n//!\n//! If you don't know what is this, please **DO NOT** implement this method.\n//! Since the default implementation return `GENL_ID_GENERATE`, which means\n//! the family ID is allocated by the kernel dynamically.\n//!\n//! ### `command()`\n//! This method tells the generic netlink command id of the packet\n//! The return value is used to fill the `cmd` field in the generic netlink header.\n//!\n//! ### `version()`\n//! This method return the family version of the payload.\n//! The return value is used to fill the `version` field in the generic netlink header.\n//!\n//! ## Family Header\n//! Few family would use a family specific message header. For simplification\n//! and scalability, this crate treats it as a part of the payload, and make\n//! implementations to handle the header by themselves.\n//!\n//! If you are implementing such a generic family, note that you should define\n//! the header data structure in your payload type and handle the serialization.\n\n#[macro_use]\nextern crate netlink_packet_utils;\n\npub mod buffer;\npub use self::buffer::GenlBuffer;\n\npub mod constants;\n\npub mod ctrl;\n\npub mod header;\npub use self::header::GenlHeader;\n\npub mod message;\npub use self::message::GenlMessage;\n\npub mod traits;\npub use self::traits::GenlFamily;\n"
  },
  {
    "path": "netlink-packet-generic/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Message definition and method implementations\n\nuse crate::{buffer::GenlBuffer, header::GenlHeader, traits::*};\nuse netlink_packet_core::{\n    DecodeError,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\nuse netlink_packet_utils::{Emitable, ParseableParametrized};\nuse std::fmt::Debug;\n\n#[cfg(doc)]\nuse netlink_packet_core::NetlinkMessage;\n\n/// Represent the generic netlink messages\n///\n/// This type can wrap data types `F` which represents a generic family payload.\n/// The message can be serialize/deserialize if the type `F` implements [`GenlFamily`],\n/// [`Emitable`], and [`ParseableParametrized<[u8], GenlHeader>`](ParseableParametrized).\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct GenlMessage<F> {\n    pub header: GenlHeader,\n    pub payload: F,\n    resolved_family_id: u16,\n}\n\nimpl<F> GenlMessage<F>\nwhere\n    F: Debug,\n{\n    /// Construct the message\n    pub fn new(header: GenlHeader, payload: F, family_id: u16) -> Self {\n        Self {\n            header,\n            payload,\n            resolved_family_id: family_id,\n        }\n    }\n\n    /// Construct the message by the given header and payload\n    pub fn from_parts(header: GenlHeader, payload: F) -> Self {\n        Self {\n            header,\n            payload,\n            resolved_family_id: 0,\n        }\n    }\n\n    /// Consume this message and return its header and payload\n    pub fn into_parts(self) -> (GenlHeader, F) {\n        (self.header, self.payload)\n    }\n\n    /// Return the previously set resolved family ID in this message.\n    ///\n    /// This value would be used to serialize the message only if\n    /// the ([`GenlFamily::family_id()`]) return 0 in the underlying type.\n    pub fn resolved_family_id(&self) -> u16 {\n        self.resolved_family_id\n    }\n\n    /// Set the resolved dynamic family ID of the message, if the generic family\n    /// uses dynamic generated ID by kernel.\n    ///\n    /// This method is a interface to provide other high level library to\n    /// set the resolved family ID before the message is serialized.\n    ///\n    /// # Usage\n    /// Normally, you don't have to call this function directly if you are\n    /// using library which helps you handle the dynamic family id.\n    ///\n    /// If you are the developer of some high level generic netlink library,\n    /// you can call this method to set the family id resolved by your resolver.\n    /// Without having to modify the `message_type` field of the serialized\n    /// netlink packet header before sending it.\n    pub fn set_resolved_family_id(&mut self, family_id: u16) {\n        self.resolved_family_id = family_id;\n    }\n}\n\nimpl<F> GenlMessage<F>\nwhere\n    F: GenlFamily + Debug,\n{\n    /// Build the message from the payload\n    ///\n    /// This function would automatically fill the header for you. You can directly emit\n    /// the message without having to call [`finalize()`](Self::finalize).\n    pub fn from_payload(payload: F) -> Self {\n        Self {\n            header: GenlHeader {\n                cmd: payload.command(),\n                version: payload.version(),\n            },\n            payload,\n            resolved_family_id: 0,\n        }\n    }\n\n    /// Ensure the header ([`GenlHeader`]) is consistent with the payload (`F: GenlFamily`):\n    ///\n    /// - Fill the command and version number into the header\n    ///\n    /// If you are not 100% sure the header is correct, this method should be called before calling\n    /// [`Emitable::emit()`], as it could get error result if the header is inconsistent with the message.\n    pub fn finalize(&mut self) {\n        self.header.cmd = self.payload.command();\n        self.header.version = self.payload.version();\n    }\n\n    /// Return the resolved family ID which should be filled into the `message_type`\n    /// field in [`NetlinkHeader`].\n    ///\n    /// The implementation of [`NetlinkSerializable::message_type()`] would use\n    /// this function's result as its the return value. Thus, the family id can\n    /// be automatically filled into the `message_type` during the call to\n    /// [`NetlinkMessage::finalize()`].\n    pub fn family_id(&self) -> u16 {\n        let static_id = self.payload.family_id();\n        if static_id == 0 {\n            self.resolved_family_id\n        } else {\n            static_id\n        }\n    }\n}\n\nimpl<F> Emitable for GenlMessage<F>\nwhere\n    F: GenlFamily + Emitable + Debug,\n{\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.payload.buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n\n        let buffer = &mut buffer[self.header.buffer_len()..];\n        self.payload.emit(buffer);\n    }\n}\n\nimpl<F> NetlinkSerializable for GenlMessage<F>\nwhere\n    F: GenlFamily + Emitable + Debug,\n{\n    fn message_type(&self) -> u16 {\n        self.family_id()\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl<F> NetlinkDeserializable for GenlMessage<F>\nwhere\n    F: ParseableParametrized<[u8], GenlHeader> + Debug,\n{\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        let buffer = GenlBuffer::new_checked(payload)?;\n        GenlMessage::parse_with_param(&buffer, header.message_type)\n    }\n}\n\nimpl<F> From<GenlMessage<F>> for NetlinkPayload<GenlMessage<F>>\nwhere\n    F: Debug,\n{\n    fn from(message: GenlMessage<F>) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-generic/src/traits.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! Traits for implementing generic netlink family\n\n/// Provide the definition for generic netlink family\n///\n/// Family payload type should implement this trait to provide necessary\n/// informations in order to build the packet headers (`nlmsghdr` and `genlmsghdr`).\n///\n/// If you are looking for an example implementation, you can refer to the\n/// [`crate::ctrl`] module.\npub trait GenlFamily {\n    /// Return the unique family name registered in the kernel\n    ///\n    /// Let the resolver lookup the dynamically assigned ID\n    fn family_name() -> &'static str;\n\n    /// Return the assigned family ID\n    ///\n    /// # Note\n    /// The implementation of generic family should assign the ID to `GENL_ID_GENERATE` (0x0).\n    /// So the controller can dynamically assign the family ID.\n    ///\n    /// Regarding to the reason above, you should not have to implement the function\n    /// unless the family uses static ID.\n    fn family_id(&self) -> u16 {\n        0\n    }\n\n    /// Return the command type of the current message\n    fn command(&self) -> u8;\n\n    /// Indicate the protocol version\n    fn version(&self) -> u8;\n}\n"
  },
  {
    "path": "netlink-packet-generic/tests/query_family_id.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_REQUEST};\nuse netlink_packet_generic::{\n    ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},\n    GenlMessage,\n};\nuse netlink_sys::{protocols::NETLINK_GENERIC, Socket, SocketAddr};\n\n#[test]\nfn query_family_id() {\n    let mut socket = Socket::new(NETLINK_GENERIC).unwrap();\n    socket.bind_auto().unwrap();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut genlmsg = GenlMessage::from_payload(GenlCtrl {\n        cmd: GenlCtrlCmd::GetFamily,\n        nlas: vec![GenlCtrlAttrs::FamilyName(\"nlctrl\".to_owned())],\n    });\n    genlmsg.finalize();\n    let mut nlmsg = NetlinkMessage::from(genlmsg);\n    nlmsg.header.flags = NLM_F_REQUEST;\n    nlmsg.finalize();\n\n    println!(\"Buffer length: {}\", nlmsg.buffer_len());\n    let mut txbuf = vec![0u8; nlmsg.buffer_len()];\n    nlmsg.serialize(&mut txbuf);\n\n    socket.send(&txbuf, 0).unwrap();\n\n    let (rxbuf, _addr) = socket.recv_from_full().unwrap();\n    let rx_packet = <NetlinkMessage<GenlMessage<GenlCtrl>>>::deserialize(&rxbuf).unwrap();\n\n    if let NetlinkPayload::InnerMessage(genlmsg) = rx_packet.payload {\n        if GenlCtrlCmd::NewFamily == genlmsg.payload.cmd {\n            let family_id = genlmsg\n                .payload\n                .nlas\n                .iter()\n                .find_map(|nla| {\n                    if let GenlCtrlAttrs::FamilyId(id) = nla {\n                        Some(*id)\n                    } else {\n                        None\n                    }\n                })\n                .expect(\"Cannot find FamilyId attribute\");\n            // nlctrl's family must be 0x10\n            assert_eq!(0x10, family_id);\n        } else {\n            panic!(\"Invalid payload type: {:?}\", genlmsg.payload.cmd);\n        }\n    } else {\n        panic!(\"Failed to get family ID\");\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/Cargo.toml",
    "content": "[package]\nauthors = [\"Loïc Damien <loic.damien@dzamlo.ch>\"]\nname = \"netlink-packet-netfilter\"\nversion = \"0.1.0\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\", \"netfilter\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink packet types for the netfilter subprotocol\"\n\n[dependencies]\nanyhow = \"1.0.32\"\nbyteorder = \"1.3.4\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nbitflags = \"1.2.1\"\nlibc = \"0.2.77\"\nderive_more = \"0.99.16\"\n\n[dev-dependencies]\nnetlink-sys = { version = \"0.8.3\", path = \"../netlink-sys\" }\n"
  },
  {
    "path": "netlink-packet-netfilter/examples/nflog.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n// To run this example:\n//   1) create a iptables/nft rules that send packet with group 1, for example:\n//          sudo iptables -A INPUT -j NFLOG --nflog-group 1\n//   2) build the example:\n//          cargo build --example nflog\n//   3) run it as root:\n//          sudo ../target/debug/examples/nflog\n\nuse std::{net::Ipv4Addr, time::Duration};\n\nuse byteorder::{ByteOrder, NetworkEndian};\nuse netlink_packet_netfilter::{\n    constants::*,\n    nflog::{\n        config_request,\n        nlas::{\n            config::{ConfigCmd, ConfigFlags, ConfigMode, Timeout},\n            packet::PacketNla,\n        },\n        NfLogMessage,\n    },\n    nl::{NetlinkMessage, NetlinkPayload},\n    NetfilterMessage,\n    NetfilterMessageInner,\n};\nuse netlink_sys::{constants::NETLINK_NETFILTER, Socket};\n\nfn get_packet_nlas(message: &NetlinkMessage<NetfilterMessage>) -> &[PacketNla] {\n    if let NetlinkPayload::InnerMessage(NetfilterMessage {\n        inner: NetfilterMessageInner::NfLog(NfLogMessage::Packet(nlas)),\n        ..\n    }) = &message.payload\n    {\n        nlas\n    } else {\n        &[]\n    }\n}\n\nfn main() {\n    let mut receive_buffer = vec![0; 4096];\n\n    // First, we bind the socket\n    let mut socket = Socket::new(NETLINK_NETFILTER).unwrap();\n    socket.bind_auto().unwrap();\n\n    // Then we issue the PfBind command\n    let packet = config_request(AF_INET, 0, vec![ConfigCmd::PfBind.into()]);\n    let mut buf = vec![0; packet.header.length as usize];\n    packet.serialize(&mut buf[..]);\n    println!(\">>> {:?}\", packet);\n    socket.send(&buf[..], 0).unwrap();\n\n    // And check there is no error\n    let size = socket.recv(&mut &mut receive_buffer[..], 0).unwrap();\n    let bytes = &receive_buffer[..size];\n    let rx_packet = <NetlinkMessage<NetfilterMessage>>::deserialize(bytes).unwrap();\n    println!(\"<<< {:?}\", rx_packet);\n    assert!(matches!(rx_packet.payload, NetlinkPayload::Ack(_)));\n\n    // After that we issue a Bind command, to start receiving packets. We can also set various parameters at the same time\n    let timeout: Timeout = Duration::from_millis(100).into();\n    let packet = config_request(\n        AF_INET,\n        1,\n        vec![\n            ConfigCmd::Bind.into(),\n            ConfigFlags::SEQ_GLOBAL.into(),\n            ConfigMode::PACKET_MAX.into(),\n            timeout.into(),\n        ],\n    );\n    let mut buf = vec![0; packet.header.length as usize];\n    packet.serialize(&mut buf[..]);\n    println!(\">>> {:?}\", packet);\n    socket.send(&buf[..], 0).unwrap();\n\n    let size = socket.recv(&mut &mut receive_buffer[..], 0).unwrap();\n    let bytes = &receive_buffer[..size];\n    let rx_packet = <NetlinkMessage<NetfilterMessage>>::deserialize(bytes).unwrap();\n    println!(\"<<< {:?}\", rx_packet);\n    assert!(matches!(rx_packet.payload, NetlinkPayload::Ack(_)));\n\n    // And now we can receive the packets\n    loop {\n        match socket.recv(&mut &mut receive_buffer[..], 0) {\n            Ok(size) => {\n                let mut offset = 0;\n                loop {\n                    let bytes = &receive_buffer[offset..];\n\n                    let rx_packet = <NetlinkMessage<NetfilterMessage>>::deserialize(bytes).unwrap();\n\n                    for nla in get_packet_nlas(&rx_packet) {\n                        if let PacketNla::Payload(payload) = nla {\n                            let src = Ipv4Addr::from(NetworkEndian::read_u32(&payload[12..]));\n                            let dst = Ipv4Addr::from(NetworkEndian::read_u32(&payload[16..]));\n                            println!(\"Packet from {} to {}\", src, dst);\n                            break;\n                        }\n                    }\n\n                    offset += rx_packet.header.length as usize;\n                    if offset == size || rx_packet.header.length == 0 {\n                        break;\n                    }\n                }\n            }\n            Err(e) => {\n                println!(\"error while receiving packets: {:?}\", e);\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    message::{NetfilterHeader, NetfilterMessage, NetfilterMessageInner, NETFILTER_HEADER_LEN},\n    nflog::NfLogMessage,\n    traits::{Parseable, ParseableParametrized},\n    DecodeError,\n};\nuse anyhow::Context;\nuse netlink_packet_utils::{\n    buffer,\n    nla::{DefaultNla, NlaBuffer, NlasIterator},\n};\n\nbuffer!(NetfilterBuffer(NETFILTER_HEADER_LEN) {\n    header: (slice, ..NETFILTER_HEADER_LEN),\n    payload: (slice, NETFILTER_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NetfilterBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n\n    pub fn parse_all_nlas<F, U>(&self, f: F) -> Result<Vec<U>, DecodeError>\n    where\n        F: Fn(NlaBuffer<&[u8]>) -> Result<U, DecodeError>,\n    {\n        Ok(self\n            .nlas()\n            .map(|buf| f(buf?))\n            .collect::<Result<Vec<_>, _>>()\n            .context(\"failed to parse NLAs\")?)\n    }\n\n    pub fn default_nlas(&self) -> Result<Vec<DefaultNla>, DecodeError> {\n        self.parse_all_nlas(|buf| DefaultNla::parse(&buf))\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NetfilterBuffer<&'a T>, u16>\n    for NetfilterMessage\n{\n    fn parse_with_param(\n        buf: &NetfilterBuffer<&'a T>,\n        message_type: u16,\n    ) -> Result<Self, DecodeError> {\n        let header_buf = crate::message::NetfilterHeaderBuffer::new(buf.inner());\n        let header =\n            NetfilterHeader::parse(&header_buf).context(\"failed to parse netfilter header\")?;\n        let subsys = (message_type >> 8) as u8;\n        let message_type = message_type as u8;\n        let inner = match subsys {\n            NfLogMessage::SUBSYS => NetfilterMessageInner::NfLog(\n                NfLogMessage::parse_with_param(buf, message_type)\n                    .context(\"failed to parse nflog payload\")?,\n            ),\n            _ => NetfilterMessageInner::Other {\n                subsys,\n                message_type,\n                nlas: buf.default_nlas()?,\n            },\n        };\n        Ok(NetfilterMessage::new(header, inner))\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub use netlink_packet_core::constants::*;\n\npub const AF_UNSPEC: u8 = libc::AF_UNSPEC as u8;\npub const AF_UNIX: u8 = libc::AF_UNIX as u8;\npub const AF_LOCAL: u8 = libc::AF_LOCAL as u8;\npub const AF_INET: u8 = libc::AF_INET as u8;\npub const AF_AX25: u8 = libc::AF_AX25 as u8;\npub const AF_IPX: u8 = libc::AF_IPX as u8;\npub const AF_APPLETALK: u8 = libc::AF_APPLETALK as u8;\npub const AF_NETROM: u8 = libc::AF_NETROM as u8;\npub const AF_BRIDGE: u8 = libc::AF_BRIDGE as u8;\npub const AF_ATMPVC: u8 = libc::AF_ATMPVC as u8;\npub const AF_X25: u8 = libc::AF_X25 as u8;\npub const AF_INET6: u8 = libc::AF_INET6 as u8;\npub const AF_ROSE: u8 = libc::AF_ROSE as u8;\npub const AF_DECNET: u8 = libc::AF_DECnet as u8;\npub const AF_NETBEUI: u8 = libc::AF_NETBEUI as u8;\npub const AF_SECURITY: u8 = libc::AF_SECURITY as u8;\npub const AF_KEY: u8 = libc::AF_KEY as u8;\npub const AF_NETLINK: u8 = libc::AF_NETLINK as u8;\npub const AF_ROUTE: u8 = libc::AF_ROUTE as u8;\npub const AF_PACKET: u8 = libc::AF_PACKET as u8;\npub const AF_ASH: u8 = libc::AF_ASH as u8;\npub const AF_ECONET: u8 = libc::AF_ECONET as u8;\npub const AF_ATMSVC: u8 = libc::AF_ATMSVC as u8;\npub const AF_RDS: u8 = libc::AF_RDS as u8;\npub const AF_SNA: u8 = libc::AF_SNA as u8;\npub const AF_IRDA: u8 = libc::AF_IRDA as u8;\npub const AF_PPPOX: u8 = libc::AF_PPPOX as u8;\npub const AF_WANPIPE: u8 = libc::AF_WANPIPE as u8;\npub const AF_LLC: u8 = libc::AF_LLC as u8;\npub const AF_CAN: u8 = libc::AF_CAN as u8;\npub const AF_TIPC: u8 = libc::AF_TIPC as u8;\npub const AF_BLUETOOTH: u8 = libc::AF_BLUETOOTH as u8;\npub const AF_IUCV: u8 = libc::AF_IUCV as u8;\npub const AF_RXRPC: u8 = libc::AF_RXRPC as u8;\npub const AF_ISDN: u8 = libc::AF_ISDN as u8;\npub const AF_PHONET: u8 = libc::AF_PHONET as u8;\npub const AF_IEEE802154: u8 = libc::AF_IEEE802154 as u8;\npub const AF_CAIF: u8 = libc::AF_CAIF as u8;\npub const AF_ALG: u8 = libc::AF_ALG as u8;\n\npub const NFNETLINK_V0: u8 = libc::NFNETLINK_V0 as u8;\n\npub const NFNL_SUBSYS_NONE: u8 = libc::NFNL_SUBSYS_NONE as u8;\npub const NFNL_SUBSYS_CTNETLINK: u8 = libc::NFNL_SUBSYS_CTNETLINK as u8;\npub const NFNL_SUBSYS_CTNETLINK_EXP: u8 = libc::NFNL_SUBSYS_CTNETLINK_EXP as u8;\npub const NFNL_SUBSYS_QUEUE: u8 = libc::NFNL_SUBSYS_QUEUE as u8;\npub const NFNL_SUBSYS_ULOG: u8 = libc::NFNL_SUBSYS_ULOG as u8;\npub const NFNL_SUBSYS_OSF: u8 = libc::NFNL_SUBSYS_OSF as u8;\npub const NFNL_SUBSYS_IPSET: u8 = libc::NFNL_SUBSYS_IPSET as u8;\npub const NFNL_SUBSYS_ACCT: u8 = libc::NFNL_SUBSYS_ACCT as u8;\npub const NFNL_SUBSYS_CTNETLINK_TIMEOUT: u8 = libc::NFNL_SUBSYS_CTNETLINK_TIMEOUT as u8;\npub const NFNL_SUBSYS_CTHELPER: u8 = libc::NFNL_SUBSYS_CTHELPER as u8;\npub const NFNL_SUBSYS_NFTABLES: u8 = libc::NFNL_SUBSYS_NFTABLES as u8;\npub const NFNL_SUBSYS_NFT_COMPAT: u8 = libc::NFNL_SUBSYS_NFT_COMPAT as u8;\n\npub const NFULA_CFG_CMD: u16 = libc::NFULA_CFG_CMD as u16;\npub const NFULA_CFG_MODE: u16 = libc::NFULA_CFG_MODE as u16;\npub const NFULA_CFG_NLBUFSIZ: u16 = libc::NFULA_CFG_NLBUFSIZ as u16;\npub const NFULA_CFG_TIMEOUT: u16 = libc::NFULA_CFG_TIMEOUT as u16;\npub const NFULA_CFG_QTHRESH: u16 = libc::NFULA_CFG_QTHRESH as u16;\npub const NFULA_CFG_FLAGS: u16 = libc::NFULA_CFG_FLAGS as u16;\npub const NLBUFSIZ_MAX: u32 = 131072;\n\npub const NFULA_PACKET_HDR: u16 = libc::NFULA_PACKET_HDR as u16;\npub const NFULA_MARK: u16 = libc::NFULA_MARK as u16;\npub const NFULA_TIMESTAMP: u16 = libc::NFULA_TIMESTAMP as u16;\npub const NFULA_IFINDEX_INDEV: u16 = libc::NFULA_IFINDEX_INDEV as u16;\npub const NFULA_IFINDEX_OUTDEV: u16 = libc::NFULA_IFINDEX_OUTDEV as u16;\npub const NFULA_IFINDEX_PHYSINDEV: u16 = libc::NFULA_IFINDEX_PHYSINDEV as u16;\npub const NFULA_IFINDEX_PHYSOUTDEV: u16 = libc::NFULA_IFINDEX_PHYSOUTDEV as u16;\npub const NFULA_HWADDR: u16 = libc::NFULA_HWADDR as u16;\npub const NFULA_PAYLOAD: u16 = libc::NFULA_PAYLOAD as u16;\npub const NFULA_PREFIX: u16 = libc::NFULA_PREFIX as u16;\npub const NFULA_UID: u16 = libc::NFULA_UID as u16;\npub const NFULA_SEQ: u16 = libc::NFULA_SEQ as u16;\npub const NFULA_SEQ_GLOBAL: u16 = libc::NFULA_SEQ_GLOBAL as u16;\npub const NFULA_GID: u16 = libc::NFULA_GID as u16;\npub const NFULA_HWTYPE: u16 = libc::NFULA_HWTYPE as u16;\npub const NFULA_HWHEADER: u16 = libc::NFULA_HWHEADER as u16;\npub const NFULA_HWLEN: u16 = libc::NFULA_HWLEN as u16;\npub const NFULA_CT: u16 = libc::NFULA_CT as u16;\npub const NFULA_CT_INFO: u16 = libc::NFULA_CT_INFO as u16;\n\npub const NFULNL_MSG_CONFIG: u8 = libc::NFULNL_MSG_CONFIG as u8;\npub const NFULNL_MSG_PACKET: u8 = libc::NFULNL_MSG_PACKET as u8;\n"
  },
  {
    "path": "netlink-packet-netfilter/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub extern crate netlink_packet_core as nl;\npub(crate) extern crate netlink_packet_utils as utils;\n\npub use self::utils::{nla, traits, DecodeError};\n\npub(crate) mod buffer;\npub mod constants;\nmod message;\npub use message::{NetfilterHeader, NetfilterMessage, NetfilterMessageInner};\npub mod nflog;\n"
  },
  {
    "path": "netlink-packet-netfilter/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::{\n    DecodeError,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\nuse netlink_packet_utils::{buffer, nla::DefaultNla, Emitable, Parseable, ParseableParametrized};\n\nuse crate::{buffer::NetfilterBuffer, nflog::NfLogMessage};\n\npub const NETFILTER_HEADER_LEN: usize = 4;\n\nbuffer!(NetfilterHeaderBuffer(NETFILTER_HEADER_LEN) {\n    family: (u8, 0),\n    version: (u8, 1),\n    res_id: (u16, 2..4),\n});\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct NetfilterHeader {\n    pub family: u8,\n    pub version: u8,\n    pub res_id: u16,\n}\n\nimpl NetfilterHeader {\n    pub fn new(family: u8, version: u8, res_id: u16) -> Self {\n        Self {\n            family,\n            version,\n            res_id,\n        }\n    }\n}\n\nimpl Emitable for NetfilterHeader {\n    fn buffer_len(&self) -> usize {\n        NETFILTER_HEADER_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = NetfilterHeaderBuffer::new(buf);\n        buf.set_family(self.family);\n        buf.set_version(self.version);\n        buf.set_res_id(self.res_id.to_be());\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<NetfilterHeaderBuffer<T>> for NetfilterHeader {\n    fn parse(buf: &NetfilterHeaderBuffer<T>) -> Result<Self, DecodeError> {\n        buf.check_buffer_length()?;\n        Ok(NetfilterHeader {\n            family: buf.family(),\n            version: buf.version(),\n            res_id: u16::from_be(buf.res_id()),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum NetfilterMessageInner {\n    NfLog(NfLogMessage),\n    Other {\n        subsys: u8,\n        message_type: u8,\n        nlas: Vec<DefaultNla>,\n    },\n}\n\nimpl From<NfLogMessage> for NetfilterMessageInner {\n    fn from(message: NfLogMessage) -> Self {\n        Self::NfLog(message)\n    }\n}\n\nimpl Emitable for NetfilterMessageInner {\n    fn buffer_len(&self) -> usize {\n        match self {\n            NetfilterMessageInner::NfLog(message) => message.buffer_len(),\n            NetfilterMessageInner::Other { nlas, .. } => nlas.as_slice().buffer_len(),\n        }\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        match self {\n            NetfilterMessageInner::NfLog(message) => message.emit(buffer),\n            NetfilterMessageInner::Other { nlas, .. } => nlas.as_slice().emit(buffer),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct NetfilterMessage {\n    pub header: NetfilterHeader,\n    pub inner: NetfilterMessageInner,\n}\n\nimpl NetfilterMessage {\n    pub fn new<T: Into<NetfilterMessageInner>>(header: NetfilterHeader, inner: T) -> Self {\n        Self {\n            header,\n            inner: inner.into(),\n        }\n    }\n\n    pub fn subsys(&self) -> u8 {\n        match self.inner {\n            NetfilterMessageInner::NfLog(_) => NfLogMessage::SUBSYS,\n            NetfilterMessageInner::Other { subsys, .. } => subsys,\n        }\n    }\n\n    pub fn message_type(&self) -> u8 {\n        match self.inner {\n            NetfilterMessageInner::NfLog(ref message) => message.message_type(),\n            NetfilterMessageInner::Other { message_type, .. } => message_type,\n        }\n    }\n}\n\nimpl Emitable for NetfilterMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.inner.buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.inner.emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl NetlinkSerializable for NetfilterMessage {\n    fn message_type(&self) -> u16 {\n        ((self.subsys() as u16) << 8) | self.message_type() as u16\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl NetlinkDeserializable for NetfilterMessage {\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        match NetfilterBuffer::new_checked(payload) {\n            Err(e) => Err(e),\n            Ok(buffer) => match NetfilterMessage::parse_with_param(&buffer, header.message_type) {\n                Err(e) => Err(e),\n                Ok(message) => Ok(message),\n            },\n        }\n    }\n}\n\nimpl From<NetfilterMessage> for NetlinkPayload<NetfilterMessage> {\n    fn from(message: NetfilterMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    buffer::NetfilterBuffer,\n    constants::{NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, NFULNL_MSG_PACKET},\n    nflog::nlas::{config::ConfigNla, packet::PacketNla},\n    nla::DefaultNla,\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum NfLogMessage {\n    Config(Vec<ConfigNla>),\n    Packet(Vec<PacketNla>),\n    Other {\n        message_type: u8,\n        nlas: Vec<DefaultNla>,\n    },\n}\n\nimpl NfLogMessage {\n    pub const SUBSYS: u8 = NFNL_SUBSYS_ULOG;\n\n    pub fn message_type(&self) -> u8 {\n        match self {\n            NfLogMessage::Config(_) => NFULNL_MSG_CONFIG,\n            NfLogMessage::Packet(_) => NFULNL_MSG_PACKET,\n            NfLogMessage::Other { message_type, .. } => *message_type,\n        }\n    }\n}\n\nimpl Emitable for NfLogMessage {\n    fn buffer_len(&self) -> usize {\n        match self {\n            NfLogMessage::Config(nlas) => nlas.as_slice().buffer_len(),\n            NfLogMessage::Packet(nlas) => nlas.as_slice().buffer_len(),\n            NfLogMessage::Other { nlas, .. } => nlas.as_slice().buffer_len(),\n        }\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        match self {\n            NfLogMessage::Config(nlas) => nlas.as_slice().emit(buffer),\n            NfLogMessage::Packet(nlas) => nlas.as_slice().emit(buffer),\n            NfLogMessage::Other { nlas, .. } => nlas.as_slice().emit(buffer),\n        };\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NetfilterBuffer<&'a T>, u8>\n    for NfLogMessage\n{\n    fn parse_with_param(\n        buf: &NetfilterBuffer<&'a T>,\n        message_type: u8,\n    ) -> Result<Self, DecodeError> {\n        Ok(match message_type {\n            NFULNL_MSG_CONFIG => {\n                let nlas = buf.parse_all_nlas(|nla_buf| ConfigNla::parse(&nla_buf))?;\n                NfLogMessage::Config(nlas)\n            }\n            NFULNL_MSG_PACKET => {\n                let nlas = buf.parse_all_nlas(|nla_buf| PacketNla::parse(&nla_buf))?;\n                NfLogMessage::Packet(nlas)\n            }\n            _ => NfLogMessage::Other {\n                message_type,\n                nlas: buf.default_nlas()?,\n            },\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod message;\npub use message::NfLogMessage;\npub mod nlas;\n\nuse crate::{\n    constants::NFNETLINK_V0,\n    nflog::nlas::config::ConfigNla,\n    nl::{NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_REQUEST},\n    NetfilterHeader,\n    NetfilterMessage,\n};\n\npub fn config_request(\n    family: u8,\n    group_num: u16,\n    nlas: Vec<ConfigNla>,\n) -> NetlinkMessage<NetfilterMessage> {\n    let mut message = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_ACK,\n            ..Default::default()\n        },\n        payload: NetlinkPayload::from(NetfilterMessage::new(\n            NetfilterHeader::new(family, NFNETLINK_V0, group_num),\n            NfLogMessage::Config(nlas),\n        )),\n    };\n    message.finalize();\n    message\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/config_cmd.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_utils::nla::Nla;\n\nconst NFULA_CFG_CMD: u16 = libc::NFULA_CFG_CMD as u16;\nconst NFULNL_CFG_CMD_NONE: u8 = libc::NFULNL_CFG_CMD_NONE as u8;\nconst NFULNL_CFG_CMD_BIND: u8 = libc::NFULNL_CFG_CMD_BIND as u8;\nconst NFULNL_CFG_CMD_UNBIND: u8 = libc::NFULNL_CFG_CMD_UNBIND as u8;\nconst NFULNL_CFG_CMD_PF_BIND: u8 = libc::NFULNL_CFG_CMD_PF_BIND as u8;\nconst NFULNL_CFG_CMD_PF_UNBIND: u8 = libc::NFULNL_CFG_CMD_PF_UNBIND as u8;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum ConfigCmd {\n    None,\n    Bind,\n    Unbind,\n    PfBind,\n    PfUnbind,\n    Other(u8),\n}\n\nimpl From<ConfigCmd> for u8 {\n    fn from(cmd: ConfigCmd) -> Self {\n        match cmd {\n            ConfigCmd::None => NFULNL_CFG_CMD_NONE,\n            ConfigCmd::Bind => NFULNL_CFG_CMD_BIND,\n            ConfigCmd::Unbind => NFULNL_CFG_CMD_UNBIND,\n            ConfigCmd::PfBind => NFULNL_CFG_CMD_PF_BIND,\n            ConfigCmd::PfUnbind => NFULNL_CFG_CMD_PF_UNBIND,\n            ConfigCmd::Other(cmd) => cmd,\n        }\n    }\n}\n\nimpl From<u8> for ConfigCmd {\n    fn from(cmd: u8) -> Self {\n        match cmd {\n            NFULNL_CFG_CMD_NONE => ConfigCmd::None,\n            NFULNL_CFG_CMD_BIND => ConfigCmd::Bind,\n            NFULNL_CFG_CMD_UNBIND => ConfigCmd::Unbind,\n            NFULNL_CFG_CMD_PF_BIND => ConfigCmd::PfBind,\n            NFULNL_CFG_CMD_PF_UNBIND => ConfigCmd::PfUnbind,\n            cmd => ConfigCmd::Other(cmd),\n        }\n    }\n}\n\nimpl Nla for ConfigCmd {\n    fn value_len(&self) -> usize {\n        1\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_CFG_CMD\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        buffer[0] = (*self).into();\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/config_flags.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::mem::size_of;\n\nuse bitflags::bitflags;\nuse byteorder::{BigEndian, ByteOrder};\nuse netlink_packet_utils::nla::Nla;\n\nconst NFULA_CFG_FLAGS: u16 = libc::NFULA_CFG_FLAGS as u16;\n\nbitflags! {\n    pub struct ConfigFlags: u16 {\n        const SEQ = libc:: NFULNL_CFG_F_SEQ as u16;\n        const SEQ_GLOBAL = libc:: NFULNL_CFG_F_SEQ_GLOBAL as u16;\n        const CONNTRACK = libc:: NFULNL_CFG_F_CONNTRACK as u16;\n    }\n}\n\n// see https://github.com/bitflags/bitflags/issues/263\nimpl ConfigFlags {\n    pub fn from_bits_preserve(bits: u16) -> Self {\n        ConfigFlags { bits }\n    }\n}\n\nimpl Nla for ConfigFlags {\n    fn value_len(&self) -> usize {\n        size_of::<Self>()\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_CFG_FLAGS\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        BigEndian::write_u16(buffer, self.bits);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/config_mode.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_utils::{buffer, errors::DecodeError, nla::Nla, Parseable};\n\nconst NFULA_CFG_MODE: u16 = libc::NFULA_CFG_MODE as u16;\nconst NFULNL_COPY_NONE: u8 = libc::NFULNL_COPY_NONE as u8;\nconst NFULNL_COPY_META: u8 = libc::NFULNL_COPY_META as u8;\nconst NFULNL_COPY_PACKET: u8 = libc::NFULNL_COPY_PACKET as u8;\n\nconst CONFIG_MODE_LEN: usize = 6;\n\nbuffer!(ConfigModeBuffer(CONFIG_MODE_LEN) {\n    copy_range: (u32, 0..4),\n    copy_mode: (u8, 4),\n});\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum CopyMode {\n    None,\n    Meta,\n    Packet,\n    Other(u8),\n}\n\nimpl From<CopyMode> for u8 {\n    fn from(cmd: CopyMode) -> Self {\n        match cmd {\n            CopyMode::None => NFULNL_COPY_NONE,\n            CopyMode::Meta => NFULNL_COPY_META,\n            CopyMode::Packet => NFULNL_COPY_PACKET,\n            CopyMode::Other(cmd) => cmd,\n        }\n    }\n}\n\nimpl From<u8> for CopyMode {\n    fn from(cmd: u8) -> Self {\n        match cmd {\n            NFULNL_COPY_NONE => CopyMode::None,\n            NFULNL_COPY_META => CopyMode::Meta,\n            NFULNL_COPY_PACKET => CopyMode::Packet,\n            cmd => CopyMode::Other(cmd),\n        }\n    }\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct ConfigMode {\n    copy_range: u32,\n    copy_mode: CopyMode,\n}\n\nimpl ConfigMode {\n    pub const NONE: Self = Self {\n        copy_range: 0,\n        copy_mode: CopyMode::None,\n    };\n\n    pub const META: Self = Self {\n        copy_range: 0,\n        copy_mode: CopyMode::Meta,\n    };\n\n    pub const PACKET_MAX: Self = Self {\n        copy_range: 0,\n        copy_mode: CopyMode::Packet,\n    };\n\n    pub fn new(copy_range: u32, copy_mode: CopyMode) -> Self {\n        Self {\n            copy_range,\n            copy_mode,\n        }\n    }\n\n    pub fn new_packet(copy_range: u32) -> Self {\n        Self::new(copy_range, CopyMode::Packet)\n    }\n}\n\nimpl Nla for ConfigMode {\n    fn value_len(&self) -> usize {\n        CONFIG_MODE_LEN\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_CFG_MODE\n    }\n\n    fn emit_value(&self, buf: &mut [u8]) {\n        let mut buf = ConfigModeBuffer::new(buf);\n        buf.set_copy_range(self.copy_range.to_be());\n        buf.set_copy_mode(self.copy_mode.into())\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<ConfigModeBuffer<T>> for ConfigMode {\n    fn parse(buf: &ConfigModeBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(ConfigMode {\n            copy_range: u32::from_be(buf.copy_range()),\n            copy_mode: buf.copy_mode().into(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\nmod config_cmd;\nmod config_flags;\nmod config_mode;\nmod nla;\nmod timeout;\n\npub use config_cmd::ConfigCmd;\npub use config_flags::ConfigFlags;\npub use config_mode::{ConfigMode, CopyMode};\npub use nla::ConfigNla;\npub use timeout::Timeout;\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/nla.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{BigEndian, ByteOrder};\nuse derive_more::{From, IsVariant};\n\nuse crate::{\n    constants::{\n        NFULA_CFG_CMD,\n        NFULA_CFG_FLAGS,\n        NFULA_CFG_MODE,\n        NFULA_CFG_NLBUFSIZ,\n        NFULA_CFG_QTHRESH,\n        NFULA_CFG_TIMEOUT,\n    },\n    nflog::nlas::config::{\n        config_mode::ConfigModeBuffer,\n        ConfigCmd,\n        ConfigFlags,\n        ConfigMode,\n        Timeout,\n    },\n    nl::DecodeError,\n    nla::{DefaultNla, Nla, NlaBuffer},\n    traits::Parseable,\n    utils::parsers::{parse_u16_be, parse_u32_be, parse_u8},\n};\n\n#[derive(Clone, Debug, PartialEq, Eq, From, IsVariant)]\npub enum ConfigNla {\n    Cmd(ConfigCmd),\n    Mode(ConfigMode),\n    #[from(ignore)]\n    NlBufSiz(u32),\n    Timeout(Timeout),\n    #[from(ignore)]\n    QThresh(u32),\n    Flags(ConfigFlags),\n    Other(DefaultNla),\n}\n\nimpl Nla for ConfigNla {\n    fn value_len(&self) -> usize {\n        match self {\n            ConfigNla::Cmd(attr) => attr.value_len(),\n            ConfigNla::Mode(attr) => attr.value_len(),\n            ConfigNla::NlBufSiz(_) => 4,\n            ConfigNla::Timeout(attr) => attr.value_len(),\n            ConfigNla::QThresh(_) => 4,\n            ConfigNla::Flags(attr) => attr.value_len(),\n            ConfigNla::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            ConfigNla::Cmd(attr) => attr.kind(),\n            ConfigNla::Mode(attr) => attr.kind(),\n            ConfigNla::NlBufSiz(_) => NFULA_CFG_NLBUFSIZ,\n            ConfigNla::Timeout(attr) => attr.kind(),\n            ConfigNla::QThresh(_) => NFULA_CFG_QTHRESH,\n            ConfigNla::Flags(attr) => attr.kind(),\n            ConfigNla::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            ConfigNla::Cmd(attr) => attr.emit_value(buffer),\n            ConfigNla::Mode(attr) => attr.emit_value(buffer),\n            ConfigNla::NlBufSiz(buf_siz) => BigEndian::write_u32(buffer, *buf_siz),\n            ConfigNla::Timeout(attr) => attr.emit_value(buffer),\n            ConfigNla::QThresh(q_thresh) => BigEndian::write_u32(buffer, *q_thresh),\n            ConfigNla::Flags(attr) => attr.emit_value(buffer),\n            ConfigNla::Other(attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>> for ConfigNla {\n    fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {\n        let kind = buf.kind();\n        let payload = buf.value();\n        let nla = match kind {\n            NFULA_CFG_CMD => {\n                ConfigCmd::from(parse_u8(payload).context(\"invalid NFULA_CFG_CMD value\")?).into()\n            }\n            NFULA_CFG_MODE => {\n                let buf = ConfigModeBuffer::new_checked(payload)?;\n                ConfigMode::parse(&buf)?.into()\n            }\n            NFULA_CFG_NLBUFSIZ => ConfigNla::NlBufSiz(\n                parse_u32_be(payload).context(\"invalid NFULA_CFG_NLBUFSIZ value\")?,\n            ),\n            NFULA_CFG_TIMEOUT => {\n                Timeout::new(parse_u32_be(payload).context(\"invalid NFULA_CFG_TIMEOUT value\")?)\n                    .into()\n            }\n            NFULA_CFG_QTHRESH => ConfigNla::QThresh(\n                parse_u32_be(payload).context(\"invalid NFULA_CFG_QTHRESH value\")?,\n            ),\n            NFULA_CFG_FLAGS => ConfigFlags::from_bits_preserve(\n                parse_u16_be(payload).context(\"invalid NFULA_CFG_FLAGS value\")?,\n            )\n            .into(),\n            _ => ConfigNla::Other(DefaultNla::parse(buf)?),\n        };\n        Ok(nla)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/config/timeout.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{convert::TryInto, mem::size_of, time::Duration};\n\nuse byteorder::{BigEndian, ByteOrder};\nuse netlink_packet_utils::nla::Nla;\n\nconst NFULA_CFG_TIMEOUT: u16 = libc::NFULA_CFG_TIMEOUT as u16;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct Timeout {\n    hundredth: u32,\n}\n\nimpl Timeout {\n    pub fn new(hundredth: u32) -> Self {\n        Self { hundredth }\n    }\n}\n\nimpl From<Duration> for Timeout {\n    fn from(duration: Duration) -> Self {\n        let hundredth = (duration.as_millis() / 10).try_into().unwrap_or(u32::MAX);\n        Self { hundredth }\n    }\n}\n\nimpl Nla for Timeout {\n    fn value_len(&self) -> usize {\n        size_of::<u32>()\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_CFG_TIMEOUT\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        BigEndian::write_u32(buffer, self.hundredth);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod config;\npub mod packet;\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/packet/hw_addr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{constants::NFULA_HWADDR, nla::Nla, traits::Parseable, utils::buffer, DecodeError};\n\nconst HW_ADDR_LEN: usize = 12;\n\nbuffer!(HwAddrBuffer(HW_ADDR_LEN) {\n    hw_addr_len: (u16, 0..2),\n    hw_addr_0: (u8, 4),\n    hw_addr_1: (u8, 5),\n    hw_addr_2: (u8, 6),\n    hw_addr_3: (u8, 7),\n    hw_addr_4: (u8, 8),\n    hw_addr_5: (u8, 9),\n    hw_addr_6: (u8, 10),\n    hw_addr_7: (u8, 11),\n});\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct HwAddr {\n    len: u16,\n    address: [u8; 8],\n}\n\nimpl Nla for HwAddr {\n    fn value_len(&self) -> usize {\n        HW_ADDR_LEN\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_HWADDR\n    }\n\n    fn emit_value(&self, buf: &mut [u8]) {\n        let mut buf = HwAddrBuffer::new(buf);\n        buf.set_hw_addr_len(self.len.to_be());\n        buf.set_hw_addr_0(self.address[0]);\n        buf.set_hw_addr_1(self.address[1]);\n        buf.set_hw_addr_2(self.address[2]);\n        buf.set_hw_addr_3(self.address[3]);\n        buf.set_hw_addr_4(self.address[4]);\n        buf.set_hw_addr_5(self.address[5]);\n        buf.set_hw_addr_6(self.address[6]);\n        buf.set_hw_addr_7(self.address[7]);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<HwAddrBuffer<T>> for HwAddr {\n    fn parse(buf: &HwAddrBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(HwAddr {\n            len: u16::from_be(buf.hw_addr_len()),\n            address: [\n                buf.hw_addr_0(),\n                buf.hw_addr_1(),\n                buf.hw_addr_2(),\n                buf.hw_addr_3(),\n                buf.hw_addr_4(),\n                buf.hw_addr_5(),\n                buf.hw_addr_6(),\n                buf.hw_addr_7(),\n            ],\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/packet/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod hw_addr;\nmod nla;\nmod packet_hdr;\nmod timestamp;\n\npub use hw_addr::{HwAddr, HwAddrBuffer};\npub use nla::PacketNla;\npub use packet_hdr::{PacketHdr, PacketHdrBuffer};\npub use timestamp::{TimeStamp, TimeStampBuffer};\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/packet/nla.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::ffi::{CStr, CString};\n\nuse anyhow::Context;\nuse byteorder::{BigEndian, ByteOrder};\nuse derive_more::{From, IsVariant};\n\nuse crate::{\n    constants::{\n        NFULA_GID,\n        NFULA_HWADDR,\n        NFULA_HWHEADER,\n        NFULA_HWLEN,\n        NFULA_HWTYPE,\n        NFULA_IFINDEX_INDEV,\n        NFULA_IFINDEX_OUTDEV,\n        NFULA_IFINDEX_PHYSINDEV,\n        NFULA_IFINDEX_PHYSOUTDEV,\n        NFULA_MARK,\n        NFULA_PACKET_HDR,\n        NFULA_PAYLOAD,\n        NFULA_PREFIX,\n        NFULA_SEQ,\n        NFULA_SEQ_GLOBAL,\n        NFULA_TIMESTAMP,\n        NFULA_UID,\n    },\n    nflog::nlas::packet::{\n        hw_addr::{HwAddr, HwAddrBuffer},\n        packet_hdr::{PacketHdr, PacketHdrBuffer},\n        timestamp::{TimeStamp, TimeStampBuffer},\n    },\n    nla::{DefaultNla, Nla, NlaBuffer},\n    traits::Parseable,\n    utils::parsers::{parse_u16_be, parse_u32_be},\n    DecodeError,\n};\n\n#[derive(Clone, Debug, PartialEq, Eq, From, IsVariant)]\npub enum PacketNla {\n    #[from]\n    PacketHdr(PacketHdr),\n    Mark(u32),\n    #[from]\n    Timestamp(TimeStamp),\n    IfIndexInDev(u32),\n    IfIndexOutDev(u32),\n    IfIndexPhysInDev(u32),\n    IfIndexPhysOutDev(u32),\n    #[from]\n    HwAddr(HwAddr),\n    Payload(Vec<u8>),\n    Prefix(CString),\n    Uid(u32),\n    Seq(u32),\n    SeqGlobal(u32),\n    Gid(u32),\n    HwType(u16),\n    HwHeader(Vec<u8>),\n    HwHeaderLen(u16),\n    #[from]\n    Other(DefaultNla),\n}\n\nimpl Nla for PacketNla {\n    fn value_len(&self) -> usize {\n        match self {\n            PacketNla::PacketHdr(attr) => attr.value_len(),\n            PacketNla::Mark(_) => 4,\n            PacketNla::Timestamp(attr) => attr.value_len(),\n            PacketNla::IfIndexInDev(_) => 4,\n            PacketNla::IfIndexOutDev(_) => 4,\n            PacketNla::IfIndexPhysInDev(_) => 4,\n            PacketNla::IfIndexPhysOutDev(_) => 4,\n            PacketNla::HwAddr(attr) => attr.value_len(),\n            PacketNla::Payload(vec) => vec.len(),\n            PacketNla::Prefix(cstring) => cstring.as_bytes_with_nul().len(),\n            PacketNla::Uid(_) => 4,\n            PacketNla::Seq(_) => 4,\n            PacketNla::SeqGlobal(_) => 4,\n            PacketNla::Gid(_) => 4,\n            PacketNla::HwType(_) => 2,\n            PacketNla::HwHeader(vec) => vec.len(),\n            PacketNla::HwHeaderLen(_) => 2,\n            PacketNla::Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            PacketNla::PacketHdr(attr) => attr.kind(),\n            PacketNla::Mark(_) => NFULA_MARK,\n            PacketNla::Timestamp(attr) => attr.kind(),\n            PacketNla::IfIndexInDev(_) => NFULA_IFINDEX_INDEV,\n            PacketNla::IfIndexOutDev(_) => NFULA_IFINDEX_OUTDEV,\n            PacketNla::IfIndexPhysInDev(_) => NFULA_IFINDEX_PHYSINDEV,\n            PacketNla::IfIndexPhysOutDev(_) => NFULA_IFINDEX_PHYSOUTDEV,\n            PacketNla::HwAddr(attr) => attr.kind(),\n            PacketNla::Payload(_) => NFULA_PAYLOAD,\n            PacketNla::Prefix(_) => NFULA_PREFIX,\n            PacketNla::Uid(_) => NFULA_UID,\n            PacketNla::Seq(_) => NFULA_SEQ,\n            PacketNla::SeqGlobal(_) => NFULA_SEQ_GLOBAL,\n            PacketNla::Gid(_) => NFULA_GID,\n            PacketNla::HwType(_) => NFULA_HWTYPE,\n            PacketNla::HwHeader(_) => NFULA_HWHEADER,\n            PacketNla::HwHeaderLen(_) => NFULA_HWLEN,\n            PacketNla::Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            PacketNla::PacketHdr(attr) => attr.emit_value(buffer),\n            PacketNla::Mark(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::Timestamp(attr) => attr.emit_value(buffer),\n            PacketNla::IfIndexInDev(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::IfIndexOutDev(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::IfIndexPhysInDev(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::IfIndexPhysOutDev(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::HwAddr(attr) => attr.emit_value(buffer),\n            PacketNla::Payload(vec) => buffer.copy_from_slice(vec),\n            PacketNla::Prefix(cstring) => buffer.copy_from_slice(cstring.as_bytes_with_nul()),\n            PacketNla::Uid(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::Seq(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::SeqGlobal(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::Gid(value) => BigEndian::write_u32(buffer, *value),\n            PacketNla::HwType(value) => BigEndian::write_u16(buffer, *value),\n            PacketNla::HwHeader(vec) => buffer.copy_from_slice(vec),\n            PacketNla::HwHeaderLen(value) => BigEndian::write_u16(buffer, *value),\n            PacketNla::Other(attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>> for PacketNla {\n    fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {\n        let kind = buf.kind();\n        let payload = buf.value();\n        let nla = match kind {\n            NFULA_PACKET_HDR => {\n                let buf = PacketHdrBuffer::new_checked(payload)\n                    .context(\"invalid NFULA_PACKET_HDR value\")?;\n                PacketHdr::parse(&buf)?.into()\n            }\n\n            NFULA_MARK => {\n                PacketNla::Mark(parse_u32_be(payload).context(\"invalid NFULA_MARK value\")?)\n            }\n            NFULA_TIMESTAMP => {\n                let buf = TimeStampBuffer::new_checked(&payload)\n                    .context(\"invalid NFULA_TIMESTAMP value\")?;\n                PacketNla::Timestamp(TimeStamp::parse(&buf)?)\n            }\n            NFULA_IFINDEX_INDEV => PacketNla::IfIndexInDev(\n                parse_u32_be(payload).context(\"invalid NFULA_IFINDEX_INDEV value\")?,\n            ),\n            NFULA_IFINDEX_OUTDEV => PacketNla::IfIndexOutDev(\n                parse_u32_be(payload).context(\"invalid NFULA_IFINDEX_OUTDEV value\")?,\n            ),\n            NFULA_IFINDEX_PHYSINDEV => PacketNla::IfIndexPhysInDev(\n                parse_u32_be(payload).context(\"invalid NFULA_IFINDEX_PHYSINDEV value\")?,\n            ),\n            NFULA_IFINDEX_PHYSOUTDEV => PacketNla::IfIndexPhysOutDev(\n                parse_u32_be(payload).context(\"invalid NFULA_IFINDEX_PHYSOUTDEV value\")?,\n            ),\n            NFULA_HWADDR => {\n                let buf =\n                    HwAddrBuffer::new_checked(payload).context(\"invalid NFULA_HWADDR value\")?;\n                PacketNla::HwAddr(HwAddr::parse(&buf)?)\n            }\n            NFULA_PAYLOAD => PacketNla::Payload(payload.to_vec()),\n            NFULA_PREFIX => PacketNla::Prefix(\n                CStr::from_bytes_with_nul(payload)\n                    .context(\"invalid NFULA_PREFIX value\")?\n                    .to_owned(),\n            ),\n            NFULA_UID => PacketNla::Uid(parse_u32_be(payload).context(\"invalid NFULA_UID value\")?),\n            NFULA_SEQ => PacketNla::Seq(parse_u32_be(payload).context(\"invalid NFULA_SEQ value\")?),\n            NFULA_SEQ_GLOBAL => PacketNla::SeqGlobal(\n                parse_u32_be(payload).context(\"invalid NFULA_SEQ_GLOBAL value\")?,\n            ),\n            NFULA_GID => PacketNla::Gid(parse_u32_be(payload).context(\"invalid NFULA_GID value\")?),\n            NFULA_HWTYPE => {\n                PacketNla::HwType(parse_u16_be(payload).context(\"invalid NFULA_HWTYPE value\")?)\n            }\n            NFULA_HWHEADER => PacketNla::HwHeader(payload.to_vec()),\n            NFULA_HWLEN => {\n                PacketNla::HwHeaderLen(parse_u16_be(payload).context(\"invalid NFULA_HWLEN value\")?)\n            }\n\n            _ => PacketNla::Other(DefaultNla::parse(buf)?),\n        };\n        Ok(nla)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/packet/packet_hdr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_utils::{buffer, nla::Nla, Parseable};\n\nconst PACKET_HDR_LEN: usize = 4;\npub const NFULA_PACKET_HDR: u16 = libc::NFULA_PACKET_HDR as u16;\n\nbuffer!(PacketHdrBuffer(PACKET_HDR_LEN) {\n    hw_protocol: (u16, 0..2),\n    hook: (u8, 2),\n    pad: (u8, 3),\n});\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct PacketHdr {\n    hw_protocol: u16,\n    hook: u8,\n}\n\nimpl Nla for PacketHdr {\n    fn value_len(&self) -> usize {\n        PACKET_HDR_LEN\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_PACKET_HDR\n    }\n\n    fn emit_value(&self, buf: &mut [u8]) {\n        let mut buf = PacketHdrBuffer::new(buf);\n        buf.set_hw_protocol(self.hw_protocol.to_be());\n        buf.set_hook(self.hook)\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<PacketHdrBuffer<T>> for PacketHdr {\n    fn parse(buf: &PacketHdrBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(PacketHdr {\n            hw_protocol: u16::from_be(buf.hw_protocol()),\n            hook: buf.hook(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-netfilter/src/nflog/nlas/packet/timestamp.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::DecodeError;\nuse netlink_packet_utils::{buffer, nla::Nla, Parseable};\n\nuse crate::constants::NFULA_TIMESTAMP;\n\nconst TIMESTAMP_LEN: usize = 16;\n\nbuffer!(TimeStampBuffer(TIMESTAMP_LEN) {\n    sec: (u64, 0..8),\n    usec: (u64, 8..16),\n});\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct TimeStamp {\n    sec: u64,\n    usec: u64,\n}\n\nimpl Nla for TimeStamp {\n    fn value_len(&self) -> usize {\n        TIMESTAMP_LEN\n    }\n\n    fn kind(&self) -> u16 {\n        NFULA_TIMESTAMP\n    }\n\n    fn emit_value(&self, buf: &mut [u8]) {\n        let mut buf = TimeStampBuffer::new(buf);\n        buf.set_sec(self.sec.to_be());\n        buf.set_usec(self.usec.to_be())\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<TimeStampBuffer<T>> for TimeStamp {\n    fn parse(buf: &TimeStampBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(TimeStamp {\n            sec: u64::from_be(buf.sec()),\n            usec: u64::from_be(buf.usec()),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/Cargo.toml",
    "content": "[package]\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-packet-route\"\nversion = \"0.13.0\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink packet types\"\n\n[features]\nrich_nlas = []\n\n[dependencies]\nanyhow = \"1.0.31\"\nbyteorder = \"1.3.2\"\nlibc = \"0.2.66\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nbitflags = \"1.2.1\"\n\n[[example]]\nname = \"dump_packet_links\"\n\n[dev-dependencies]\ncriterion = \"0.3.0\"\npcap-file = \"1.1.1\"\nlazy_static = \"1.4.0\"\nnetlink-sys = { version = \"0.8.3\", path = \"../netlink-sys\" }\npretty_assertions = \"0.7.2\"\n\n[[bench]]\nname = \"link_message\"\nharness = false\n\n[[bench]]\nname = \"rtnetlink_dump\"\nharness = false\n"
  },
  {
    "path": "netlink-packet-route/benches/link_message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse criterion::{criterion_group, criterion_main, Criterion};\n\nuse netlink_packet_route::{\n    nlas::link::Nla,\n    traits::{Parseable, ParseableParametrized},\n    LinkHeader,\n    LinkMessage,\n    LinkMessageBuffer,\n};\n\nconst LINKMSG1: [u8; 96] = [\n    0x00, // address family\n    0x00, // reserved\n    0x04, 0x03, // link layer type 772 = loopback\n    0x01, 0x00, 0x00, 0x00, // interface index = 1\n    // Note: in the wireshark capture, the thrid byte is 0x01\n    // but that does not correpond to any of the IFF_ flags...\n    0x49, 0x00, 0x00, 0x00, // device flags: UP, LOOPBACK, RUNNING, LOWERUP\n    0x00, 0x00, 0x00, 0x00, // reserved 2 (aka device change flag)\n    // nlas\n    0x07, 0x00, 0x03, 0x00, 0x6c, 0x6f, 0x00, // device name L=7,T=3,V=lo\n    0x00, // padding\n    0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00, // TxQueue length L=8,T=13,V=1000\n    0x05, 0x00, 0x10, 0x00, 0x00, // OperState L=5,T=16,V=0 (unknown)\n    0x00, 0x00, 0x00, // padding\n    0x05, 0x00, 0x11, 0x00, 0x00, // Link mode L=5,T=17,V=0\n    0x00, 0x00, 0x00, // padding\n    0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, // MTU L=8,T=4,V=65536\n    0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, // Group L=8,T=27,V=9\n    0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, // Promiscuity L=8,T=30,V=0\n    0x08, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, // Number of Tx Queues L=8,T=31,V=1\n    0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00,\n    0x00, // Maximum GSO segment count L=8,T=40,V=65536\n    0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, // Maximum GSO size L=8,T=41,V=65536\n];\n\nfn b1(c: &mut Criterion) {\n    c.bench_function(\"parse LinkMessage header\", |b| {\n        b.iter(|| {\n            LinkHeader::parse(&LinkMessageBuffer::new(&LINKMSG1[..])).unwrap();\n        })\n    });\n\n    c.bench_function(\"parse LinkMessage nlas\", |b| {\n        b.iter(|| {\n            Vec::<Nla>::parse_with_param(&LinkMessageBuffer::new(&&LINKMSG1[..]), 0_u8).unwrap();\n        })\n    });\n\n    c.bench_function(\"parse LinkMessage\", |b| {\n        b.iter(|| {\n            LinkMessage::parse(&LinkMessageBuffer::new(&&LINKMSG1[..])).unwrap();\n        })\n    });\n}\n\ncriterion_group!(benches, b1);\ncriterion_main!(benches);\n"
  },
  {
    "path": "netlink-packet-route/benches/rtnetlink_dump.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::fs::File;\n\nuse criterion::{criterion_group, criterion_main, Criterion};\nuse pcap_file::PcapReader;\n\nuse netlink_packet_route::{NetlinkMessage, RtnlMessage};\n\nfn bench(c: &mut Criterion) {\n    let pcap_reader = PcapReader::new(File::open(\"data/rtnetlink.pcap\").unwrap()).unwrap();\n    let packets: Vec<Vec<u8>> = pcap_reader\n        .map(|pkt| pkt.unwrap().data.into_owned().to_vec())\n        .collect();\n\n    c.bench_function(\"parse\", move |b| {\n        b.iter(|| {\n            for (i, buf) in packets.iter().enumerate() {\n                NetlinkMessage::<RtnlMessage>::deserialize(&buf[16..])\n                    .unwrap_or_else(|_| panic!(\"message {} failed\", i));\n            }\n        })\n    });\n}\n\ncriterion_group!(benches, bench);\ncriterion_main!(benches);\n"
  },
  {
    "path": "netlink-packet-route/data/README.md",
    "content": "The rtnetlink dump was generated with:\n\n```\nsudo ip link add name qemu-br1 type bridge\nsudo ip link set qemu-br1 up\nsudo ip address add 192.168.10.1/24 dev qemu-br1\n\ndocker run -d -it busybox /bin/sh\n\nsudo ip netns add blue\nsudo ip link add veth0 type veth peer name veth1\nsudo ip netns list\nsudo ip link set veth1 netns blue\nsudo ip -6 link add vxlan100 type vxlan id 100 dstport 4789 local 2001:db8:1::1 group ff05::100 dev veth0 ttl 5\nsudo brctl addbr br100\nsudo brctl addif br100 vxlan100\nsudo ip link show\nsudo ip address show\nsudo ip neigh show\nsudo ip route show\n\ntc qdisc show\n```\n"
  },
  {
    "path": "netlink-packet-route/examples/dump_neighbours.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{convert::TryFrom, net::IpAddr, string::ToString};\n\nuse netlink_packet_route::{\n    constants::*,\n    nlas::neighbour::Nla,\n    NeighbourMessage,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    RtnlMessage,\n};\nuse netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut req = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_DUMP | NLM_F_REQUEST,\n            ..Default::default()\n        },\n        payload: NetlinkPayload::from(RtnlMessage::GetNeighbour(NeighbourMessage::default())),\n    };\n    // IMPORTANT: call `finalize()` to automatically set the\n    // `message_type` and `length` fields to the appropriate values in\n    // the netlink header.\n    req.finalize();\n\n    let mut buf = vec![0; req.header.length as usize];\n    req.serialize(&mut buf[..]);\n\n    println!(\">>> {:?}\", req);\n    socket.send(&buf[..], 0).unwrap();\n\n    let mut receive_buffer = vec![0; 4096];\n    let mut offset = 0;\n\n    'outer: loop {\n        let size = socket.recv(&mut &mut receive_buffer[..], 0).unwrap();\n\n        loop {\n            let bytes = &receive_buffer[offset..];\n            // Parse the message\n            let msg: NetlinkMessage<RtnlMessage> = NetlinkMessage::deserialize(bytes).unwrap();\n\n            match msg.payload {\n                NetlinkPayload::Done => break 'outer,\n                NetlinkPayload::InnerMessage(RtnlMessage::NewNeighbour(entry)) => {\n                    let address_family = entry.header.family as u16;\n                    if address_family == AF_INET || address_family == AF_INET6 {\n                        print_entry(entry);\n                    }\n                }\n                NetlinkPayload::Error(err) => {\n                    eprintln!(\"Received a netlink error message: {:?}\", err);\n                    return;\n                }\n                _ => {}\n            }\n\n            offset += msg.header.length as usize;\n            if offset == size || msg.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n\nfn format_ip(buf: &[u8]) -> String {\n    if let Ok(bytes) = <&[u8; 4]>::try_from(buf) {\n        IpAddr::from(*bytes).to_string()\n    } else if let Ok(bytes) = <&[u8; 16]>::try_from(buf) {\n        IpAddr::from(*bytes).to_string()\n    } else {\n        panic!(\"Invalid IP Address\");\n    }\n}\n\nfn format_mac(buf: &[u8]) -> String {\n    assert_eq!(buf.len(), 6);\n    format!(\n        \"{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}\",\n        buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]\n    )\n}\n\nfn state_str(value: u16) -> &'static str {\n    match value {\n        NUD_INCOMPLETE => \"INCOMPLETE\",\n        NUD_REACHABLE => \"REACHABLE\",\n        NUD_STALE => \"STALE\",\n        NUD_DELAY => \"DELAY\",\n        NUD_PROBE => \"PROBE\",\n        NUD_FAILED => \"FAILED\",\n        NUD_NOARP => \"NOARP\",\n        NUD_PERMANENT => \"PERMANENT\",\n        NUD_NONE => \"NONE\",\n        _ => \"UNKNOWN\",\n    }\n}\n\nfn print_entry(entry: NeighbourMessage) {\n    let state = state_str(entry.header.state);\n    let dest = entry\n        .nlas\n        .iter()\n        .find_map(|nla| {\n            if let Nla::Destination(addr) = nla {\n                Some(format_ip(&addr[..]))\n            } else {\n                None\n            }\n        })\n        .unwrap();\n    let lladdr = entry\n        .nlas\n        .iter()\n        .find_map(|nla| {\n            if let Nla::LinkLocalAddress(addr) = nla {\n                Some(format_mac(&addr[..]))\n            } else {\n                None\n            }\n        })\n        .unwrap();\n\n    println!(\"{:<30} {:<20} ({})\", dest, lladdr, state);\n}\n"
  },
  {
    "path": "netlink-packet-route/examples/dump_packet_link_bridge_vlan.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_route::{\n    nlas::link::Nla,\n    LinkMessage,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    RtnlMessage,\n    AF_BRIDGE,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n    RTEXT_FILTER_BRVLAN_COMPRESSED,\n};\nuse netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut message = LinkMessage::default();\n    message.header.interface_family = AF_BRIDGE as u8;\n    message\n        .nlas\n        .push(Nla::ExtMask(RTEXT_FILTER_BRVLAN_COMPRESSED));\n    let mut packet = NetlinkMessage {\n        header: NetlinkHeader::default(),\n        payload: NetlinkPayload::from(RtnlMessage::GetLink(message)),\n    };\n    packet.header.flags = NLM_F_DUMP | NLM_F_REQUEST;\n    packet.header.sequence_number = 1;\n    packet.finalize();\n\n    let mut buf = vec![0; packet.header.length as usize];\n\n    // Before calling serialize, it is important to check that the buffer in which we're emitting is big\n    // enough for the packet, other `serialize()` panics.\n    assert!(buf.len() == packet.buffer_len());\n    packet.serialize(&mut buf[..]);\n\n    println!(\">>> {:?}\", packet);\n    socket.send(&buf[..], 0).unwrap();\n\n    let mut receive_buffer = vec![0; 4096];\n    let mut offset = 0;\n\n    // we set the NLM_F_DUMP flag so we expect a multipart rx_packet in response.\n    loop {\n        let size = socket.recv(&mut &mut receive_buffer[..], 0).unwrap();\n\n        loop {\n            let bytes = &receive_buffer[offset..];\n            // Note that we're parsing a NetlinkBuffer<&&[u8]>, NOT a NetlinkBuffer<&[u8]> here.\n            // This is important because Parseable<NetlinkMessage> is only implemented for\n            // NetlinkBuffer<&'a T>, where T implements AsRef<[u8] + 'a. This is not\n            // particularly user friendly, but this is a low level library anyway.\n            //\n            // Note also that the same could be written more explicitely with:\n            //\n            // let rx_packet =\n            //     <NetlinkBuffer<_> as Parseable<NetlinkMessage>>::parse(NetlinkBuffer::new(&bytes))\n            //         .unwrap();\n            //\n            let rx_packet: NetlinkMessage<RtnlMessage> =\n                NetlinkMessage::deserialize(bytes).unwrap();\n\n            println!(\"<<< {:?}\", rx_packet);\n\n            if rx_packet.payload == NetlinkPayload::Done {\n                println!(\"Done!\");\n                return;\n            }\n\n            offset += rx_packet.header.length as usize;\n            if offset == size || rx_packet.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/examples/dump_packet_links.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_route::{\n    LinkMessage,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    RtnlMessage,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\nuse netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut packet = NetlinkMessage {\n        header: NetlinkHeader::default(),\n        payload: NetlinkPayload::from(RtnlMessage::GetLink(LinkMessage::default())),\n    };\n    packet.header.flags = NLM_F_DUMP | NLM_F_REQUEST;\n    packet.header.sequence_number = 1;\n    packet.finalize();\n\n    let mut buf = vec![0; packet.header.length as usize];\n\n    // Before calling serialize, it is important to check that the buffer in which we're emitting is big\n    // enough for the packet, other `serialize()` panics.\n    assert!(buf.len() == packet.buffer_len());\n    packet.serialize(&mut buf[..]);\n\n    println!(\">>> {:?}\", packet);\n    socket.send(&buf[..], 0).unwrap();\n\n    let mut receive_buffer = vec![0; 4096];\n    let mut offset = 0;\n\n    // we set the NLM_F_DUMP flag so we expect a multipart rx_packet in response.\n    loop {\n        let size = socket.recv(&mut &mut receive_buffer[..], 0).unwrap();\n\n        loop {\n            let bytes = &receive_buffer[offset..];\n            // Note that we're parsing a NetlinkBuffer<&&[u8]>, NOT a NetlinkBuffer<&[u8]> here.\n            // This is important because Parseable<NetlinkMessage> is only implemented for\n            // NetlinkBuffer<&'a T>, where T implements AsRef<[u8] + 'a. This is not\n            // particularly user friendly, but this is a low level library anyway.\n            //\n            // Note also that the same could be written more explicitely with:\n            //\n            // let rx_packet =\n            //     <NetlinkBuffer<_> as Parseable<NetlinkMessage>>::parse(NetlinkBuffer::new(&bytes))\n            //         .unwrap();\n            //\n            let rx_packet: NetlinkMessage<RtnlMessage> =\n                NetlinkMessage::deserialize(bytes).unwrap();\n\n            println!(\"<<< {:?}\", rx_packet);\n\n            if rx_packet.payload == NetlinkPayload::Done {\n                println!(\"Done!\");\n                return;\n            }\n\n            offset += rx_packet.header.length as usize;\n            if offset == size || rx_packet.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/examples/dump_rules.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_route::{\n    constants::*,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    RtnlMessage,\n    RuleMessage,\n};\nuse netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut packet = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_DUMP,\n            ..Default::default()\n        },\n        payload: NetlinkPayload::from(RtnlMessage::GetRule(RuleMessage::default())),\n    };\n\n    packet.finalize();\n\n    let mut buf = vec![0; packet.header.length as usize];\n\n    // Before calling serialize, it is important to check that the buffer in which we're emitting is big\n    // enough for the packet, other `serialize()` panics.\n\n    assert!(buf.len() == packet.buffer_len());\n\n    packet.serialize(&mut buf[..]);\n\n    println!(\">>> {:?}\", packet);\n    if let Err(e) = socket.send(&buf[..], 0) {\n        println!(\"SEND ERROR {}\", e);\n    }\n\n    let mut receive_buffer = vec![0; 4096];\n    let mut offset = 0;\n\n    // we set the NLM_F_DUMP flag so we expect a multipart rx_packet in response.\n    while let Ok(size) = socket.recv(&mut &mut receive_buffer[..], 0) {\n        loop {\n            let bytes = &receive_buffer[offset..];\n            let rx_packet = <NetlinkMessage<RtnlMessage>>::deserialize(bytes).unwrap();\n            println!(\"<<< {:?}\", rx_packet);\n\n            if rx_packet.payload == NetlinkPayload::Done {\n                println!(\"Done!\");\n                return;\n            }\n\n            offset += rx_packet.header.length as usize;\n            if offset == size || rx_packet.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/examples/new_rule.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_core::{NetlinkHeader, NetlinkMessage, NetlinkPayload};\nuse netlink_packet_route::{constants::*, rule, RtnlMessage, RuleHeader, RuleMessage};\nuse netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut msg = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK,\n            ..Default::default()\n        },\n        payload: NetlinkPayload::from(RtnlMessage::NewRule(RuleMessage {\n            header: RuleHeader {\n                family: AF_INET as u8,\n                table: RT_TABLE_DEFAULT,\n                action: FR_ACT_TO_TBL,\n                ..Default::default()\n            },\n            nlas: vec![\n                rule::Nla::Table(254),\n                rule::Nla::SuppressPrefixLen(4294967295),\n                rule::Nla::Priority(1000),\n                rule::Nla::Protocol(2),\n            ],\n        })),\n    };\n\n    msg.finalize();\n    let mut buf = vec![0; 1024 * 8];\n\n    msg.serialize(&mut buf[..msg.buffer_len()]);\n\n    println!(\">>> {:?}\", msg);\n\n    socket\n        .send(&buf, 0)\n        .expect(\"failed to send netlink message\");\n\n    let mut receive_buffer = vec![0; 4096];\n\n    while let Ok(_size) = socket.recv(&mut receive_buffer, 0) {\n        loop {\n            let bytes = &receive_buffer[..];\n            let rx_packet = <NetlinkMessage<RtnlMessage>>::deserialize(bytes);\n            println!(\"<<< {:?}\", rx_packet);\n            if let Ok(rx_packet) = rx_packet {\n                if let NetlinkPayload::Error(e) = rx_packet.payload {\n                    eprintln!(\"{:?}\", e);\n                }\n            }\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/fuzz/.gitignore",
    "content": "\ntarget\ncorpus\nartifacts\n"
  },
  {
    "path": "netlink-packet-route/fuzz/Cargo.toml",
    "content": "[package]\nname = \"netlink-packet-route-fuzz\"\nversion = \"0.0.1\"\nauthors = [\"Automatically generated\"]\npublish = false\nedition = \"2018\"\n\n[package.metadata]\ncargo-fuzz = true\n\n[dependencies]\nnetlink-packet-route = { path = \"../\", version = \"0.13\" }\nlibfuzzer-sys = { git = \"https://github.com/rust-fuzz/libfuzzer-sys.git\" }\n\n[[bin]]\nname = \"netlink-route\"\npath = \"fuzz_targets/netlink.rs\"\n"
  },
  {
    "path": "netlink-packet-route/fuzz/fuzz_targets/netlink.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#![no_main]\nuse libfuzzer_sys::fuzz_target;\nuse netlink_packet_route::{NetlinkMessage, RtnlMessage};\n\nfuzz_target!(|data: &[u8]| {\n    let _ = NetlinkMessage::<RtnlMessage>::deserialize(data);\n});\n"
  },
  {
    "path": "netlink-packet-route/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_use]\nextern crate bitflags;\n#[macro_use]\npub(crate) extern crate netlink_packet_utils as utils;\npub(crate) use self::utils::parsers;\npub use self::utils::{traits, DecodeError};\n\npub use netlink_packet_core::{\n    ErrorMessage,\n    NetlinkBuffer,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n};\npub(crate) use netlink_packet_core::{NetlinkDeserializable, NetlinkSerializable};\n\npub mod rtnl;\npub use self::rtnl::*;\n\n#[cfg(test)]\n#[macro_use]\nextern crate lazy_static;\n\n#[cfg(test)]\n#[macro_use]\nextern crate pretty_assertions;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/address/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const ADDRESS_HEADER_LEN: usize = 8;\n\nbuffer!(AddressMessageBuffer(ADDRESS_HEADER_LEN) {\n    family: (u8, 0),\n    prefix_len: (u8, 1),\n    flags: (u8, 2),\n    scope: (u8, 3),\n    index: (u32, 4..ADDRESS_HEADER_LEN),\n    payload: (slice, ADDRESS_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> AddressMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/address/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    nlas::address::Nla,\n    traits::{Emitable, Parseable},\n    AddressMessageBuffer,\n    DecodeError,\n    ADDRESS_HEADER_LEN,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct AddressMessage {\n    pub header: AddressHeader,\n    pub nlas: Vec<Nla>,\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct AddressHeader {\n    pub family: u8,\n    pub prefix_len: u8,\n    pub flags: u8,\n    pub scope: u8,\n    pub index: u32,\n}\n\nimpl Emitable for AddressHeader {\n    fn buffer_len(&self) -> usize {\n        ADDRESS_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = AddressMessageBuffer::new(buffer);\n        packet.set_family(self.family);\n        packet.set_prefix_len(self.prefix_len);\n        packet.set_flags(self.flags);\n        packet.set_scope(self.scope);\n        packet.set_index(self.index);\n    }\n}\n\nimpl Emitable for AddressMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<AddressMessageBuffer<T>> for AddressHeader {\n    fn parse(buf: &AddressMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            family: buf.family(),\n            prefix_len: buf.prefix_len(),\n            flags: buf.flags(),\n            scope: buf.scope(),\n            index: buf.index(),\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<AddressMessageBuffer<&'a T>> for AddressMessage {\n    fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(AddressMessage {\n            header: AddressHeader::parse(buf).context(\"failed to parse address message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse address message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<AddressMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/address/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\npub use self::buffer::*;\n\nmod message;\npub use self::message::*;\n\npub mod nlas;\npub use self::nlas::*;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/address/nlas/cache_info.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]\npub struct CacheInfo {\n    pub ifa_preferred: i32,\n    pub ifa_valid: i32,\n    pub cstamp: i32,\n    pub tstamp: i32,\n}\n\npub const ADDRESSS_CACHE_INFO_LEN: usize = 16;\nbuffer!(CacheInfoBuffer(ADDRESSS_CACHE_INFO_LEN) {\n    ifa_preferred: (i32, 0..4),\n    ifa_valid: (i32, 4..8),\n    cstamp: (i32, 8..12),\n    tstamp: (i32, 12..16),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<CacheInfoBuffer<T>> for CacheInfo {\n    fn parse(buf: &CacheInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(CacheInfo {\n            ifa_preferred: buf.ifa_preferred(),\n            ifa_valid: buf.ifa_valid(),\n            cstamp: buf.cstamp(),\n            tstamp: buf.tstamp(),\n        })\n    }\n}\n\nimpl Emitable for CacheInfo {\n    fn buffer_len(&self) -> usize {\n        ADDRESSS_CACHE_INFO_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = CacheInfoBuffer::new(buffer);\n        buffer.set_ifa_preferred(self.ifa_preferred);\n        buffer.set_ifa_valid(self.ifa_valid);\n        buffer.set_cstamp(self.cstamp);\n        buffer.set_tstamp(self.tstamp);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/address/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod cache_info;\npub use self::cache_info::*;\n\nuse std::mem::size_of;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::{parse_string, parse_u32},\n    traits::Parseable,\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    Address(Vec<u8>),\n    Local(Vec<u8>),\n    Label(String),\n    Broadcast(Vec<u8>),\n    Anycast(Vec<u8>),\n    CacheInfo(Vec<u8>),\n    Multicast(Vec<u8>),\n    Flags(u32),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes)\n                | Address(ref bytes)\n                | Local(ref bytes)\n                | Broadcast(ref bytes)\n                | Anycast(ref bytes)\n                | Multicast(ref bytes) => bytes.len(),\n\n            // strings: +1 because we need to append a nul byte\n            Label(ref string) => string.as_bytes().len() + 1,\n\n            // u32\n            Flags(_) => size_of::<u32>(),\n\n            // Native\n            CacheInfo(ref buffer) => buffer.len(),\n\n            // Defaults\n            Other(ref attr)  => attr.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes)\n                | Address(ref bytes)\n                | Local(ref bytes)\n                | Broadcast(ref bytes)\n                | Anycast(ref bytes)\n                | CacheInfo(ref bytes)\n                | Multicast(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n\n            // String\n            Label(ref string) => {\n                buffer[..string.len()].copy_from_slice(string.as_bytes());\n                buffer[string.len()] = 0;\n            }\n\n            // u32\n            Flags(ref value) => NativeEndian::write_u32(buffer, *value),\n\n\n            // Default\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => IFA_UNSPEC,\n            Address(_) => IFA_ADDRESS,\n            Local(_) => IFA_LOCAL,\n            Label(_) => IFA_LABEL,\n            Broadcast(_) => IFA_BROADCAST,\n            Anycast(_) => IFA_ANYCAST,\n            CacheInfo(_) => IFA_CACHEINFO,\n            Multicast(_) => IFA_MULTICAST,\n            Flags(_) => IFA_FLAGS,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFA_UNSPEC => Unspec(payload.to_vec()),\n            IFA_ADDRESS => Address(payload.to_vec()),\n            IFA_LOCAL => Local(payload.to_vec()),\n            IFA_LABEL => Label(parse_string(payload).context(\"invalid IFA_LABEL value\")?),\n            IFA_BROADCAST => Broadcast(payload.to_vec()),\n            IFA_ANYCAST => Anycast(payload.to_vec()),\n            IFA_CACHEINFO => CacheInfo(payload.to_vec()),\n            IFA_MULTICAST => Multicast(payload.to_vec()),\n            IFA_FLAGS => Flags(parse_u32(payload).context(\"invalid IFA_FLAGS value\")?),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    traits::{Parseable, ParseableParametrized},\n    AddressHeader,\n    AddressMessage,\n    AddressMessageBuffer,\n    DecodeError,\n    LinkMessage,\n    LinkMessageBuffer,\n    NeighbourMessage,\n    NeighbourMessageBuffer,\n    NeighbourTableMessage,\n    NeighbourTableMessageBuffer,\n    NsidMessage,\n    NsidMessageBuffer,\n    RouteHeader,\n    RouteMessage,\n    RouteMessageBuffer,\n    RtnlMessage,\n    RuleMessage,\n    RuleMessageBuffer,\n    TcMessage,\n    TcMessageBuffer,\n};\nuse anyhow::Context;\n\nbuffer!(RtnlMessageBuffer);\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<RtnlMessageBuffer<&'a T>, u16>\n    for RtnlMessage\n{\n    #[rustfmt::skip]\n    fn parse_with_param(buf: &RtnlMessageBuffer<&'a T>, message_type: u16) -> Result<Self, DecodeError> {\n        use self::RtnlMessage::*;\n        let message = match message_type {\n\n            // Link messages\n            RTM_NEWLINK | RTM_GETLINK | RTM_DELLINK | RTM_SETLINK => {\n                let msg = match LinkMessageBuffer::new_checked(&buf.inner()) {\n                    Ok(buf) => LinkMessage::parse(&buf).context(\"invalid link message\")?,\n                    // HACK: iproute2 sends invalid RTM_GETLINK message, where the header is\n                    // limited to the interface family (1 byte) and 3 bytes of padding.\n                    Err(e) => {\n                        if buf.inner().len() == 4 && message_type == RTM_GETLINK {\n                            let mut msg = LinkMessage::default();\n                            msg.header.interface_family = buf.inner()[0];\n                            msg\n                        } else {\n                            return Err(e);\n                        }\n                    }\n                };\n                match message_type {\n                    RTM_NEWLINK => NewLink(msg),\n                    RTM_GETLINK => GetLink(msg),\n                    RTM_DELLINK => DelLink(msg),\n                    RTM_SETLINK => SetLink(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            // Address messages\n            RTM_NEWADDR | RTM_GETADDR | RTM_DELADDR => {\n                let msg = match AddressMessageBuffer::new_checked(&buf.inner()) {\n                    Ok(buf) => AddressMessage::parse(&buf).context(\"invalid link message\")?,\n                    // HACK: iproute2 sends invalid RTM_GETADDR message, where the header is\n                    // limited to the interface family (1 byte) and 3 bytes of padding.\n                    Err(e) => {\n                        if buf.inner().len() == 4 && message_type == RTM_GETADDR {\n                            let mut msg = AddressMessage {\n                                header: AddressHeader::default(),\n                                nlas: vec![],\n                            };\n                            msg.header.family = buf.inner()[0];\n                            msg\n                        } else {\n                            return Err(e);\n                        }\n                    }\n                };\n                match message_type {\n                    RTM_NEWADDR => NewAddress(msg),\n                    RTM_GETADDR => GetAddress(msg),\n                    RTM_DELADDR => DelAddress(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            // Neighbour messages\n            RTM_NEWNEIGH | RTM_GETNEIGH | RTM_DELNEIGH => {\n                let err = \"invalid neighbour message\";\n                let msg = NeighbourMessage::parse(&NeighbourMessageBuffer::new_checked(&buf.inner()).context(err)?).context(err)?;\n                match message_type {\n                    RTM_GETNEIGH => GetNeighbour(msg),\n                    RTM_NEWNEIGH => NewNeighbour(msg),\n                    RTM_DELNEIGH => DelNeighbour(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            // Neighbour table messages\n            RTM_NEWNEIGHTBL | RTM_GETNEIGHTBL | RTM_SETNEIGHTBL => {\n                let err = \"invalid neighbour table message\";\n                let msg = NeighbourTableMessage::parse(&NeighbourTableMessageBuffer::new_checked(&buf.inner()).context(err)?).context(err)?;\n                match message_type {\n                    RTM_GETNEIGHTBL => GetNeighbourTable(msg),\n                    RTM_NEWNEIGHTBL => NewNeighbourTable(msg),\n                    RTM_SETNEIGHTBL => SetNeighbourTable(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            // Route messages\n            RTM_NEWROUTE | RTM_GETROUTE | RTM_DELROUTE => {\n                let msg = match RouteMessageBuffer::new_checked(&buf.inner()) {\n                    Ok(buf) => RouteMessage::parse(&buf).context(\"invalid route message\")?,\n                    // HACK: iproute2 sends invalid RTM_GETROUTE message, where the header is\n                    // limited to the interface family (1 byte) and 3 bytes of padding.\n                    Err(e) => {\n                        // Not only does iproute2 sends invalid messages, it's also inconsistent in\n                        // doing so: for link and address messages, the length advertised in the\n                        // netlink header includes the 3 bytes of padding but it does not seem to\n                        // be the case for the route message, hence the buf.length() == 1 check.\n                        if (buf.inner().len() == 4 || buf.inner().len() == 1) && message_type == RTM_GETROUTE {\n                            let mut msg = RouteMessage {\n                                header: RouteHeader::default(),\n                                nlas: vec![],\n                            };\n                            msg.header.address_family = buf.inner()[0];\n                            msg\n                        } else {\n                            return Err(e);\n                        }\n                    }\n                };\n                match message_type {\n                    RTM_NEWROUTE => NewRoute(msg),\n                    RTM_GETROUTE => GetRoute(msg),\n                    RTM_DELROUTE => DelRoute(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            RTM_NEWRULE | RTM_GETRULE | RTM_DELRULE => {\n                let err = \"invalid fib rule message\";\n                let msg = RuleMessage::parse(&RuleMessageBuffer::new_checked(&buf.inner()).context(err)?).context(err)?;\n                match message_type {\n                    RTM_NEWRULE => NewRule(msg),\n                    RTM_DELRULE => DelRule(msg),\n                    RTM_GETRULE => GetRule(msg),\n                    _ => unreachable!()\n                }\n            }\n            // TC Messages\n            RTM_NEWQDISC | RTM_DELQDISC | RTM_GETQDISC |\n            RTM_NEWTCLASS | RTM_DELTCLASS | RTM_GETTCLASS |\n            RTM_NEWTFILTER | RTM_DELTFILTER | RTM_GETTFILTER |\n            RTM_NEWCHAIN | RTM_DELCHAIN | RTM_GETCHAIN => {\n                let err = \"invalid tc message\";\n                let msg = TcMessage::parse(&TcMessageBuffer::new_checked(&buf.inner()).context(err)?).context(err)?;\n                match message_type {\n                    RTM_NEWQDISC => NewQueueDiscipline(msg),\n                    RTM_DELQDISC => DelQueueDiscipline(msg),\n                    RTM_GETQDISC => GetQueueDiscipline(msg),\n                    RTM_NEWTCLASS => NewTrafficClass(msg),\n                    RTM_DELTCLASS => DelTrafficClass(msg),\n                    RTM_GETTCLASS => GetTrafficClass(msg),\n                    RTM_NEWTFILTER => NewTrafficFilter(msg),\n                    RTM_DELTFILTER => DelTrafficFilter(msg),\n                    RTM_GETTFILTER => GetTrafficFilter(msg),\n                    RTM_NEWCHAIN => NewTrafficChain(msg),\n                    RTM_DELCHAIN => DelTrafficChain(msg),\n                    RTM_GETCHAIN => GetTrafficChain(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            // ND ID Messages\n            RTM_NEWNSID | RTM_GETNSID | RTM_DELNSID => {\n                let err = \"invalid nsid message\";\n                let msg = NsidMessage::parse(&NsidMessageBuffer::new_checked(&buf.inner()).context(err)?).context(err)?;\n                match message_type {\n                    RTM_NEWNSID => NewNsId(msg),\n                    RTM_DELNSID => DelNsId(msg),\n                    RTM_GETNSID => GetNsId(msg),\n                    _ => unreachable!(),\n                }\n            }\n\n            _ => return Err(format!(\"Unknown message type: {}\", message_type).into()),\n        };\n        Ok(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub use netlink_packet_core::constants::*;\n\npub const RTM_BASE: u16 = 16;\npub const RTM_NEWLINK: u16 = 16;\npub const RTM_DELLINK: u16 = 17;\npub const RTM_GETLINK: u16 = 18;\npub const RTM_SETLINK: u16 = 19;\npub const RTM_NEWADDR: u16 = 20;\npub const RTM_DELADDR: u16 = 21;\npub const RTM_GETADDR: u16 = 22;\npub const RTM_NEWROUTE: u16 = 24;\npub const RTM_DELROUTE: u16 = 25;\npub const RTM_GETROUTE: u16 = 26;\npub const RTM_NEWNEIGH: u16 = 28;\npub const RTM_DELNEIGH: u16 = 29;\npub const RTM_GETNEIGH: u16 = 30;\npub const RTM_NEWRULE: u16 = 32;\npub const RTM_DELRULE: u16 = 33;\npub const RTM_GETRULE: u16 = 34;\npub const RTM_NEWQDISC: u16 = 36;\npub const RTM_DELQDISC: u16 = 37;\npub const RTM_GETQDISC: u16 = 38;\npub const RTM_NEWTCLASS: u16 = 40;\npub const RTM_DELTCLASS: u16 = 41;\npub const RTM_GETTCLASS: u16 = 42;\npub const RTM_NEWTFILTER: u16 = 44;\npub const RTM_DELTFILTER: u16 = 45;\npub const RTM_GETTFILTER: u16 = 46;\npub const RTM_NEWACTION: u16 = 48;\npub const RTM_DELACTION: u16 = 49;\npub const RTM_GETACTION: u16 = 50;\npub const RTM_NEWPREFIX: u16 = 52;\npub const RTM_GETMULTICAST: u16 = 58;\npub const RTM_GETANYCAST: u16 = 62;\npub const RTM_NEWNEIGHTBL: u16 = 64;\npub const RTM_GETNEIGHTBL: u16 = 66;\npub const RTM_SETNEIGHTBL: u16 = 67;\npub const RTM_NEWNDUSEROPT: u16 = 68;\npub const RTM_NEWADDRLABEL: u16 = 72;\npub const RTM_DELADDRLABEL: u16 = 73;\npub const RTM_GETADDRLABEL: u16 = 74;\npub const RTM_GETDCB: u16 = 78;\npub const RTM_SETDCB: u16 = 79;\npub const RTM_NEWNETCONF: u16 = 80;\npub const RTM_DELNETCONF: u16 = 81;\npub const RTM_GETNETCONF: u16 = 82;\npub const RTM_NEWMDB: u16 = 84;\npub const RTM_DELMDB: u16 = 85;\npub const RTM_GETMDB: u16 = 86;\npub const RTM_NEWNSID: u16 = 88;\npub const RTM_DELNSID: u16 = 89;\npub const RTM_GETNSID: u16 = 90;\npub const RTM_NEWSTATS: u16 = 92;\npub const RTM_GETSTATS: u16 = 94;\npub const RTM_NEWCACHEREPORT: u16 = 96;\npub const RTM_NEWCHAIN: u16 = 100;\npub const RTM_DELCHAIN: u16 = 101;\npub const RTM_GETCHAIN: u16 = 102;\npub const RTM_NEWLINKPROP: u16 = 108;\npub const RTM_DELLINKPROP: u16 = 109;\n\n/// Unknown route\npub const RTN_UNSPEC: u8 = 0;\n/// A gateway or direct route\npub const RTN_UNICAST: u8 = 1;\n/// A local interface route\npub const RTN_LOCAL: u8 = 2;\n/// A local broadcast route (sent as a broadcast)\npub const RTN_BROADCAST: u8 = 3;\n/// A local broadcast route (sent as a unicast)\npub const RTN_ANYCAST: u8 = 4;\n/// A multicast route\npub const RTN_MULTICAST: u8 = 5;\n/// A packet dropping route\npub const RTN_BLACKHOLE: u8 = 6;\n/// An unreachable destination\npub const RTN_UNREACHABLE: u8 = 7;\n/// A packet rejection route\npub const RTN_PROHIBIT: u8 = 8;\n/// Continue routing lookup in another table\npub const RTN_THROW: u8 = 9;\n/// A network address translation rule\npub const RTN_NAT: u8 = 10;\n/// Refer to an external resolver (not implemented)\npub const RTN_XRESOLVE: u8 = 11;\n\n/// Unknown\npub const RTPROT_UNSPEC: u8 = 0;\n/// Route was learnt by an ICMP redirect\npub const RTPROT_REDIRECT: u8 = 1;\n/// Route was learnt by the kernel\npub const RTPROT_KERNEL: u8 = 2;\n/// Route was learnt during boot\npub const RTPROT_BOOT: u8 = 3;\n/// Route was set statically\npub const RTPROT_STATIC: u8 = 4;\npub const RTPROT_GATED: u8 = 8;\npub const RTPROT_RA: u8 = 9;\npub const RTPROT_MRT: u8 = 10;\npub const RTPROT_ZEBRA: u8 = 11;\npub const RTPROT_BIRD: u8 = 12;\npub const RTPROT_DNROUTED: u8 = 13;\npub const RTPROT_XORP: u8 = 14;\npub const RTPROT_NTK: u8 = 15;\npub const RTPROT_DHCP: u8 = 16;\npub const RTPROT_MROUTED: u8 = 17;\npub const RTPROT_BABEL: u8 = 42;\n\n/// The destination is globally valid.\npub const RT_SCOPE_UNIVERSE: u8 = 0;\n/// (IPv6 only) the destination is site local, i.e. it is valid inside this site.  This is for interior\n/// routes in the local autonomous system\npub const RT_SCOPE_SITE: u8 = 200;\n/// The destination is link local\npub const RT_SCOPE_LINK: u8 = 253;\n/// The destination is valid only on this host\npub const RT_SCOPE_HOST: u8 = 254;\n/// Destination doesn't exist\npub const RT_SCOPE_NOWHERE: u8 = 255;\n\n/// An unspecified routing table\npub const RT_TABLE_UNSPEC: u8 = 0;\n\n/// A route table introduced for compatibility with old software which do not support table IDs\n/// greater than 255. See commit `709772e6e065` in the kernel:\n///\n/// ```no_rust\n/// commit 709772e6e06564ed94ba740de70185ac3d792773\n/// Author: Krzysztof Piotr Oledzki <ole@ans.pl>\n/// Date:   Tue Jun 10 15:44:49 2008 -0700\n///\n///     net: Fix routing tables with id > 255 for legacy software\n///\n///     Most legacy software do not like tables > 255 as rtm_table is u8\n///     so tb_id is sent &0xff and it is possible to mismatch for example\n///     table 510 with table 254 (main).\n///\n///     This patch introduces RT_TABLE_COMPAT=252 so the code uses it if\n///     tb_id > 255. It makes such old applications happy, new\n///     ones are still able to use RTA_TABLE to get a proper table id.\n///\n///     Signed-off-by: Krzysztof Piotr Oledzki <ole@ans.pl>\n///     Acked-by: Patrick McHardy <kaber@trash.net>\n///     Signed-off-by: David S. Miller <davem@davemloft.net>\n/// ```\npub const RT_TABLE_COMPAT: u8 = 252;\n\n/// The default routing table.\n///\n/// The default table is empty and has little use. It has been kept when the current incarnation of\n/// advanced routing has been introduced in Linux 2.1.68 after a first tentative using \"classes\" in\n/// Linux 2.1.15.\n/// # Source\n///\n/// This documentation is taken from [Vincent Bernat's excellent\n/// blog](https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux#builtin-tables)\npub const RT_TABLE_DEFAULT: u8 = 253;\n\n/// The main routing table.\n///\n/// By default, apart from the local ones which are added to the local table, routes that are added\n/// to this table.\npub const RT_TABLE_MAIN: u8 = 254;\n\n/// The local table.\n///\n/// This table is populated automatically by the kernel when addresses are configured.\n///\n/// On a machine that has `192.168.44.211/24` configured on `wlp58s0`, `iproute2` shows the following routes in the local table:\n///\n/// ```no_rust\n/// $ ip route show table local\n///\n/// broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1\n/// local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1\n/// local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1\n/// broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1\n///\n/// broadcast 192.168.44.0 dev wlp58s0 proto kernel scope link src 192.168.44.211\n/// local 192.168.44.211 dev wlp58s0 proto kernel scope host src 192.168.44.211\n/// broadcast 192.168.44.255 dev wlp58s0 proto kernel scope link src 192.168.44.211\n/// ```\n///\n/// When the IP address `192.168.44.211` was configured on the `wlp58s0` interface, the kernel\n/// automatically added the appropriate routes:\n///\n/// - a route for `192.168.44.211` for local unicast delivery to the IP address\n/// - a route for `192.168.44.255` for broadcast delivery to the broadcast address\n/// - a route for `192.168.44.0` for broadcast delivery to the network address\n///\n/// When `127.0.0.1` was configured on the loopback interface, the same kind of routes were added to\n/// the local table. However, a loopback address receives a special treatment and the kernel also\n/// adds the whole subnet to the local table.\n///\n/// Note that this is similar for IPv6:\n///\n/// ```no_rust\n/// $ ip -6 route show table local\n/// local ::1 dev lo proto kernel metric 0 pref medium\n/// local fe80::7de1:4914:99b7:aa28 dev wlp58s0 proto kernel metric 0 pref medium\n/// ff00::/8 dev wlp58s0 metric 256 pref medium\n/// ```\n///\n/// # Source\n///\n/// This documentation is adapted from [Vincent Bernat's excellent\n/// blog](https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux#builtin-tables)\npub const RT_TABLE_LOCAL: u8 = 255;\n\n/// If the route changes, notify the user via rtnetlink\npub const RTM_F_NOTIFY: u32 = 256;\n/// This route is cloned. Cloned routes are routes coming from the cache instead of the FIB. For\n/// IPv4, the cache was removed in Linux 3.6 (see [IPv4 route lookup on Linux] for more information\n/// about IPv4 routing)\n///\n/// [IPv4 route lookup on Linux]: https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux\npub const RTM_F_CLONED: u32 = 512;\n/// Multipath equalizer (not yet implemented)\npub const RTM_F_EQUALIZE: u32 = 1024;\n/// Prefix addresses\npub const RTM_F_PREFIX: u32 = 2048;\n/// Show the table from which the lookup result comes. Note that before commit `c36ba6603a11`, Linux\n/// would always hardcode [`RouteMessageHeader.table`] (known as `rtmsg.rtm_table` in the kernel) to\n/// `RT_TABLE_MAIN`.\n///\n/// [`RouteMessageHeader.table`]: ../struct.RouteMessageHeader.html#structfield.table\npub const RTM_F_LOOKUP_TABLE: u32 = 4096;\n/// Return the full FIB lookup match (see commit `b61798130f1be5bff08712308126c2d7ebe390ef`)\npub const RTM_F_FIB_MATCH: u32 = 8192;\n\npub const AF_UNSPEC: u16 = libc::AF_UNSPEC as u16;\npub const AF_UNIX: u16 = libc::AF_UNIX as u16;\n// pub const AF_LOCAL: u16 = libc::AF_LOCAL as u16;\npub const AF_INET: u16 = libc::AF_INET as u16;\npub const AF_AX25: u16 = libc::AF_AX25 as u16;\npub const AF_IPX: u16 = libc::AF_IPX as u16;\npub const AF_APPLETALK: u16 = libc::AF_APPLETALK as u16;\npub const AF_NETROM: u16 = libc::AF_NETROM as u16;\npub const AF_BRIDGE: u16 = libc::AF_BRIDGE as u16;\npub const AF_ATMPVC: u16 = libc::AF_ATMPVC as u16;\npub const AF_X25: u16 = libc::AF_X25 as u16;\npub const AF_INET6: u16 = libc::AF_INET6 as u16;\npub const AF_ROSE: u16 = libc::AF_ROSE as u16;\npub const AF_DECNET: u16 = libc::AF_DECnet as u16;\npub const AF_NETBEUI: u16 = libc::AF_NETBEUI as u16;\npub const AF_SECURITY: u16 = libc::AF_SECURITY as u16;\npub const AF_KEY: u16 = libc::AF_KEY as u16;\npub const AF_NETLINK: u16 = libc::AF_NETLINK as u16;\n// pub const AF_ROUTE: u16 = libc::AF_ROUTE as u16;\npub const AF_PACKET: u16 = libc::AF_PACKET as u16;\npub const AF_ASH: u16 = libc::AF_ASH as u16;\npub const AF_ECONET: u16 = libc::AF_ECONET as u16;\npub const AF_ATMSVC: u16 = libc::AF_ATMSVC as u16;\npub const AF_RDS: u16 = libc::AF_RDS as u16;\npub const AF_SNA: u16 = libc::AF_SNA as u16;\npub const AF_IRDA: u16 = libc::AF_IRDA as u16;\npub const AF_PPPOX: u16 = libc::AF_PPPOX as u16;\npub const AF_WANPIPE: u16 = libc::AF_WANPIPE as u16;\npub const AF_LLC: u16 = libc::AF_LLC as u16;\npub const AF_CAN: u16 = libc::AF_CAN as u16;\npub const AF_TIPC: u16 = libc::AF_TIPC as u16;\npub const AF_BLUETOOTH: u16 = libc::AF_BLUETOOTH as u16;\npub const AF_IUCV: u16 = libc::AF_IUCV as u16;\npub const AF_RXRPC: u16 = libc::AF_RXRPC as u16;\npub const AF_ISDN: u16 = libc::AF_ISDN as u16;\npub const AF_PHONET: u16 = libc::AF_PHONET as u16;\npub const AF_IEEE802154: u16 = libc::AF_IEEE802154 as u16;\npub const AF_CAIF: u16 = libc::AF_CAIF as u16;\npub const AF_ALG: u16 = libc::AF_ALG as u16;\n\npub const NETNSA_NONE: u16 = 0;\npub const NETNSA_NSID: u16 = 1;\npub const NETNSA_PID: u16 = 2;\npub const NETNSA_FD: u16 = 3;\npub const NETNSA_NSID_NOT_ASSIGNED: i32 = -1;\n\n/// Neighbour cache entry state: the neighbour has not (yet) been resolved\npub const NUD_INCOMPLETE: u16 = 1;\n/// Neighbour cache entry state: the neighbour entry is valid until its lifetime expires\npub const NUD_REACHABLE: u16 = 2;\n/// Neighbour cache entry state: the neighbour entry is valid but suspicious\npub const NUD_STALE: u16 = 4;\n/// Neighbour cache entry state: the validation of this entry is currently delayed\npub const NUD_DELAY: u16 = 8;\n/// Neighbour cache entry state: the neighbour entry is being probed\npub const NUD_PROBE: u16 = 16;\n/// Neighbour cache entry state: the validation of this entry has failed\npub const NUD_FAILED: u16 = 32;\n/// Neighbour cache entry state: entry is valid and the kernel will not try to validate or refresh\n/// it.\npub const NUD_NOARP: u16 = 64;\n/// Neighbour cache entry state: entry is valid forever and can only be removed explicitly from\n/// userspace.\npub const NUD_PERMANENT: u16 = 128;\n/// Neighbour cache entry state: pseudo state for fresh entries or before deleting entries\npub const NUD_NONE: u16 = 0;\n\n// Neighbour cache entry flags\npub const NTF_USE: u8 = 1;\npub const NTF_SELF: u8 = 2;\npub const NTF_MASTER: u8 = 4;\npub const NTF_PROXY: u8 = 8;\npub const NTF_EXT_LEARNED: u8 = 16;\npub const NTF_OFFLOADED: u8 = 32;\npub const NTF_ROUTER: u8 = 128;\n\npub const TCA_UNSPEC: u16 = 0;\npub const TCA_KIND: u16 = 1;\npub const TCA_OPTIONS: u16 = 2;\npub const TCA_STATS: u16 = 3;\npub const TCA_XSTATS: u16 = 4;\npub const TCA_RATE: u16 = 5;\npub const TCA_FCNT: u16 = 6;\npub const TCA_STATS2: u16 = 7;\npub const TCA_STAB: u16 = 8;\npub const TCA_PAD: u16 = 9;\npub const TCA_DUMP_INVISIBLE: u16 = 10;\npub const TCA_CHAIN: u16 = 11;\npub const TCA_HW_OFFLOAD: u16 = 12;\npub const TCA_INGRESS_BLOCK: u16 = 13;\npub const TCA_EGRESS_BLOCK: u16 = 14;\npub const TCA_STATS_UNSPEC: u16 = 0;\npub const TCA_STATS_BASIC: u16 = 1;\npub const TCA_STATS_RATE_EST: u16 = 2;\npub const TCA_STATS_QUEUE: u16 = 3;\npub const TCA_STATS_APP: u16 = 4;\npub const TCA_STATS_RATE_EST64: u16 = 5;\npub const TCA_STATS_PAD: u16 = 6;\npub const TCA_STATS_BASIC_HW: u16 = 7;\n\npub const NDTA_UNSPEC: u16 = 0;\npub const NDTA_NAME: u16 = 1;\npub const NDTA_THRESH1: u16 = 2;\npub const NDTA_THRESH2: u16 = 3;\npub const NDTA_THRESH3: u16 = 4;\npub const NDTA_CONFIG: u16 = 5;\npub const NDTA_PARMS: u16 = 6;\npub const NDTA_STATS: u16 = 7;\npub const NDTA_GC_INTERVAL: u16 = 8;\npub const NDTA_PAD: u16 = 9;\n\npub const RTA_UNSPEC: u16 = 0;\npub const RTA_DST: u16 = 1;\npub const RTA_SRC: u16 = 2;\npub const RTA_IIF: u16 = 3;\npub const RTA_OIF: u16 = 4;\npub const RTA_GATEWAY: u16 = 5;\npub const RTA_PRIORITY: u16 = 6;\npub const RTA_PREFSRC: u16 = 7;\npub const RTA_METRICS: u16 = 8;\npub const RTA_MULTIPATH: u16 = 9;\npub const RTA_PROTOINFO: u16 = 10;\npub const RTA_FLOW: u16 = 11;\npub const RTA_CACHEINFO: u16 = 12;\npub const RTA_SESSION: u16 = 13;\npub const RTA_MP_ALGO: u16 = 14;\npub const RTA_TABLE: u16 = 15;\npub const RTA_MARK: u16 = 16;\npub const RTA_MFC_STATS: u16 = 17;\npub const RTA_VIA: u16 = 18;\npub const RTA_NEWDST: u16 = 19;\npub const RTA_PREF: u16 = 20;\npub const RTA_ENCAP_TYPE: u16 = 21;\npub const RTA_ENCAP: u16 = 22;\npub const RTA_EXPIRES: u16 = 23;\npub const RTA_PAD: u16 = 24;\npub const RTA_UID: u16 = 25;\npub const RTA_TTL_PROPAGATE: u16 = 26;\n\npub const RTAX_UNSPEC: u16 = 0;\npub const RTAX_LOCK: u16 = 1;\npub const RTAX_MTU: u16 = 2;\npub const RTAX_WINDOW: u16 = 3;\npub const RTAX_RTT: u16 = 4;\npub const RTAX_RTTVAR: u16 = 5;\npub const RTAX_SSTHRESH: u16 = 6;\npub const RTAX_CWND: u16 = 7;\npub const RTAX_ADVMSS: u16 = 8;\npub const RTAX_REORDERING: u16 = 9;\npub const RTAX_HOPLIMIT: u16 = 10;\npub const RTAX_INITCWND: u16 = 11;\npub const RTAX_FEATURES: u16 = 12;\npub const RTAX_RTO_MIN: u16 = 13;\npub const RTAX_INITRWND: u16 = 14;\npub const RTAX_QUICKACK: u16 = 15;\npub const RTAX_CC_ALGO: u16 = 16;\npub const RTAX_FASTOPEN_NO_COOKIE: u16 = 17;\n\npub const IFLA_INFO_UNSPEC: u16 = 0;\npub const IFLA_INFO_KIND: u16 = 1;\npub const IFLA_INFO_DATA: u16 = 2;\npub const IFLA_INFO_XSTATS: u16 = 3;\npub const IFLA_INFO_SLAVE_KIND: u16 = 4;\npub const IFLA_INFO_SLAVE_DATA: u16 = 5;\n// Bridge flags\npub const IFLA_BRIDGE_FLAGS: u16 = 0;\npub const BRIDGE_FLAGS_MASTER: u16 = 1; /* Bridge command to/from master */\npub const BRIDGE_FLAGS_SELF: u16 = 2; /* Bridge command to/from lowerdev */\n\npub const IFLA_BRIDGE_VLAN_INFO: u16 = 2;\npub const BRIDGE_VLAN_INFO_MASTER: u16 = 1;\npub const BRIDGE_VLAN_INFO_PVID: u16 = 4;\npub const BRIDGE_VLAN_INFO_UNTAGGED: u16 = 8;\npub const BRIDGE_VLAN_INFO_RANGE_BEGIN: u16 = 16;\npub const BRIDGE_VLAN_INFO_RANGE_END: u16 = 32;\n\npub const IFLA_BR_UNSPEC: u16 = 0;\npub const IFLA_BR_FORWARD_DELAY: u16 = 1;\npub const IFLA_BR_HELLO_TIME: u16 = 2;\npub const IFLA_BR_MAX_AGE: u16 = 3;\npub const IFLA_BR_AGEING_TIME: u16 = 4;\npub const IFLA_BR_STP_STATE: u16 = 5;\npub const IFLA_BR_PRIORITY: u16 = 6;\npub const IFLA_BR_VLAN_FILTERING: u16 = 7;\npub const IFLA_BR_VLAN_PROTOCOL: u16 = 8;\npub const IFLA_BR_GROUP_FWD_MASK: u16 = 9;\npub const IFLA_BR_ROOT_ID: u16 = 10;\npub const IFLA_BR_BRIDGE_ID: u16 = 11;\npub const IFLA_BR_ROOT_PORT: u16 = 12;\npub const IFLA_BR_ROOT_PATH_COST: u16 = 13;\npub const IFLA_BR_TOPOLOGY_CHANGE: u16 = 14;\npub const IFLA_BR_TOPOLOGY_CHANGE_DETECTED: u16 = 15;\npub const IFLA_BR_HELLO_TIMER: u16 = 16;\npub const IFLA_BR_TCN_TIMER: u16 = 17;\npub const IFLA_BR_TOPOLOGY_CHANGE_TIMER: u16 = 18;\npub const IFLA_BR_GC_TIMER: u16 = 19;\npub const IFLA_BR_GROUP_ADDR: u16 = 20;\npub const IFLA_BR_FDB_FLUSH: u16 = 21;\npub const IFLA_BR_MCAST_ROUTER: u16 = 22;\npub const IFLA_BR_MCAST_SNOOPING: u16 = 23;\npub const IFLA_BR_MCAST_QUERY_USE_IFADDR: u16 = 24;\npub const IFLA_BR_MCAST_QUERIER: u16 = 25;\npub const IFLA_BR_MCAST_HASH_ELASTICITY: u16 = 26;\npub const IFLA_BR_MCAST_HASH_MAX: u16 = 27;\npub const IFLA_BR_MCAST_LAST_MEMBER_CNT: u16 = 28;\npub const IFLA_BR_MCAST_STARTUP_QUERY_CNT: u16 = 29;\npub const IFLA_BR_MCAST_LAST_MEMBER_INTVL: u16 = 30;\npub const IFLA_BR_MCAST_MEMBERSHIP_INTVL: u16 = 31;\npub const IFLA_BR_MCAST_QUERIER_INTVL: u16 = 32;\npub const IFLA_BR_MCAST_QUERY_INTVL: u16 = 33;\npub const IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: u16 = 34;\npub const IFLA_BR_MCAST_STARTUP_QUERY_INTVL: u16 = 35;\npub const IFLA_BR_NF_CALL_IPTABLES: u16 = 36;\npub const IFLA_BR_NF_CALL_IP6TABLES: u16 = 37;\npub const IFLA_BR_NF_CALL_ARPTABLES: u16 = 38;\npub const IFLA_BR_VLAN_DEFAULT_PVID: u16 = 39;\npub const IFLA_BR_PAD: u16 = 40;\npub const IFLA_BR_VLAN_STATS_ENABLED: u16 = 41;\npub const IFLA_BR_MCAST_STATS_ENABLED: u16 = 42;\npub const IFLA_BR_MCAST_IGMP_VERSION: u16 = 43;\npub const IFLA_BR_MCAST_MLD_VERSION: u16 = 44;\npub const IFLA_BR_VLAN_STATS_PER_PORT: u16 = 45;\npub const IFLA_BR_MULTI_BOOLOPT: u16 = 46;\npub const IFLA_MACVLAN_UNSPEC: u16 = 0;\npub const IFLA_MACVLAN_MODE: u16 = 1;\npub const IFLA_MACVLAN_FLAGS: u16 = 2;\npub const IFLA_MACVLAN_MACADDR_MODE: u16 = 3;\npub const IFLA_MACVLAN_MACADDR: u16 = 4;\npub const IFLA_MACVLAN_MACADDR_DATA: u16 = 5;\npub const IFLA_MACVLAN_MACADDR_COUNT: u16 = 6;\npub const IFLA_VLAN_UNSPEC: u16 = 0;\npub const IFLA_VLAN_ID: u16 = 1;\npub const IFLA_VLAN_FLAGS: u16 = 2;\npub const IFLA_VLAN_EGRESS_QOS: u16 = 3;\npub const IFLA_VLAN_INGRESS_QOS: u16 = 4;\npub const IFLA_VLAN_PROTOCOL: u16 = 5;\npub const IFLA_VRF_UNSPEC: u16 = 0;\npub const IFLA_VRF_TABLE: u16 = 1;\npub const IFLA_IPVLAN_UNSPEC: u16 = 0;\npub const IFLA_IPVLAN_MODE: u16 = 1;\npub const IFLA_IPVLAN_FLAGS: u16 = 2;\npub const IFLA_IPOIB_UNSPEC: u16 = 0;\npub const IFLA_IPOIB_PKEY: u16 = 1;\npub const IFLA_IPOIB_MODE: u16 = 2;\npub const IFLA_IPOIB_UMCAST: u16 = 3;\npub const VETH_INFO_UNSPEC: u16 = 0;\npub const VETH_INFO_PEER: u16 = 1;\n\npub const ARPHRD_NETROM: u16 = 0;\npub const ARPHRD_ETHER: u16 = 1;\npub const ARPHRD_EETHER: u16 = 2;\npub const ARPHRD_AX25: u16 = 3;\npub const ARPHRD_PRONET: u16 = 4;\npub const ARPHRD_CHAOS: u16 = 5;\npub const ARPHRD_IEEE802: u16 = 6;\npub const ARPHRD_ARCNET: u16 = 7;\npub const ARPHRD_APPLETLK: u16 = 8;\npub const ARPHRD_DLCI: u16 = 15;\npub const ARPHRD_ATM: u16 = 19;\npub const ARPHRD_METRICOM: u16 = 23;\npub const ARPHRD_IEEE1394: u16 = 24;\npub const ARPHRD_EUI64: u16 = 27;\npub const ARPHRD_INFINIBAND: u16 = 32;\npub const ARPHRD_SLIP: u16 = 256;\npub const ARPHRD_CSLIP: u16 = 257;\npub const ARPHRD_SLIP6: u16 = 258;\npub const ARPHRD_CSLIP6: u16 = 259;\npub const ARPHRD_RSRVD: u16 = 260;\npub const ARPHRD_ADAPT: u16 = 264;\npub const ARPHRD_ROSE: u16 = 270;\npub const ARPHRD_X25: u16 = 271;\npub const ARPHRD_HWX25: u16 = 272;\npub const ARPHRD_CAN: u16 = 280;\npub const ARPHRD_PPP: u16 = 512;\npub const ARPHRD_CISCO: u16 = 513;\npub const ARPHRD_HDLC: u16 = 513;\npub const ARPHRD_LAPB: u16 = 516;\npub const ARPHRD_DDCMP: u16 = 517;\npub const ARPHRD_RAWHDLC: u16 = 518;\npub const ARPHRD_RAWIP: u16 = 519;\npub const ARPHRD_TUNNEL: u16 = 768;\npub const ARPHRD_TUNNEL6: u16 = 769;\npub const ARPHRD_FRAD: u16 = 770;\npub const ARPHRD_SKIP: u16 = 771;\npub const ARPHRD_LOOPBACK: u16 = 772;\npub const ARPHRD_LOCALTLK: u16 = 773;\npub const ARPHRD_FDDI: u16 = 774;\npub const ARPHRD_BIF: u16 = 775;\npub const ARPHRD_SIT: u16 = 776;\npub const ARPHRD_IPDDP: u16 = 777;\npub const ARPHRD_IPGRE: u16 = 778;\npub const ARPHRD_PIMREG: u16 = 779;\npub const ARPHRD_HIPPI: u16 = 780;\npub const ARPHRD_ASH: u16 = 781;\npub const ARPHRD_ECONET: u16 = 782;\npub const ARPHRD_IRDA: u16 = 783;\npub const ARPHRD_FCPP: u16 = 784;\npub const ARPHRD_FCAL: u16 = 785;\npub const ARPHRD_FCPL: u16 = 786;\npub const ARPHRD_FCFABRIC: u16 = 787;\npub const ARPHRD_IEEE802_TR: u16 = 800;\npub const ARPHRD_IEEE80211: u16 = 801;\npub const ARPHRD_IEEE80211_PRISM: u16 = 802;\npub const ARPHRD_IEEE80211_RADIOTAP: u16 = 803;\npub const ARPHRD_IEEE802154: u16 = 804;\npub const ARPHRD_IEEE802154_MONITOR: u16 = 805;\npub const ARPHRD_PHONET: u16 = 820;\npub const ARPHRD_PHONET_PIPE: u16 = 821;\npub const ARPHRD_CAIF: u16 = 822;\npub const ARPHRD_IP6GRE: u16 = 823;\npub const ARPHRD_NETLINK: u16 = 824;\npub const ARPHRD_6LOWPAN: u16 = 825;\npub const ARPHRD_VSOCKMON: u16 = 826;\npub const ARPHRD_VOID: u16 = 65535;\npub const ARPHRD_NONE: u16 = 65534;\n\npub const IFA_UNSPEC: u16 = 0;\npub const IFA_ADDRESS: u16 = 1;\npub const IFA_LOCAL: u16 = 2;\npub const IFA_LABEL: u16 = 3;\npub const IFA_BROADCAST: u16 = 4;\npub const IFA_ANYCAST: u16 = 5;\npub const IFA_CACHEINFO: u16 = 6;\npub const IFA_MULTICAST: u16 = 7;\npub const IFA_FLAGS: u16 = 8;\n\npub const IFLA_UNSPEC: u16 = 0;\npub const IFLA_ADDRESS: u16 = 1;\npub const IFLA_BROADCAST: u16 = 2;\npub const IFLA_IFNAME: u16 = 3;\npub const IFLA_MTU: u16 = 4;\npub const IFLA_LINK: u16 = 5;\npub const IFLA_QDISC: u16 = 6;\npub const IFLA_STATS: u16 = 7;\npub const IFLA_COST: u16 = 8;\npub const IFLA_PRIORITY: u16 = 9;\npub const IFLA_MASTER: u16 = 10;\npub const IFLA_WIRELESS: u16 = 11;\npub const IFLA_PROTINFO: u16 = 12;\npub const IFLA_TXQLEN: u16 = 13;\npub const IFLA_MAP: u16 = 14;\npub const IFLA_WEIGHT: u16 = 15;\npub const IFLA_OPERSTATE: u16 = 16;\npub const IFLA_LINKMODE: u16 = 17;\npub const IFLA_LINKINFO: u16 = 18;\npub const IFLA_NET_NS_PID: u16 = 19;\npub const IFLA_IFALIAS: u16 = 20;\npub const IFLA_NUM_VF: u16 = 21;\npub const IFLA_VFINFO_LIST: u16 = 22;\npub const IFLA_STATS64: u16 = 23;\npub const IFLA_VF_PORTS: u16 = 24;\npub const IFLA_PORT_SELF: u16 = 25;\npub const IFLA_AF_SPEC: u16 = 26;\npub const IFLA_GROUP: u16 = 27;\npub const IFLA_NET_NS_FD: u16 = 28;\npub const IFLA_EXT_MASK: u16 = 29;\npub const IFLA_PROMISCUITY: u16 = 30;\npub const IFLA_NUM_TX_QUEUES: u16 = 31;\npub const IFLA_NUM_RX_QUEUES: u16 = 32;\npub const IFLA_CARRIER: u16 = 33;\npub const IFLA_PHYS_PORT_ID: u16 = 34;\npub const IFLA_CARRIER_CHANGES: u16 = 35;\npub const IFLA_PHYS_SWITCH_ID: u16 = 36;\npub const IFLA_LINK_NETNSID: u16 = 37;\npub const IFLA_PHYS_PORT_NAME: u16 = 38;\npub const IFLA_PROTO_DOWN: u16 = 39;\npub const IFLA_GSO_MAX_SEGS: u16 = 40;\npub const IFLA_GSO_MAX_SIZE: u16 = 41;\npub const IFLA_PAD: u16 = 42;\npub const IFLA_XDP: u16 = 43;\npub const IFLA_EVENT: u16 = 44;\npub const IFLA_NEW_NETNSID: u16 = 45;\npub const IFLA_IF_NETNSID: u16 = 46;\npub const IFLA_CARRIER_UP_COUNT: u16 = 47;\npub const IFLA_CARRIER_DOWN_COUNT: u16 = 48;\npub const IFLA_NEW_IFINDEX: u16 = 49;\npub const IFLA_MIN_MTU: u16 = 50;\npub const IFLA_MAX_MTU: u16 = 51;\npub const IFLA_PROP_LIST: u16 = 52;\npub const IFLA_ALT_IFNAME: u16 = 53;\npub const IFLA_PERM_ADDRESS: u16 = 54;\npub const IFLA_PROTO_DOWN_REASON: u16 = 55;\npub const IFLA_INET_UNSPEC: u16 = 0;\npub const IFLA_INET_CONF: u16 = 1;\npub const IFLA_INET6_UNSPEC: u16 = 0;\npub const IFLA_INET6_FLAGS: u16 = 1;\npub const IFLA_INET6_CONF: u16 = 2;\npub const IFLA_INET6_STATS: u16 = 3;\n// pub const IFLA_INET6_MCAST: u16 = 4;\npub const IFLA_INET6_CACHEINFO: u16 = 5;\npub const IFLA_INET6_ICMP6STATS: u16 = 6;\npub const IFLA_INET6_TOKEN: u16 = 7;\npub const IFLA_INET6_ADDR_GEN_MODE: u16 = 8;\n\n/// Link is up (administratively).\npub const IFF_UP: u32 = libc::IFF_UP as u32;\n/// Link is up and carrier is OK (RFC2863 OPER_UP)\npub const IFF_RUNNING: u32 = libc::IFF_RUNNING as u32;\n/// Link layer is operational\npub const IFF_LOWER_UP: u32 = libc::IFF_LOWER_UP as u32;\n/// Driver signals IFF_DORMANT\npub const IFF_DORMANT: u32 = libc::IFF_DORMANT as u32;\n/// Link supports broadcasting\npub const IFF_BROADCAST: u32 = libc::IFF_BROADCAST as u32;\n/// Link supports multicasting\npub const IFF_MULTICAST: u32 = libc::IFF_MULTICAST as u32;\n/// Link supports multicast routing\npub const IFF_ALLMULTI: u32 = libc::IFF_ALLMULTI as u32;\n/// Tell driver to do debugging (currently unused)\npub const IFF_DEBUG: u32 = libc::IFF_DEBUG as u32;\n/// Link loopback network\npub const IFF_LOOPBACK: u32 = libc::IFF_LOOPBACK as u32;\n/// u32erface is point-to-point link\npub const IFF_POINTOPOINT: u32 = libc::IFF_POINTOPOINT as u32;\n/// ARP is not supported\npub const IFF_NOARP: u32 = libc::IFF_NOARP as u32;\n/// Receive all packets.\npub const IFF_PROMISC: u32 = libc::IFF_PROMISC as u32;\n/// Master of a load balancer (bonding)\npub const IFF_MASTER: u32 = libc::IFF_MASTER as u32;\n/// Slave of a load balancer\npub const IFF_SLAVE: u32 = libc::IFF_SLAVE as u32;\n/// Link selects port automatically (only used by ARM ethernet)\npub const IFF_PORTSEL: u32 = libc::IFF_PORTSEL as u32;\n/// Driver supports setting media type (only used by ARM ethernet)\npub const IFF_AUTOMEDIA: u32 = libc::IFF_AUTOMEDIA as u32;\n// /// Echo sent packets (testing feature, CAN only)\n// pub const IFF_ECHO: u32 = libc::IFF_ECHO as u32;\n// /// Dialup device with changing addresses (unused, BSD compatibility)\n// pub const IFF_DYNAMIC: u32 = libc::IFF_DYNAMIC as u32;\n// /// Avoid use of trailers (unused, BSD compatibility)\n// pub const IFF_NOTRAILERS: u32 = libc::IFF_NOTRAILERS as u32;\n\npub const IF_OPER_UNKNOWN: u8 = 0;\npub const IF_OPER_NOTPRESENT: u8 = 1;\npub const IF_OPER_DOWN: u8 = 2;\npub const IF_OPER_LOWERLAYERDOWN: u8 = 3;\npub const IF_OPER_TESTING: u8 = 4;\npub const IF_OPER_DORMANT: u8 = 5;\npub const IF_OPER_UP: u8 = 6;\n\n/// Neighbour cache entry type: unknown type\npub const NDA_UNSPEC: u16 = 0;\n/// Neighbour cache entry type: entry for a network layer destination\n/// address\npub const NDA_DST: u16 = 1;\n/// Neighbour cache entry type: entry for a link layer destination\n/// address\npub const NDA_LLADDR: u16 = 2;\n/// Neighbour cache entry type: entry for cache statistics\npub const NDA_CACHEINFO: u16 = 3;\npub const NDA_PROBES: u16 = 4;\npub const NDA_VLAN: u16 = 5;\npub const NDA_PORT: u16 = 6;\npub const NDA_VNI: u16 = 7;\npub const NDA_IFINDEX: u16 = 8;\npub const NDA_MASTER: u16 = 9;\npub const NDA_LINK_NETNSID: u16 = 10;\npub const NDA_SRC_VNI: u16 = 11;\n\n/// see `https://github.com/torvalds/linux/blob/master/include/uapi/linux/fib_rules.h`\n\npub const FR_ACT_UNSPEC: u8 = 0;\n/// Pass to fixed table\npub const FR_ACT_TO_TBL: u8 = 1;\n/// Jump to another rule\npub const FR_ACT_GOTO: u8 = 2;\n/// No operation\npub const FR_ACT_NOP: u8 = 3;\npub const FR_ACT_RES3: u8 = 4;\npub const FR_ACT_RES4: u8 = 5;\n/// Drop without notification\npub const FR_ACT_BLACKHOLE: u8 = 6;\n/// Drop with `ENETUNREACH`\npub const FR_ACT_UNREACHABLE: u8 = 7;\n/// Drop with `EACCES`\npub const FR_ACT_PROHIBIT: u8 = 8;\n\npub const FRA_UNSPEC: u16 = 0;\n/// Destination address\npub const FRA_DST: u16 = 1;\n/// Source address\npub const FRA_SRC: u16 = 2;\n/// Interface name\npub const FRA_IIFNAME: u16 = 3;\n/// Target to jump to\npub const FRA_GOTO: u16 = 4;\n\npub const FRA_UNUSED2: u16 = 5;\n\n/// priority/preference\npub const FRA_PRIORITY: u16 = 6;\n\npub const FRA_UNUSED3: u16 = 7;\npub const FRA_UNUSED4: u16 = 8;\npub const FRA_UNUSED5: u16 = 9;\n\n/// mark\npub const FRA_FWMARK: u16 = 10;\n/// flow/class id\npub const FRA_FLOW: u16 = 11;\npub const FRA_TUN_ID: u16 = 12;\npub const FRA_SUPPRESS_IFGROUP: u16 = 13;\npub const FRA_SUPPRESS_PREFIXLEN: u16 = 14;\n/// Extended table id\npub const FRA_TABLE: u16 = 15;\n/// mask for netfilter mark\npub const FRA_FWMASK: u16 = 16;\npub const FRA_OIFNAME: u16 = 17;\npub const FRA_PAD: u16 = 18;\n/// iif or oif is l3mdev goto its table\npub const FRA_L3MDEV: u16 = 19;\n/// UID range\npub const FRA_UID_RANGE: u16 = 20;\n/// Originator of the rule\npub const FRA_PROTOCOL: u16 = 21;\n/// IP protocol\npub const FRA_IP_PROTO: u16 = 22;\n/// Source port\npub const FRA_SPORT_RANGE: u16 = 23;\n/// Destination port\npub const FRA_DPORT_RANGE: u16 = 24;\n\npub const FIB_RULE_PERMANENT: u32 = 1;\npub const FIB_RULE_INVERT: u32 = 2;\npub const FIB_RULE_UNRESOLVED: u32 = 4;\npub const FIB_RULE_IIF_DETACHED: u32 = 8;\npub const FIB_RULE_DEV_DETACHED: u32 = FIB_RULE_IIF_DETACHED;\npub const FIB_RULE_OIF_DETACHED: u32 = 10;\n/// try to find source address in routing lookups\npub const FIB_RULE_FIND_SADDR: u32 = 10000;\n\n// pub const MACVLAN_FLAG_NOPROMISC: int = 1;\n// pub const IPVLAN_F_PRIVATE: int = 1;\n// pub const IPVLAN_F_VEPA: int = 2;\n// pub const MAX_VLAN_LIST_LEN: int = 1;\n// pub const PORT_PROFILE_MAX: int = 40;\n// pub const PORT_UUID_MAX: int = 16;\n// pub const PORT_SELF_VF: int = -1;\n// pub const XDP_FLAGS_UPDATE_IF_NOEXIST: int = 1;\n// pub const XDP_FLAGS_SKB_MODE: int = 2;\n// pub const XDP_FLAGS_DRV_MODE: int = 4;\n// pub const XDP_FLAGS_HW_MODE: int = 8;\n// pub const XDP_FLAGS_MODES: int = 14;\n// pub const XDP_FLAGS_MASK: int = 15;\n\npub const IFA_F_SECONDARY: u32 = 1;\npub const IFA_F_TEMPORARY: u32 = 1;\npub const IFA_F_NODAD: u32 = 2;\npub const IFA_F_OPTIMISTIC: u32 = 4;\npub const IFA_F_DADFAILED: u32 = 8;\npub const IFA_F_HOMEADDRESS: u32 = 16;\npub const IFA_F_DEPRECATED: u32 = 32;\npub const IFA_F_TENTATIVE: u32 = 64;\npub const IFA_F_PERMANENT: u32 = 128;\npub const IFA_F_MANAGETEMPADDR: u32 = 256;\npub const IFA_F_NOPREFIXROUTE: u32 = 512;\npub const IFA_F_MCAUTOJOIN: u32 = 1024;\npub const IFA_F_STABLE_PRIVACY: u32 = 2048;\n\n// pub const RTNL_FAMILY_IPMR: int = 128;\n// pub const RTNL_FAMILY_IP6MR: int = 129;\n// pub const RTNL_FAMILY_MAX: int = 129;\n// pub const RTA_ALIGNTO: int = 4;\n//\npub const RTNH_F_DEAD: u8 = 1;\npub const RTNH_F_PERVASIVE: u8 = 2;\npub const RTNH_F_ONLINK: u8 = 4;\npub const RTNH_F_OFFLOAD: u8 = 8;\npub const RTNH_F_LINKDOWN: u8 = 16;\npub const RTNH_F_UNRESOLVED: u8 = 32;\n// pub const RTNH_COMPARE_MASK: int = 25;\n// pub const RTNH_ALIGNTO: int = 4;\n// pub const RTNETLINK_HAVE_PEERINFO: int = 1;\n// pub const RTAX_FEATURE_ECN: int = 1;\n// pub const RTAX_FEATURE_SACK: int = 2;\n// pub const RTAX_FEATURE_TIMESTAMP: int = 4;\n// pub const RTAX_FEATURE_ALLFRAG: int = 8;\n// pub const RTAX_FEATURE_MASK: int = 15;\npub const TCM_IFINDEX_MAGIC_BLOCK: u32 = 0xffff_ffff;\n// pub const TCA_FLAG_LARGE_DUMP_ON: int = 1;\n\npub const RTEXT_FILTER_VF: u32 = 1;\npub const RTEXT_FILTER_BRVLAN: u32 = 2;\npub const RTEXT_FILTER_BRVLAN_COMPRESSED: u32 = 4;\npub const RTEXT_FILTER_SKIP_STATS: u32 = 8;\n\n// pub const ARPOP_REQUEST: int = 1;\n// pub const ARPOP_REPLY: int = 2;\n//\n// pub const IN6_ADDR_GEN_MODE_EUI64: int = 0;\n// pub const IN6_ADDR_GEN_MODE_NONE: int = 1;\n// pub const IN6_ADDR_GEN_MODE_STABLE_PRIVACY: int = 2;\n// pub const IN6_ADDR_GEN_MODE_RANDOM: int = 3;\n//\n// pub const BRIDGE_MODE_UNSPEC: int = 0;\n// pub const BRIDGE_MODE_HAIRPIN: int = 1;\n//\n// pub const IFLA_BRPORT_UNSPEC: int = 0;\n// pub const IFLA_BRPORT_STATE: int = 1;\n// pub const IFLA_BRPORT_PRIORITY: int = 2;\n// pub const IFLA_BRPORT_COST: int = 3;\n// pub const IFLA_BRPORT_MODE: int = 4;\n// pub const IFLA_BRPORT_GUARD: int = 5;\n// pub const IFLA_BRPORT_PROTECT: int = 6;\n// pub const IFLA_BRPORT_FAST_LEAVE: int = 7;\n// pub const IFLA_BRPORT_LEARNING: int = 8;\n// pub const IFLA_BRPORT_UNICAST_FLOOD: int = 9;\n// pub const IFLA_BRPORT_PROXYARP: int = 10;\n// pub const IFLA_BRPORT_LEARNING_SYNC: int = 11;\n// pub const IFLA_BRPORT_PROXYARP_WIFI: int = 12;\n// pub const IFLA_BRPORT_ROOT_ID: int = 13;\n// pub const IFLA_BRPORT_BRIDGE_ID: int = 14;\n// pub const IFLA_BRPORT_DESIGNATED_PORT: int = 15;\n// pub const IFLA_BRPORT_DESIGNATED_COST: int = 16;\n// pub const IFLA_BRPORT_ID: int = 17;\n// pub const IFLA_BRPORT_NO: int = 18;\n// pub const IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: int = 19;\n// pub const IFLA_BRPORT_CONFIG_PENDING: int = 20;\n// pub const IFLA_BRPORT_MESSAGE_AGE_TIMER: int = 21;\n// pub const IFLA_BRPORT_FORWARD_DELAY_TIMER: int = 22;\n// pub const IFLA_BRPORT_HOLD_TIMER: int = 23;\n// pub const IFLA_BRPORT_FLUSH: int = 24;\n// pub const IFLA_BRPORT_MULTICAST_ROUTER: int = 25;\n// pub const IFLA_BRPORT_PAD: int = 26;\n// pub const IFLA_BRPORT_MCAST_FLOOD: int = 27;\n// pub const IFLA_BRPORT_MCAST_TO_UCAST: int = 28;\n// pub const IFLA_BRPORT_VLAN_TUNNEL: int = 29;\n// pub const IFLA_BRPORT_BCAST_FLOOD: int = 30;\n// pub const IFLA_BRPORT_GROUP_FWD_MASK: int = 31;\n// pub const IFLA_BRPORT_NEIGH_SUPPRESS: int = 32;\n//\n// pub const IFLA_VLAN_QOS_UNSPEC: int = 0;\n// pub const IFLA_VLAN_QOS_MAPPING: int = 1;\n//\n// pub const IFLA_MACVLAN_UNSPEC: int = 0;\n// pub const IFLA_MACVLAN_MODE: int = 1;\n// pub const IFLA_MACVLAN_FLAGS: int = 2;\n// pub const IFLA_MACVLAN_MACADDR_MODE: int = 3;\n// pub const IFLA_MACVLAN_MACADDR: int = 4;\n// pub const IFLA_MACVLAN_MACADDR_DATA: int = 5;\n// pub const IFLA_MACVLAN_MACADDR_COUNT: int = 6;\n//\n// Available MACVLAN MODES\npub const MACVLAN_MODE_PRIVATE: u32 = 1;\npub const MACVLAN_MODE_VEPA: u32 = 2;\npub const MACVLAN_MODE_BRIDGE: u32 = 4;\npub const MACVLAN_MODE_PASSTHRU: u32 = 8;\npub const MACVLAN_MODE_SOURCE: u32 = 16;\n//\n// pub const MACVLAN_MACADDR_ADD: int = 0;\n// pub const MACVLAN_MACADDR_DEL: int = 1;\n// pub const MACVLAN_MACADDR_FLUSH: int = 2;\n// pub const MACVLAN_MACADDR_SET: int = 3;\n//\n// pub const IFLA_VRF_UNSPEC: int = 0;\n// pub const IFLA_VRF_TABLE: int = 1;\n//\n// pub const IFLA_VRF_PORT_UNSPEC: int = 0;\n// pub const IFLA_VRF_PORT_TABLE: int = 1;\n//\n// pub const IFLA_MACSEC_UNSPEC: int = 0;\n// pub const IFLA_MACSEC_SCI: int = 1;\n// pub const IFLA_MACSEC_PORT: int = 2;\n// pub const IFLA_MACSEC_ICV_LEN: int = 3;\n// pub const IFLA_MACSEC_CIPHER_SUITE: int = 4;\n// pub const IFLA_MACSEC_WINDOW: int = 5;\n// pub const IFLA_MACSEC_ENCODING_SA: int = 6;\n// pub const IFLA_MACSEC_ENCRYPT: int = 7;\n// pub const IFLA_MACSEC_PROTECT: int = 8;\n// pub const IFLA_MACSEC_INC_SCI: int = 9;\n// pub const IFLA_MACSEC_ES: int = 10;\n// pub const IFLA_MACSEC_SCB: int = 11;\n// pub const IFLA_MACSEC_REPLAY_PROTECT: int = 12;\n// pub const IFLA_MACSEC_VALIDATION: int = 13;\n// pub const IFLA_MACSEC_PAD: int = 14;\n//\n// pub const MACSEC_VALIDATE_DISABLED: int = 0;\n// pub const MACSEC_VALIDATE_CHECK: int = 1;\n// pub const MACSEC_VALIDATE_STRICT: int = 2;\n// pub const MACSEC_VALIDATE_MAX: int = 2;\n//\n// pub const IFLA_IPVLAN_UNSPEC: int = 0;\n// pub const IFLA_IPVLAN_MODE: int = 1;\n// pub const IFLA_IPVLAN_FLAGS: int = 2;\n//\n// pub const IPVLAN_MODE_L2: int = 0;\n// pub const IPVLAN_MODE_L3: int = 1;\n// pub const IPVLAN_MODE_L3S: int = 2;\n// pub const IPVLAN_MODE_MAX: int = 3;\n//\n// FROM https://elixir.bootlin.com/linux/v5.9.8/source/include/uapi/linux/if_link.h#L531\npub const IFLA_VXLAN_UNSPEC: u16 = 0;\npub const IFLA_VXLAN_ID: u16 = 1;\npub const IFLA_VXLAN_GROUP: u16 = 2;\npub const IFLA_VXLAN_LINK: u16 = 3;\npub const IFLA_VXLAN_LOCAL: u16 = 4;\npub const IFLA_VXLAN_TTL: u16 = 5;\npub const IFLA_VXLAN_TOS: u16 = 6;\npub const IFLA_VXLAN_LEARNING: u16 = 7;\npub const IFLA_VXLAN_AGEING: u16 = 8;\npub const IFLA_VXLAN_LIMIT: u16 = 9;\npub const IFLA_VXLAN_PORT_RANGE: u16 = 10;\npub const IFLA_VXLAN_PROXY: u16 = 11;\npub const IFLA_VXLAN_RSC: u16 = 12;\npub const IFLA_VXLAN_L2MISS: u16 = 13;\npub const IFLA_VXLAN_L3MISS: u16 = 14;\npub const IFLA_VXLAN_PORT: u16 = 15;\npub const IFLA_VXLAN_GROUP6: u16 = 16;\npub const IFLA_VXLAN_LOCAL6: u16 = 17;\npub const IFLA_VXLAN_UDP_CSUM: u16 = 18;\npub const IFLA_VXLAN_UDP_ZERO_CSUM6_TX: u16 = 19;\npub const IFLA_VXLAN_UDP_ZERO_CSUM6_RX: u16 = 20;\npub const IFLA_VXLAN_REMCSUM_TX: u16 = 21;\npub const IFLA_VXLAN_REMCSUM_RX: u16 = 22;\npub const IFLA_VXLAN_GBP: u16 = 23;\npub const IFLA_VXLAN_REMCSUM_NOPARTIAL: u16 = 24;\npub const IFLA_VXLAN_COLLECT_METADATA: u16 = 25;\npub const IFLA_VXLAN_LABEL: u16 = 26;\npub const IFLA_VXLAN_GPE: u16 = 27;\npub const IFLA_VXLAN_TTL_INHERIT: u16 = 28;\npub const IFLA_VXLAN_DF: u16 = 29;\npub const __IFLA_VXLAN_MAX: u16 = 30;\n//\n// pub const IFLA_GENEVE_UNSPEC: int = 0;\n// pub const IFLA_GENEVE_ID: int = 1;\n// pub const IFLA_GENEVE_REMOTE: int = 2;\n// pub const IFLA_GENEVE_TTL: int = 3;\n// pub const IFLA_GENEVE_TOS: int = 4;\n// pub const IFLA_GENEVE_PORT: int = 5;\n// pub const IFLA_GENEVE_COLLECT_METADATA: int = 6;\n// pub const IFLA_GENEVE_REMOTE6: int = 7;\n// pub const IFLA_GENEVE_UDP_CSUM: int = 8;\n// pub const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: int = 9;\n// pub const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: int = 10;\n// pub const IFLA_GENEVE_LABEL: int = 11;\n//\n// pub const IFLA_PPP_UNSPEC: int = 0;\n// pub const IFLA_PPP_DEV_FD: int = 1;\n//\n// pub const GTP_ROLE_GGSN: int = 0;\n// pub const GTP_ROLE_SGSN: int = 1;\n//\n// pub const IFLA_GTP_UNSPEC: int = 0;\n// pub const IFLA_GTP_FD0: int = 1;\n// pub const IFLA_GTP_FD1: int = 2;\n// pub const IFLA_GTP_PDP_HASHSIZE: int = 3;\n// pub const IFLA_GTP_ROLE: int = 4;\n\npub const IFLA_BOND_UNSPEC: u16 = 0;\npub const IFLA_BOND_MODE: u16 = 1;\npub const IFLA_BOND_ACTIVE_SLAVE: u16 = 2;\npub const IFLA_BOND_MIIMON: u16 = 3;\npub const IFLA_BOND_UPDELAY: u16 = 4;\npub const IFLA_BOND_DOWNDELAY: u16 = 5;\npub const IFLA_BOND_USE_CARRIER: u16 = 6;\npub const IFLA_BOND_ARP_INTERVAL: u16 = 7;\npub const IFLA_BOND_ARP_IP_TARGET: u16 = 8;\npub const IFLA_BOND_ARP_VALIDATE: u16 = 9;\npub const IFLA_BOND_ARP_ALL_TARGETS: u16 = 10;\npub const IFLA_BOND_PRIMARY: u16 = 11;\npub const IFLA_BOND_PRIMARY_RESELECT: u16 = 12;\npub const IFLA_BOND_FAIL_OVER_MAC: u16 = 13;\npub const IFLA_BOND_XMIT_HASH_POLICY: u16 = 14;\npub const IFLA_BOND_RESEND_IGMP: u16 = 15;\npub const IFLA_BOND_NUM_PEER_NOTIF: u16 = 16;\npub const IFLA_BOND_ALL_SLAVES_ACTIVE: u16 = 17;\npub const IFLA_BOND_MIN_LINKS: u16 = 18;\npub const IFLA_BOND_LP_INTERVAL: u16 = 19;\npub const IFLA_BOND_PACKETS_PER_SLAVE: u16 = 20;\npub const IFLA_BOND_AD_LACP_RATE: u16 = 21;\npub const IFLA_BOND_AD_SELECT: u16 = 22;\npub const IFLA_BOND_AD_INFO: u16 = 23;\npub const IFLA_BOND_AD_ACTOR_SYS_PRIO: u16 = 24;\npub const IFLA_BOND_AD_USER_PORT_KEY: u16 = 25;\npub const IFLA_BOND_AD_ACTOR_SYSTEM: u16 = 26;\npub const IFLA_BOND_TLB_DYNAMIC_LB: u16 = 27;\npub const IFLA_BOND_PEER_NOTIF_DELAY: u16 = 28;\npub const IFLA_BOND_AD_LACP_ACTIVE: u16 = 29;\npub const IFLA_BOND_MISSED_MAX: u16 = 30;\npub const IFLA_BOND_NS_IP6_TARGET: u16 = 31;\n\npub const IFLA_BOND_AD_INFO_UNSPEC: u16 = 0;\npub const IFLA_BOND_AD_INFO_AGGREGATOR: u16 = 1;\npub const IFLA_BOND_AD_INFO_NUM_PORTS: u16 = 2;\npub const IFLA_BOND_AD_INFO_ACTOR_KEY: u16 = 3;\npub const IFLA_BOND_AD_INFO_PARTNER_KEY: u16 = 4;\npub const IFLA_BOND_AD_INFO_PARTNER_MAC: u16 = 5;\n\n// pub const IFLA_BOND_SLAVE_UNSPEC: int = 0;\n// pub const IFLA_BOND_SLAVE_STATE: int = 1;\n// pub const IFLA_BOND_SLAVE_MII_STATUS: int = 2;\n// pub const IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: int = 3;\n// pub const IFLA_BOND_SLAVE_PERM_HWADDR: int = 4;\n// pub const IFLA_BOND_SLAVE_QUEUE_ID: int = 5;\n// pub const IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: int = 6;\n// pub const IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: int = 7;\n// pub const IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: int = 8;\n//\n// pub const IFLA_VF_INFO_UNSPEC: int = 0;\n// pub const IFLA_VF_INFO: int = 1;\n//\n// pub const IFLA_VF_UNSPEC: int = 0;\n// pub const IFLA_VF_MAC: int = 1;\n// pub const IFLA_VF_VLAN: int = 2;\n// pub const IFLA_VF_TX_RATE: int = 3;\n// pub const IFLA_VF_SPOOFCHK: int = 4;\n// pub const IFLA_VF_LINK_STATE: int = 5;\n// pub const IFLA_VF_RATE: int = 6;\n// pub const IFLA_VF_RSS_QUERY_EN: int = 7;\n// pub const IFLA_VF_STATS: int = 8;\n// pub const IFLA_VF_TRUST: int = 9;\n// pub const IFLA_VF_IB_NODE_GUID: int = 10;\n// pub const IFLA_VF_IB_PORT_GUID: int = 11;\n// pub const IFLA_VF_VLAN_LIST: int = 12;\n//\n// pub const IFLA_VF_VLAN_INFO_UNSPEC: int = 0;\n// pub const IFLA_VF_VLAN_INFO: int = 1;\n//\n// pub const NDUSEROPT_UNSPEC: int = 0;\n// pub const NDUSEROPT_SRCADDR: int = 1;\n//\npub const RTNLGRP_NONE: u32 = 0;\npub const RTNLGRP_LINK: u32 = 1;\npub const RTNLGRP_NOTIFY: u32 = 2;\npub const RTNLGRP_NEIGH: u32 = 3;\npub const RTNLGRP_TC: u32 = 4;\npub const RTNLGRP_IPV4_IFADDR: u32 = 5;\npub const RTNLGRP_IPV4_MROUTE: u32 = 6;\npub const RTNLGRP_IPV4_ROUTE: u32 = 7;\npub const RTNLGRP_IPV4_RULE: u32 = 8;\npub const RTNLGRP_IPV6_IFADDR: u32 = 9;\npub const RTNLGRP_IPV6_MROUTE: u32 = 10;\npub const RTNLGRP_IPV6_ROUTE: u32 = 11;\npub const RTNLGRP_IPV6_IFINFO: u32 = 12;\npub const RTNLGRP_DECNET_IFADDR: u32 = 13;\npub const RTNLGRP_NOP2: u32 = 14;\npub const RTNLGRP_DECNET_ROUTE: u32 = 15;\npub const RTNLGRP_DECNET_RULE: u32 = 16;\npub const RTNLGRP_NOP4: u32 = 17;\npub const RTNLGRP_IPV6_PREFIX: u32 = 18;\npub const RTNLGRP_IPV6_RULE: u32 = 19;\npub const RTNLGRP_ND_USEROPT: u32 = 20;\npub const RTNLGRP_PHONET_IFADDR: u32 = 21;\npub const RTNLGRP_PHONET_ROUTE: u32 = 22;\npub const RTNLGRP_DCB: u32 = 23;\npub const RTNLGRP_IPV4_NETCONF: u32 = 24;\npub const RTNLGRP_IPV6_NETCONF: u32 = 25;\npub const RTNLGRP_MDB: u32 = 26;\npub const RTNLGRP_MPLS_ROUTE: u32 = 27;\npub const RTNLGRP_NSID: u32 = 28;\npub const RTNLGRP_MPLS_NETCONF: u32 = 29;\npub const RTNLGRP_IPV4_MROUTE_R: u32 = 30;\npub const RTNLGRP_IPV6_MROUTE_R: u32 = 31;\n//\n// pub const IFLA_VF_LINK_STATE_AUTO: int = 0;\n// pub const IFLA_VF_LINK_STATE_ENABLE: int = 1;\n// pub const IFLA_VF_LINK_STATE_DISABLE: int = 2;\n//\n// pub const IFLA_VF_STATS_RX_PACKETS: int = 0;\n// pub const IFLA_VF_STATS_TX_PACKETS: int = 1;\n// pub const IFLA_VF_STATS_RX_BYTES: int = 2;\n// pub const IFLA_VF_STATS_TX_BYTES: int = 3;\n// pub const IFLA_VF_STATS_BROADCAST: int = 4;\n// pub const IFLA_VF_STATS_MULTICAST: int = 5;\n// pub const IFLA_VF_STATS_PAD: int = 6;\n// pub const IFLA_VF_STATS_RX_DROPPED: int = 7;\n// pub const IFLA_VF_STATS_TX_DROPPED: int = 8;\n//\n// pub const IFLA_VF_PORT_UNSPEC: int = 0;\n// pub const IFLA_VF_PORT: int = 1;\n//\n// pub const IFLA_PORT_UNSPEC: int = 0;\n// pub const IFLA_PORT_VF: int = 1;\n// pub const IFLA_PORT_PROFILE: int = 2;\n// pub const IFLA_PORT_VSI_TYPE: int = 3;\n// pub const IFLA_PORT_INSTANCE_UUID: int = 4;\n// pub const IFLA_PORT_HOST_UUID: int = 5;\n// pub const IFLA_PORT_REQUEST: int = 6;\n// pub const IFLA_PORT_RESPONSE: int = 7;\n//\n// pub const PORT_REQUEST_PREASSOCIATE: int = 0;\n// pub const PORT_REQUEST_PREASSOCIATE_RR: int = 1;\n// pub const PORT_REQUEST_ASSOCIATE: int = 2;\n// pub const PORT_REQUEST_DISASSOCIATE: int = 3;\n//\n// pub const PORT_VDP_RESPONSE_SUCCESS: int = 0;\n// pub const PORT_VDP_RESPONSE_INVALID_FORMAT: int = 1;\n// pub const PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES: int = 2;\n// pub const PORT_VDP_RESPONSE_UNUSED_VTID: int = 3;\n// pub const PORT_VDP_RESPONSE_VTID_VIOLATION: int = 4;\n// pub const PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION: int = 5;\n// pub const PORT_VDP_RESPONSE_OUT_OF_SYNC: int = 6;\n// pub const PORT_PROFILE_RESPONSE_SUCCESS: int = 256;\n// pub const PORT_PROFILE_RESPONSE_INPROGRESS: int = 257;\n// pub const PORT_PROFILE_RESPONSE_INVALID: int = 258;\n// pub const PORT_PROFILE_RESPONSE_BADSTATE: int = 259;\n// pub const PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES: int = 260;\n// pub const PORT_PROFILE_RESPONSE_ERROR: int = 261;\n//\n// pub const IFLA_IPOIB_UNSPEC: int = 0;\n// pub const IFLA_IPOIB_PKEY: int = 1;\n// pub const IFLA_IPOIB_MODE: int = 2;\n// pub const IFLA_IPOIB_UMCAST: int = 3;\n//\n// pub const IPOIB_MODE_DATAGRAM: int = 0;\n// pub const IPOIB_MODE_CONNECTED: int = 1;\n//\n// pub const IFLA_HSR_UNSPEC: int = 0;\n// pub const IFLA_HSR_SLAVE1: int = 1;\n// pub const IFLA_HSR_SLAVE2: int = 2;\n// pub const IFLA_HSR_MULTICAST_SPEC: int = 3;\n// pub const IFLA_HSR_SUPERVISION_ADDR: int = 4;\n// pub const IFLA_HSR_SEQ_NR: int = 5;\n// pub const IFLA_HSR_VERSION: int = 6;\n//\n// pub const IFLA_STATS_UNSPEC: int = 0;\n// pub const IFLA_STATS_LINK_64: int = 1;\n// pub const IFLA_STATS_LINK_XSTATS: int = 2;\n// pub const IFLA_STATS_LINK_XSTATS_SLAVE: int = 3;\n// pub const IFLA_STATS_LINK_OFFLOAD_XSTATS: int = 4;\n// pub const IFLA_STATS_AF_SPEC: int = 5;\n//\n// pub const LINK_XSTATS_TYPE_UNSPEC: int = 0;\n// pub const LINK_XSTATS_TYPE_BRIDGE: int = 1;\n//\n// pub const IFLA_OFFLOAD_XSTATS_UNSPEC: int = 0;\n// pub const IFLA_OFFLOAD_XSTATS_CPU_HIT: int = 1;\n//\n// pub const XDP_ATTACHED_NONE: int = 0;\n// pub const XDP_ATTACHED_DRV: int = 1;\n// pub const XDP_ATTACHED_SKB: int = 2;\n// pub const XDP_ATTACHED_HW: int = 3;\n\npub const IFLA_XDP_UNSPEC: u32 = 0;\npub const IFLA_XDP_FD: u32 = 1;\npub const IFLA_XDP_ATTACHED: u32 = 2;\npub const IFLA_XDP_FLAGS: u32 = 3;\npub const IFLA_XDP_PROG_ID: u32 = 4;\n\n// pub const IFLA_EVENT_NONE: int = 0;\n// pub const IFLA_EVENT_REBOOT: int = 1;\n// pub const IFLA_EVENT_FEATURES: int = 2;\n// pub const IFLA_EVENT_BONDING_FAILOVER: int = 3;\n// pub const IFLA_EVENT_NOTIFY_PEERS: int = 4;\n// pub const IFLA_EVENT_IGMP_RESEND: int = 5;\n// pub const IFLA_EVENT_BONDING_OPTIONS: int = 6;\n//\n// pub const NDTPA_UNSPEC: int = 0;\n// pub const NDTPA_IFINDEX: int = 1;\n// pub const NDTPA_REFCNT: int = 2;\n// pub const NDTPA_REACHABLE_TIME: int = 3;\n// pub const NDTPA_BASE_REACHABLE_TIME: int = 4;\n// pub const NDTPA_RETRANS_TIME: int = 5;\n// pub const NDTPA_GC_STALETIME: int = 6;\n// pub const NDTPA_DELAY_PROBE_TIME: int = 7;\n// pub const NDTPA_QUEUE_LEN: int = 8;\n// pub const NDTPA_APP_PROBES: int = 9;\n// pub const NDTPA_UCAST_PROBES: int = 10;\n// pub const NDTPA_MCAST_PROBES: int = 11;\n// pub const NDTPA_ANYCAST_DELAY: int = 12;\n// pub const NDTPA_PROXY_DELAY: int = 13;\n// pub const NDTPA_PROXY_QLEN: int = 14;\n// pub const NDTPA_LOCKTIME: int = 15;\n// pub const NDTPA_QUEUE_LENBYTES: int = 16;\n// pub const NDTPA_MCAST_REPROBES: int = 17;\n// pub const NDTPA_PAD: int = 18;\n//\n// #[allow(overflowing_literals)]\n// pub const RT_TABLE_MAX: int = 0xffff_ffff;\n//\n// pub const PREFIX_UNSPEC: int = 0;\n// pub const PREFIX_ADDRESS: int = 1;\n// pub const PREFIX_CACHEINFO: int = 2;\n\npub const LWTUNNEL_ENCAP_NONE: u16 = 0;\npub const LWTUNNEL_ENCAP_MPLS: u16 = 1;\npub const LWTUNNEL_ENCAP_IP: u16 = 2;\npub const LWTUNNEL_ENCAP_ILA: u16 = 3;\npub const LWTUNNEL_ENCAP_IP6: u16 = 4;\npub const LWTUNNEL_ENCAP_SEG6: u16 = 5;\npub const LWTUNNEL_ENCAP_BPF: u16 = 6;\npub const LWTUNNEL_ENCAP_SEG6_LOCAL: u16 = 7;\npub const LWTUNNEL_ENCAP_RPL: u16 = 8;\n\npub const MPLS_IPTUNNEL_UNSPEC: u16 = 0;\npub const MPLS_IPTUNNEL_DST: u16 = 1;\npub const MPLS_IPTUNNEL_TTL: u16 = 2;\n\n// Available MACVTAP MODES\npub const MACVTAP_MODE_PRIVATE: u32 = 1;\npub const MACVTAP_MODE_VEPA: u32 = 2;\npub const MACVTAP_MODE_BRIDGE: u32 = 4;\npub const MACVTAP_MODE_PASSTHRU: u32 = 8;\npub const MACVTAP_MODE_SOURCE: u32 = 16;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const LINK_HEADER_LEN: usize = 16;\n\nbuffer!(LinkMessageBuffer(LINK_HEADER_LEN) {\n    interface_family: (u8, 0),\n    reserved_1: (u8, 1),\n    link_layer_type: (u16, 2..4),\n    link_index: (u32, 4..8),\n    flags: (u32, 8..12),\n    change_mask: (u32, 12..LINK_HEADER_LEN),\n    payload: (slice, LINK_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> LinkMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n    LinkMessageBuffer,\n    LINK_HEADER_LEN,\n};\n\n/// High level representation of `RTM_GETLINK`, `RTM_SETLINK`, `RTM_NEWLINK` and `RTM_DELLINK`\n/// messages headers.\n///\n/// These headers have the following structure:\n///\n/// ```no_rust\n/// 0                8                16              24               32\n/// +----------------+----------------+----------------+----------------+\n/// |interface family|    reserved    |         link layer type         |\n/// +----------------+----------------+----------------+----------------+\n/// |                             link index                            |\n/// +----------------+----------------+----------------+----------------+\n/// |                               flags                               |\n/// +----------------+----------------+----------------+----------------+\n/// |                            change mask                            |\n/// +----------------+----------------+----------------+----------------+\n/// ```\n///\n/// `LinkHeader` exposes all these fields except for the \"reserved\" one.\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct LinkHeader {\n    /// Address family: one of the `AF_*` constants.\n    pub interface_family: u8,\n    /// Link index.\n    pub index: u32,\n    /// Link type. It should be set to one of the `ARPHRD_*`\n    /// constants. The most common value is `ARPHRD_ETHER` for\n    /// Ethernet.\n    pub link_layer_type: u16,\n    /// State of the link, described by a combinations of `IFF_*`\n    /// constants, for instance `IFF_UP | IFF_LOWER_UP`.\n    pub flags: u32,\n    /// Change mask for the `flags` field. Reserved, it should be set\n    /// to `0xffff_ffff`.\n    pub change_mask: u32,\n}\n\nimpl Emitable for LinkHeader {\n    fn buffer_len(&self) -> usize {\n        LINK_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = LinkMessageBuffer::new(buffer);\n        packet.set_interface_family(self.interface_family);\n        packet.set_link_index(self.index);\n        packet.set_change_mask(self.change_mask);\n        packet.set_link_layer_type(self.link_layer_type);\n        packet.set_flags(self.flags);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<LinkMessageBuffer<T>> for LinkHeader {\n    fn parse(buf: &LinkMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            interface_family: buf.interface_family(),\n            link_layer_type: buf.link_layer_type(),\n            index: buf.link_index(),\n            change_mask: buf.change_mask(),\n            flags: buf.flags(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    nlas::link::Nla,\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n    LinkHeader,\n    LinkMessageBuffer,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct LinkMessage {\n    pub header: LinkHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl Emitable for LinkMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<LinkMessageBuffer<&'a T>> for LinkMessage {\n    fn parse(buf: &LinkMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let header = LinkHeader::parse(buf).context(\"failed to parse link message header\")?;\n        let interface_family = header.interface_family;\n        let nlas = Vec::<Nla>::parse_with_param(buf, interface_family)\n            .context(\"failed to parse link message NLAs\")?;\n        Ok(LinkMessage { header, nlas })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<LinkMessageBuffer<&'a T>, u16> for Vec<Nla> {\n    fn parse_with_param(buf: &LinkMessageBuffer<&'a T>, family: u16) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse_with_param(&nla_buf?, family)?);\n        }\n        Ok(nlas)\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<LinkMessageBuffer<&'a T>, u8> for Vec<Nla> {\n    fn parse_with_param(buf: &LinkMessageBuffer<&'a T>, family: u8) -> Result<Self, DecodeError> {\n        Vec::<Nla>::parse_with_param(buf, u16::from(family))\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::{\n        constants::*,\n        nlas::link::{Nla, State},\n        traits::{Emitable, ParseableParametrized},\n        LinkHeader,\n        LinkMessage,\n        LinkMessageBuffer,\n    };\n\n    #[rustfmt::skip]\n    static HEADER: [u8; 96] = [\n        0x00, // interface family\n        0x00, // reserved\n        0x04, 0x03, // link layer type 772 = loopback\n        0x01, 0x00, 0x00, 0x00, // interface index = 1\n        // Note: in the wireshark capture, the thrid byte is 0x01\n        // but that does not correpond to any of the IFF_ flags...\n        0x49, 0x00, 0x00, 0x00, // device flags: UP, LOOPBACK, RUNNING, LOWERUP\n        0x00, 0x00, 0x00, 0x00, // reserved 2 (aka device change flag)\n\n        // nlas\n        0x07, 0x00, 0x03, 0x00, 0x6c, 0x6f, 0x00, // device name L=7,T=3,V=lo\n        0x00, // padding\n        0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00, // TxQueue length L=8,T=13,V=1000\n        0x05, 0x00, 0x10, 0x00, 0x00, // OperState L=5,T=16,V=0 (unknown)\n        0x00, 0x00, 0x00, // padding\n        0x05, 0x00, 0x11, 0x00, 0x00, // Link mode L=5,T=17,V=0\n        0x00, 0x00, 0x00, // padding\n        0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, // MTU L=8,T=4,V=65536\n        0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, // Group L=8,T=27,V=9\n        0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, // Promiscuity L=8,T=30,V=0\n        0x08, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, // Number of Tx Queues L=8,T=31,V=1\n        0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00, 0x00, // Maximum GSO segment count L=8,T=40,V=65536\n        0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, // Maximum GSO size L=8,T=41,V=65536\n    ];\n\n    #[test]\n    fn packet_header_read() {\n        let packet = LinkMessageBuffer::new(&HEADER[0..16]);\n        assert_eq!(packet.interface_family(), 0);\n        assert_eq!(packet.reserved_1(), 0);\n        assert_eq!(packet.link_layer_type(), ARPHRD_LOOPBACK);\n        assert_eq!(packet.link_index(), 1);\n        assert_eq!(packet.flags(), IFF_UP | IFF_LOOPBACK | IFF_RUNNING);\n        assert_eq!(packet.change_mask(), 0);\n    }\n\n    #[test]\n    fn packet_header_build() {\n        let mut buf = vec![0xff; 16];\n        {\n            let mut packet = LinkMessageBuffer::new(&mut buf);\n            packet.set_interface_family(0);\n            packet.set_reserved_1(0);\n            packet.set_link_layer_type(ARPHRD_LOOPBACK);\n            packet.set_link_index(1);\n            packet.set_flags(IFF_UP | IFF_LOOPBACK | IFF_RUNNING);\n            packet.set_change_mask(0);\n        }\n        assert_eq!(&buf[..], &HEADER[0..16]);\n    }\n\n    #[test]\n    fn packet_nlas_read() {\n        let packet = LinkMessageBuffer::new(&HEADER[..]);\n        assert_eq!(packet.nlas().count(), 10);\n        let mut nlas = packet.nlas();\n\n        // device name L=7,T=3,V=lo\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 7);\n        assert_eq!(nla.kind(), 3);\n        assert_eq!(nla.value(), &[0x6c, 0x6f, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::IfName(String::from(\"lo\")));\n\n        // TxQueue length L=8,T=13,V=1000\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 8);\n        assert_eq!(nla.kind(), 13);\n        assert_eq!(nla.value(), &[0xe8, 0x03, 0x00, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::TxQueueLen(1000));\n\n        // OperState L=5,T=16,V=0 (unknown)\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 5);\n        assert_eq!(nla.kind(), 16);\n        assert_eq!(nla.value(), &[0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::OperState(State::Unknown));\n\n        // Link mode L=5,T=17,V=0\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 5);\n        assert_eq!(nla.kind(), 17);\n        assert_eq!(nla.value(), &[0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::Mode(0));\n\n        // MTU L=8,T=4,V=65536\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 8);\n        assert_eq!(nla.kind(), 4);\n        assert_eq!(nla.value(), &[0x00, 0x00, 0x01, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::Mtu(65_536));\n\n        // 0x00, 0x00, 0x00, 0x00,\n        // Group L=8,T=27,V=9\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 8);\n        assert_eq!(nla.kind(), 27);\n        assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::Group(0));\n\n        // Promiscuity L=8,T=30,V=0\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 8);\n        assert_eq!(nla.kind(), 30);\n        assert_eq!(nla.value(), &[0x00, 0x00, 0x00, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::Promiscuity(0));\n\n        // Number of Tx Queues L=8,T=31,V=1\n        // 0x01, 0x00, 0x00, 0x00\n        let nla = nlas.next().unwrap().unwrap();\n        nla.check_buffer_length().unwrap();\n        assert_eq!(nla.length(), 8);\n        assert_eq!(nla.kind(), 31);\n        assert_eq!(nla.value(), &[0x01, 0x00, 0x00, 0x00]);\n        let parsed = Nla::parse_with_param(&nla, AF_INET).unwrap();\n        assert_eq!(parsed, Nla::NumTxQueues(1));\n    }\n\n    #[test]\n    fn emit() {\n        let header = LinkHeader {\n            link_layer_type: ARPHRD_LOOPBACK,\n            index: 1,\n            flags: IFF_UP | IFF_LOOPBACK | IFF_RUNNING | IFF_LOWER_UP,\n            ..Default::default()\n        };\n\n        let nlas = vec![\n            Nla::IfName(\"lo\".into()),\n            Nla::TxQueueLen(1000),\n            Nla::OperState(State::Unknown),\n            Nla::Mode(0),\n            Nla::Mtu(0x1_0000),\n            Nla::Group(0),\n            Nla::Promiscuity(0),\n            Nla::NumTxQueues(1),\n            Nla::GsoMaxSegs(0xffff),\n            Nla::GsoMaxSize(0x1_0000),\n        ];\n\n        let packet = LinkMessage { header, nlas };\n\n        let mut buf = vec![0; 96];\n\n        assert_eq!(packet.buffer_len(), 96);\n        packet.emit(&mut buf[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\nmod header;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, header::*, message::*};\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/af_spec_bridge.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::convert::TryFrom;\n\nuse anyhow::Context;\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::parse_u16,\n    traits::Parseable,\n    DecodeError,\n};\n\nuse byteorder::{ByteOrder, NativeEndian};\n\n#[derive(Clone, Eq, PartialEq, Debug)]\npub enum AfSpecBridge {\n    Flags(u16),\n    VlanInfo(BridgeVlanInfo),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for AfSpecBridge {\n    fn value_len(&self) -> usize {\n        use self::AfSpecBridge::*;\n        match *self {\n            VlanInfo(_) => 4,\n            Flags(_) => 2,\n            Other(ref nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::AfSpecBridge::*;\n        match *self {\n            Flags(value) => NativeEndian::write_u16(buffer, value),\n            VlanInfo(ref info) => {\n                (&mut buffer[..4]).copy_from_slice(<[u8; 4]>::from(info).as_slice())\n            }\n            Other(ref nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::AfSpecBridge::*;\n        match *self {\n            Flags(_) => IFLA_BRIDGE_FLAGS,\n            VlanInfo(_) => IFLA_BRIDGE_VLAN_INFO,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AfSpecBridge {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::AfSpecBridge::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_BRIDGE_VLAN_INFO => VlanInfo(\n                BridgeVlanInfo::try_from(payload).context(\"Invalid IFLA_BRIDGE_VLAN_INFO value\")?,\n            ),\n            IFLA_BRIDGE_FLAGS => {\n                Flags(parse_u16(payload).context(\"invalid IFLA_BRIDGE_FLAGS value\")?)\n            }\n            kind => Other(DefaultNla::parse(buf).context(format!(\"Unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]\npub struct BridgeVlanInfo {\n    pub flags: u16,\n    pub vid: u16,\n}\n\nimpl From<&BridgeVlanInfo> for [u8; 4] {\n    fn from(d: &BridgeVlanInfo) -> Self {\n        let mut ret = [0u8; 4];\n        NativeEndian::write_u16(&mut ret[0..2], d.flags);\n        NativeEndian::write_u16(&mut ret[2..4], d.vid);\n        ret\n    }\n}\n\nimpl TryFrom<&[u8]> for BridgeVlanInfo {\n    type Error = DecodeError;\n    fn try_from(raw: &[u8]) -> Result<Self, DecodeError> {\n        if raw.len() == 4 {\n            Ok(Self {\n                flags: parse_u16(&raw[0..2])\n                    .context(format!(\"Invalid IFLA_BRIDGE_VLAN_INFO value: {:?}\", raw))?,\n                vid: parse_u16(&raw[2..4])\n                    .context(format!(\"Invalid IFLA_BRIDGE_VLAN_INFO value: {:?}\", raw))?,\n            })\n        } else {\n            Err(DecodeError::from(format!(\n                \"Invalid IFLA_BRIDGE_VLAN_INFO value, expecting [u8;4], but got {:?}\",\n                raw\n            )))\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/af_spec_inet.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse super::{inet, inet6};\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer, NlasIterator},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Clone, Eq, PartialEq, Debug)]\npub enum AfSpecInet {\n    Unspec(Vec<u8>),\n    Unix(Vec<u8>),\n    Ax25(Vec<u8>),\n    Ipx(Vec<u8>),\n    AppleTalk(Vec<u8>),\n    Netrom(Vec<u8>),\n    Bridge(Vec<u8>),\n    AtmPvc(Vec<u8>),\n    X25(Vec<u8>),\n    Inet(Vec<inet::Inet>),\n    Inet6(Vec<inet6::Inet6>),\n    Rose(Vec<u8>),\n    DecNet(Vec<u8>),\n    NetbEui(Vec<u8>),\n    Security(Vec<u8>),\n    Key(Vec<u8>),\n    Netlink(Vec<u8>),\n    Packet(Vec<u8>),\n    Ash(Vec<u8>),\n    EcoNet(Vec<u8>),\n    AtmSvc(Vec<u8>),\n    Rds(Vec<u8>),\n    Sna(Vec<u8>),\n    Irda(Vec<u8>),\n    Pppox(Vec<u8>),\n    WanPipe(Vec<u8>),\n    Llc(Vec<u8>),\n    Can(Vec<u8>),\n    Tipc(Vec<u8>),\n    Bluetooth(Vec<u8>),\n    Iucv(Vec<u8>),\n    RxRpc(Vec<u8>),\n    Isdn(Vec<u8>),\n    Phonet(Vec<u8>),\n    Ieee802154(Vec<u8>),\n    Caif(Vec<u8>),\n    Alg(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for AfSpecInet {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::AfSpecInet::*;\n        match *self {\n            Unspec(ref bytes)\n                | Unix(ref bytes)\n                | Ax25(ref bytes)\n                | Ipx(ref bytes)\n                | AppleTalk(ref bytes)\n                | Netrom(ref bytes)\n                | Bridge(ref bytes)\n                | AtmPvc(ref bytes)\n                | X25(ref bytes)\n                | Rose(ref bytes)\n                | DecNet(ref bytes)\n                | NetbEui(ref bytes)\n                | Security(ref bytes)\n                | Key(ref bytes)\n                | Netlink(ref bytes)\n                | Packet(ref bytes)\n                | Ash(ref bytes)\n                | EcoNet(ref bytes)\n                | AtmSvc(ref bytes)\n                | Rds(ref bytes)\n                | Sna(ref bytes)\n                | Irda(ref bytes)\n                | Pppox(ref bytes)\n                | WanPipe(ref bytes)\n                | Llc(ref bytes)\n                | Can(ref bytes)\n                | Tipc(ref bytes)\n                | Bluetooth(ref bytes)\n                | Iucv(ref bytes)\n                | RxRpc(ref bytes)\n                | Isdn(ref bytes)\n                | Phonet(ref bytes)\n                | Ieee802154(ref bytes)\n                | Caif(ref bytes)\n                | Alg(ref bytes)\n                => bytes.len(),\n            Inet6(ref nlas) => nlas.as_slice().buffer_len(),\n            Inet(ref nlas) =>  nlas.as_slice().buffer_len(),\n            Other(ref nla) => nla.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::AfSpecInet::*;\n        match *self {\n            Unspec(ref bytes)\n                | Unix(ref bytes)\n                | Ax25(ref bytes)\n                | Ipx(ref bytes)\n                | AppleTalk(ref bytes)\n                | Netrom(ref bytes)\n                | Bridge(ref bytes)\n                | AtmPvc(ref bytes)\n                | X25(ref bytes)\n                | Rose(ref bytes)\n                | DecNet(ref bytes)\n                | NetbEui(ref bytes)\n                | Security(ref bytes)\n                | Key(ref bytes)\n                | Netlink(ref bytes)\n                | Packet(ref bytes)\n                | Ash(ref bytes)\n                | EcoNet(ref bytes)\n                | AtmSvc(ref bytes)\n                | Rds(ref bytes)\n                | Sna(ref bytes)\n                | Irda(ref bytes)\n                | Pppox(ref bytes)\n                | WanPipe(ref bytes)\n                | Llc(ref bytes)\n                | Can(ref bytes)\n                | Tipc(ref bytes)\n                | Bluetooth(ref bytes)\n                | Iucv(ref bytes)\n                | RxRpc(ref bytes)\n                | Isdn(ref bytes)\n                | Phonet(ref bytes)\n                | Ieee802154(ref bytes)\n                | Caif(ref bytes)\n                | Alg(ref bytes)\n                => buffer[..bytes.len()].copy_from_slice(bytes.as_slice()),\n            Inet6(ref nlas) => nlas.as_slice().emit(buffer),\n            Inet(ref nlas) => nlas.as_slice().emit(buffer),\n            Other(ref nla)  => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::AfSpecInet::*;\n        match *self {\n            Inet(_) => AF_INET,\n            Unspec(_) => AF_UNSPEC,\n            Unix(_) => AF_UNIX,\n            Ax25(_) => AF_AX25,\n            Ipx(_) => AF_IPX,\n            AppleTalk(_) => AF_APPLETALK,\n            Netrom(_) => AF_NETROM,\n            Bridge(_) => AF_BRIDGE,\n            AtmPvc(_) => AF_ATMPVC,\n            X25(_) => AF_X25,\n            Inet6(_) => AF_INET6,\n            Rose(_) => AF_ROSE,\n            DecNet(_) => AF_DECNET,\n            NetbEui(_) => AF_NETBEUI,\n            Security(_) => AF_SECURITY,\n            Key(_) => AF_KEY,\n            Netlink(_) => AF_NETLINK,\n            Packet(_) => AF_PACKET,\n            Ash(_) => AF_ASH,\n            EcoNet(_) => AF_ECONET,\n            AtmSvc(_) => AF_ATMSVC,\n            Rds(_) => AF_RDS,\n            Sna(_) => AF_SNA,\n            Irda(_) => AF_IRDA,\n            Pppox(_) => AF_PPPOX,\n            WanPipe(_) => AF_WANPIPE,\n            Llc(_) => AF_LLC,\n            Can(_) => AF_CAN,\n            Tipc(_) => AF_TIPC,\n            Bluetooth(_) => AF_BLUETOOTH,\n            Iucv(_) => AF_IUCV,\n            RxRpc(_) => AF_RXRPC,\n            Isdn(_) => AF_ISDN,\n            Phonet(_) => AF_PHONET,\n            Ieee802154(_) => AF_IEEE802154,\n            Caif(_) => AF_CAIF,\n            Alg(_) => AF_ALG,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for AfSpecInet {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::AfSpecInet::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            AF_UNSPEC => Unspec(payload.to_vec()),\n            AF_INET => {\n                let mut nlas = vec![];\n                for nla in NlasIterator::new(payload) {\n                    let nla = nla.context(\"invalid AF_INET value\")?;\n                    nlas.push(inet::Inet::parse(&nla).context(\"invalid AF_INET value\")?);\n                }\n                Inet(nlas)\n            }\n            AF_INET6 => {\n                let mut nlas = vec![];\n                for nla in NlasIterator::new(payload) {\n                    let nla = nla.context(\"invalid AF_INET6 value\")?;\n                    nlas.push(inet6::Inet6::parse(&nla).context(\"invalid AF_INET6 value\")?);\n                }\n                Inet6(nlas)\n            }\n            AF_UNIX => Unix(payload.to_vec()),\n            AF_AX25 => Ax25(payload.to_vec()),\n            AF_IPX => Ipx(payload.to_vec()),\n            AF_APPLETALK => AppleTalk(payload.to_vec()),\n            AF_NETROM => Netrom(payload.to_vec()),\n            AF_BRIDGE => Bridge(payload.to_vec()),\n            AF_ATMPVC => AtmPvc(payload.to_vec()),\n            AF_X25 => X25(payload.to_vec()),\n            AF_ROSE => Rose(payload.to_vec()),\n            AF_DECNET => DecNet(payload.to_vec()),\n            AF_NETBEUI => NetbEui(payload.to_vec()),\n            AF_SECURITY => Security(payload.to_vec()),\n            AF_KEY => Key(payload.to_vec()),\n            AF_NETLINK => Netlink(payload.to_vec()),\n            AF_PACKET => Packet(payload.to_vec()),\n            AF_ASH => Ash(payload.to_vec()),\n            AF_ECONET => EcoNet(payload.to_vec()),\n            AF_ATMSVC => AtmSvc(payload.to_vec()),\n            AF_RDS => Rds(payload.to_vec()),\n            AF_SNA => Sna(payload.to_vec()),\n            AF_IRDA => Irda(payload.to_vec()),\n            AF_PPPOX => Pppox(payload.to_vec()),\n            AF_WANPIPE => WanPipe(payload.to_vec()),\n            AF_LLC => Llc(payload.to_vec()),\n            AF_CAN => Can(payload.to_vec()),\n            AF_TIPC => Tipc(payload.to_vec()),\n            AF_BLUETOOTH => Bluetooth(payload.to_vec()),\n            AF_IUCV => Iucv(payload.to_vec()),\n            AF_RXRPC => RxRpc(payload.to_vec()),\n            AF_ISDN => Isdn(payload.to_vec()),\n            AF_PHONET => Phonet(payload.to_vec()),\n            AF_IEEE802154 => Ieee802154(payload.to_vec()),\n            AF_CAIF => Caif(payload.to_vec()),\n            AF_ALG => Alg(payload.to_vec()),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"Unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/bond.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    nlas::{Nla, NlaBuffer, NlasIterator},\n    parsers::{parse_ip, parse_mac, parse_u16, parse_u32, parse_u8},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse std::{\n    net::{IpAddr, Ipv4Addr, Ipv6Addr},\n    ops::Deref,\n};\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum BondAdInfo {\n    Aggregator(u16),\n    NumPorts(u16),\n    ActorKey(u16),\n    PartnerKey(u16),\n    PartnerMac([u8; 6]),\n}\n\nimpl Nla for BondAdInfo {\n    fn value_len(&self) -> usize {\n        use self::BondAdInfo::*;\n        match self {\n            Aggregator(_) | NumPorts(_) | ActorKey(_) | PartnerKey(_) => 2,\n            PartnerMac(_) => 6,\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::BondAdInfo::*;\n        match self {\n            Aggregator(_) => IFLA_BOND_AD_INFO_AGGREGATOR,\n            NumPorts(_) => IFLA_BOND_AD_INFO_NUM_PORTS,\n            ActorKey(_) => IFLA_BOND_AD_INFO_ACTOR_KEY,\n            PartnerKey(_) => IFLA_BOND_AD_INFO_PARTNER_KEY,\n            PartnerMac(_) => IFLA_BOND_AD_INFO_PARTNER_MAC,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::BondAdInfo::*;\n        match self {\n            Aggregator(d) | NumPorts(d) | ActorKey(d) | PartnerKey(d) => {\n                NativeEndian::write_u16(buffer, *d)\n            }\n            PartnerMac(mac) => buffer.copy_from_slice(mac),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for BondAdInfo {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::BondAdInfo::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_BOND_AD_INFO_AGGREGATOR => Aggregator(\n                parse_u16(payload).context(\"invalid IFLA_BOND_AD_INFO_AGGREGATOR value\")?,\n            ),\n            IFLA_BOND_AD_INFO_NUM_PORTS => {\n                NumPorts(parse_u16(payload).context(\"invalid IFLA_BOND_AD_INFO_NUM_PORTS value\")?)\n            }\n            IFLA_BOND_AD_INFO_ACTOR_KEY => {\n                ActorKey(parse_u16(payload).context(\"invalid IFLA_BOND_AD_INFO_ACTOR_KEY value\")?)\n            }\n            IFLA_BOND_AD_INFO_PARTNER_KEY => PartnerKey(\n                parse_u16(payload).context(\"invalid IFLA_BOND_AD_INFO_PARTNER_KEY value\")?,\n            ),\n            IFLA_BOND_AD_INFO_PARTNER_MAC => PartnerMac(\n                parse_mac(payload).context(\"invalid IFLA_BOND_AD_INFO_PARTNER_MAC value\")?,\n            ),\n            _ => return Err(format!(\"unknown NLA type {}\", buf.kind()).into()),\n        })\n    }\n}\n\n// Some attributes (ARP_IP_TARGET, NS_IP6_TARGET) contain a nested\n// list of IP addresses, where each element uses the index as NLA kind\n// and the address as value. InfoBond exposes vectors of IP addresses,\n// and we use this struct for serialization.\nstruct BondIpAddrNla {\n    index: u16,\n    addr: IpAddr,\n}\n\nstruct BondIpAddrNlaList(Vec<BondIpAddrNla>);\n\nimpl Deref for BondIpAddrNlaList {\n    type Target = Vec<BondIpAddrNla>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl From<&Vec<Ipv4Addr>> for BondIpAddrNlaList {\n    fn from(addrs: &Vec<Ipv4Addr>) -> Self {\n        let mut nlas = Vec::new();\n        for (i, addr) in addrs.iter().enumerate() {\n            let nla = BondIpAddrNla {\n                index: i as u16,\n                addr: IpAddr::V4(*addr),\n            };\n            nlas.push(nla);\n        }\n        BondIpAddrNlaList(nlas)\n    }\n}\n\nimpl From<&Vec<Ipv6Addr>> for BondIpAddrNlaList {\n    fn from(addrs: &Vec<Ipv6Addr>) -> Self {\n        let mut nlas = Vec::new();\n        for (i, addr) in addrs.iter().enumerate() {\n            let nla = BondIpAddrNla {\n                index: i as u16,\n                addr: IpAddr::V6(*addr),\n            };\n            nlas.push(nla);\n        }\n        BondIpAddrNlaList(nlas)\n    }\n}\n\nimpl Nla for BondIpAddrNla {\n    fn value_len(&self) -> usize {\n        if self.addr.is_ipv4() {\n            4\n        } else {\n            16\n        }\n    }\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self.addr {\n            IpAddr::V4(addr) => buffer.copy_from_slice(&addr.octets()),\n            IpAddr::V6(addr) => buffer.copy_from_slice(&addr.octets()),\n        }\n    }\n    fn kind(&self) -> u16 {\n        self.index\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoBond {\n    Mode(u8),\n    ActiveSlave(u32),\n    MiiMon(u32),\n    UpDelay(u32),\n    DownDelay(u32),\n    UseCarrier(u8),\n    ArpInterval(u32),\n    ArpIpTarget(Vec<Ipv4Addr>),\n    ArpValidate(u32),\n    ArpAllTargets(u32),\n    Primary(u32),\n    PrimaryReselect(u8),\n    FailOverMac(u8),\n    XmitHashPolicy(u8),\n    ResendIgmp(u32),\n    NumPeerNotif(u8),\n    AllSlavesActive(u8),\n    MinLinks(u32),\n    LpInterval(u32),\n    PacketsPerSlave(u32),\n    AdLacpRate(u8),\n    AdSelect(u8),\n    AdInfo(Vec<BondAdInfo>),\n    AdActorSysPrio(u16),\n    AdUserPortKey(u16),\n    AdActorSystem([u8; 6]),\n    TlbDynamicLb(u8),\n    PeerNotifDelay(u32),\n    AdLacpActive(u8),\n    MissedMax(u8),\n    NsIp6Target(Vec<Ipv6Addr>),\n}\n\nimpl Nla for InfoBond {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::InfoBond::*;\n        match *self {\n            Mode(_)\n                | UseCarrier(_)\n                | PrimaryReselect(_)\n                | FailOverMac(_)\n                | XmitHashPolicy(_)\n                | NumPeerNotif(_)\n                | AllSlavesActive(_)\n                | AdLacpActive(_)\n                | AdLacpRate(_)\n                | AdSelect(_)\n                | TlbDynamicLb(_)\n                | MissedMax(_)\n            => 1,\n            AdActorSysPrio(_)\n                | AdUserPortKey(_)\n            => 2,\n            ActiveSlave(_)\n                | MiiMon(_)\n                | UpDelay(_)\n                | DownDelay(_)\n                | ArpInterval(_)\n                | ArpValidate(_)\n                | ArpAllTargets(_)\n                | Primary(_)\n                | ResendIgmp(_)\n                | MinLinks(_)\n                | LpInterval(_)\n                | PacketsPerSlave(_)\n                | PeerNotifDelay(_)\n                => 4,\n            ArpIpTarget(ref addrs)\n                => {\n                    BondIpAddrNlaList::from(addrs).as_slice().buffer_len()\n                },\n            NsIp6Target(ref addrs)\n                =>  {\n                    BondIpAddrNlaList::from(addrs).as_slice().buffer_len()\n                },\n            AdActorSystem(_) => 6,\n            AdInfo(ref infos)\n            => infos.as_slice().buffer_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoBond::*;\n        match self {\n            Mode(value)\n                | UseCarrier(value)\n                | PrimaryReselect(value)\n                | FailOverMac(value)\n                | XmitHashPolicy(value)\n                | NumPeerNotif(value)\n                | AllSlavesActive(value)\n                | AdLacpActive(value)\n                | AdLacpRate(value)\n                | AdSelect(value)\n                | TlbDynamicLb(value)\n                | MissedMax(value)\n            => buffer[0] = *value,\n            AdActorSysPrio(value)\n                | AdUserPortKey(value)\n            => NativeEndian::write_u16(buffer, *value),\n            ActiveSlave(value)\n                | MiiMon(value)\n                | UpDelay(value)\n                | DownDelay(value)\n                | ArpInterval(value)\n                | ArpValidate(value)\n                | ArpAllTargets(value)\n                | Primary(value)\n                | ResendIgmp(value)\n                | MinLinks(value)\n                | LpInterval(value)\n                | PacketsPerSlave(value)\n                | PeerNotifDelay(value)\n             => NativeEndian::write_u32(buffer, *value),\n            AdActorSystem(bytes) => buffer.copy_from_slice(bytes),\n            ArpIpTarget(addrs) => {\n                BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)\n            },\n            NsIp6Target(addrs) => {\n                BondIpAddrNlaList::from(addrs).as_slice().emit(buffer)\n            },\n            AdInfo(infos) => infos.as_slice().emit(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoBond::*;\n\n        match self {\n            Mode(_) => IFLA_BOND_MODE,\n            ActiveSlave(_) => IFLA_BOND_ACTIVE_SLAVE,\n            MiiMon(_) => IFLA_BOND_MIIMON,\n            UpDelay(_) => IFLA_BOND_UPDELAY,\n            DownDelay(_) => IFLA_BOND_DOWNDELAY,\n            UseCarrier(_) => IFLA_BOND_USE_CARRIER,\n            ArpInterval(_) => IFLA_BOND_ARP_INTERVAL,\n            ArpIpTarget(_) => IFLA_BOND_ARP_IP_TARGET,\n            ArpValidate(_) => IFLA_BOND_ARP_VALIDATE,\n            ArpAllTargets(_) => IFLA_BOND_ARP_ALL_TARGETS,\n            Primary(_) => IFLA_BOND_PRIMARY,\n            PrimaryReselect(_) => IFLA_BOND_PRIMARY_RESELECT,\n            FailOverMac(_) => IFLA_BOND_FAIL_OVER_MAC,\n            XmitHashPolicy(_) => IFLA_BOND_XMIT_HASH_POLICY,\n            ResendIgmp(_) => IFLA_BOND_RESEND_IGMP,\n            NumPeerNotif(_) => IFLA_BOND_NUM_PEER_NOTIF,\n            AllSlavesActive(_) => IFLA_BOND_ALL_SLAVES_ACTIVE,\n            MinLinks(_) => IFLA_BOND_MIN_LINKS,\n            LpInterval(_) => IFLA_BOND_LP_INTERVAL,\n            PacketsPerSlave(_) => IFLA_BOND_PACKETS_PER_SLAVE,\n            AdLacpRate(_) => IFLA_BOND_AD_LACP_RATE,\n            AdSelect(_) => IFLA_BOND_AD_SELECT,\n            AdInfo(_) => IFLA_BOND_AD_INFO,\n            AdActorSysPrio(_) => IFLA_BOND_AD_ACTOR_SYS_PRIO,\n            AdUserPortKey(_) => IFLA_BOND_AD_USER_PORT_KEY,\n            AdActorSystem(_) => IFLA_BOND_AD_ACTOR_SYSTEM,\n            TlbDynamicLb(_) => IFLA_BOND_TLB_DYNAMIC_LB,\n            PeerNotifDelay(_) => IFLA_BOND_PEER_NOTIF_DELAY,\n            AdLacpActive(_) => IFLA_BOND_AD_LACP_ACTIVE,\n            MissedMax(_) => IFLA_BOND_MISSED_MAX,\n            NsIp6Target(_) => IFLA_BOND_NS_IP6_TARGET,\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBond {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoBond::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_BOND_MODE => Mode(parse_u8(payload).context(\"invalid IFLA_BOND_MODE value\")?),\n            IFLA_BOND_ACTIVE_SLAVE => {\n                ActiveSlave(parse_u32(payload).context(\"invalid IFLA_BOND_ACTIVE_SLAVE value\")?)\n            }\n            IFLA_BOND_MIIMON => {\n                MiiMon(parse_u32(payload).context(\"invalid IFLA_BOND_MIIMON value\")?)\n            }\n            IFLA_BOND_UPDELAY => {\n                UpDelay(parse_u32(payload).context(\"invalid IFLA_BOND_UPDELAY value\")?)\n            }\n            IFLA_BOND_DOWNDELAY => {\n                DownDelay(parse_u32(payload).context(\"invalid IFLA_BOND_DOWNDELAY value\")?)\n            }\n            IFLA_BOND_USE_CARRIER => {\n                UseCarrier(parse_u8(payload).context(\"invalid IFLA_BOND_USE_CARRIER value\")?)\n            }\n            IFLA_BOND_ARP_INTERVAL => {\n                ArpInterval(parse_u32(payload).context(\"invalid IFLA_BOND_ARP_INTERVAL value\")?)\n            }\n            IFLA_BOND_ARP_IP_TARGET => {\n                let mut addrs = Vec::<Ipv4Addr>::new();\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(\"invalid IFLA_BOND_ARP_IP_TARGET value\")?;\n                    if let Ok(IpAddr::V4(addr)) = parse_ip(nla.value()) {\n                        addrs.push(addr);\n                    }\n                }\n                ArpIpTarget(addrs)\n            }\n            IFLA_BOND_ARP_VALIDATE => {\n                ArpValidate(parse_u32(payload).context(\"invalid IFLA_BOND_ARP_VALIDATE value\")?)\n            }\n            IFLA_BOND_ARP_ALL_TARGETS => ArpAllTargets(\n                parse_u32(payload).context(\"invalid IFLA_BOND_ARP_ALL_TARGETS value\")?,\n            ),\n            IFLA_BOND_PRIMARY => {\n                Primary(parse_u32(payload).context(\"invalid IFLA_BOND_PRIMARY value\")?)\n            }\n            IFLA_BOND_PRIMARY_RESELECT => PrimaryReselect(\n                parse_u8(payload).context(\"invalid IFLA_BOND_PRIMARY_RESELECT value\")?,\n            ),\n            IFLA_BOND_FAIL_OVER_MAC => {\n                FailOverMac(parse_u8(payload).context(\"invalid IFLA_BOND_FAIL_OVER_MAC value\")?)\n            }\n            IFLA_BOND_XMIT_HASH_POLICY => XmitHashPolicy(\n                parse_u8(payload).context(\"invalid IFLA_BOND_XMIT_HASH_POLICY value\")?,\n            ),\n            IFLA_BOND_RESEND_IGMP => {\n                ResendIgmp(parse_u32(payload).context(\"invalid IFLA_BOND_RESEND_IGMP value\")?)\n            }\n            IFLA_BOND_NUM_PEER_NOTIF => {\n                NumPeerNotif(parse_u8(payload).context(\"invalid IFLA_BOND_NUM_PEER_NOTIF value\")?)\n            }\n            IFLA_BOND_ALL_SLAVES_ACTIVE => AllSlavesActive(\n                parse_u8(payload).context(\"invalid IFLA_BOND_ALL_SLAVES_ACTIVE value\")?,\n            ),\n            IFLA_BOND_MIN_LINKS => {\n                MinLinks(parse_u32(payload).context(\"invalid IFLA_BOND_MIN_LINKS value\")?)\n            }\n            IFLA_BOND_LP_INTERVAL => {\n                LpInterval(parse_u32(payload).context(\"invalid IFLA_BOND_LP_INTERVAL value\")?)\n            }\n            IFLA_BOND_PACKETS_PER_SLAVE => PacketsPerSlave(\n                parse_u32(payload).context(\"invalid IFLA_BOND_PACKETS_PER_SLAVE value\")?,\n            ),\n            IFLA_BOND_AD_LACP_RATE => {\n                AdLacpRate(parse_u8(payload).context(\"invalid IFLA_BOND_AD_LACP_RATE value\")?)\n            }\n            IFLA_BOND_AD_SELECT => {\n                AdSelect(parse_u8(payload).context(\"invalid IFLA_BOND_AD_SELECT value\")?)\n            }\n            IFLA_BOND_AD_INFO => {\n                let mut infos = Vec::new();\n                let err = \"failed to parse IFLA_BOND_AD_INFO\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(err)?;\n                    let info = BondAdInfo::parse(nla).context(err)?;\n                    infos.push(info);\n                }\n                AdInfo(infos)\n            }\n            IFLA_BOND_AD_ACTOR_SYS_PRIO => AdActorSysPrio(\n                parse_u16(payload).context(\"invalid IFLA_BOND_AD_ACTOR_SYS_PRIO value\")?,\n            ),\n            IFLA_BOND_AD_USER_PORT_KEY => AdUserPortKey(\n                parse_u16(payload).context(\"invalid IFLA_BOND_AD_USER_PORT_KEY value\")?,\n            ),\n            IFLA_BOND_AD_ACTOR_SYSTEM => AdActorSystem(\n                parse_mac(payload).context(\"invalid IFLA_BOND_AD_ACTOR_SYSTEM value\")?,\n            ),\n            IFLA_BOND_TLB_DYNAMIC_LB => {\n                TlbDynamicLb(parse_u8(payload).context(\"invalid IFLA_BOND_TLB_DYNAMIC_LB value\")?)\n            }\n            IFLA_BOND_PEER_NOTIF_DELAY => PeerNotifDelay(\n                parse_u32(payload).context(\"invalid IFLA_BOND_PEER_NOTIF_DELAY value\")?,\n            ),\n            IFLA_BOND_AD_LACP_ACTIVE => {\n                AdLacpActive(parse_u8(payload).context(\"invalid IFLA_BOND_AD_LACP_ACTIVE value\")?)\n            }\n            IFLA_BOND_MISSED_MAX => {\n                MissedMax(parse_u8(payload).context(\"invalid IFLA_BOND_MISSED_MAX value\")?)\n            }\n            IFLA_BOND_NS_IP6_TARGET => {\n                let mut addrs = Vec::<Ipv6Addr>::new();\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(\"invalid IFLA_BOND_NS_IP6_TARGET value\")?;\n                    if let Ok(IpAddr::V6(addr)) = parse_ip(nla.value()) {\n                        addrs.push(addr);\n                    }\n                }\n                NsIp6Target(addrs)\n            }\n            _ => return Err(format!(\"unknown NLA type {}\", buf.kind()).into()),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet/dev_conf.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const DEV_CONF_LEN: usize = 124;\n\nbuffer!(InetDevConfBuffer(DEV_CONF_LEN) {\n    forwarding: (i32, 0..4),\n    mc_forwarding: (i32, 4..8),\n    proxy_arp: (i32, 8..12),\n    accept_redirects: (i32, 12..16),\n    secure_redirects: (i32, 16..20),\n    send_redirects: (i32, 20..24),\n    shared_media: (i32, 24..28),\n    rp_filter: (i32, 28..32),\n    accept_source_route: (i32, 32..36),\n    bootp_relay: (i32, 36..40),\n    log_martians: (i32, 40..44),\n    tag: (i32, 44..48),\n    arpfilter: (i32, 48..52),\n    medium_id: (i32, 52..56),\n    noxfrm: (i32, 56..60),\n    nopolicy: (i32, 60..64),\n    force_igmp_version: (i32, 64..68),\n    arp_announce: (i32, 68..72),\n    arp_ignore: (i32, 72..76),\n    promote_secondaries: (i32, 76..80),\n    arp_accept: (i32, 80..84),\n    arp_notify: (i32, 84..88),\n    accept_local: (i32, 88..92),\n    src_vmark: (i32, 92..96),\n    proxy_arp_pvlan: (i32, 96..100),\n    route_localnet: (i32, 100..104),\n    igmpv2_unsolicited_report_interval: (i32, 104..108),\n    igmpv3_unsolicited_report_interval: (i32, 108..112),\n    ignore_routes_with_linkdown: (i32, 112..116),\n    drop_unicast_in_l2_multicast: (i32, 116..120),\n    drop_gratuitous_arp: (i32, 120..124),\n});\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub struct InetDevConf {\n    pub forwarding: i32,\n    pub mc_forwarding: i32,\n    pub proxy_arp: i32,\n    pub accept_redirects: i32,\n    pub secure_redirects: i32,\n    pub send_redirects: i32,\n    pub shared_media: i32,\n    pub rp_filter: i32,\n    pub accept_source_route: i32,\n    pub bootp_relay: i32,\n    pub log_martians: i32,\n    pub tag: i32,\n    pub arpfilter: i32,\n    pub medium_id: i32,\n    pub noxfrm: i32,\n    pub nopolicy: i32,\n    pub force_igmp_version: i32,\n    pub arp_announce: i32,\n    pub arp_ignore: i32,\n    pub promote_secondaries: i32,\n    pub arp_accept: i32,\n    pub arp_notify: i32,\n    pub accept_local: i32,\n    pub src_vmark: i32,\n    pub proxy_arp_pvlan: i32,\n    pub route_localnet: i32,\n    pub igmpv2_unsolicited_report_interval: i32,\n    pub igmpv3_unsolicited_report_interval: i32,\n    pub ignore_routes_with_linkdown: i32,\n    pub drop_unicast_in_l2_multicast: i32,\n    pub drop_gratuitous_arp: i32,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<InetDevConfBuffer<T>> for InetDevConf {\n    fn parse(buf: &InetDevConfBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            forwarding: buf.forwarding(),\n            mc_forwarding: buf.mc_forwarding(),\n            proxy_arp: buf.proxy_arp(),\n            accept_redirects: buf.accept_redirects(),\n            secure_redirects: buf.secure_redirects(),\n            send_redirects: buf.send_redirects(),\n            shared_media: buf.shared_media(),\n            rp_filter: buf.rp_filter(),\n            accept_source_route: buf.accept_source_route(),\n            bootp_relay: buf.bootp_relay(),\n            log_martians: buf.log_martians(),\n            tag: buf.tag(),\n            arpfilter: buf.arpfilter(),\n            medium_id: buf.medium_id(),\n            noxfrm: buf.noxfrm(),\n            nopolicy: buf.nopolicy(),\n            force_igmp_version: buf.force_igmp_version(),\n            arp_announce: buf.arp_announce(),\n            arp_ignore: buf.arp_ignore(),\n            promote_secondaries: buf.promote_secondaries(),\n            arp_accept: buf.arp_accept(),\n            arp_notify: buf.arp_notify(),\n            accept_local: buf.accept_local(),\n            src_vmark: buf.src_vmark(),\n            proxy_arp_pvlan: buf.proxy_arp_pvlan(),\n            route_localnet: buf.route_localnet(),\n            igmpv2_unsolicited_report_interval: buf.igmpv2_unsolicited_report_interval(),\n            igmpv3_unsolicited_report_interval: buf.igmpv3_unsolicited_report_interval(),\n            ignore_routes_with_linkdown: buf.ignore_routes_with_linkdown(),\n            drop_unicast_in_l2_multicast: buf.drop_unicast_in_l2_multicast(),\n            drop_gratuitous_arp: buf.drop_gratuitous_arp(),\n        })\n    }\n}\n\nimpl Emitable for InetDevConf {\n    fn buffer_len(&self) -> usize {\n        DEV_CONF_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = InetDevConfBuffer::new(buffer);\n        buffer.set_forwarding(self.forwarding);\n        buffer.set_mc_forwarding(self.mc_forwarding);\n        buffer.set_proxy_arp(self.proxy_arp);\n        buffer.set_accept_redirects(self.accept_redirects);\n        buffer.set_secure_redirects(self.secure_redirects);\n        buffer.set_send_redirects(self.send_redirects);\n        buffer.set_shared_media(self.shared_media);\n        buffer.set_rp_filter(self.rp_filter);\n        buffer.set_accept_source_route(self.accept_source_route);\n        buffer.set_bootp_relay(self.bootp_relay);\n        buffer.set_log_martians(self.log_martians);\n        buffer.set_tag(self.tag);\n        buffer.set_arpfilter(self.arpfilter);\n        buffer.set_medium_id(self.medium_id);\n        buffer.set_noxfrm(self.noxfrm);\n        buffer.set_nopolicy(self.nopolicy);\n        buffer.set_force_igmp_version(self.force_igmp_version);\n        buffer.set_arp_announce(self.arp_announce);\n        buffer.set_arp_ignore(self.arp_ignore);\n        buffer.set_promote_secondaries(self.promote_secondaries);\n        buffer.set_arp_accept(self.arp_accept);\n        buffer.set_arp_notify(self.arp_notify);\n        buffer.set_accept_local(self.accept_local);\n        buffer.set_src_vmark(self.src_vmark);\n        buffer.set_proxy_arp_pvlan(self.proxy_arp_pvlan);\n        buffer.set_route_localnet(self.route_localnet);\n        buffer.set_igmpv2_unsolicited_report_interval(self.igmpv2_unsolicited_report_interval);\n        buffer.set_igmpv3_unsolicited_report_interval(self.igmpv3_unsolicited_report_interval);\n        buffer.set_ignore_routes_with_linkdown(self.ignore_routes_with_linkdown);\n        buffer.set_drop_unicast_in_l2_multicast(self.drop_unicast_in_l2_multicast);\n        buffer.set_drop_gratuitous_arp(self.drop_gratuitous_arp);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    constants::{IFLA_INET_CONF, IFLA_INET_UNSPEC},\n    nlas::{DefaultNla, Nla, NlaBuffer},\n    traits::Parseable,\n    DecodeError,\n};\n\nmod dev_conf;\npub use self::dev_conf::*;\n\n#[derive(Clone, Eq, PartialEq, Debug)]\npub enum Inet {\n    DevConf(Vec<u8>),\n    Unspec(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl Nla for Inet {\n    fn value_len(&self) -> usize {\n        use self::Inet::*;\n        match *self {\n            Unspec(ref bytes) => bytes.len(),\n            DevConf(_) => DEV_CONF_LEN,\n            Other(ref nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Inet::*;\n        match *self {\n            Unspec(ref bytes) => buffer[..bytes.len()].copy_from_slice(bytes.as_slice()),\n            DevConf(ref dev_conf) => buffer[..dev_conf.len()].copy_from_slice(dev_conf.as_slice()),\n            Other(ref nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Inet::*;\n        match *self {\n            Unspec(_) => IFLA_INET_UNSPEC,\n            DevConf(_) => IFLA_INET_CONF,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Inet {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Inet::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_INET_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_INET_CONF => DevConf(payload.to_vec()),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet6/cache.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub struct Inet6CacheInfo {\n    pub max_reasm_len: i32,\n    pub tstamp: i32,\n    pub reachable_time: i32,\n    pub retrans_time: i32,\n}\n\npub const LINK_INET6_CACHE_INFO_LEN: usize = 16;\nbuffer!(Inet6CacheInfoBuffer(LINK_INET6_CACHE_INFO_LEN) {\n    max_reasm_len: (i32, 0..4),\n    tstamp: (i32, 4..8),\n    reachable_time: (i32, 8..12),\n    retrans_time: (i32, 12..16),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<Inet6CacheInfoBuffer<T>> for Inet6CacheInfo {\n    fn parse(buf: &Inet6CacheInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            max_reasm_len: buf.max_reasm_len(),\n            tstamp: buf.tstamp(),\n            reachable_time: buf.reachable_time(),\n            retrans_time: buf.retrans_time(),\n        })\n    }\n}\n\nimpl Emitable for Inet6CacheInfo {\n    fn buffer_len(&self) -> usize {\n        LINK_INET6_CACHE_INFO_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = Inet6CacheInfoBuffer::new(buffer);\n        buffer.set_max_reasm_len(self.max_reasm_len);\n        buffer.set_tstamp(self.tstamp);\n        buffer.set_reachable_time(self.reachable_time);\n        buffer.set_retrans_time(self.retrans_time);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet6/dev_conf.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const LINK_INET6_DEV_CONF_LEN: usize = 204;\nbuffer!(Inet6DevConfBuffer(LINK_INET6_DEV_CONF_LEN) {\n    forwarding: (i32, 0..4),\n    hoplimit: (i32, 4..8),\n    mtu6: (i32, 8..12),\n    accept_ra: (i32, 12..16),\n    accept_redirects: (i32, 16..20),\n    autoconf: (i32, 20..24),\n    dad_transmits: (i32, 24..28),\n    rtr_solicits: (i32, 28..32),\n    rtr_solicit_interval: (i32, 32..36),\n    rtr_solicit_delay: (i32, 36..40),\n    use_tempaddr: (i32, 40..44),\n    temp_valid_lft: (i32, 44..48),\n    temp_prefered_lft: (i32, 48..52),\n    regen_max_retry: (i32, 52..56),\n    max_desync_factor: (i32, 56..60),\n    max_addresses: (i32, 60..64),\n    force_mld_version: (i32, 64..68),\n    accept_ra_defrtr: (i32, 68..72),\n    accept_ra_pinfo: (i32, 72..76),\n    accept_ra_rtr_pref: (i32, 76..80),\n    rtr_probe_interval: (i32, 80..84),\n    accept_ra_rt_info_max_plen: (i32, 84..88),\n    proxy_ndp: (i32, 88..92),\n    optimistic_dad: (i32, 92..96),\n    accept_source_route: (i32, 96..100),\n    mc_forwarding: (i32, 100..104),\n    disable_ipv6: (i32, 104..108),\n    accept_dad: (i32, 108..112),\n    force_tllao: (i32, 112..116),\n    ndisc_notify: (i32, 116..120),\n    mldv1_unsolicited_report_interval: (i32, 120..124),\n    mldv2_unsolicited_report_interval: (i32, 124..128),\n    suppress_frag_ndisc: (i32, 128..132),\n    accept_ra_from_local: (i32, 132..136),\n    use_optimistic: (i32, 136..140),\n    accept_ra_mtu: (i32, 140..144),\n    stable_secret: (i32, 144..148),\n    use_oif_addrs_only: (i32, 148..152),\n    accept_ra_min_hop_limit: (i32, 152..156),\n    ignore_routes_with_linkdown: (i32, 156..160),\n    drop_unicast_in_l2_multicast: (i32, 160..164),\n    drop_unsolicited_na: (i32, 164..168),\n    keep_addr_on_down: (i32, 168..172),\n    rtr_solicit_max_interval: (i32, 172..176),\n    seg6_enabled: (i32, 176..180),\n    seg6_require_hmac: (i32, 180..184),\n    enhanced_dad: (i32, 184..188),\n    addr_gen_mode: (i32, 188..192),\n    disable_policy: (i32, 192..196),\n    accept_ra_rt_info_min_plen: (i32, 196..200),\n    ndisc_tclass: (i32, 200..204),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<Inet6DevConfBuffer<T>> for Inet6DevConf {\n    fn parse(buf: &Inet6DevConfBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            forwarding: buf.forwarding(),\n            hoplimit: buf.hoplimit(),\n            mtu6: buf.mtu6(),\n            accept_ra: buf.accept_ra(),\n            accept_redirects: buf.accept_redirects(),\n            autoconf: buf.autoconf(),\n            dad_transmits: buf.dad_transmits(),\n            rtr_solicits: buf.rtr_solicits(),\n            rtr_solicit_interval: buf.rtr_solicit_interval(),\n            rtr_solicit_delay: buf.rtr_solicit_delay(),\n            use_tempaddr: buf.use_tempaddr(),\n            temp_valid_lft: buf.temp_valid_lft(),\n            temp_prefered_lft: buf.temp_prefered_lft(),\n            regen_max_retry: buf.regen_max_retry(),\n            max_desync_factor: buf.max_desync_factor(),\n            max_addresses: buf.max_addresses(),\n            force_mld_version: buf.force_mld_version(),\n            accept_ra_defrtr: buf.accept_ra_defrtr(),\n            accept_ra_pinfo: buf.accept_ra_pinfo(),\n            accept_ra_rtr_pref: buf.accept_ra_rtr_pref(),\n            rtr_probe_interval: buf.rtr_probe_interval(),\n            accept_ra_rt_info_max_plen: buf.accept_ra_rt_info_max_plen(),\n            proxy_ndp: buf.proxy_ndp(),\n            optimistic_dad: buf.optimistic_dad(),\n            accept_source_route: buf.accept_source_route(),\n            mc_forwarding: buf.mc_forwarding(),\n            disable_ipv6: buf.disable_ipv6(),\n            accept_dad: buf.accept_dad(),\n            force_tllao: buf.force_tllao(),\n            ndisc_notify: buf.ndisc_notify(),\n            mldv1_unsolicited_report_interval: buf.mldv1_unsolicited_report_interval(),\n            mldv2_unsolicited_report_interval: buf.mldv2_unsolicited_report_interval(),\n            suppress_frag_ndisc: buf.suppress_frag_ndisc(),\n            accept_ra_from_local: buf.accept_ra_from_local(),\n            use_optimistic: buf.use_optimistic(),\n            accept_ra_mtu: buf.accept_ra_mtu(),\n            stable_secret: buf.stable_secret(),\n            use_oif_addrs_only: buf.use_oif_addrs_only(),\n            accept_ra_min_hop_limit: buf.accept_ra_min_hop_limit(),\n            ignore_routes_with_linkdown: buf.ignore_routes_with_linkdown(),\n            drop_unicast_in_l2_multicast: buf.drop_unicast_in_l2_multicast(),\n            drop_unsolicited_na: buf.drop_unsolicited_na(),\n            keep_addr_on_down: buf.keep_addr_on_down(),\n            rtr_solicit_max_interval: buf.rtr_solicit_max_interval(),\n            seg6_enabled: buf.seg6_enabled(),\n            seg6_require_hmac: buf.seg6_require_hmac(),\n            enhanced_dad: buf.enhanced_dad(),\n            addr_gen_mode: buf.addr_gen_mode(),\n            disable_policy: buf.disable_policy(),\n            accept_ra_rt_info_min_plen: buf.accept_ra_rt_info_min_plen(),\n            ndisc_tclass: buf.ndisc_tclass(),\n        })\n    }\n}\n\nimpl Emitable for Inet6DevConf {\n    fn buffer_len(&self) -> usize {\n        LINK_INET6_DEV_CONF_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = Inet6DevConfBuffer::new(buffer);\n        buffer.set_forwarding(self.forwarding);\n        buffer.set_hoplimit(self.hoplimit);\n        buffer.set_mtu6(self.mtu6);\n        buffer.set_accept_ra(self.accept_ra);\n        buffer.set_accept_redirects(self.accept_redirects);\n        buffer.set_autoconf(self.autoconf);\n        buffer.set_dad_transmits(self.dad_transmits);\n        buffer.set_rtr_solicits(self.rtr_solicits);\n        buffer.set_rtr_solicit_interval(self.rtr_solicit_interval);\n        buffer.set_rtr_solicit_delay(self.rtr_solicit_delay);\n        buffer.set_use_tempaddr(self.use_tempaddr);\n        buffer.set_temp_valid_lft(self.temp_valid_lft);\n        buffer.set_temp_prefered_lft(self.temp_prefered_lft);\n        buffer.set_regen_max_retry(self.regen_max_retry);\n        buffer.set_max_desync_factor(self.max_desync_factor);\n        buffer.set_max_addresses(self.max_addresses);\n        buffer.set_force_mld_version(self.force_mld_version);\n        buffer.set_accept_ra_defrtr(self.accept_ra_defrtr);\n        buffer.set_accept_ra_pinfo(self.accept_ra_pinfo);\n        buffer.set_accept_ra_rtr_pref(self.accept_ra_rtr_pref);\n        buffer.set_rtr_probe_interval(self.rtr_probe_interval);\n        buffer.set_accept_ra_rt_info_max_plen(self.accept_ra_rt_info_max_plen);\n        buffer.set_proxy_ndp(self.proxy_ndp);\n        buffer.set_optimistic_dad(self.optimistic_dad);\n        buffer.set_accept_source_route(self.accept_source_route);\n        buffer.set_mc_forwarding(self.mc_forwarding);\n        buffer.set_disable_ipv6(self.disable_ipv6);\n        buffer.set_accept_dad(self.accept_dad);\n        buffer.set_force_tllao(self.force_tllao);\n        buffer.set_ndisc_notify(self.ndisc_notify);\n        buffer.set_mldv1_unsolicited_report_interval(self.mldv1_unsolicited_report_interval);\n        buffer.set_mldv2_unsolicited_report_interval(self.mldv2_unsolicited_report_interval);\n        buffer.set_suppress_frag_ndisc(self.suppress_frag_ndisc);\n        buffer.set_accept_ra_from_local(self.accept_ra_from_local);\n        buffer.set_use_optimistic(self.use_optimistic);\n        buffer.set_accept_ra_mtu(self.accept_ra_mtu);\n        buffer.set_stable_secret(self.stable_secret);\n        buffer.set_use_oif_addrs_only(self.use_oif_addrs_only);\n        buffer.set_accept_ra_min_hop_limit(self.accept_ra_min_hop_limit);\n        buffer.set_ignore_routes_with_linkdown(self.ignore_routes_with_linkdown);\n        buffer.set_drop_unicast_in_l2_multicast(self.drop_unicast_in_l2_multicast);\n        buffer.set_drop_unsolicited_na(self.drop_unsolicited_na);\n        buffer.set_keep_addr_on_down(self.keep_addr_on_down);\n        buffer.set_rtr_solicit_max_interval(self.rtr_solicit_max_interval);\n        buffer.set_seg6_enabled(self.seg6_enabled);\n        buffer.set_seg6_require_hmac(self.seg6_require_hmac);\n        buffer.set_enhanced_dad(self.enhanced_dad);\n        buffer.set_addr_gen_mode(self.addr_gen_mode);\n        buffer.set_disable_policy(self.disable_policy);\n        buffer.set_accept_ra_rt_info_min_plen(self.accept_ra_rt_info_min_plen);\n        buffer.set_ndisc_tclass(self.ndisc_tclass);\n    }\n}\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub struct Inet6DevConf {\n    pub forwarding: i32,\n    pub hoplimit: i32,\n    pub mtu6: i32,\n    pub accept_ra: i32,\n    pub accept_redirects: i32,\n    pub autoconf: i32,\n    pub dad_transmits: i32,\n    pub rtr_solicits: i32,\n    pub rtr_solicit_interval: i32,\n    pub rtr_solicit_delay: i32,\n    pub use_tempaddr: i32,\n    pub temp_valid_lft: i32,\n    pub temp_prefered_lft: i32,\n    pub regen_max_retry: i32,\n    pub max_desync_factor: i32,\n    pub max_addresses: i32,\n    pub force_mld_version: i32,\n    pub accept_ra_defrtr: i32,\n    pub accept_ra_pinfo: i32,\n    pub accept_ra_rtr_pref: i32,\n    pub rtr_probe_interval: i32,\n    pub accept_ra_rt_info_max_plen: i32,\n    pub proxy_ndp: i32,\n    pub optimistic_dad: i32,\n    pub accept_source_route: i32,\n    pub mc_forwarding: i32,\n    pub disable_ipv6: i32,\n    pub accept_dad: i32,\n    pub force_tllao: i32,\n    pub ndisc_notify: i32,\n    pub mldv1_unsolicited_report_interval: i32,\n    pub mldv2_unsolicited_report_interval: i32,\n    pub suppress_frag_ndisc: i32,\n    pub accept_ra_from_local: i32,\n    pub use_optimistic: i32,\n    pub accept_ra_mtu: i32,\n    pub stable_secret: i32,\n    pub use_oif_addrs_only: i32,\n    pub accept_ra_min_hop_limit: i32,\n    pub ignore_routes_with_linkdown: i32,\n    pub drop_unicast_in_l2_multicast: i32,\n    pub drop_unsolicited_na: i32,\n    pub keep_addr_on_down: i32,\n    pub rtr_solicit_max_interval: i32,\n    pub seg6_enabled: i32,\n    pub seg6_require_hmac: i32,\n    pub enhanced_dad: i32,\n    pub addr_gen_mode: i32,\n    pub disable_policy: i32,\n    pub accept_ra_rt_info_min_plen: i32,\n    pub ndisc_tclass: i32,\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet6/icmp6_stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub struct Icmp6Stats {\n    pub num: i64,\n    pub in_msgs: i64,\n    pub in_errors: i64,\n    pub out_msgs: i64,\n    pub out_errors: i64,\n    pub csum_errors: i64,\n}\n\npub const ICMP6_STATS_LEN: usize = 48;\nbuffer!(Icmp6StatsBuffer(ICMP6_STATS_LEN) {\n    num: (i64, 0..8),\n    in_msgs: (i64, 8..16),\n    in_errors: (i64, 16..24),\n    out_msgs: (i64, 24..32),\n    out_errors: (i64, 32..40),\n    csum_errors: (i64, 40..48),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<Icmp6StatsBuffer<T>> for Icmp6Stats {\n    fn parse(buf: &Icmp6StatsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            num: buf.num(),\n            in_msgs: buf.in_msgs(),\n            in_errors: buf.in_errors(),\n            out_msgs: buf.out_msgs(),\n            out_errors: buf.out_errors(),\n            csum_errors: buf.csum_errors(),\n        })\n    }\n}\n\nimpl Emitable for Icmp6Stats {\n    fn buffer_len(&self) -> usize {\n        ICMP6_STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = Icmp6StatsBuffer::new(buffer);\n        buffer.set_num(self.num);\n        buffer.set_in_msgs(self.in_msgs);\n        buffer.set_in_errors(self.in_errors);\n        buffer.set_out_msgs(self.out_msgs);\n        buffer.set_out_errors(self.out_errors);\n        buffer.set_csum_errors(self.csum_errors);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet6/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{DefaultNla, Nla, NlaBuffer},\n    parsers::{parse_ipv6, parse_u32, parse_u8},\n    traits::Parseable,\n    DecodeError,\n};\n\nmod cache;\npub use self::cache::*;\nmod dev_conf;\npub use self::dev_conf::*;\nmod icmp6_stats;\npub use self::icmp6_stats::*;\nmod stats;\npub use self::stats::*;\n\n#[derive(Clone, Eq, PartialEq, Debug)]\npub enum Inet6 {\n    Flags(u32),\n    CacheInfo(Vec<u8>),\n    DevConf(Vec<u8>),\n    Unspec(Vec<u8>),\n    Stats(Vec<u8>),\n    IcmpStats(Vec<u8>),\n    Token([u8; 16]),\n    AddrGenMode(u8),\n    Other(DefaultNla),\n}\n\nimpl Nla for Inet6 {\n    fn value_len(&self) -> usize {\n        use self::Inet6::*;\n        match *self {\n            Unspec(ref bytes) => bytes.len(),\n            CacheInfo(ref cache_info) => cache_info.len(),\n            DevConf(ref dev_conf) => dev_conf.len(),\n            Stats(ref stats) => stats.len(),\n            IcmpStats(ref icmp_stats) => icmp_stats.len(),\n            Flags(_) => 4,\n            Token(_) => 16,\n            AddrGenMode(_) => 1,\n            Other(ref nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Inet6::*;\n        match *self {\n            Unspec(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Flags(ref value) => NativeEndian::write_u32(buffer, *value),\n            CacheInfo(ref cache_info) => buffer.copy_from_slice(cache_info.as_slice()),\n            DevConf(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Stats(ref inet6_stats) => buffer.copy_from_slice(inet6_stats.as_slice()),\n            IcmpStats(ref icmp6_stats) => buffer.copy_from_slice(icmp6_stats.as_slice()),\n            Token(ref ipv6) => buffer.copy_from_slice(&ipv6[..]),\n            AddrGenMode(value) => buffer[0] = value,\n            Other(ref nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Inet6::*;\n        match *self {\n            Unspec(_) => IFLA_INET6_UNSPEC,\n            Flags(_) => IFLA_INET6_FLAGS,\n            CacheInfo(_) => IFLA_INET6_CACHEINFO,\n            DevConf(_) => IFLA_INET6_CONF,\n            Stats(_) => IFLA_INET6_STATS,\n            IcmpStats(_) => IFLA_INET6_ICMP6STATS,\n            Token(_) => IFLA_INET6_TOKEN,\n            AddrGenMode(_) => IFLA_INET6_ADDR_GEN_MODE,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Inet6 {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Inet6::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_INET6_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_INET6_FLAGS => {\n                Flags(parse_u32(payload).context(\"invalid IFLA_INET6_FLAGS value\")?)\n            }\n            IFLA_INET6_CACHEINFO => CacheInfo(payload.to_vec()),\n            IFLA_INET6_CONF => DevConf(payload.to_vec()),\n            IFLA_INET6_STATS => Stats(payload.to_vec()),\n            IFLA_INET6_ICMP6STATS => IcmpStats(payload.to_vec()),\n            IFLA_INET6_TOKEN => {\n                Token(parse_ipv6(payload).context(\"invalid IFLA_INET6_TOKEN value\")?)\n            }\n            IFLA_INET6_ADDR_GEN_MODE => {\n                AddrGenMode(parse_u8(payload).context(\"invalid IFLA_INET6_ADDR_GEN_MODE value\")?)\n            }\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/inet6/stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const INET6_STATS_LEN: usize = 288;\nbuffer!(Inet6StatsBuffer(INET6_STATS_LEN) {\n    num: (i64, 0..8),\n    in_pkts: (i64, 8..16),\n    in_octets: (i64, 16..24),\n    in_delivers: (i64, 24..32),\n    out_forw_datagrams: (i64, 32..40),\n    out_pkts: (i64, 40..48),\n    out_octets: (i64, 48..56),\n    in_hdr_errors: (i64, 56..64),\n    in_too_big_errors: (i64, 64..72),\n    in_no_routes: (i64, 72..80),\n    in_addr_errors: (i64, 80..88),\n    in_unknown_protos: (i64, 88..96),\n    in_truncated_pkts: (i64, 96..104),\n    in_discards: (i64, 104..112),\n    out_discards: (i64, 112..120),\n    out_no_routes: (i64, 120..128),\n    reasm_timeout: (i64, 128..136),\n    reasm_reqds: (i64, 136..144),\n    reasm_oks: (i64, 144..152),\n    reasm_fails: (i64, 152..160),\n    frag_oks: (i64, 160..168),\n    frag_fails: (i64, 168..176),\n    frag_creates: (i64, 176..184),\n    in_mcast_pkts: (i64, 184..192),\n    out_mcast_pkts: (i64, 192..200),\n    in_bcast_pkts: (i64, 200..208),\n    out_bcast_pkts: (i64, 208..216),\n    in_mcast_octets: (i64, 216..224),\n    out_mcast_octets: (i64, 224..232),\n    in_bcast_octets: (i64, 232..240),\n    out_bcast_octets: (i64, 240..248),\n    in_csum_errors: (i64, 248..256),\n    in_no_ect_pkts: (i64, 256..264),\n    in_ect1_pkts: (i64, 264..272),\n    in_ect0_pkts: (i64, 272..280),\n    in_ce_pkts: (i64, 280..288),\n});\n\n#[derive(Clone, Copy, Eq, PartialEq, Debug)]\npub struct Inet6Stats {\n    pub num: i64,\n    pub in_pkts: i64,\n    pub in_octets: i64,\n    pub in_delivers: i64,\n    pub out_forw_datagrams: i64,\n    pub out_pkts: i64,\n    pub out_octets: i64,\n    pub in_hdr_errors: i64,\n    pub in_too_big_errors: i64,\n    pub in_no_routes: i64,\n    pub in_addr_errors: i64,\n    pub in_unknown_protos: i64,\n    pub in_truncated_pkts: i64,\n    pub in_discards: i64,\n    pub out_discards: i64,\n    pub out_no_routes: i64,\n    pub reasm_timeout: i64,\n    pub reasm_reqds: i64,\n    pub reasm_oks: i64,\n    pub reasm_fails: i64,\n    pub frag_oks: i64,\n    pub frag_fails: i64,\n    pub frag_creates: i64,\n    pub in_mcast_pkts: i64,\n    pub out_mcast_pkts: i64,\n    pub in_bcast_pkts: i64,\n    pub out_bcast_pkts: i64,\n    pub in_mcast_octets: i64,\n    pub out_mcast_octets: i64,\n    pub in_bcast_octets: i64,\n    pub out_bcast_octets: i64,\n    pub in_csum_errors: i64,\n    pub in_no_ect_pkts: i64,\n    pub in_ect1_pkts: i64,\n    pub in_ect0_pkts: i64,\n    pub in_ce_pkts: i64,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<Inet6StatsBuffer<T>> for Inet6Stats {\n    fn parse(buf: &Inet6StatsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            num: buf.num(),\n            in_pkts: buf.in_pkts(),\n            in_octets: buf.in_octets(),\n            in_delivers: buf.in_delivers(),\n            out_forw_datagrams: buf.out_forw_datagrams(),\n            out_pkts: buf.out_pkts(),\n            out_octets: buf.out_octets(),\n            in_hdr_errors: buf.in_hdr_errors(),\n            in_too_big_errors: buf.in_too_big_errors(),\n            in_no_routes: buf.in_no_routes(),\n            in_addr_errors: buf.in_addr_errors(),\n            in_unknown_protos: buf.in_unknown_protos(),\n            in_truncated_pkts: buf.in_truncated_pkts(),\n            in_discards: buf.in_discards(),\n            out_discards: buf.out_discards(),\n            out_no_routes: buf.out_no_routes(),\n            reasm_timeout: buf.reasm_timeout(),\n            reasm_reqds: buf.reasm_reqds(),\n            reasm_oks: buf.reasm_oks(),\n            reasm_fails: buf.reasm_fails(),\n            frag_oks: buf.frag_oks(),\n            frag_fails: buf.frag_fails(),\n            frag_creates: buf.frag_creates(),\n            in_mcast_pkts: buf.in_mcast_pkts(),\n            out_mcast_pkts: buf.out_mcast_pkts(),\n            in_bcast_pkts: buf.in_bcast_pkts(),\n            out_bcast_pkts: buf.out_bcast_pkts(),\n            in_mcast_octets: buf.in_mcast_octets(),\n            out_mcast_octets: buf.out_mcast_octets(),\n            in_bcast_octets: buf.in_bcast_octets(),\n            out_bcast_octets: buf.out_bcast_octets(),\n            in_csum_errors: buf.in_csum_errors(),\n            in_no_ect_pkts: buf.in_no_ect_pkts(),\n            in_ect1_pkts: buf.in_ect1_pkts(),\n            in_ect0_pkts: buf.in_ect0_pkts(),\n            in_ce_pkts: buf.in_ce_pkts(),\n        })\n    }\n}\n\nimpl Emitable for Inet6Stats {\n    fn buffer_len(&self) -> usize {\n        INET6_STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = Inet6StatsBuffer::new(buffer);\n        buffer.set_num(self.num);\n        buffer.set_in_pkts(self.in_pkts);\n        buffer.set_in_octets(self.in_octets);\n        buffer.set_in_delivers(self.in_delivers);\n        buffer.set_out_forw_datagrams(self.out_forw_datagrams);\n        buffer.set_out_pkts(self.out_pkts);\n        buffer.set_out_octets(self.out_octets);\n        buffer.set_in_hdr_errors(self.in_hdr_errors);\n        buffer.set_in_too_big_errors(self.in_too_big_errors);\n        buffer.set_in_no_routes(self.in_no_routes);\n        buffer.set_in_addr_errors(self.in_addr_errors);\n        buffer.set_in_unknown_protos(self.in_unknown_protos);\n        buffer.set_in_truncated_pkts(self.in_truncated_pkts);\n        buffer.set_in_discards(self.in_discards);\n        buffer.set_out_discards(self.out_discards);\n        buffer.set_out_no_routes(self.out_no_routes);\n        buffer.set_reasm_timeout(self.reasm_timeout);\n        buffer.set_reasm_reqds(self.reasm_reqds);\n        buffer.set_reasm_oks(self.reasm_oks);\n        buffer.set_reasm_fails(self.reasm_fails);\n        buffer.set_frag_oks(self.frag_oks);\n        buffer.set_frag_fails(self.frag_fails);\n        buffer.set_frag_creates(self.frag_creates);\n        buffer.set_in_mcast_pkts(self.in_mcast_pkts);\n        buffer.set_out_mcast_pkts(self.out_mcast_pkts);\n        buffer.set_in_bcast_pkts(self.in_bcast_pkts);\n        buffer.set_out_bcast_pkts(self.out_bcast_pkts);\n        buffer.set_in_mcast_octets(self.in_mcast_octets);\n        buffer.set_out_mcast_octets(self.out_mcast_octets);\n        buffer.set_in_bcast_octets(self.in_bcast_octets);\n        buffer.set_out_bcast_octets(self.out_bcast_octets);\n        buffer.set_in_csum_errors(self.in_csum_errors);\n        buffer.set_in_no_ect_pkts(self.in_no_ect_pkts);\n        buffer.set_in_ect1_pkts(self.in_ect1_pkts);\n        buffer.set_in_ect0_pkts(self.in_ect0_pkts);\n        buffer.set_in_ce_pkts(self.in_ce_pkts);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/link_infos.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::bond::InfoBond;\nuse crate::{\n    constants::*,\n    nlas::{DefaultNla, Nla, NlaBuffer, NlasIterator},\n    parsers::{parse_mac, parse_string, parse_u16, parse_u16_be, parse_u32, parse_u64, parse_u8},\n    traits::{Emitable, Parseable},\n    DecodeError,\n    LinkMessage,\n    LinkMessageBuffer,\n};\n\nuse anyhow::Context;\nuse byteorder::{BigEndian, ByteOrder, NativeEndian};\n\nconst DUMMY: &str = \"dummy\";\nconst IFB: &str = \"ifb\";\nconst BRIDGE: &str = \"bridge\";\nconst TUN: &str = \"tun\";\nconst NLMON: &str = \"nlmon\";\nconst VLAN: &str = \"vlan\";\nconst VETH: &str = \"veth\";\nconst VXLAN: &str = \"vxlan\";\nconst BOND: &str = \"bond\";\nconst IPVLAN: &str = \"ipvlan\";\nconst MACVLAN: &str = \"macvlan\";\nconst MACVTAP: &str = \"macvtap\";\nconst GRETAP: &str = \"gretap\";\nconst IP6GRETAP: &str = \"ip6gretap\";\nconst IPIP: &str = \"ipip\";\nconst SIT: &str = \"sit\";\nconst GRE: &str = \"gre\";\nconst IP6GRE: &str = \"ip6gre\";\nconst VTI: &str = \"vti\";\nconst VRF: &str = \"vrf\";\nconst GTP: &str = \"gtp\";\nconst IPOIB: &str = \"ipoib\";\nconst WIREGUARD: &str = \"wireguard\";\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Info {\n    Unspec(Vec<u8>),\n    Xstats(Vec<u8>),\n    Kind(InfoKind),\n    Data(InfoData),\n    SlaveKind(Vec<u8>),\n    SlaveData(Vec<u8>),\n}\n\nimpl Nla for Info {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Info::*;\n        match self {\n            Unspec(ref bytes)\n                | Xstats(ref bytes)\n                | SlaveKind(ref bytes)\n                | SlaveData(ref bytes)\n                => bytes.len(),\n            Kind(ref nla) => nla.value_len(),\n            Data(ref nla) => nla.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Info::*;\n        match self {\n            Unspec(ref bytes)\n                | Xstats(ref bytes)\n                | SlaveKind(ref bytes)\n                | SlaveData(ref bytes)\n                => buffer.copy_from_slice(bytes),\n            Kind(ref nla) => nla.emit_value(buffer),\n            Data(ref nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Info::*;\n        match self {\n            Unspec(_) => IFLA_INFO_UNSPEC,\n            Xstats(_) => IFLA_INFO_XSTATS,\n            SlaveKind(_) => IFLA_INFO_SLAVE_KIND,\n            SlaveData(_) => IFLA_INFO_DATA,\n            Kind(_) => IFLA_INFO_KIND,\n            Data(_) => IFLA_INFO_DATA,\n        }\n    }\n}\n\npub(crate) struct VecInfo(pub(crate) Vec<Info>);\n\n// We cannot `impl Parseable<_> for Info` because some attributes\n// depend on each other. To parse IFLA_INFO_DATA we first need to\n// parse the preceding IFLA_INFO_KIND for example.\n//\n// Moreover, with cannot `impl Parseable for Vec<Info>` due to the\n// orphan rule: `Parseable` and `Vec<_>` are both defined outside of\n// this crate. Thus, we create this internal VecInfo struct that wraps\n// `Vec<Info>` and allows us to circumvent the orphan rule.\n//\n// The downside is that this impl will not be exposed.\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VecInfo {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut res = Vec::new();\n        let nlas = NlasIterator::new(buf.into_inner());\n        let mut link_info_kind: Option<InfoKind> = None;\n        for nla in nlas {\n            let nla = nla?;\n            match nla.kind() {\n                IFLA_INFO_UNSPEC => res.push(Info::Unspec(nla.value().to_vec())),\n                IFLA_INFO_XSTATS => res.push(Info::Xstats(nla.value().to_vec())),\n                IFLA_INFO_SLAVE_KIND => res.push(Info::SlaveKind(nla.value().to_vec())),\n                IFLA_INFO_SLAVE_DATA => res.push(Info::SlaveData(nla.value().to_vec())),\n                IFLA_INFO_KIND => {\n                    let parsed = InfoKind::parse(&nla)?;\n                    res.push(Info::Kind(parsed.clone()));\n                    link_info_kind = Some(parsed);\n                }\n                IFLA_INFO_DATA => {\n                    if let Some(link_info_kind) = link_info_kind {\n                        let payload = nla.value();\n                        let info_data = match link_info_kind {\n                            InfoKind::Dummy => InfoData::Dummy(payload.to_vec()),\n                            InfoKind::Ifb => InfoData::Ifb(payload.to_vec()),\n                            InfoKind::Bridge => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'bridge')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoBridge::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Bridge(v)\n                            }\n                            InfoKind::Vlan => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'vlan')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoVlan::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Vlan(v)\n                            }\n                            InfoKind::Tun => InfoData::Tun(payload.to_vec()),\n                            InfoKind::Nlmon => InfoData::Nlmon(payload.to_vec()),\n                            InfoKind::Veth => {\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'veth')\";\n                                let nla_buf = NlaBuffer::new_checked(&payload).context(err)?;\n                                let parsed = VethInfo::parse(&nla_buf).context(err)?;\n                                InfoData::Veth(parsed)\n                            }\n                            InfoKind::Vxlan => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'vxlan')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoVxlan::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Vxlan(v)\n                            }\n                            InfoKind::Bond => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'bond')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoBond::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Bond(v)\n                            }\n                            InfoKind::IpVlan => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'ipvlan')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoIpVlan::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::IpVlan(v)\n                            }\n                            InfoKind::MacVlan => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'macvlan')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoMacVlan::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::MacVlan(v)\n                            }\n                            InfoKind::MacVtap => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'macvtap')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoMacVtap::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::MacVtap(v)\n                            }\n                            InfoKind::GreTap => InfoData::GreTap(payload.to_vec()),\n                            InfoKind::GreTap6 => InfoData::GreTap6(payload.to_vec()),\n                            InfoKind::IpTun => InfoData::IpTun(payload.to_vec()),\n                            InfoKind::SitTun => InfoData::SitTun(payload.to_vec()),\n                            InfoKind::GreTun => InfoData::GreTun(payload.to_vec()),\n                            InfoKind::GreTun6 => InfoData::GreTun6(payload.to_vec()),\n                            InfoKind::Vti => InfoData::Vti(payload.to_vec()),\n                            InfoKind::Vrf => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'vrf')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoVrf::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Vrf(v)\n                            }\n                            InfoKind::Gtp => InfoData::Gtp(payload.to_vec()),\n                            InfoKind::Ipoib => {\n                                let mut v = Vec::new();\n                                let err =\n                                    \"failed to parse IFLA_INFO_DATA (IFLA_INFO_KIND is 'ipoib')\";\n                                for nla in NlasIterator::new(payload) {\n                                    let nla = &nla.context(err)?;\n                                    let parsed = InfoIpoib::parse(nla).context(err)?;\n                                    v.push(parsed);\n                                }\n                                InfoData::Ipoib(v)\n                            }\n                            InfoKind::Wireguard => InfoData::Wireguard(payload.to_vec()),\n                            InfoKind::Other(_) => InfoData::Other(payload.to_vec()),\n                        };\n                        res.push(Info::Data(info_data));\n                    } else {\n                        return Err(\"IFLA_INFO_DATA is not preceded by an IFLA_INFO_KIND\".into());\n                    }\n                    link_info_kind = None;\n                }\n                _ => return Err(format!(\"unknown NLA type {}\", nla.kind()).into()),\n            }\n        }\n        Ok(VecInfo(res))\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoData {\n    Bridge(Vec<InfoBridge>),\n    Tun(Vec<u8>),\n    Nlmon(Vec<u8>),\n    Vlan(Vec<InfoVlan>),\n    Dummy(Vec<u8>),\n    Ifb(Vec<u8>),\n    Veth(VethInfo),\n    Vxlan(Vec<InfoVxlan>),\n    Bond(Vec<InfoBond>),\n    IpVlan(Vec<InfoIpVlan>),\n    MacVlan(Vec<InfoMacVlan>),\n    MacVtap(Vec<InfoMacVtap>),\n    GreTap(Vec<u8>),\n    GreTap6(Vec<u8>),\n    IpTun(Vec<u8>),\n    SitTun(Vec<u8>),\n    GreTun(Vec<u8>),\n    GreTun6(Vec<u8>),\n    Vti(Vec<u8>),\n    Vrf(Vec<InfoVrf>),\n    Gtp(Vec<u8>),\n    Ipoib(Vec<InfoIpoib>),\n    Wireguard(Vec<u8>),\n    Other(Vec<u8>),\n}\n\nimpl Nla for InfoData {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::InfoData::*;\n        match self {\n            Bond(ref nlas) => nlas.as_slice().buffer_len(),\n            Bridge(ref nlas) => nlas.as_slice().buffer_len(),\n            Vlan(ref nlas) =>  nlas.as_slice().buffer_len(),\n            Veth(ref msg) => msg.buffer_len(),\n            IpVlan(ref nlas) => nlas.as_slice().buffer_len(),\n            Ipoib(ref nlas) => nlas.as_slice().buffer_len(),\n            MacVlan(ref nlas) => nlas.as_slice().buffer_len(),\n            MacVtap(ref nlas) => nlas.as_slice().buffer_len(),\n            Vrf(ref nlas) => nlas.as_slice().buffer_len(),\n            Vxlan(ref nlas) => nlas.as_slice().buffer_len(),\n            Dummy(ref bytes)\n                | Tun(ref bytes)\n                | Nlmon(ref bytes)\n                | Ifb(ref bytes)\n                | GreTap(ref bytes)\n                | GreTap6(ref bytes)\n                | IpTun(ref bytes)\n                | SitTun(ref bytes)\n                | GreTun(ref bytes)\n                | GreTun6(ref bytes)\n                | Vti(ref bytes)\n                | Gtp(ref bytes)\n                | Wireguard(ref bytes)\n                | Other(ref bytes)\n                => bytes.len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoData::*;\n        match self {\n            Bond(ref nlas) => nlas.as_slice().emit(buffer),\n            Bridge(ref nlas) => nlas.as_slice().emit(buffer),\n            Vlan(ref nlas) => nlas.as_slice().emit(buffer),\n            Veth(ref msg) => msg.emit(buffer),\n            IpVlan(ref nlas) => nlas.as_slice().emit(buffer),\n            Ipoib(ref nlas) => nlas.as_slice().emit(buffer),\n            MacVlan(ref nlas) => nlas.as_slice().emit(buffer),\n            MacVtap(ref nlas) => nlas.as_slice().emit(buffer),\n            Vrf(ref nlas) => nlas.as_slice().emit(buffer),\n            Vxlan(ref nlas) => nlas.as_slice().emit(buffer),\n            Dummy(ref bytes)\n                | Tun(ref bytes)\n                | Nlmon(ref bytes)\n                | Ifb(ref bytes)\n                | GreTap(ref bytes)\n                | GreTap6(ref bytes)\n                | IpTun(ref bytes)\n                | SitTun(ref bytes)\n                | GreTun(ref bytes)\n                | GreTun6(ref bytes)\n                | Vti(ref bytes)\n                | Gtp(ref bytes)\n                | Wireguard(ref bytes)\n                | Other(ref bytes)\n                => buffer.copy_from_slice(bytes),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        IFLA_INFO_DATA\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoKind {\n    Dummy,\n    Ifb,\n    Bridge,\n    Tun,\n    Nlmon,\n    Vlan,\n    Veth,\n    Vxlan,\n    Bond,\n    IpVlan,\n    MacVlan,\n    MacVtap,\n    GreTap,\n    GreTap6,\n    IpTun,\n    SitTun,\n    GreTun,\n    GreTun6,\n    Vti,\n    Vrf,\n    Gtp,\n    Ipoib,\n    Wireguard,\n    Other(String),\n}\n\nimpl Nla for InfoKind {\n    fn value_len(&self) -> usize {\n        use self::InfoKind::*;\n        let len = match *self {\n            Dummy => DUMMY.len(),\n            Ifb => IFB.len(),\n            Bridge => BRIDGE.len(),\n            Tun => TUN.len(),\n            Nlmon => NLMON.len(),\n            Vlan => VLAN.len(),\n            Veth => VETH.len(),\n            Vxlan => VXLAN.len(),\n            Bond => BOND.len(),\n            IpVlan => IPVLAN.len(),\n            MacVlan => MACVLAN.len(),\n            MacVtap => MACVTAP.len(),\n            GreTap => GRETAP.len(),\n            GreTap6 => IP6GRETAP.len(),\n            IpTun => IPIP.len(),\n            SitTun => SIT.len(),\n            GreTun => GRE.len(),\n            GreTun6 => IP6GRE.len(),\n            Vti => VTI.len(),\n            Vrf => VRF.len(),\n            Gtp => GTP.len(),\n            Ipoib => IPOIB.len(),\n            Wireguard => WIREGUARD.len(),\n            Other(ref s) => s.len(),\n        };\n        len + 1\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoKind::*;\n        let s = match *self {\n            Dummy => DUMMY,\n            Ifb => IFB,\n            Bridge => BRIDGE,\n            Tun => TUN,\n            Nlmon => NLMON,\n            Vlan => VLAN,\n            Veth => VETH,\n            Vxlan => VXLAN,\n            Bond => BOND,\n            IpVlan => IPVLAN,\n            MacVlan => MACVLAN,\n            MacVtap => MACVTAP,\n            GreTap => GRETAP,\n            GreTap6 => IP6GRETAP,\n            IpTun => IPIP,\n            SitTun => SIT,\n            GreTun => GRE,\n            GreTun6 => IP6GRE,\n            Vti => VTI,\n            Vrf => VRF,\n            Gtp => GTP,\n            Ipoib => IPOIB,\n            Wireguard => WIREGUARD,\n            Other(ref s) => s.as_str(),\n        };\n        buffer[..s.len()].copy_from_slice(s.as_bytes());\n        buffer[s.len()] = 0;\n    }\n\n    fn kind(&self) -> u16 {\n        IFLA_INFO_KIND\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoKind {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<InfoKind, DecodeError> {\n        use self::InfoKind::*;\n        if buf.kind() != IFLA_INFO_KIND {\n            return Err(\n                format!(\"failed to parse IFLA_INFO_KIND: NLA type is {}\", buf.kind()).into(),\n            );\n        }\n        let s = parse_string(buf.value()).context(\"invalid IFLA_INFO_KIND value\")?;\n        Ok(match s.as_str() {\n            DUMMY => Dummy,\n            IFB => Ifb,\n            BRIDGE => Bridge,\n            TUN => Tun,\n            NLMON => Nlmon,\n            VLAN => Vlan,\n            VETH => Veth,\n            VXLAN => Vxlan,\n            BOND => Bond,\n            IPVLAN => IpVlan,\n            MACVLAN => MacVlan,\n            MACVTAP => MacVtap,\n            GRETAP => GreTap,\n            IP6GRETAP => GreTap6,\n            IPIP => IpTun,\n            SIT => SitTun,\n            GRE => GreTun,\n            IP6GRE => GreTun6,\n            VTI => Vti,\n            VRF => Vrf,\n            GTP => Gtp,\n            IPOIB => Ipoib,\n            WIREGUARD => Wireguard,\n            _ => Other(s),\n        })\n    }\n}\n\n// https://elixir.bootlin.com/linux/v5.9.8/source/drivers/net/vxlan.c#L3332\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoVxlan {\n    Unspec(Vec<u8>),\n    Id(u32),\n    Group(Vec<u8>),\n    Group6(Vec<u8>),\n    Link(u32),\n    Local(Vec<u8>),\n    Local6(Vec<u8>),\n    Tos(u8),\n    Ttl(u8),\n    Label(u32),\n    Learning(u8),\n    Ageing(u32),\n    Limit(u32),\n    PortRange((u16, u16)),\n    Proxy(u8),\n    Rsc(u8),\n    L2Miss(u8),\n    L3Miss(u8),\n    CollectMetadata(u8),\n    Port(u16),\n    UDPCsum(u8),\n    UDPZeroCsumTX(u8),\n    UDPZeroCsumRX(u8),\n    RemCsumTX(u8),\n    RemCsumRX(u8),\n    Gbp(u8),\n    Gpe(u8),\n    RemCsumNoPartial(u8),\n    TtlInherit(u8),\n    Df(u8),\n}\n\nimpl Nla for InfoVxlan {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::InfoVxlan::*;\n        match *self {\n            Tos(_)\n                | Ttl(_)\n                | Learning(_)\n                | Proxy(_)\n                | Rsc(_)\n                | L2Miss(_)\n                | L3Miss(_)\n                | CollectMetadata(_)\n                | UDPCsum(_)\n                | UDPZeroCsumTX(_)\n                | UDPZeroCsumRX(_)\n                | RemCsumTX(_)\n                | RemCsumRX(_)\n                | Gbp(_)\n                | Gpe(_)\n                | RemCsumNoPartial(_)\n                | TtlInherit(_)\n                | Df(_)\n            => 1,\n            Port(_) => 2,\n            Id(_)\n                | Label(_)\n                | Link(_)\n                | Ageing(_)\n                | Limit(_)\n                | PortRange(_)\n            => 4,\n            Local(ref bytes)\n                | Local6(ref bytes)\n                | Group(ref bytes)\n                | Group6(ref bytes)\n                | Unspec(ref bytes)\n            => bytes.len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoVxlan::*;\n        match self {\n            Unspec(ref bytes) => buffer.copy_from_slice(bytes),\n            Id(ref value)\n                | Label(ref value)\n                | Link(ref value)\n                | Ageing(ref value)\n                | Limit(ref value)\n            => NativeEndian::write_u32(buffer, *value),\n            Tos(ref value)\n                | Ttl(ref value)\n                | Learning (ref value)\n                | Proxy(ref value)\n                | Rsc(ref value)\n                | L2Miss(ref value)\n                | L3Miss(ref value)\n                | CollectMetadata(ref value)\n                | UDPCsum(ref value)\n                | UDPZeroCsumTX(ref value)\n                | UDPZeroCsumRX(ref value)\n                | RemCsumTX(ref value)\n                | RemCsumRX(ref value)\n                | Gbp(ref value)\n                | Gpe(ref value)\n                | RemCsumNoPartial(ref value)\n                | TtlInherit(ref value)\n                | Df(ref value)\n            =>  buffer[0] = *value,\n            Local(ref value)\n                | Group(ref value)\n                | Group6(ref value)\n                | Local6(ref value)\n            => buffer.copy_from_slice(value.as_slice()),\n            Port(ref value) => NativeEndian::write_u16(buffer, *value),\n            PortRange(ref range) => {\n                NativeEndian::write_u16(buffer, range.0);\n                NativeEndian::write_u16(buffer, range.1)\n            }\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoVxlan::*;\n\n        match self {\n            Id(_) => IFLA_VXLAN_ID,\n            Group(_) => IFLA_VXLAN_GROUP,\n            Group6(_) => IFLA_VXLAN_GROUP6,\n            Link(_) => IFLA_VXLAN_LINK,\n            Local(_) => IFLA_VXLAN_LOCAL,\n            Local6(_) => IFLA_VXLAN_LOCAL6,\n            Tos(_) => IFLA_VXLAN_TOS,\n            Ttl(_) => IFLA_VXLAN_TTL,\n            Label(_) => IFLA_VXLAN_LABEL,\n            Learning(_) => IFLA_VXLAN_LEARNING,\n            Ageing(_) => IFLA_VXLAN_AGEING,\n            Limit(_) => IFLA_VXLAN_LIMIT,\n            PortRange(_) => IFLA_VXLAN_PORT_RANGE,\n            Proxy(_) => IFLA_VXLAN_PROXY,\n            Rsc(_) => IFLA_VXLAN_RSC,\n            L2Miss(_) => IFLA_VXLAN_L2MISS,\n            L3Miss(_) => IFLA_VXLAN_L3MISS,\n            CollectMetadata(_) => IFLA_VXLAN_COLLECT_METADATA,\n            Port(_) => IFLA_VXLAN_PORT,\n            UDPCsum(_) => IFLA_VXLAN_UDP_CSUM,\n            UDPZeroCsumTX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_TX,\n            UDPZeroCsumRX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_RX,\n            RemCsumTX(_) => IFLA_VXLAN_REMCSUM_TX,\n            RemCsumRX(_) => IFLA_VXLAN_REMCSUM_RX,\n            Gbp(_) => IFLA_VXLAN_GBP,\n            Gpe(_) => IFLA_VXLAN_GPE,\n            RemCsumNoPartial(_) => IFLA_VXLAN_REMCSUM_NOPARTIAL,\n            TtlInherit(_) => IFLA_VXLAN_TTL_INHERIT,\n            Df(_) => IFLA_VXLAN_DF,\n            Unspec(_) => IFLA_VXLAN_UNSPEC,\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVxlan {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoVxlan::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_VLAN_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_VXLAN_ID => Id(parse_u32(payload).context(\"invalid IFLA_VXLAN_ID value\")?),\n            IFLA_VXLAN_GROUP => Group(payload.to_vec()),\n            IFLA_VXLAN_GROUP6 => Group6(payload.to_vec()),\n            IFLA_VXLAN_LINK => Link(parse_u32(payload).context(\"invalid IFLA_VXLAN_LINK value\")?),\n            IFLA_VXLAN_LOCAL => Local(payload.to_vec()),\n            IFLA_VXLAN_LOCAL6 => Local6(payload.to_vec()),\n            IFLA_VXLAN_TOS => Tos(parse_u8(payload).context(\"invalid IFLA_VXLAN_TOS value\")?),\n            IFLA_VXLAN_TTL => Ttl(parse_u8(payload).context(\"invalid IFLA_VXLAN_TTL value\")?),\n            IFLA_VXLAN_LABEL => {\n                Label(parse_u32(payload).context(\"invalid IFLA_VXLAN_LABEL value\")?)\n            }\n            IFLA_VXLAN_LEARNING => {\n                Learning(parse_u8(payload).context(\"invalid IFLA_VXLAN_LEARNING value\")?)\n            }\n            IFLA_VXLAN_AGEING => {\n                Ageing(parse_u32(payload).context(\"invalid IFLA_VXLAN_AGEING value\")?)\n            }\n            IFLA_VXLAN_LIMIT => {\n                Limit(parse_u32(payload).context(\"invalid IFLA_VXLAN_LIMIT value\")?)\n            }\n            IFLA_VXLAN_PROXY => Proxy(parse_u8(payload).context(\"invalid IFLA_VXLAN_PROXY value\")?),\n            IFLA_VXLAN_RSC => Rsc(parse_u8(payload).context(\"invalid IFLA_VXLAN_RSC value\")?),\n            IFLA_VXLAN_L2MISS => {\n                L2Miss(parse_u8(payload).context(\"invalid IFLA_VXLAN_L2MISS value\")?)\n            }\n            IFLA_VXLAN_L3MISS => {\n                L3Miss(parse_u8(payload).context(\"invalid IFLA_VXLAN_L3MISS value\")?)\n            }\n            IFLA_VXLAN_COLLECT_METADATA => CollectMetadata(\n                parse_u8(payload).context(\"invalid IFLA_VXLAN_COLLECT_METADATA value\")?,\n            ),\n            IFLA_VXLAN_PORT_RANGE => {\n                let err = \"invalid IFLA_VXLAN_PORT value\";\n                if payload.len() != 4 {\n                    return Err(err.into());\n                }\n                let low = parse_u16(&payload[0..2]).context(err)?;\n                let high = parse_u16(&payload[2..]).context(err)?;\n                PortRange((low, high))\n            }\n            IFLA_VXLAN_PORT => {\n                Port(parse_u16_be(payload).context(\"invalid IFLA_VXLAN_PORT value\")?)\n            }\n            IFLA_VXLAN_UDP_CSUM => {\n                UDPCsum(parse_u8(payload).context(\"invalid IFLA_VXLAN_UDP_CSUM value\")?)\n            }\n            IFLA_VXLAN_UDP_ZERO_CSUM6_TX => UDPZeroCsumTX(\n                parse_u8(payload).context(\"invalid IFLA_VXLAN_UDP_ZERO_CSUM6_TX value\")?,\n            ),\n            IFLA_VXLAN_UDP_ZERO_CSUM6_RX => UDPZeroCsumRX(\n                parse_u8(payload).context(\"invalid IFLA_VXLAN_UDP_ZERO_CSUM6_RX value\")?,\n            ),\n            IFLA_VXLAN_REMCSUM_TX => {\n                RemCsumTX(parse_u8(payload).context(\"invalid IFLA_VXLAN_REMCSUM_TX value\")?)\n            }\n            IFLA_VXLAN_REMCSUM_RX => {\n                RemCsumRX(parse_u8(payload).context(\"invalid IFLA_VXLAN_REMCSUM_RX value\")?)\n            }\n            IFLA_VXLAN_DF => Df(parse_u8(payload).context(\"invalid IFLA_VXLAN_DF value\")?),\n            IFLA_VXLAN_GBP => Gbp(parse_u8(payload).context(\"invalid IFLA_VXLAN_GBP value\")?),\n            IFLA_VXLAN_GPE => Gpe(parse_u8(payload).context(\"invalid IFLA_VXLAN_GPE value\")?),\n            IFLA_VXLAN_REMCSUM_NOPARTIAL => RemCsumNoPartial(\n                parse_u8(payload).context(\"invalid IFLA_VXLAN_REMCSUM_NO_PARTIAL\")?,\n            ),\n            IFLA_VXLAN_TTL_INHERIT => {\n                TtlInherit(parse_u8(payload).context(\"invalid IFLA_VXLAN_TTL_INHERIT value\")?)\n            }\n            __IFLA_VXLAN_MAX => Unspec(payload.to_vec()),\n            _ => return Err(format!(\"unknown NLA type {}\", buf.kind()).into()),\n        })\n    }\n}\n\n// https://elixir.bootlin.com/linux/latest/source/net/8021q/vlan_netlink.c#L21\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoVlan {\n    Unspec(Vec<u8>),\n    Id(u16),\n    Flags((u32, u32)),\n    EgressQos(Vec<u8>),\n    IngressQos(Vec<u8>),\n    Protocol(u16),\n}\n\nimpl Nla for InfoVlan {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::InfoVlan::*;\n        match self {\n            Id(_) | Protocol(_) => 2,\n            Flags(_) => 8,\n            Unspec(bytes)\n                | EgressQos(bytes)\n                | IngressQos(bytes)\n                => bytes.len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoVlan::*;\n        match self {\n            Unspec(ref bytes)\n                | EgressQos(ref bytes)\n                | IngressQos(ref bytes)\n                => buffer.copy_from_slice(bytes),\n\n            Id(ref value)\n                | Protocol(ref value)\n                => NativeEndian::write_u16(buffer, *value),\n\n            Flags(ref flags) => {\n                NativeEndian::write_u32(buffer, flags.0);\n                NativeEndian::write_u32(buffer, flags.1)\n            }\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoVlan::*;\n        match self {\n            Unspec(_) => IFLA_VLAN_UNSPEC,\n            Id(_) => IFLA_VLAN_ID,\n            Flags(_) => IFLA_VLAN_FLAGS,\n            EgressQos(_) => IFLA_VLAN_EGRESS_QOS,\n            IngressQos(_) => IFLA_VLAN_INGRESS_QOS,\n            Protocol(_) => IFLA_VLAN_PROTOCOL,\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVlan {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoVlan::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_VLAN_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_VLAN_ID => Id(parse_u16(payload).context(\"invalid IFLA_VLAN_ID value\")?),\n            IFLA_VLAN_FLAGS => {\n                let err = \"invalid IFLA_VLAN_FLAGS value\";\n                if payload.len() != 8 {\n                    return Err(err.into());\n                }\n                let flags = parse_u32(&payload[0..4]).context(err)?;\n                let mask = parse_u32(&payload[4..]).context(err)?;\n                Flags((flags, mask))\n            }\n            IFLA_VLAN_EGRESS_QOS => EgressQos(payload.to_vec()),\n            IFLA_VLAN_INGRESS_QOS => IngressQos(payload.to_vec()),\n            IFLA_VLAN_PROTOCOL => {\n                Protocol(parse_u16_be(payload).context(\"invalid IFLA_VLAN_PROTOCOL value\")?)\n            }\n            _ => return Err(format!(\"unknown NLA type {}\", buf.kind()).into()),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoBridge {\n    Unspec(Vec<u8>),\n    GroupAddr([u8; 6]),\n    // FIXME: what type is this? putting Vec<u8> for now but it might\n    // be a boolean actually\n    FdbFlush(Vec<u8>),\n    Pad(Vec<u8>),\n    HelloTimer(u64),\n    TcnTimer(u64),\n    TopologyChangeTimer(u64),\n    GcTimer(u64),\n    MulticastMembershipInterval(u64),\n    MulticastQuerierInterval(u64),\n    MulticastQueryInterval(u64),\n    MulticastQueryResponseInterval(u64),\n    MulticastLastMemberInterval(u64),\n    MulticastStartupQueryInterval(u64),\n    ForwardDelay(u32),\n    HelloTime(u32),\n    MaxAge(u32),\n    AgeingTime(u32),\n    StpState(u32),\n    MulticastHashElasticity(u32),\n    MulticastHashMax(u32),\n    MulticastLastMemberCount(u32),\n    MulticastStartupQueryCount(u32),\n    RootPathCost(u32),\n    Priority(u16),\n    VlanProtocol(u16),\n    GroupFwdMask(u16),\n    RootId((u16, [u8; 6])),\n    BridgeId((u16, [u8; 6])),\n    RootPort(u16),\n    VlanDefaultPvid(u16),\n    VlanFiltering(u8),\n    TopologyChange(u8),\n    TopologyChangeDetected(u8),\n    MulticastRouter(u8),\n    MulticastSnooping(u8),\n    MulticastQueryUseIfaddr(u8),\n    MulticastQuerier(u8),\n    NfCallIpTables(u8),\n    NfCallIp6Tables(u8),\n    NfCallArpTables(u8),\n    VlanStatsEnabled(u8),\n    MulticastStatsEnabled(u8),\n    MulticastIgmpVersion(u8),\n    MulticastMldVersion(u8),\n    VlanStatsPerHost(u8),\n    MultiBoolOpt(u64),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoBridge {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::InfoBridge::*;\n        match self {\n            Unspec(bytes)\n                | FdbFlush(bytes)\n                | Pad(bytes)\n                => bytes.len(),\n            HelloTimer(_)\n                | TcnTimer(_)\n                | TopologyChangeTimer(_)\n                | GcTimer(_)\n                | MulticastMembershipInterval(_)\n                | MulticastQuerierInterval(_)\n                | MulticastQueryInterval(_)\n                | MulticastQueryResponseInterval(_)\n                | MulticastLastMemberInterval(_)\n                | MulticastStartupQueryInterval(_)\n                => 8,\n            ForwardDelay(_)\n                | HelloTime(_)\n                | MaxAge(_)\n                | AgeingTime(_)\n                | StpState(_)\n                | MulticastHashElasticity(_)\n                | MulticastHashMax(_)\n                | MulticastLastMemberCount(_)\n                | MulticastStartupQueryCount(_)\n                | RootPathCost(_)\n                => 4,\n            Priority(_)\n                | VlanProtocol(_)\n                | GroupFwdMask(_)\n                | RootPort(_)\n                | VlanDefaultPvid(_)\n                => 2,\n\n            RootId(_)\n                | BridgeId(_)\n                | MultiBoolOpt(_)\n                => 8,\n\n            GroupAddr(_) => 6,\n\n            VlanFiltering(_)\n                | TopologyChange(_)\n                | TopologyChangeDetected(_)\n                | MulticastRouter(_)\n                | MulticastSnooping(_)\n                | MulticastQueryUseIfaddr(_)\n                | MulticastQuerier(_)\n                | NfCallIpTables(_)\n                | NfCallIp6Tables(_)\n                | NfCallArpTables(_)\n                | VlanStatsEnabled(_)\n                | MulticastStatsEnabled(_)\n                | MulticastIgmpVersion(_)\n                | MulticastMldVersion(_)\n                | VlanStatsPerHost(_)\n                => 1,\n            Other(nla)\n                => nla.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoBridge::*;\n        match self {\n            Unspec(ref bytes)\n                | FdbFlush(ref bytes)\n                | Pad(ref bytes)\n                => buffer.copy_from_slice(bytes),\n\n            HelloTimer(ref value)\n                | TcnTimer(ref value)\n                | TopologyChangeTimer(ref value)\n                | GcTimer(ref value)\n                | MulticastMembershipInterval(ref value)\n                | MulticastQuerierInterval(ref value)\n                | MulticastQueryInterval(ref value)\n                | MulticastQueryResponseInterval(ref value)\n                | MulticastLastMemberInterval(ref value)\n                | MulticastStartupQueryInterval(ref value)\n                | MultiBoolOpt(ref value)\n                => NativeEndian::write_u64(buffer, *value),\n\n            ForwardDelay(ref value)\n                | HelloTime(ref value)\n                | MaxAge(ref value)\n                | AgeingTime(ref value)\n                | StpState(ref value)\n                | MulticastHashElasticity(ref value)\n                | MulticastHashMax(ref value)\n                | MulticastLastMemberCount(ref value)\n                | MulticastStartupQueryCount(ref value)\n                | RootPathCost(ref value)\n                => NativeEndian::write_u32(buffer, *value),\n\n            Priority(ref value)\n                | GroupFwdMask(ref value)\n                | RootPort(ref value)\n                | VlanDefaultPvid(ref value)\n                => NativeEndian::write_u16(buffer, *value),\n\n            VlanProtocol(ref value)\n                => BigEndian::write_u16(buffer, *value),\n\n            RootId((ref priority, ref address))\n                | BridgeId((ref priority, ref address))\n                => {\n                    NativeEndian::write_u16(buffer, *priority);\n                    buffer[2..].copy_from_slice(&address[..]);\n                }\n\n            GroupAddr(ref value) => buffer.copy_from_slice(&value[..]),\n\n            VlanFiltering(ref value)\n                | TopologyChange(ref value)\n                | TopologyChangeDetected(ref value)\n                | MulticastRouter(ref value)\n                | MulticastSnooping(ref value)\n                | MulticastQueryUseIfaddr(ref value)\n                | MulticastQuerier(ref value)\n                | NfCallIpTables(ref value)\n                | NfCallIp6Tables(ref value)\n                | NfCallArpTables(ref value)\n                | VlanStatsEnabled(ref value)\n                | MulticastStatsEnabled(ref value)\n                | MulticastIgmpVersion(ref value)\n                | MulticastMldVersion(ref value)\n                | VlanStatsPerHost(ref value)\n                => buffer[0] = *value,\n\n            Other(nla)\n                => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoBridge::*;\n        match self {\n            Unspec(_) => IFLA_BR_UNSPEC,\n            GroupAddr(_) => IFLA_BR_GROUP_ADDR,\n            FdbFlush(_) => IFLA_BR_FDB_FLUSH,\n            Pad(_) => IFLA_BR_PAD,\n            HelloTimer(_) => IFLA_BR_HELLO_TIMER,\n            TcnTimer(_) => IFLA_BR_TCN_TIMER,\n            TopologyChangeTimer(_) => IFLA_BR_TOPOLOGY_CHANGE_TIMER,\n            GcTimer(_) => IFLA_BR_GC_TIMER,\n            MulticastMembershipInterval(_) => IFLA_BR_MCAST_MEMBERSHIP_INTVL,\n            MulticastQuerierInterval(_) => IFLA_BR_MCAST_QUERIER_INTVL,\n            MulticastQueryInterval(_) => IFLA_BR_MCAST_QUERY_INTVL,\n            MulticastQueryResponseInterval(_) => IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,\n            ForwardDelay(_) => IFLA_BR_FORWARD_DELAY,\n            HelloTime(_) => IFLA_BR_HELLO_TIME,\n            MaxAge(_) => IFLA_BR_MAX_AGE,\n            AgeingTime(_) => IFLA_BR_AGEING_TIME,\n            StpState(_) => IFLA_BR_STP_STATE,\n            MulticastHashElasticity(_) => IFLA_BR_MCAST_HASH_ELASTICITY,\n            MulticastHashMax(_) => IFLA_BR_MCAST_HASH_MAX,\n            MulticastLastMemberCount(_) => IFLA_BR_MCAST_LAST_MEMBER_CNT,\n            MulticastStartupQueryCount(_) => IFLA_BR_MCAST_STARTUP_QUERY_CNT,\n            MulticastLastMemberInterval(_) => IFLA_BR_MCAST_LAST_MEMBER_INTVL,\n            MulticastStartupQueryInterval(_) => IFLA_BR_MCAST_STARTUP_QUERY_INTVL,\n            RootPathCost(_) => IFLA_BR_ROOT_PATH_COST,\n            Priority(_) => IFLA_BR_PRIORITY,\n            VlanProtocol(_) => IFLA_BR_VLAN_PROTOCOL,\n            GroupFwdMask(_) => IFLA_BR_GROUP_FWD_MASK,\n            RootId(_) => IFLA_BR_ROOT_ID,\n            BridgeId(_) => IFLA_BR_BRIDGE_ID,\n            RootPort(_) => IFLA_BR_ROOT_PORT,\n            VlanDefaultPvid(_) => IFLA_BR_VLAN_DEFAULT_PVID,\n            VlanFiltering(_) => IFLA_BR_VLAN_FILTERING,\n            TopologyChange(_) => IFLA_BR_TOPOLOGY_CHANGE,\n            TopologyChangeDetected(_) => IFLA_BR_TOPOLOGY_CHANGE_DETECTED,\n            MulticastRouter(_) => IFLA_BR_MCAST_ROUTER,\n            MulticastSnooping(_) => IFLA_BR_MCAST_SNOOPING,\n            MulticastQueryUseIfaddr(_) => IFLA_BR_MCAST_QUERY_USE_IFADDR,\n            MulticastQuerier(_) => IFLA_BR_MCAST_QUERIER,\n            NfCallIpTables(_) => IFLA_BR_NF_CALL_IPTABLES,\n            NfCallIp6Tables(_) => IFLA_BR_NF_CALL_IP6TABLES,\n            NfCallArpTables(_) => IFLA_BR_NF_CALL_ARPTABLES,\n            VlanStatsEnabled(_) => IFLA_BR_VLAN_STATS_ENABLED,\n            MulticastStatsEnabled(_) => IFLA_BR_MCAST_STATS_ENABLED,\n            MulticastIgmpVersion(_) => IFLA_BR_MCAST_IGMP_VERSION,\n            MulticastMldVersion(_) => IFLA_BR_MCAST_MLD_VERSION,\n            VlanStatsPerHost(_) => IFLA_BR_VLAN_STATS_PER_PORT,\n            MultiBoolOpt(_) => IFLA_BR_MULTI_BOOLOPT,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoBridge {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoBridge::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_BR_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_BR_FDB_FLUSH => FdbFlush(payload.to_vec()),\n            IFLA_BR_PAD => Pad(payload.to_vec()),\n            IFLA_BR_HELLO_TIMER => {\n                HelloTimer(parse_u64(payload).context(\"invalid IFLA_BR_HELLO_TIMER value\")?)\n            }\n            IFLA_BR_TCN_TIMER => {\n                TcnTimer(parse_u64(payload).context(\"invalid IFLA_BR_TCN_TIMER value\")?)\n            }\n            IFLA_BR_TOPOLOGY_CHANGE_TIMER => TopologyChangeTimer(\n                parse_u64(payload).context(\"invalid IFLA_BR_TOPOLOGY_CHANGE_TIMER value\")?,\n            ),\n            IFLA_BR_GC_TIMER => {\n                GcTimer(parse_u64(payload).context(\"invalid IFLA_BR_GC_TIMER value\")?)\n            }\n            IFLA_BR_MCAST_LAST_MEMBER_INTVL => MulticastLastMemberInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_LAST_MEMBER_INTVL value\")?,\n            ),\n            IFLA_BR_MCAST_MEMBERSHIP_INTVL => MulticastMembershipInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_MEMBERSHIP_INTVL value\")?,\n            ),\n            IFLA_BR_MCAST_QUERIER_INTVL => MulticastQuerierInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_QUERIER_INTVL value\")?,\n            ),\n            IFLA_BR_MCAST_QUERY_INTVL => MulticastQueryInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_QUERY_INTVL value\")?,\n            ),\n            IFLA_BR_MCAST_QUERY_RESPONSE_INTVL => MulticastQueryResponseInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_QUERY_RESPONSE_INTVL value\")?,\n            ),\n            IFLA_BR_MCAST_STARTUP_QUERY_INTVL => MulticastStartupQueryInterval(\n                parse_u64(payload).context(\"invalid IFLA_BR_MCAST_STARTUP_QUERY_INTVL value\")?,\n            ),\n            IFLA_BR_FORWARD_DELAY => {\n                ForwardDelay(parse_u32(payload).context(\"invalid IFLA_BR_FORWARD_DELAY value\")?)\n            }\n            IFLA_BR_HELLO_TIME => {\n                HelloTime(parse_u32(payload).context(\"invalid IFLA_BR_HELLO_TIME value\")?)\n            }\n            IFLA_BR_MAX_AGE => MaxAge(parse_u32(payload).context(\"invalid IFLA_BR_MAX_AGE value\")?),\n            IFLA_BR_AGEING_TIME => {\n                AgeingTime(parse_u32(payload).context(\"invalid IFLA_BR_AGEING_TIME value\")?)\n            }\n            IFLA_BR_STP_STATE => {\n                StpState(parse_u32(payload).context(\"invalid IFLA_BR_STP_STATE value\")?)\n            }\n            IFLA_BR_MCAST_HASH_ELASTICITY => MulticastHashElasticity(\n                parse_u32(payload).context(\"invalid IFLA_BR_MCAST_HASH_ELASTICITY value\")?,\n            ),\n            IFLA_BR_MCAST_HASH_MAX => MulticastHashMax(\n                parse_u32(payload).context(\"invalid IFLA_BR_MCAST_HASH_MAX value\")?,\n            ),\n            IFLA_BR_MCAST_LAST_MEMBER_CNT => MulticastLastMemberCount(\n                parse_u32(payload).context(\"invalid IFLA_BR_MCAST_LAST_MEMBER_CNT value\")?,\n            ),\n            IFLA_BR_MCAST_STARTUP_QUERY_CNT => MulticastStartupQueryCount(\n                parse_u32(payload).context(\"invalid IFLA_BR_MCAST_STARTUP_QUERY_CNT value\")?,\n            ),\n            IFLA_BR_ROOT_PATH_COST => {\n                RootPathCost(parse_u32(payload).context(\"invalid IFLA_BR_ROOT_PATH_COST value\")?)\n            }\n            IFLA_BR_PRIORITY => {\n                Priority(parse_u16(payload).context(\"invalid IFLA_BR_PRIORITY value\")?)\n            }\n            IFLA_BR_VLAN_PROTOCOL => {\n                VlanProtocol(parse_u16_be(payload).context(\"invalid IFLA_BR_VLAN_PROTOCOL value\")?)\n            }\n            IFLA_BR_GROUP_FWD_MASK => {\n                GroupFwdMask(parse_u16(payload).context(\"invalid IFLA_BR_GROUP_FWD_MASK value\")?)\n            }\n            IFLA_BR_ROOT_ID | IFLA_BR_BRIDGE_ID => {\n                if payload.len() != 8 {\n                    return Err(\"invalid IFLA_BR_ROOT_ID or IFLA_BR_BRIDGE_ID value\".into());\n                }\n\n                let priority = NativeEndian::read_u16(&payload[..2]);\n                let address = parse_mac(&payload[2..])\n                    .context(\"invalid IFLA_BR_ROOT_ID or IFLA_BR_BRIDGE_ID value\")?;\n\n                match buf.kind() {\n                    IFLA_BR_ROOT_ID => RootId((priority, address)),\n                    IFLA_BR_BRIDGE_ID => BridgeId((priority, address)),\n                    _ => unreachable!(),\n                }\n            }\n            IFLA_BR_GROUP_ADDR => {\n                GroupAddr(parse_mac(payload).context(\"invalid IFLA_BR_GROUP_ADDR value\")?)\n            }\n            IFLA_BR_ROOT_PORT => {\n                RootPort(parse_u16(payload).context(\"invalid IFLA_BR_ROOT_PORT value\")?)\n            }\n            IFLA_BR_VLAN_DEFAULT_PVID => VlanDefaultPvid(\n                parse_u16(payload).context(\"invalid IFLA_BR_VLAN_DEFAULT_PVID value\")?,\n            ),\n            IFLA_BR_VLAN_FILTERING => {\n                VlanFiltering(parse_u8(payload).context(\"invalid IFLA_BR_VLAN_FILTERING value\")?)\n            }\n            IFLA_BR_TOPOLOGY_CHANGE => {\n                TopologyChange(parse_u8(payload).context(\"invalid IFLA_BR_TOPOLOGY_CHANGE value\")?)\n            }\n            IFLA_BR_TOPOLOGY_CHANGE_DETECTED => TopologyChangeDetected(\n                parse_u8(payload).context(\"invalid IFLA_BR_TOPOLOGY_CHANGE_DETECTED value\")?,\n            ),\n            IFLA_BR_MCAST_ROUTER => {\n                MulticastRouter(parse_u8(payload).context(\"invalid IFLA_BR_MCAST_ROUTER value\")?)\n            }\n            IFLA_BR_MCAST_SNOOPING => MulticastSnooping(\n                parse_u8(payload).context(\"invalid IFLA_BR_MCAST_SNOOPING value\")?,\n            ),\n            IFLA_BR_MCAST_QUERY_USE_IFADDR => MulticastQueryUseIfaddr(\n                parse_u8(payload).context(\"invalid IFLA_BR_MCAST_QUERY_USE_IFADDR value\")?,\n            ),\n            IFLA_BR_MCAST_QUERIER => {\n                MulticastQuerier(parse_u8(payload).context(\"invalid IFLA_BR_MCAST_QUERIER value\")?)\n            }\n            IFLA_BR_NF_CALL_IPTABLES => {\n                NfCallIpTables(parse_u8(payload).context(\"invalid IFLA_BR_NF_CALL_IPTABLES value\")?)\n            }\n            IFLA_BR_NF_CALL_IP6TABLES => NfCallIp6Tables(\n                parse_u8(payload).context(\"invalid IFLA_BR_NF_CALL_IP6TABLES value\")?,\n            ),\n            IFLA_BR_NF_CALL_ARPTABLES => NfCallArpTables(\n                parse_u8(payload).context(\"invalid IFLA_BR_NF_CALL_ARPTABLES value\")?,\n            ),\n            IFLA_BR_VLAN_STATS_ENABLED => VlanStatsEnabled(\n                parse_u8(payload).context(\"invalid IFLA_BR_VLAN_STATS_ENABLED value\")?,\n            ),\n            IFLA_BR_MCAST_STATS_ENABLED => MulticastStatsEnabled(\n                parse_u8(payload).context(\"invalid IFLA_BR_MCAST_STATS_ENABLED value\")?,\n            ),\n            IFLA_BR_MCAST_IGMP_VERSION => MulticastIgmpVersion(\n                parse_u8(payload).context(\"invalid IFLA_BR_MCAST_IGMP_VERSION value\")?,\n            ),\n            IFLA_BR_MCAST_MLD_VERSION => MulticastMldVersion(\n                parse_u8(payload).context(\"invalid IFLA_BR_MCAST_MLD_VERSION value\")?,\n            ),\n            IFLA_BR_VLAN_STATS_PER_PORT => VlanStatsPerHost(\n                parse_u8(payload).context(\"invalid IFLA_BR_VLAN_STATS_PER_PORT value\")?,\n            ),\n            IFLA_BR_MULTI_BOOLOPT => {\n                MultiBoolOpt(parse_u64(payload).context(\"invalid IFLA_BR_MULTI_BOOLOPT value\")?)\n            }\n            _ => Other(\n                DefaultNla::parse(buf)\n                    .context(\"invalid link info bridge NLA value (unknown type)\")?,\n            ),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoIpoib {\n    Unspec(Vec<u8>),\n    Pkey(u16),\n    Mode(u16),\n    UmCast(u16),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoIpoib {\n    fn value_len(&self) -> usize {\n        use self::InfoIpoib::*;\n        match self {\n            Unspec(bytes) => bytes.len(),\n            Pkey(_) | Mode(_) | UmCast(_) => 2,\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoIpoib::*;\n        match self {\n            Unspec(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Pkey(value) => NativeEndian::write_u16(buffer, *value),\n            Mode(value) => NativeEndian::write_u16(buffer, *value),\n            UmCast(value) => NativeEndian::write_u16(buffer, *value),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoIpoib::*;\n        match self {\n            Unspec(_) => IFLA_IPOIB_UNSPEC,\n            Pkey(_) => IFLA_IPOIB_PKEY,\n            Mode(_) => IFLA_IPOIB_MODE,\n            UmCast(_) => IFLA_IPOIB_UMCAST,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpoib {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoIpoib::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_IPOIB_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_IPOIB_PKEY => Pkey(parse_u16(payload).context(\"invalid IFLA_IPOIB_PKEY value\")?),\n            IFLA_IPOIB_MODE => Mode(parse_u16(payload).context(\"invalid IFLA_IPOIB_MODE value\")?),\n            IFLA_IPOIB_UMCAST => {\n                UmCast(parse_u16(payload).context(\"invalid IFLA_IPOIB_UMCAST value\")?)\n            }\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum VethInfo {\n    Unspec(Vec<u8>),\n    Peer(LinkMessage),\n    Other(DefaultNla),\n}\n\nimpl Nla for VethInfo {\n    fn value_len(&self) -> usize {\n        use self::VethInfo::*;\n        match *self {\n            Unspec(ref bytes) => bytes.len(),\n            Peer(ref message) => message.buffer_len(),\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::VethInfo::*;\n        match *self {\n            Unspec(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Peer(ref message) => message.emit(buffer),\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::VethInfo::*;\n        match *self {\n            Unspec(_) => VETH_INFO_UNSPEC,\n            Peer(_) => VETH_INFO_PEER,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for VethInfo {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::VethInfo::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            VETH_INFO_UNSPEC => Unspec(payload.to_vec()),\n            VETH_INFO_PEER => {\n                let err = \"failed to parse veth link info\";\n                let buffer = LinkMessageBuffer::new_checked(&payload).context(err)?;\n                Peer(LinkMessage::parse(&buffer).context(err)?)\n            }\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoIpVlan {\n    Unspec(Vec<u8>),\n    Mode(u16),\n    Flags(u16),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoIpVlan {\n    fn value_len(&self) -> usize {\n        use self::InfoIpVlan::*;\n        match self {\n            Unspec(bytes) => bytes.len(),\n            Mode(_) | Flags(_) => 2,\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoIpVlan::*;\n        match self {\n            Unspec(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Mode(value) => NativeEndian::write_u16(buffer, *value),\n            Flags(value) => NativeEndian::write_u16(buffer, *value),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoIpVlan::*;\n        match self {\n            Unspec(_) => IFLA_IPVLAN_UNSPEC,\n            Mode(_) => IFLA_IPVLAN_MODE,\n            Flags(_) => IFLA_IPVLAN_FLAGS,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpVlan {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoIpVlan::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_IPVLAN_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_IPVLAN_MODE => Mode(parse_u16(payload).context(\"invalid IFLA_IPVLAN_MODE value\")?),\n            IFLA_IPVLAN_FLAGS => {\n                Flags(parse_u16(payload).context(\"invalid IFLA_IPVLAN_FLAGS value\")?)\n            }\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoVrf {\n    TableId(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoVrf {\n    fn value_len(&self) -> usize {\n        use self::InfoVrf::*;\n        match self {\n            TableId(_) => 4,\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoVrf::*;\n        match self {\n            TableId(value) => NativeEndian::write_u32(buffer, *value),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoVrf::*;\n        match self {\n            TableId(_) => IFLA_VRF_TABLE,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVrf {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoVrf::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_VRF_TABLE => TableId(parse_u32(payload).context(\"invalid IFLA_VRF_TABLE value\")?),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoMacVlan {\n    Unspec(Vec<u8>),\n    Mode(u32),\n    Flags(u16),\n    MacAddrMode(u32),\n    MacAddr([u8; 6]),\n    MacAddrData(Vec<InfoMacVlan>),\n    MacAddrCount(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoMacVlan {\n    fn value_len(&self) -> usize {\n        use self::InfoMacVlan::*;\n        match self {\n            Unspec(bytes) => bytes.len(),\n            Mode(_) => 4,\n            Flags(_) => 2,\n            MacAddrMode(_) => 4,\n            MacAddr(_) => 6,\n            MacAddrData(ref nlas) => nlas.as_slice().buffer_len(),\n            MacAddrCount(_) => 4,\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoMacVlan::*;\n        match self {\n            Unspec(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Mode(value) => NativeEndian::write_u32(buffer, *value),\n            Flags(value) => NativeEndian::write_u16(buffer, *value),\n            MacAddrMode(value) => NativeEndian::write_u32(buffer, *value),\n            MacAddr(bytes) => buffer.copy_from_slice(bytes),\n            MacAddrData(ref nlas) => nlas.as_slice().emit(buffer),\n            MacAddrCount(value) => NativeEndian::write_u32(buffer, *value),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoMacVlan::*;\n        match self {\n            Unspec(_) => IFLA_MACVLAN_UNSPEC,\n            Mode(_) => IFLA_MACVLAN_MODE,\n            Flags(_) => IFLA_MACVLAN_FLAGS,\n            MacAddrMode(_) => IFLA_MACVLAN_MACADDR_MODE,\n            MacAddr(_) => IFLA_MACVLAN_MACADDR,\n            MacAddrData(_) => IFLA_MACVLAN_MACADDR_DATA,\n            MacAddrCount(_) => IFLA_MACVLAN_MACADDR_COUNT,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacVlan {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoMacVlan::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_MACVLAN_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_MACVLAN_MODE => {\n                Mode(parse_u32(payload).context(\"invalid IFLA_MACVLAN_MODE value\")?)\n            }\n            IFLA_MACVLAN_FLAGS => {\n                Flags(parse_u16(payload).context(\"invalid IFLA_MACVLAN_FLAGS value\")?)\n            }\n            IFLA_MACVLAN_MACADDR_MODE => {\n                MacAddrMode(parse_u32(payload).context(\"invalid IFLA_MACVLAN_MACADDR_MODE value\")?)\n            }\n            IFLA_MACVLAN_MACADDR => {\n                MacAddr(parse_mac(payload).context(\"invalid IFLA_MACVLAN_MACADDR value\")?)\n            }\n            IFLA_MACVLAN_MACADDR_DATA => {\n                let mut mac_data = Vec::new();\n                let err = \"failed to parse IFLA_MACVLAN_MACADDR_DATA\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(err)?;\n                    let parsed = InfoMacVlan::parse(nla).context(err)?;\n                    mac_data.push(parsed);\n                }\n                MacAddrData(mac_data)\n            }\n            IFLA_MACVLAN_MACADDR_COUNT => MacAddrCount(\n                parse_u32(payload).context(\"invalid IFLA_MACVLAN_MACADDR_COUNT value\")?,\n            ),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum InfoMacVtap {\n    Unspec(Vec<u8>),\n    Mode(u32),\n    Flags(u16),\n    MacAddrMode(u32),\n    MacAddr([u8; 6]),\n    MacAddrData(Vec<InfoMacVtap>),\n    MacAddrCount(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for InfoMacVtap {\n    fn value_len(&self) -> usize {\n        use self::InfoMacVtap::*;\n        match self {\n            Unspec(bytes) => bytes.len(),\n            Mode(_) => 4,\n            Flags(_) => 2,\n            MacAddrMode(_) => 4,\n            MacAddr(_) => 6,\n            MacAddrData(ref nlas) => nlas.as_slice().buffer_len(),\n            MacAddrCount(_) => 4,\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::InfoMacVtap::*;\n        match self {\n            Unspec(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Mode(value) => NativeEndian::write_u32(buffer, *value),\n            Flags(value) => NativeEndian::write_u16(buffer, *value),\n            MacAddrMode(value) => NativeEndian::write_u32(buffer, *value),\n            MacAddr(bytes) => buffer.copy_from_slice(bytes),\n            MacAddrData(ref nlas) => nlas.as_slice().emit(buffer),\n            MacAddrCount(value) => NativeEndian::write_u32(buffer, *value),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::InfoMacVtap::*;\n        match self {\n            Unspec(_) => IFLA_MACVLAN_UNSPEC,\n            Mode(_) => IFLA_MACVLAN_MODE,\n            Flags(_) => IFLA_MACVLAN_FLAGS,\n            MacAddrMode(_) => IFLA_MACVLAN_MACADDR_MODE,\n            MacAddr(_) => IFLA_MACVLAN_MACADDR,\n            MacAddrData(_) => IFLA_MACVLAN_MACADDR_DATA,\n            MacAddrCount(_) => IFLA_MACVLAN_MACADDR_COUNT,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoMacVtap {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::InfoMacVtap::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_MACVLAN_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_MACVLAN_MODE => {\n                Mode(parse_u32(payload).context(\"invalid IFLA_MACVLAN_MODE value\")?)\n            }\n            IFLA_MACVLAN_FLAGS => {\n                Flags(parse_u16(payload).context(\"invalid IFLA_MACVLAN_FLAGS value\")?)\n            }\n            IFLA_MACVLAN_MACADDR_MODE => {\n                MacAddrMode(parse_u32(payload).context(\"invalid IFLA_MACVLAN_MACADDR_MODE value\")?)\n            }\n            IFLA_MACVLAN_MACADDR => {\n                MacAddr(parse_mac(payload).context(\"invalid IFLA_MACVLAN_MACADDR value\")?)\n            }\n            IFLA_MACVLAN_MACADDR_DATA => {\n                let mut mac_data = Vec::new();\n                let err = \"failed to parse IFLA_MACVLAN_MACADDR_DATA\";\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(err)?;\n                    let parsed = InfoMacVtap::parse(nla).context(err)?;\n                    mac_data.push(parsed);\n                }\n                MacAddrData(mac_data)\n            }\n            IFLA_MACVLAN_MACADDR_COUNT => MacAddrCount(\n                parse_u32(payload).context(\"invalid IFLA_MACVLAN_MACADDR_COUNT value\")?,\n            ),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::{\n        nlas::link::{bond::*, Nla},\n        traits::Emitable,\n        LinkHeader,\n        LinkMessage,\n    };\n    use std::net::{Ipv4Addr, Ipv6Addr};\n\n    #[rustfmt::skip]\n    static BRIDGE: [u8; 424] = [\n        0x0b, 0x00, // L = 11\n        0x01, 0x00, // T = 1 (IFLA_INFO_KIND)\n        0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x00, // V = \"bridge\"\n        0x00, // padding\n\n        0x9c, 0x01, // L = 412\n        0x02, 0x00, // T = 2 (IFLA_INFO_DATA)\n\n            0x0c, 0x00, // L = 12\n            0x10, 0x00, // T = 16 (IFLA_BR_HELLO_TIMER)\n            0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 35\n\n            0x0c, 0x00, // L = 12\n            0x11, 0x00, // T = 17 (IFLA_BR_TCN_TIMER)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 0\n\n            0x0c, 0x00, // L = 12\n            0x12, 0x00, // T = 18 (IFLA_BR_TOPOLOGY_CHANGE_TIMER)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 0\n\n            0x0c, 0x00, //  L = 12\n            0x13, 0x00, // T = 19 (IFLA_BR_GC_TIMER)\n            0xb5, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 14261 (0x37b5)\n\n            0x08, 0x00, // L = 8\n            0x01, 0x00, // T = 1 (IFLA_BR_FORWARD_DELAY)\n            0xc7, 0x00, 0x00, 0x00, // V = 199\n\n            0x08, 0x00, // L = 8\n            0x02, 0x00, // T = 2 (IFLA_BR_HELLO_TIME)\n            0xc7, 0x00, 0x00, 0x00, // V = 199\n\n            0x08, 0x00, // L = 8\n            0x03, 0x00, // T = 3 (IFLA_BR_MAX_AGE)\n            0xcf, 0x07, 0x00, 0x00, // V = 1999 (0x07cf)\n\n            0x08, 0x00, // L = 8\n            0x04, 0x00, // T = 4 (IFLA_BR_AGEING_TIME)\n            0x2f, 0x75, 0x00, 0x00, // V = 29999 (0x752f)\n\n            0x08, 0x00, // L = 8\n            0x05, 0x00, // T = 5 (IFLA_BR_STP_STATE)\n            0x01, 0x00, 0x00, 0x00, // V = 1\n\n            0x06, 0x00, // L = 6\n            0x06, 0x00, // T = 6 (IFLA_BR_PRIORITY)\n            0x00, 0x80, // V =  32768 (0x8000)\n            0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x07, 0x00, // T = 7 (IFLA_BR_VLAN_FILTERING)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x06, 0x00, // L = 6\n            0x09, 0x00, // T = 9 (IFLA_BR_GROUP_FWD_MASK)\n            0x00, 0x00, // V = 0\n            0x00, 0x00, // Padding\n\n            0x0c, 0x00, // L = 12\n            0x0b, 0x00, // T = 11 (IFLA_BR_BRIDGE_ID)\n            0x80, 0x00, // V (priority) = 128 (0x80)\n            0x52, 0x54, 0x00, 0xd7, 0x19, 0x3e, // V (address) = 52:54:00:d7:19:3e\n\n            0x0c, 0x00, // L = 12\n            0x0a, 0x00, // T = 10 (IFLA_BR_ROOT_ID)\n            0x80, 0x00, // V (priority) = 128 (0x80)\n            0x52, 0x54, 0x00, 0xd7, 0x19, 0x3e, // V (address) = 52:54:00:d7:19:3e\n\n            0x06, 0x00, // L = 6\n            0x0c, 0x00, // T = 12 (IFLA_BR_ROOT_PORT)\n            0x00, 0x00, // V = 0\n            0x00, 0x00, // Padding\n\n            0x08, 0x00, // L = 8\n            0x0d, 0x00, // T = 13 (IFLA_BR_ROOT_PATH_COST)\n            0x00, 0x00, 0x00, 0x00, // V = 0\n\n            0x05, 0x00, // L = 5\n            0x0e, 0x00, // T = 14 (IFLA_BR_TOPOLOGY_CHANGE)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x0f, 0x00, // T = 15 (IFLA_BR_TOPOLOGY_CHANGE_DETECTED)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x0a, 0x00, // L = 10\n            0x14, 0x00, // T = 20 (IFLA_BR_GROUP_ADDR)\n            0x01, 0x80, 0xc2, 0x00, 0x00, 0x00, // V = 01:80:c2:00:00:00\n            0x00, 0x00, // Padding\n\n            0x06, 0x00, // L = 6\n            0x08, 0x00, // T = 8 (IFLA_BR_VLAN_PROTOCOL)\n            0x81, 0x00, // V = 33024 (big-endian)\n            0x00, 0x00, // Padding\n\n            0x06, 0x00, // L = 6\n            0x27, 0x00, // T = 39 (IFLA_BR_VLAN_DEFAULT_PVID)\n            0x01, 0x00, // V = 1\n            0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x29, 0x00, // T = 41 (IFLA_BR_VLAN_STATS_ENABLED)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x16, 0x00, // T = 22 (IFLA_BR_MCAST_ROUTER)\n            0x01, // V = 1\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x17, 0x00, // T = 23 (IFLA_BR_MCAST_SNOOPING)\n            0x01, // V = 1\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x18, 0x00, // T = 24 (IFLA_BR_MCAST_QUERY_USE_IFADDR)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x19, 0x00, // T = 25 (IFLA_BR_MCAST_QUERIER)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x2a, 0x00, // T = 42 (IFLA_BR_MCAST_STATS_ENABLED)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x08, 0x00, // L = 8\n            0x1a, 0x00, // T = 26 (IFLA_BR_MCAST_HASH_ELASTICITY)\n            0x04, 0x00, 0x00, 0x00, // V = 4\n\n            0x08, 0x00, // L = 8\n            0x1b, 0x00, // T = 27 (IFLA_BR_MCAST_HASH_MAX)\n            0x00, 0x02, 0x00, 0x00, // V = 512 (0x0200)\n\n            0x08, 0x00, // L = 8\n            0x1c, 0x00, // T = 28 (IFLA_BR_MCAST_LAST_MEMBER_CNT)\n            0x02, 0x00, 0x00, 0x00, // V = 2\n\n            0x08, 0x00, // L = 8\n            0x1d, 0x00, // T = 29 (IFLA_BR_MCAST_STARTUP_QUERY_CNT)\n            0x02, 0x00, 0x00, 0x00, // V = 2\n\n            0x05, 0x00, // L = 5\n            0x2b, 0x00, // T = 43 (IFLA_BR_MCAST_IGMP_VERSION)\n            0x02, // V = 2\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x2c, 0x00, // T = 44 (IFLA_BR_MCAST_MLD_VERSION)\n            0x01, // V = 1\n            0x00, 0x00, 0x00, // Padding\n\n            0x0c, 0x00, // L = 12\n            0x1e, 0x00, // T = 30 (IFLA_BR_MCAST_LAST_MEMBER_INTVL)\n            0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 99\n\n            0x0c, 0x00, // L = 12\n            0x1f, 0x00, // T = 31 (IFLA_BR_MCAST_MEMBERSHIP_INTVL)\n            0x8f, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 25999 (0x658f)\n\n            0x0c, 0x00, // L = 12\n            0x20, 0x00, // T = 32 (IFLA_BR_MCAST_QUERIER_INTVL)\n            0x9b, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 25499 (0x639b)\n\n            0x0c, 0x00, // L = 12\n            0x21, 0x00, // T = 33 (IFLA_BR_MCAST_QUERY_INTVL)\n            0xd3, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 12499 (0x30d3)\n\n            0x0c, 0x00, // L = 12\n            0x22, 0x00, // T = 34 (IFLA_BR_MCAST_QUERY_RESPONSE_INTVL)\n            0xe7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 999 (0x03e7)\n\n            0x0c, 0x00, // L = 12\n            0x23, 0x00, // T = 35 (IFLA_BR_MCAST_STARTUP_QUERY_INTVL)\n            0x34, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // V = 3124 (0x0c34)\n\n            0x05, 0x00, // L = 5\n            0x24, 0x00, // T = 36 (IFLA_BR_NF_CALL_IPTABLES)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x25, 0x00, // T = 37 (IFLA_BR_NF_CALL_IP6TABLES)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x26, 0x00, // T = 38 (IFLA_BR_NF_CALL_ARPTABLES)\n            0x00, // V = 0\n            0x00, 0x00, 0x00, // Padding\n\n            0x05, 0x00, // L = 5\n            0x2d, 0x00, // T = 45 (IFLA_BR_VLAN_STATS_PER_PORT)\n            0x01, // V = 1\n            0x00, 0x00, 0x00, // Padding\n\n            0x0c, 0x00, // L = 12\n            0x2e, 0x00, // T = 46 (IFLA_BR_MULTI_BOOLOPT)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // V = 0\n\n    ];\n\n    lazy_static! {\n        static ref BRIDGE_INFO: Vec<InfoBridge> = vec![\n            InfoBridge::HelloTimer(35),\n            InfoBridge::TcnTimer(0),\n            InfoBridge::TopologyChangeTimer(0),\n            InfoBridge::GcTimer(14261),\n            InfoBridge::ForwardDelay(199),\n            InfoBridge::HelloTime(199),\n            InfoBridge::MaxAge(1999),\n            InfoBridge::AgeingTime(29999),\n            InfoBridge::StpState(1),\n            InfoBridge::Priority(0x8000),\n            InfoBridge::VlanFiltering(0),\n            InfoBridge::GroupFwdMask(0),\n            InfoBridge::BridgeId((128, [0x52, 0x54, 0x00, 0xd7, 0x19, 0x3e])),\n            InfoBridge::RootId((128, [0x52, 0x54, 0x00, 0xd7, 0x19, 0x3e])),\n            InfoBridge::RootPort(0),\n            InfoBridge::RootPathCost(0),\n            InfoBridge::TopologyChange(0),\n            InfoBridge::TopologyChangeDetected(0),\n            InfoBridge::GroupAddr([0x01, 0x80, 0xc2, 0x00, 0x00, 0x00]),\n            InfoBridge::VlanProtocol(33024),\n            InfoBridge::VlanDefaultPvid(1),\n            InfoBridge::VlanStatsEnabled(0),\n            InfoBridge::MulticastRouter(1),\n            InfoBridge::MulticastSnooping(1),\n            InfoBridge::MulticastQueryUseIfaddr(0),\n            InfoBridge::MulticastQuerier(0),\n            InfoBridge::MulticastStatsEnabled(0),\n            InfoBridge::MulticastHashElasticity(4),\n            InfoBridge::MulticastHashMax(512),\n            InfoBridge::MulticastLastMemberCount(2),\n            InfoBridge::MulticastStartupQueryCount(2),\n            InfoBridge::MulticastIgmpVersion(2),\n            InfoBridge::MulticastMldVersion(1),\n            InfoBridge::MulticastLastMemberInterval(99),\n            InfoBridge::MulticastMembershipInterval(25999),\n            InfoBridge::MulticastQuerierInterval(25499),\n            InfoBridge::MulticastQueryInterval(12499),\n            InfoBridge::MulticastQueryResponseInterval(999),\n            InfoBridge::MulticastStartupQueryInterval(3124),\n            InfoBridge::NfCallIpTables(0),\n            InfoBridge::NfCallIp6Tables(0),\n            InfoBridge::NfCallArpTables(0),\n            InfoBridge::VlanStatsPerHost(1),\n            InfoBridge::MultiBoolOpt(0),\n        ];\n    }\n\n    #[test]\n    fn parse_info_kind() {\n        let info_kind_nla = NlaBuffer::new_checked(&BRIDGE[..12]).unwrap();\n        let parsed = InfoKind::parse(&info_kind_nla).unwrap();\n        assert_eq!(parsed, InfoKind::Bridge);\n    }\n\n    #[test]\n    fn parse_info_bridge() {\n        let nlas = NlasIterator::new(&BRIDGE[16..]);\n        for nla in nlas.map(|nla| nla.unwrap()) {\n            InfoBridge::parse(&nla).unwrap();\n        }\n    }\n\n    #[rustfmt::skip]\n    #[test]\n    fn parse_veth_info() {\n        let data = vec![\n            0x08, 0x00, // length = 8\n            0x01, 0x00, // type = 1 = IFLA_INFO_KIND\n            0x76, 0x65, 0x74, 0x68, // VETH\n\n            0x30, 0x00, // length = 48\n            0x02, 0x00, // type = IFLA_INFO_DATA\n\n                0x2c, 0x00, // length = 44\n                0x01, 0x00, // type = VETH_INFO_PEER\n                // The data a NEWLINK message\n                0x00, // interface family\n                0x00, // padding\n                0x00, 0x00, // link layer type\n                0x00, 0x00, 0x00, 0x00, // link index\n                0x00, 0x00, 0x00, 0x00, // flags\n                0x00, 0x00, 0x00, 0x00, // flags change mask\n                    // NLA\n                    0x10, 0x00, // length = 16\n                    0x03, 0x00, // type = IFLA_IFNAME\n                    0x76, 0x65, 0x74, 0x68, 0x63, 0x30, 0x65, 0x36, 0x30, 0x64, 0x36, 0x00,\n                    // NLA\n                    0x08, 0x00, // length = 8\n                    0x0d, 0x00, // type = IFLA_TXQLEN\n                    0x00, 0x00, 0x00, 0x00,\n        ];\n        let nla = NlaBuffer::new_checked(&data[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        let expected = vec![\n            Info::Kind(InfoKind::Veth),\n            Info::Data(InfoData::Veth(VethInfo::Peer(LinkMessage {\n                header: LinkHeader {\n                    interface_family: 0,\n                    index: 0,\n                    link_layer_type: ARPHRD_NETROM,\n                    flags: 0,\n                    change_mask: 0,\n                },\n                nlas: vec![\n                    Nla::IfName(\"vethc0e60d6\".to_string()),\n                    Nla::TxQueueLen(0),\n                ],\n            }))),\n        ];\n        assert_eq!(expected, parsed);\n    }\n\n    #[rustfmt::skip]\n    #[test]\n    fn parse_info_bond() {\n        let data = vec![\n            0x08, 0x00,                // length\n            0x01, 0x00,                // IFLA_INFO_KIND\n            0x62, 0x6f, 0x6e, 0x64,    // \"bond\"\n\n            0x80, 0x00,                // length\n            0x02, 0x00,                // IFLA_INFO_DATA\n                0x05, 0x00,            // length\n                0x01, 0x00,            // IFLA_BOND_MODE\n                0x04,                  // 4 (802.3ad)\n                0x00, 0x00, 0x00,      // padding\n\n                0x08, 0x00,             // length\n                0x03, 0x00,             // IFLA_BOND_MIIMON\n                0x32, 0x00, 0x00, 0x00, // 50\n\n                0x08, 0x00,             // length\n                0x04, 0x00,             // IFLA_BOND_UPDELAY\n                0x64, 0x00, 0x00, 0x00, // 100\n\n                0x08, 0x00,             // length\n                0x05, 0x00,             // IFLA_BOND_DOWNDELAY\n                0x64, 0x00, 0x00, 0x00, // 100\n\n                0x14, 0x00,             // length\n                0x08, 0x00,             // IFLA_BOND_ARP_IP_TARGET\n                    0x08, 0x00,              // length\n                    0x00, 0x00,              // entry #0\n                    0x01, 0x02, 0x03, 0x04,  // 1.2.3.4\n                    0x08, 0x00,              // length\n                    0x01, 0x00,              // entry #1\n                    0x09, 0x09, 0x09, 0x09,  // 9.9.9.9\n\n                0x18, 0x00,             // length\n                0x1f, 0x00,             // IFLA_BOND_NS_IP6_TARGET\n                    0x14, 0x00,              // length\n                    0x00, 0x00,              // entry #0\n                    0xfd, 0x01, 0x00, 0x00,  // fd01::1\n                    0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00, 0x00,\n                    0x00, 0x00, 0x00, 0x01,\n\n                0x08, 0x00,             // length\n                0x1c, 0x00,             // IFLA_BOND_PEER_NOTIF_DELAY\n                0xc8, 0x00, 0x00, 0x00, // 200\n\n                0x08, 0x00,             // length\n                0x12, 0x00,             // IFLA_BOND_MIN_LINKS\n                0x03, 0x00, 0x00, 0x00, // 3\n\n                0x20, 0x00,             // length\n                0x17, 0x00,             // IFLA_BOND_AD_INFO\n                    0x06, 0x00,             // length\n                    0x01, 0x00,             // IFLA_BOND_AD_INFO_AGGREGATOR\n                    0x10, 0x00,             // 16\n                    0x00, 0x00,             // padding\n                    0x06, 0x00,             // length\n                    0x02, 0x00,             // IFLA_BOND_AD_INFO_NUM_PORTS\n                    0x02, 0x00,             // 2\n                    0x00, 0x00,             // padding\n                    0x0a, 0x00,             // length\n                    0x05, 0x00,             // IFLA_BOND_AD_INFO_PARTNER_MAC\n                    0x00, 0x11, 0x22,       // 00:11:22:33:44:55\n                    0x33, 0x44, 0x55,\n                    0x00, 0x00,             // padding\n        ];\n        let nla = NlaBuffer::new_checked(&data[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        let expected = vec![\n            Info::Kind(InfoKind::Bond),\n            Info::Data(InfoData::Bond(vec![InfoBond::Mode(4),\n                                           InfoBond::MiiMon(50),\n                                           InfoBond::UpDelay(100),\n                                           InfoBond::DownDelay(100),\n                                           InfoBond::ArpIpTarget(vec!(Ipv4Addr::new(1, 2, 3, 4),\n                                                                      Ipv4Addr::new(9, 9, 9, 9))),\n                                           InfoBond::NsIp6Target(vec!(Ipv6Addr::new(0xfd01, 0, 0, 0, 0, 0, 0, 1))),\n                                           InfoBond::PeerNotifDelay(200),\n                                           InfoBond::MinLinks(3),\n                                           InfoBond::AdInfo(vec!(BondAdInfo::Aggregator(16),\n                                                                 BondAdInfo::NumPorts(2),\n                                                                 BondAdInfo::PartnerMac([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))),\n            ])),\n        ];\n        assert_eq!(expected, parsed);\n    }\n\n    #[rustfmt::skip]\n    static IPVLAN: [u8; 32] = [\n        0x0b, 0x00, // length = 11\n        0x01, 0x00, // type = 1 = IFLA_INFO_KIND\n        0x69, 0x70, 0x76, 0x6c, 0x61, 0x6e, 0x00, // V = \"ipvlan\\0\"\n        0x00, // padding\n\n        0x14, 0x00, // length = 20\n        0x02, 0x00, // type = 2 = IFLA_INFO_DATA\n            0x06, 0x00, // length = 6\n            0x01, 0x00, // type = 1 = IFLA_IPVLAN_MODE\n            0x01, 0x00, // l3\n            0x00, 0x00, // padding\n\n            0x06, 0x00, // length = 6\n            0x02, 0x00, // type = 2 = IFLA_IPVLAN_FLAGS\n            0x02, 0x00, // vepa flag\n            0x00, 0x00, // padding\n    ];\n\n    lazy_static! {\n        static ref IPVLAN_INFO: Vec<InfoIpVlan> = vec![\n            InfoIpVlan::Mode(1), // L3\n            InfoIpVlan::Flags(2), // vepa flag\n        ];\n    }\n\n    #[test]\n    fn parse_info_ipvlan() {\n        let nla = NlaBuffer::new_checked(&IPVLAN[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        let expected = vec![\n            Info::Kind(InfoKind::IpVlan),\n            Info::Data(InfoData::IpVlan(IPVLAN_INFO.clone())),\n        ];\n        assert_eq!(expected, parsed);\n    }\n\n    #[test]\n    fn emit_info_ipvlan() {\n        let nlas = vec![\n            Info::Kind(InfoKind::IpVlan),\n            Info::Data(InfoData::IpVlan(IPVLAN_INFO.clone())),\n        ];\n\n        assert_eq!(nlas.as_slice().buffer_len(), 32);\n\n        let mut vec = vec![0xff; 32];\n        nlas.as_slice().emit(&mut vec);\n        assert_eq!(&vec[..], &IPVLAN[..]);\n    }\n\n    #[rustfmt::skip]\n    static MACVLAN: [u8; 24] = [\n        0x0c, 0x00, // length = 12\n        0x01, 0x00, // type = 1 = IFLA_INFO_KIND\n        0x6d, 0x61, 0x63, 0x76, 0x6c, 0x61, 0x6e, 0x00, // V = \"macvlan\\0\"\n        0x0c, 0x00, // length = 12\n        0x02, 0x00, // type = 2 = IFLA_INFO_DATA\n            0x08, 0x00, // length = 8\n            0x01, 0x00, // type = IFLA_MACVLAN_MODE\n            0x04, 0x00, 0x00, 0x00, // V = 4 = bridge\n    ];\n\n    lazy_static! {\n        static ref MACVLAN_INFO: Vec<InfoMacVlan> = vec![\n            InfoMacVlan::Mode(4), // bridge\n        ];\n    }\n\n    #[test]\n    fn parse_info_macvlan() {\n        let nla = NlaBuffer::new_checked(&MACVLAN[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        let expected = vec![\n            Info::Kind(InfoKind::MacVlan),\n            Info::Data(InfoData::MacVlan(MACVLAN_INFO.clone())),\n        ];\n        assert_eq!(expected, parsed);\n    }\n\n    #[test]\n    fn emit_info_macvlan() {\n        let nlas = vec![\n            Info::Kind(InfoKind::MacVlan),\n            Info::Data(InfoData::MacVlan(MACVLAN_INFO.clone())),\n        ];\n\n        assert_eq!(nlas.as_slice().buffer_len(), 24);\n\n        let mut vec = vec![0xff; 24];\n        nlas.as_slice().emit(&mut vec);\n        assert_eq!(&vec[..], &MACVLAN[..]);\n    }\n\n    #[rustfmt::skip]\n    static MACVLAN_SOURCE_SET: [u8; 84] = [\n        0x0c, 0x00, // length = 12\n        0x01, 0x00, // type = 1 = IFLA_INFO_KIND\n        0x6d, 0x61, 0x63, 0x76, 0x6c, 0x61, 0x6e, 0x00, // V = \"macvlan\\0\"\n        0x48, 0x00, // length = 72\n        0x02, 0x00, // type = 2 = IFLA_INFO_DATA\n            0x08, 0x00, // length = 8\n            0x03, 0x00, // type = 3 = IFLA_MACVLAN_MACADDR_MODE\n            0x03, 0x00, 0x00, 0x00, // V = 3 = set\n\n            0x34, 0x00, // length = 52\n            0x05, 0x00, // type = 5 = IFLA_MACVLAN_MACADDR_DATA\n                0x0a, 0x00, // length = 10\n                0x04, 0x00, // type = 4 = IFLA_MACVLAN_MACADDR\n                0x22, 0xf5, 0x54, 0x09, 0x88, 0xd7, // V = mac address\n                0x00, 0x00, // padding\n\n                0x0a, 0x00, // length = 10\n                0x04, 0x00, // type = 4 = IFLA_MACVLAN_MACADDR\n                0x22, 0xf5, 0x54, 0x09, 0x99, 0x32, // V = mac address\n                0x00, 0x00, // padding\n\n                0x0a, 0x00, // length = 10\n                0x04, 0x00, // type = 4 = IFLA_MACVLAN_MACADDR\n                0x22, 0xf5, 0x54, 0x09, 0x87, 0x45, // V = mac address\n                0x00, 0x00, // padding\n\n                0x0a, 0x00, // length = 10\n                0x04, 0x00, // type = 4 = IFLA_MACVLAN_MACADDR\n                0x22, 0xf5, 0x54, 0x09, 0x11, 0x45, // V = mac address\n                0x00, 0x00, // padding\n            0x08, 0x00, // length = 8\n            0x01, 0x00, // Type = 1 = IFLA_MACVLAN_MODE\n            0x10, 0x00, 0x00, 0x00, // V = 16 = source\n    ];\n\n    lazy_static! {\n        static ref MACVLAN_SOURCE_SET_INFO: Vec<InfoMacVlan> = vec![\n            InfoMacVlan::MacAddrMode(3), // set\n            InfoMacVlan::MacAddrData(vec![\n                                 InfoMacVlan::MacAddr([0x22, 0xf5, 0x54, 0x09, 0x88, 0xd7,]),\n                                 InfoMacVlan::MacAddr([0x22, 0xf5, 0x54, 0x09, 0x99, 0x32,]),\n                                 InfoMacVlan::MacAddr([0x22, 0xf5, 0x54, 0x09, 0x87, 0x45,]),\n                                 InfoMacVlan::MacAddr([0x22, 0xf5, 0x54, 0x09, 0x11, 0x45,]),\n            ]),\n            InfoMacVlan::Mode(16), // source\n        ];\n    }\n\n    #[test]\n    fn parse_info_macvlan_source_set() {\n        let nla = NlaBuffer::new_checked(&MACVLAN_SOURCE_SET[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        let expected = vec![\n            Info::Kind(InfoKind::MacVlan),\n            Info::Data(InfoData::MacVlan(MACVLAN_SOURCE_SET_INFO.clone())),\n        ];\n        assert_eq!(expected, parsed);\n    }\n\n    #[test]\n    fn emit_info_macvlan_source_set() {\n        let nlas = vec![\n            Info::Kind(InfoKind::MacVlan),\n            Info::Data(InfoData::MacVlan(MACVLAN_SOURCE_SET_INFO.clone())),\n        ];\n\n        assert_eq!(nlas.as_slice().buffer_len(), 84);\n\n        let mut vec = vec![0xff; 84];\n        nlas.as_slice().emit(&mut vec);\n        assert_eq!(&vec[..], &MACVLAN_SOURCE_SET[..]);\n    }\n\n    #[test]\n    fn parse() {\n        let nla = NlaBuffer::new_checked(&BRIDGE[..]).unwrap();\n        let parsed = VecInfo::parse(&nla).unwrap().0;\n        assert_eq!(parsed.len(), 2);\n        assert_eq!(parsed[0], Info::Kind(InfoKind::Bridge));\n        if let Info::Data(InfoData::Bridge(nlas)) = parsed[1].clone() {\n            assert_eq!(nlas.len(), BRIDGE_INFO.len());\n            for (expected, parsed) in BRIDGE_INFO.iter().zip(nlas) {\n                assert_eq!(*expected, parsed);\n            }\n        } else {\n            panic!(\n                \"expected  Info::Data(InfoData::Bridge(_) got {:?}\",\n                parsed[1]\n            )\n        }\n    }\n\n    #[test]\n    fn emit() {\n        let nlas = vec![\n            Info::Kind(InfoKind::Bridge),\n            Info::Data(InfoData::Bridge(BRIDGE_INFO.clone())),\n        ];\n\n        assert_eq!(nlas.as_slice().buffer_len(), 424);\n\n        let mut vec = vec![0xff; 424];\n        nlas.as_slice().emit(&mut vec);\n        assert_eq!(&vec[..], &BRIDGE[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/link_state.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::constants::*;\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub enum State {\n    /// Status can't be determined\n    Unknown,\n    /// Some component is missing\n    NotPresent,\n    /// Down\n    Down,\n    /// Down due to state of lower layer\n    LowerLayerDown,\n    /// In some test mode\n    Testing,\n    /// Not up but pending an external event\n    Dormant,\n    /// Up, ready to send packets\n    Up,\n    /// Unrecognized value. This should go away when `TryFrom` is stable in Rust\n    // FIXME: there's not point in having this. When TryFrom is stable we'll remove it\n    Other(u8),\n}\n\nimpl From<u8> for State {\n    fn from(value: u8) -> Self {\n        use self::State::*;\n        match value {\n            IF_OPER_UNKNOWN => Unknown,\n            IF_OPER_NOTPRESENT => NotPresent,\n            IF_OPER_DOWN => Down,\n            IF_OPER_LOWERLAYERDOWN => LowerLayerDown,\n            IF_OPER_TESTING => Testing,\n            IF_OPER_DORMANT => Dormant,\n            IF_OPER_UP => Up,\n            _ => Other(value),\n        }\n    }\n}\n\nimpl From<State> for u8 {\n    fn from(value: State) -> Self {\n        use self::State::*;\n        match value {\n            Unknown => IF_OPER_UNKNOWN,\n            NotPresent => IF_OPER_NOTPRESENT,\n            Down => IF_OPER_DOWN,\n            LowerLayerDown => IF_OPER_LOWERLAYERDOWN,\n            Testing => IF_OPER_TESTING,\n            Dormant => IF_OPER_DORMANT,\n            Up => IF_OPER_UP,\n            Other(other) => other,\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/map.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const LINK_MAP_LEN: usize = 28;\nbuffer!(MapBuffer(LINK_MAP_LEN) {\n    memory_start: (u64, 0..8),\n    memory_end: (u64, 8..16),\n    base_address: (u64, 16..24),\n    irq: (u16, 24..26),\n    dma: (u8, 26),\n    port: (u8, 27),\n});\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct Map {\n    pub memory_start: u64,\n    pub memory_end: u64,\n    pub base_address: u64,\n    pub irq: u16,\n    pub dma: u8,\n    pub port: u8,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<MapBuffer<T>> for Map {\n    fn parse(buf: &MapBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            memory_start: buf.memory_start(),\n            memory_end: buf.memory_end(),\n            base_address: buf.base_address(),\n            irq: buf.irq(),\n            dma: buf.dma(),\n            port: buf.port(),\n        })\n    }\n}\n\nimpl Emitable for Map {\n    fn buffer_len(&self) -> usize {\n        LINK_MAP_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = MapBuffer::new(buffer);\n        buffer.set_memory_start(self.memory_start);\n        buffer.set_memory_end(self.memory_end);\n        buffer.set_base_address(self.base_address);\n        buffer.set_irq(self.irq);\n        buffer.set_dma(self.dma);\n        buffer.set_port(self.port);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod inet;\npub use self::inet::*;\n\nmod inet6;\npub use self::inet6::*;\n\nmod af_spec_inet;\npub use self::af_spec_inet::*;\n\nmod af_spec_bridge;\npub use self::af_spec_bridge::*;\n\nmod link_infos;\npub use self::link_infos::*;\n\nmod bond;\npub use self::bond::*;\n\nmod prop_list;\npub use self::prop_list::*;\n\nmod map;\npub use self::map::*;\n\nmod stats;\npub use self::stats::*;\n\nmod stats64;\npub use self::stats64::*;\n\nmod link_state;\npub use self::link_state::*;\n\n#[cfg(test)]\nmod tests;\n\nuse std::os::unix::io::RawFd;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer, NlasIterator, NLA_F_NESTED},\n    parsers::{parse_i32, parse_string, parse_u32, parse_u8},\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    // Vec<u8>\n    Unspec(Vec<u8>),\n    Cost(Vec<u8>),\n    Priority(Vec<u8>),\n    Weight(Vec<u8>),\n    VfInfoList(Vec<u8>),\n    VfPorts(Vec<u8>),\n    PortSelf(Vec<u8>),\n    PhysPortId(Vec<u8>),\n    PhysSwitchId(Vec<u8>),\n    Pad(Vec<u8>),\n    Xdp(Vec<u8>),\n    Event(Vec<u8>),\n    NewNetnsId(Vec<u8>),\n    IfNetnsId(Vec<u8>),\n    CarrierUpCount(Vec<u8>),\n    CarrierDownCount(Vec<u8>),\n    NewIfIndex(Vec<u8>),\n    Info(Vec<Info>),\n    Wireless(Vec<u8>),\n    ProtoInfo(Vec<u8>),\n    /// A list of properties for the device. For additional context see the related linux kernel\n    /// threads<sup>[1][1],[2][2]</sup>. In particular see [this message][defining message] from\n    /// the first thread describing the design.\n    ///\n    /// [1]: https://lwn.net/ml/netdev/20190719110029.29466-1-jiri@resnulli.us/\n    /// [2]: https://lwn.net/ml/netdev/20190930094820.11281-1-jiri@resnulli.us/\n    /// [defining message]: https://lwn.net/ml/netdev/20190913145012.GB2276@nanopsycho.orion/\n    PropList(Vec<Prop>),\n    /// `protodown` is a mechanism that allows protocols to hold an interface down.\n    /// This field is used to specify the reason why it is held down.\n    /// For additional context see the related linux kernel threads<sup>[1][1],[2][2]</sup>.\n    ///\n    /// [1]: https://lwn.net/ml/netdev/1595877677-45849-1-git-send-email-roopa%40cumulusnetworks.com/\n    /// [2]: https://lwn.net/ml/netdev/1596242041-14347-1-git-send-email-roopa%40cumulusnetworks.com/\n    ProtoDownReason(Vec<u8>),\n    // mac address (use to be [u8; 6] but it turns out MAC != HW address, for instance for IP over\n    // GRE where it's an IPv4!)\n    Address(Vec<u8>),\n    Broadcast(Vec<u8>),\n    /// Permanent hardware address of the device. The provides the same information\n    /// as the ethtool ioctl interface.\n    PermAddress(Vec<u8>),\n\n    // string\n    // FIXME: for empty string, should we encode the NLA as \\0 or should we not set a payload? It\n    // seems that for certain attriutes, this matter:\n    // https://elixir.bootlin.com/linux/v4.17-rc5/source/net/core/rtnetlink.c#L1660\n    IfName(String),\n    Qdisc(String),\n    IfAlias(String),\n    PhysPortName(String),\n    /// Alternate name for the device.\n    /// For additional context see the related linux kernel threads<sup>[1][1],[2][2]</sup>.\n    ///\n    /// [1]: https://lwn.net/ml/netdev/20190719110029.29466-1-jiri@resnulli.us/\n    /// [2]: https://lwn.net/ml/netdev/20190930094820.11281-1-jiri@resnulli.us/\n    AltIfName(String),\n    // byte\n    Mode(u8),\n    Carrier(u8),\n    ProtoDown(u8),\n    // u32\n    Mtu(u32),\n    Link(u32),\n    Master(u32),\n    TxQueueLen(u32),\n    NetNsPid(u32),\n    NumVf(u32),\n    Group(u32),\n    NetNsFd(RawFd),\n    ExtMask(u32),\n    Promiscuity(u32),\n    NumTxQueues(u32),\n    NumRxQueues(u32),\n    CarrierChanges(u32),\n    GsoMaxSegs(u32),\n    GsoMaxSize(u32),\n    /// The minimum MTU for the device.\n    /// For additional context see the related [linux kernel message][1].\n    ///\n    /// [1]: https://lwn.net/ml/netdev/20180727204323.19408-3-sthemmin%40microsoft.com/\n    MinMtu(u32),\n    /// The maximum MTU for the device.\n    /// For additional context see the related [linux kernel message][1].\n    ///\n    /// [1]: https://lwn.net/ml/netdev/20180727204323.19408-3-sthemmin%40microsoft.com/\n    MaxMtu(u32),\n    // i32\n    NetnsId(i32),\n    // custom\n    OperState(State),\n    Stats(Vec<u8>),\n    Stats64(Vec<u8>),\n    Map(Vec<u8>),\n    // AF_SPEC (the type of af_spec depends on the interface family of the message)\n    AfSpecInet(Vec<AfSpecInet>),\n    AfSpecBridge(Vec<AfSpecBridge>),\n    //AfSpecBridge(Vec<u8>),\n    AfSpecUnknown(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes)\n                | Cost(ref bytes)\n                | Priority(ref bytes)\n                | Weight(ref bytes)\n                | VfInfoList(ref bytes)\n                | VfPorts(ref bytes)\n                | PortSelf(ref bytes)\n                | PhysPortId(ref bytes)\n                | PhysSwitchId(ref bytes)\n                | Pad(ref bytes)\n                | Xdp(ref bytes)\n                | Event(ref bytes)\n                | NewNetnsId(ref bytes)\n                | IfNetnsId(ref bytes)\n                | Wireless(ref bytes)\n                | ProtoInfo(ref bytes)\n                | CarrierUpCount(ref bytes)\n                | CarrierDownCount(ref bytes)\n                | NewIfIndex(ref bytes)\n                | Address(ref bytes)\n                | Broadcast(ref bytes)\n                | PermAddress(ref bytes)\n                | AfSpecUnknown(ref bytes)\n                | Map(ref bytes)\n                | ProtoDownReason(ref bytes)\n                => bytes.len(),\n\n            // strings: +1 because we need to append a nul byte\n            IfName(ref string)\n                | Qdisc(ref string)\n                | IfAlias(ref string)\n                | PhysPortName(ref string)\n                | AltIfName(ref string)\n                => string.as_bytes().len() + 1,\n\n            // u8\n            Mode(_)\n                | Carrier(_)\n                | ProtoDown(_)\n                => 1,\n\n            // u32 and i32\n            Mtu(_)\n                | Link(_)\n                | Master(_)\n                | TxQueueLen(_)\n                | NetNsPid(_)\n                | NumVf(_)\n                | Group(_)\n                | NetNsFd(_)\n                | ExtMask(_)\n                | Promiscuity(_)\n                | NumTxQueues(_)\n                | NumRxQueues(_)\n                | CarrierChanges(_)\n                | GsoMaxSegs(_)\n                | GsoMaxSize(_)\n                | NetnsId(_)\n                | MinMtu(_)\n                | MaxMtu(_) => 4,\n\n            // Defaults\n            OperState(_) => 1,\n            Stats(_) => LINK_STATS_LEN,\n            Stats64(_) => LINK_STATS64_LEN,\n            Info(ref nlas) => nlas.as_slice().buffer_len(),\n            PropList(ref nlas) => nlas.as_slice().buffer_len(),\n            AfSpecInet(ref nlas) => nlas.as_slice().buffer_len(),\n            AfSpecBridge(ref nlas) => nlas.as_slice().buffer_len(),\n            Other(ref attr)  => attr.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes)\n                | Cost(ref bytes)\n                | Priority(ref bytes)\n                | Weight(ref bytes)\n                | VfInfoList(ref bytes)\n                | VfPorts(ref bytes)\n                | PortSelf(ref bytes)\n                | PhysPortId(ref bytes)\n                | PhysSwitchId(ref bytes)\n                | Wireless(ref bytes)\n                | ProtoInfo(ref bytes)\n                | Pad(ref bytes)\n                | Xdp(ref bytes)\n                | Event(ref bytes)\n                | NewNetnsId(ref bytes)\n                | IfNetnsId(ref bytes)\n                | CarrierUpCount(ref bytes)\n                | CarrierDownCount(ref bytes)\n                | NewIfIndex(ref bytes)\n                // mac address (could be [u8; 6] or [u8; 4] for example. Not sure if we should have\n                // a separate type for them\n                | Address(ref bytes)\n                | Broadcast(ref bytes)\n                | PermAddress(ref bytes)\n                | AfSpecUnknown(ref bytes)\n                | Stats(ref bytes)\n                | Stats64(ref bytes)\n                | Map(ref bytes)\n                | ProtoDownReason(ref bytes)\n                => buffer.copy_from_slice(bytes.as_slice()),\n\n            // String\n            IfName(ref string)\n                | Qdisc(ref string)\n                | IfAlias(ref string)\n                | PhysPortName(ref string)\n                | AltIfName(ref string)\n                => {\n                    buffer[..string.len()].copy_from_slice(string.as_bytes());\n                    buffer[string.len()] = 0;\n                }\n\n            // u8\n            Mode(ref val)\n                | Carrier(ref val)\n                | ProtoDown(ref val)\n                => buffer[0] = *val,\n\n            // u32\n            Mtu(ref value)\n                | Link(ref value)\n                | Master(ref value)\n                | TxQueueLen(ref value)\n                | NetNsPid(ref value)\n                | NumVf(ref value)\n                | Group(ref value)\n                | ExtMask(ref value)\n                | Promiscuity(ref value)\n                | NumTxQueues(ref value)\n                | NumRxQueues(ref value)\n                | CarrierChanges(ref value)\n                | GsoMaxSegs(ref value)\n                | GsoMaxSize(ref value)\n                | MinMtu(ref value)\n                | MaxMtu(ref value)\n                => NativeEndian::write_u32(buffer, *value),\n\n            NetnsId(ref value)\n                | NetNsFd(ref value)\n                => NativeEndian::write_i32(buffer, *value),\n\n            OperState(state) => buffer[0] = state.into(),\n            Info(ref nlas) => nlas.as_slice().emit(buffer),\n            PropList(ref nlas) => nlas.as_slice().emit(buffer),\n            AfSpecInet(ref nlas) => nlas.as_slice().emit(buffer),\n            AfSpecBridge(ref nlas) => nlas.as_slice().emit(buffer),\n            // default nlas\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(_) => IFLA_UNSPEC,\n            Cost(_) => IFLA_COST,\n            Priority(_) => IFLA_PRIORITY,\n            Weight(_) => IFLA_WEIGHT,\n            VfInfoList(_) => IFLA_VFINFO_LIST,\n            VfPorts(_) => IFLA_VF_PORTS,\n            PortSelf(_) => IFLA_PORT_SELF,\n            PhysPortId(_) => IFLA_PHYS_PORT_ID,\n            PhysSwitchId(_) => IFLA_PHYS_SWITCH_ID,\n            Info(_) => IFLA_LINKINFO,\n            Wireless(_) => IFLA_WIRELESS,\n            ProtoInfo(_) => IFLA_PROTINFO,\n            Pad(_) => IFLA_PAD,\n            Xdp(_) => IFLA_XDP,\n            Event(_) => IFLA_EVENT,\n            NewNetnsId(_) => IFLA_NEW_NETNSID,\n            IfNetnsId(_) => IFLA_IF_NETNSID,\n            CarrierUpCount(_) => IFLA_CARRIER_UP_COUNT,\n            CarrierDownCount(_) => IFLA_CARRIER_DOWN_COUNT,\n            NewIfIndex(_) => IFLA_NEW_IFINDEX,\n            PropList(_) => IFLA_PROP_LIST | NLA_F_NESTED,\n            ProtoDownReason(_) => IFLA_PROTO_DOWN_REASON,\n            // Mac address\n            Address(_) => IFLA_ADDRESS,\n            Broadcast(_) => IFLA_BROADCAST,\n            PermAddress(_) => IFLA_PERM_ADDRESS,\n            // String\n            IfName(_) => IFLA_IFNAME,\n            Qdisc(_) => IFLA_QDISC,\n            IfAlias(_) => IFLA_IFALIAS,\n            PhysPortName(_) => IFLA_PHYS_PORT_NAME,\n            AltIfName(_) => IFLA_ALT_IFNAME,\n            // u8\n            Mode(_) => IFLA_LINKMODE,\n            Carrier(_) => IFLA_CARRIER,\n            ProtoDown(_) => IFLA_PROTO_DOWN,\n            // u32\n            Mtu(_) => IFLA_MTU,\n            Link(_) => IFLA_LINK,\n            Master(_) => IFLA_MASTER,\n            TxQueueLen(_) => IFLA_TXQLEN,\n            NetNsPid(_) => IFLA_NET_NS_PID,\n            NumVf(_) => IFLA_NUM_VF,\n            Group(_) => IFLA_GROUP,\n            NetNsFd(_) => IFLA_NET_NS_FD,\n            ExtMask(_) => IFLA_EXT_MASK,\n            Promiscuity(_) => IFLA_PROMISCUITY,\n            NumTxQueues(_) => IFLA_NUM_TX_QUEUES,\n            NumRxQueues(_) => IFLA_NUM_RX_QUEUES,\n            CarrierChanges(_) => IFLA_CARRIER_CHANGES,\n            GsoMaxSegs(_) => IFLA_GSO_MAX_SEGS,\n            GsoMaxSize(_) => IFLA_GSO_MAX_SIZE,\n            MinMtu(_) => IFLA_MIN_MTU,\n            MaxMtu(_) => IFLA_MAX_MTU,\n            // i32\n            NetnsId(_) => IFLA_LINK_NETNSID,\n            // custom\n            OperState(_) => IFLA_OPERSTATE,\n            Map(_) => IFLA_MAP,\n            Stats(_) => IFLA_STATS,\n            Stats64(_) => IFLA_STATS64,\n            AfSpecInet(_) | AfSpecBridge(_) | AfSpecUnknown(_) => IFLA_AF_SPEC,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NlaBuffer<&'a T>, u16> for Nla {\n    fn parse_with_param(\n        buf: &NlaBuffer<&'a T>,\n        interface_family: u16,\n    ) -> Result<Self, DecodeError> {\n        use Nla::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            // Vec<u8>\n            IFLA_UNSPEC => Unspec(payload.to_vec()),\n            IFLA_COST => Cost(payload.to_vec()),\n            IFLA_PRIORITY => Priority(payload.to_vec()),\n            IFLA_WEIGHT => Weight(payload.to_vec()),\n            IFLA_VFINFO_LIST => VfInfoList(payload.to_vec()),\n            IFLA_VF_PORTS => VfPorts(payload.to_vec()),\n            IFLA_PORT_SELF => PortSelf(payload.to_vec()),\n            IFLA_PHYS_PORT_ID => PhysPortId(payload.to_vec()),\n            IFLA_PHYS_SWITCH_ID => PhysSwitchId(payload.to_vec()),\n            IFLA_WIRELESS => Wireless(payload.to_vec()),\n            IFLA_PROTINFO => ProtoInfo(payload.to_vec()),\n            IFLA_PAD => Pad(payload.to_vec()),\n            IFLA_XDP => Xdp(payload.to_vec()),\n            IFLA_EVENT => Event(payload.to_vec()),\n            IFLA_NEW_NETNSID => NewNetnsId(payload.to_vec()),\n            IFLA_IF_NETNSID => IfNetnsId(payload.to_vec()),\n            IFLA_CARRIER_UP_COUNT => CarrierUpCount(payload.to_vec()),\n            IFLA_CARRIER_DOWN_COUNT => CarrierDownCount(payload.to_vec()),\n            IFLA_NEW_IFINDEX => NewIfIndex(payload.to_vec()),\n            IFLA_PROP_LIST => {\n                let error_msg = \"invalid IFLA_PROP_LIST value\";\n                let mut nlas = vec![];\n                for nla in NlasIterator::new(payload) {\n                    let nla = &nla.context(error_msg)?;\n                    let parsed = Prop::parse(nla).context(error_msg)?;\n                    nlas.push(parsed);\n                }\n                PropList(nlas)\n            }\n            IFLA_PROTO_DOWN_REASON => ProtoDownReason(payload.to_vec()),\n            // HW address (we parse them as Vec for now, because for IP over GRE, the HW address is\n            // an IP instead of a MAC for example\n            IFLA_ADDRESS => Address(payload.to_vec()),\n            IFLA_BROADCAST => Broadcast(payload.to_vec()),\n            IFLA_PERM_ADDRESS => PermAddress(payload.to_vec()),\n            // String\n            IFLA_IFNAME => IfName(parse_string(payload).context(\"invalid IFLA_IFNAME value\")?),\n            IFLA_QDISC => Qdisc(parse_string(payload).context(\"invalid IFLA_QDISC value\")?),\n            IFLA_IFALIAS => IfAlias(parse_string(payload).context(\"invalid IFLA_IFALIAS value\")?),\n            IFLA_PHYS_PORT_NAME => {\n                PhysPortName(parse_string(payload).context(\"invalid IFLA_PHYS_PORT_NAME value\")?)\n            }\n            IFLA_ALT_IFNAME => {\n                AltIfName(parse_string(payload).context(\"invalid IFLA_ALT_IFNAME value\")?)\n            }\n\n            // u8\n            IFLA_LINKMODE => Mode(parse_u8(payload).context(\"invalid IFLA_LINKMODE value\")?),\n            IFLA_CARRIER => Carrier(parse_u8(payload).context(\"invalid IFLA_CARRIER value\")?),\n            IFLA_PROTO_DOWN => {\n                ProtoDown(parse_u8(payload).context(\"invalid IFLA_PROTO_DOWN value\")?)\n            }\n\n            IFLA_MTU => Mtu(parse_u32(payload).context(\"invalid IFLA_MTU value\")?),\n            IFLA_LINK => Link(parse_u32(payload).context(\"invalid IFLA_LINK value\")?),\n            IFLA_MASTER => Master(parse_u32(payload).context(\"invalid IFLA_MASTER value\")?),\n            IFLA_TXQLEN => TxQueueLen(parse_u32(payload).context(\"invalid IFLA_TXQLEN value\")?),\n            IFLA_NET_NS_PID => {\n                NetNsPid(parse_u32(payload).context(\"invalid IFLA_NET_NS_PID value\")?)\n            }\n            IFLA_NUM_VF => NumVf(parse_u32(payload).context(\"invalid IFLA_NUM_VF value\")?),\n            IFLA_GROUP => Group(parse_u32(payload).context(\"invalid IFLA_GROUP value\")?),\n            IFLA_NET_NS_FD => NetNsFd(parse_i32(payload).context(\"invalid IFLA_NET_NS_FD value\")?),\n            IFLA_EXT_MASK => ExtMask(parse_u32(payload).context(\"invalid IFLA_EXT_MASK value\")?),\n            IFLA_PROMISCUITY => {\n                Promiscuity(parse_u32(payload).context(\"invalid IFLA_PROMISCUITY value\")?)\n            }\n            IFLA_NUM_TX_QUEUES => {\n                NumTxQueues(parse_u32(payload).context(\"invalid IFLA_NUM_TX_QUEUES value\")?)\n            }\n            IFLA_NUM_RX_QUEUES => {\n                NumRxQueues(parse_u32(payload).context(\"invalid IFLA_NUM_RX_QUEUES value\")?)\n            }\n            IFLA_CARRIER_CHANGES => {\n                CarrierChanges(parse_u32(payload).context(\"invalid IFLA_CARRIER_CHANGES value\")?)\n            }\n            IFLA_GSO_MAX_SEGS => {\n                GsoMaxSegs(parse_u32(payload).context(\"invalid IFLA_GSO_MAX_SEGS value\")?)\n            }\n            IFLA_GSO_MAX_SIZE => {\n                GsoMaxSize(parse_u32(payload).context(\"invalid IFLA_GSO_MAX_SIZE value\")?)\n            }\n            IFLA_MIN_MTU => MinMtu(parse_u32(payload).context(\"invalid IFLA_MIN_MTU value\")?),\n            IFLA_MAX_MTU => MaxMtu(parse_u32(payload).context(\"invalid IFLA_MAX_MTU value\")?),\n            IFLA_LINK_NETNSID => {\n                NetnsId(parse_i32(payload).context(\"invalid IFLA_LINK_NETNSID value\")?)\n            }\n            IFLA_OPERSTATE => OperState(\n                parse_u8(payload)\n                    .context(\"invalid IFLA_OPERSTATE value\")?\n                    .into(),\n            ),\n            IFLA_MAP => Map(payload.to_vec()),\n            IFLA_STATS => Stats(payload.to_vec()),\n            IFLA_STATS64 => Stats64(payload.to_vec()),\n            IFLA_AF_SPEC => match interface_family as u16 {\n                AF_INET | AF_INET6 | AF_UNSPEC => {\n                    let mut nlas = vec![];\n                    let err = \"invalid IFLA_AF_SPEC value\";\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(err)?;\n                        nlas.push(af_spec_inet::AfSpecInet::parse(&nla).context(err)?);\n                    }\n                    AfSpecInet(nlas)\n                }\n                AF_BRIDGE => {\n                    let mut nlas = vec![];\n                    let err = \"invalid IFLA_AF_SPEC value for AF_BRIDGE\";\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(err)?;\n                        nlas.push(af_spec_bridge::AfSpecBridge::parse(&nla).context(err)?);\n                    }\n                    AfSpecBridge(nlas)\n                }\n                _ => AfSpecUnknown(payload.to_vec()),\n            },\n            IFLA_LINKINFO => {\n                let err = \"invalid IFLA_LINKINFO value\";\n                let buf = NlaBuffer::new_checked(payload).context(err)?;\n                Info(VecInfo::parse(&buf).context(err)?.0)\n            }\n\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/prop_list.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    nlas::{DefaultNla, Nla, NlaBuffer},\n    parsers::parse_string,\n    traits::Parseable,\n    DecodeError,\n};\n\nuse anyhow::Context;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Prop {\n    AltIfName(String),\n    Other(DefaultNla),\n}\n\nimpl Nla for Prop {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Prop::*;\n        match self {\n            AltIfName(ref string) => string.as_bytes().len() + 1,\n            Other(nla) => nla.value_len()\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Prop::*;\n        match self {\n            AltIfName(ref string) => {\n                buffer[..string.len()].copy_from_slice(string.as_bytes());\n                buffer[string.len()] = 0;\n            },\n            Other(nla) => nla.emit_value(buffer)\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Prop::*;\n        match self {\n            AltIfName(_) => IFLA_ALT_IFNAME,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Prop {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            IFLA_ALT_IFNAME => {\n                Prop::AltIfName(parse_string(payload).context(\"invalid IFLA_ALT_IFNAME value\")?)\n            }\n            kind => {\n                Prop::Other(DefaultNla::parse(buf).context(format!(\"Unknown NLA type {}\", kind))?)\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct Stats {\n    /// total packets received\n    pub rx_packets: u32,\n    /// total packets transmitted\n    pub tx_packets: u32,\n    /// total bytes received\n    pub rx_bytes: u32,\n    /// total bytes transmitted\n    pub tx_bytes: u32,\n    /// bad packets received\n    pub rx_errors: u32,\n    /// packet transmit problems\n    pub tx_errors: u32,\n    /// no space in linux buffers\n    pub rx_dropped: u32,\n    /// no space available in linux\n    pub tx_dropped: u32,\n    /// multicast packets received\n    pub multicast: u32,\n    pub collisions: u32,\n\n    // detailed rx_errors\n    pub rx_length_errors: u32,\n    /// receiver ring buff overflow\n    pub rx_over_errors: u32,\n    /// received packets with crc error\n    pub rx_crc_errors: u32,\n    /// received frame alignment errors\n    pub rx_frame_errors: u32,\n    /// recv'r fifo overrun\n    pub rx_fifo_errors: u32,\n    /// receiver missed packet\n    pub rx_missed_errors: u32,\n\n    // detailed tx_errors\n    pub tx_aborted_errors: u32,\n    pub tx_carrier_errors: u32,\n    pub tx_fifo_errors: u32,\n    pub tx_heartbeat_errors: u32,\n    pub tx_window_errors: u32,\n\n    // for cslip etc\n    pub rx_compressed: u32,\n    pub tx_compressed: u32,\n\n    /// dropped, no handler found\n    pub rx_nohandler: u32,\n}\n\npub const LINK_STATS_LEN: usize = 96;\n\nbuffer!(StatsBuffer(LINK_STATS_LEN) {\n    rx_packets: (u32, 0..4),\n    tx_packets: (u32, 4..8),\n    rx_bytes: (u32, 8..12),\n    tx_bytes: (u32, 12..16),\n    rx_errors: (u32, 16..20),\n    tx_errors: (u32, 20..24),\n    rx_dropped: (u32, 24..28),\n    tx_dropped: (u32, 28..32),\n    multicast: (u32, 32..36),\n    collisions: (u32, 36..40),\n    rx_length_errors: (u32, 40..44),\n    rx_over_errors: (u32, 44..48),\n    rx_crc_errors: (u32, 48..52),\n    rx_frame_errors: (u32, 52..56),\n    rx_fifo_errors: (u32, 56..60),\n    rx_missed_errors: (u32, 60..64),\n    tx_aborted_errors: (u32, 64..68),\n    tx_carrier_errors: (u32, 68..72),\n    tx_fifo_errors: (u32, 72..76),\n    tx_heartbeat_errors: (u32, 76..80),\n    tx_window_errors: (u32, 80..84),\n    rx_compressed: (u32, 84..88),\n    tx_compressed: (u32, 88..92),\n    rx_nohandler: (u32, 92..96),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<StatsBuffer<T>> for Stats {\n    fn parse(buf: &StatsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            rx_packets: buf.rx_packets(),\n            tx_packets: buf.tx_packets(),\n            rx_bytes: buf.rx_bytes(),\n            tx_bytes: buf.tx_bytes(),\n            rx_errors: buf.rx_errors(),\n            tx_errors: buf.tx_errors(),\n            rx_dropped: buf.rx_dropped(),\n            tx_dropped: buf.tx_dropped(),\n            multicast: buf.multicast(),\n            collisions: buf.collisions(),\n            rx_length_errors: buf.rx_length_errors(),\n            rx_over_errors: buf.rx_over_errors(),\n            rx_crc_errors: buf.rx_crc_errors(),\n            rx_frame_errors: buf.rx_frame_errors(),\n            rx_fifo_errors: buf.rx_fifo_errors(),\n            rx_missed_errors: buf.rx_missed_errors(),\n            tx_aborted_errors: buf.tx_aborted_errors(),\n            tx_carrier_errors: buf.tx_carrier_errors(),\n            tx_fifo_errors: buf.tx_fifo_errors(),\n            tx_heartbeat_errors: buf.tx_heartbeat_errors(),\n            tx_window_errors: buf.tx_window_errors(),\n            rx_compressed: buf.rx_compressed(),\n            tx_compressed: buf.tx_compressed(),\n            rx_nohandler: buf.rx_nohandler(),\n        })\n    }\n}\n\nimpl Emitable for Stats {\n    fn buffer_len(&self) -> usize {\n        LINK_STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatsBuffer::new(buffer);\n        buffer.set_rx_packets(self.rx_packets);\n        buffer.set_tx_packets(self.tx_packets);\n        buffer.set_rx_bytes(self.rx_bytes);\n        buffer.set_tx_bytes(self.tx_bytes);\n        buffer.set_rx_errors(self.rx_errors);\n        buffer.set_tx_errors(self.tx_errors);\n        buffer.set_rx_dropped(self.rx_dropped);\n        buffer.set_tx_dropped(self.tx_dropped);\n        buffer.set_multicast(self.multicast);\n        buffer.set_collisions(self.collisions);\n        buffer.set_rx_length_errors(self.rx_length_errors);\n        buffer.set_rx_over_errors(self.rx_over_errors);\n        buffer.set_rx_crc_errors(self.rx_crc_errors);\n        buffer.set_rx_frame_errors(self.rx_frame_errors);\n        buffer.set_rx_fifo_errors(self.rx_fifo_errors);\n        buffer.set_rx_missed_errors(self.rx_missed_errors);\n        buffer.set_tx_aborted_errors(self.tx_aborted_errors);\n        buffer.set_tx_carrier_errors(self.tx_carrier_errors);\n        buffer.set_tx_fifo_errors(self.tx_fifo_errors);\n        buffer.set_tx_heartbeat_errors(self.tx_heartbeat_errors);\n        buffer.set_tx_window_errors(self.tx_window_errors);\n        buffer.set_rx_compressed(self.rx_compressed);\n        buffer.set_tx_compressed(self.tx_compressed);\n        buffer.set_rx_nohandler(self.rx_nohandler);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/stats64.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const LINK_STATS64_LEN: usize = 192;\nbuffer!(Stats64Buffer(LINK_STATS64_LEN) {\n    rx_packets: (u64, 0..8),\n    tx_packets: (u64, 8..16),\n    rx_bytes: (u64, 16..24),\n    tx_bytes: (u64, 24..32),\n    rx_errors: (u64, 32..40),\n    tx_errors: (u64, 40..48),\n    rx_dropped: (u64, 48..56),\n    tx_dropped: (u64, 56..64),\n    multicast: (u64, 64..72),\n    collisions: (u64, 72..80),\n    rx_length_errors: (u64, 80..88),\n    rx_over_errors: (u64, 88..96),\n    rx_crc_errors: (u64, 96..104),\n    rx_frame_errors: (u64, 104..112),\n    rx_fifo_errors: (u64, 112..120),\n    rx_missed_errors: (u64, 120..128),\n    tx_aborted_errors: (u64, 128..136),\n    tx_carrier_errors: (u64, 136..144),\n    tx_fifo_errors: (u64, 144..152),\n    tx_heartbeat_errors: (u64, 152..160),\n    tx_window_errors: (u64, 160..168),\n    rx_compressed: (u64, 168..176),\n    tx_compressed: (u64, 176..184),\n    rx_nohandler: (u64, 184..192),\n});\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct Stats64 {\n    /// total packets received\n    pub rx_packets: u64,\n    /// total packets transmitted\n    pub tx_packets: u64,\n    /// total bytes received\n    pub rx_bytes: u64,\n    /// total bytes transmitted\n    pub tx_bytes: u64,\n    /// bad packets received\n    pub rx_errors: u64,\n    /// packet transmit problems\n    pub tx_errors: u64,\n    /// no space in linux buffers\n    pub rx_dropped: u64,\n    /// no space available in linux\n    pub tx_dropped: u64,\n    /// multicast packets received\n    pub multicast: u64,\n    pub collisions: u64,\n\n    // detailed rx_errors\n    pub rx_length_errors: u64,\n    /// receiver ring buff overflow\n    pub rx_over_errors: u64,\n    /// received packets with crc error\n    pub rx_crc_errors: u64,\n    /// received frame alignment errors\n    pub rx_frame_errors: u64,\n    /// recv'r fifo overrun\n    pub rx_fifo_errors: u64,\n    /// receiver missed packet\n    pub rx_missed_errors: u64,\n\n    // detailed tx_errors\n    pub tx_aborted_errors: u64,\n    pub tx_carrier_errors: u64,\n    pub tx_fifo_errors: u64,\n    pub tx_heartbeat_errors: u64,\n    pub tx_window_errors: u64,\n\n    // for cslip etc\n    pub rx_compressed: u64,\n    pub tx_compressed: u64,\n\n    /// dropped, no handler found\n    pub rx_nohandler: u64,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<Stats64Buffer<T>> for Stats64 {\n    fn parse(buf: &Stats64Buffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            rx_packets: buf.rx_packets(),\n            tx_packets: buf.tx_packets(),\n            rx_bytes: buf.rx_bytes(),\n            tx_bytes: buf.tx_bytes(),\n            rx_errors: buf.rx_errors(),\n            tx_errors: buf.tx_errors(),\n            rx_dropped: buf.rx_dropped(),\n            tx_dropped: buf.tx_dropped(),\n            multicast: buf.multicast(),\n            collisions: buf.collisions(),\n            rx_length_errors: buf.rx_length_errors(),\n            rx_over_errors: buf.rx_over_errors(),\n            rx_crc_errors: buf.rx_crc_errors(),\n            rx_frame_errors: buf.rx_frame_errors(),\n            rx_fifo_errors: buf.rx_fifo_errors(),\n            rx_missed_errors: buf.rx_missed_errors(),\n            tx_aborted_errors: buf.tx_aborted_errors(),\n            tx_carrier_errors: buf.tx_carrier_errors(),\n            tx_fifo_errors: buf.tx_fifo_errors(),\n            tx_heartbeat_errors: buf.tx_heartbeat_errors(),\n            tx_window_errors: buf.tx_window_errors(),\n            rx_compressed: buf.rx_compressed(),\n            tx_compressed: buf.tx_compressed(),\n            rx_nohandler: buf.rx_nohandler(),\n        })\n    }\n}\n\nimpl Emitable for Stats64 {\n    fn buffer_len(&self) -> usize {\n        LINK_STATS64_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = Stats64Buffer::new(buffer);\n        buffer.set_rx_packets(self.rx_packets);\n        buffer.set_tx_packets(self.tx_packets);\n        buffer.set_rx_bytes(self.rx_bytes);\n        buffer.set_tx_bytes(self.tx_bytes);\n        buffer.set_rx_errors(self.rx_errors);\n        buffer.set_tx_errors(self.tx_errors);\n        buffer.set_rx_dropped(self.rx_dropped);\n        buffer.set_tx_dropped(self.tx_dropped);\n        buffer.set_multicast(self.multicast);\n        buffer.set_collisions(self.collisions);\n        buffer.set_rx_length_errors(self.rx_length_errors);\n        buffer.set_rx_over_errors(self.rx_over_errors);\n        buffer.set_rx_crc_errors(self.rx_crc_errors);\n        buffer.set_rx_frame_errors(self.rx_frame_errors);\n        buffer.set_rx_fifo_errors(self.rx_fifo_errors);\n        buffer.set_rx_missed_errors(self.rx_missed_errors);\n        buffer.set_tx_aborted_errors(self.tx_aborted_errors);\n        buffer.set_tx_carrier_errors(self.tx_carrier_errors);\n        buffer.set_tx_fifo_errors(self.tx_fifo_errors);\n        buffer.set_tx_heartbeat_errors(self.tx_heartbeat_errors);\n        buffer.set_tx_window_errors(self.tx_window_errors);\n        buffer.set_rx_compressed(self.rx_compressed);\n        buffer.set_tx_compressed(self.tx_compressed);\n        buffer.set_rx_nohandler(self.rx_nohandler);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/link/nlas/tests.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{utils::nla::Nla, DecodeError};\n\nuse super::*;\n// https://lists.infradead.org/pipermail/libnl/2015-November/002034.html\n// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/if_link.h#L89\n#[rustfmt::skip]\nstatic BYTES: [u8; 748] = [\n    // AF_SPEC (L=748, T=26)\n    0xec, 0x02, 0x1a, 0x00,\n        // AF_INET (L=132, T=2)\n        0x84, 0x00, 0x02, 0x00,\n            // IFLA_INET_CONF (L=128, T=1)\n            0x80, 0x00, 0x01, 0x00,\n            0x01, 0x00, 0x00, 0x00, // 1  forwarding\n            0x00, 0x00, 0x00, 0x00, // 2  mc_forwarding\n            0x00, 0x00, 0x00, 0x00, // 3  proxy_arp\n            0x01, 0x00, 0x00, 0x00, // 4  accept_redirects\n            0x01, 0x00, 0x00, 0x00, // 5  secure_redirects\n            0x01, 0x00, 0x00, 0x00, // 6  send_redirects\n            0x01, 0x00, 0x00, 0x00, // 7  shared_media\n            0x00, 0x00, 0x00, 0x00, // 8  rp_filter\n            0x01, 0x00, 0x00, 0x00, // 9  accept_source_route\n            0x00, 0x00, 0x00, 0x00, // 10 bootp_relay   (40 bytes)\n            0x00, 0x00, 0x00, 0x00, // 11 log_martians\n            0x00, 0x00, 0x00, 0x00, // 12 tag\n            0x00, 0x00, 0x00, 0x00, // 13 arpfilter\n            0x00, 0x00, 0x00, 0x00, // 14 medium_id\n            0x01, 0x00, 0x00, 0x00, // 15 noxfrm\n            0x01, 0x00, 0x00, 0x00, // 16 nopolicy\n            0x00, 0x00, 0x00, 0x00, // 17 force_igmp_version\n            0x00, 0x00, 0x00, 0x00, // 18 arp_announce\n            0x00, 0x00, 0x00, 0x00, // 19 arp_ignore\n            0x00, 0x00, 0x00, 0x00, // 20 promote_secondaries  (80 bytes)\n            0x00, 0x00, 0x00, 0x00, // 21 arp_accept\n            0x00, 0x00, 0x00, 0x00, // 22 arp_notify\n            0x00, 0x00, 0x00, 0x00, // 23 accept_local\n            0x00, 0x00, 0x00, 0x00, // 24 src_vmark\n            0x00, 0x00, 0x00, 0x00, // 25 proxy_arp_pvlan\n            0x00, 0x00, 0x00, 0x00, // 26 route_localnet\n            0x10, 0x27, 0x00, 0x00, // 27 igmpv2_unsolicited_report_interval\n            0xe8, 0x03, 0x00, 0x00, // 28 igmpv3_unsolicited_report_interval\n            0x00, 0x00, 0x00, 0x00, // 29 ignore_routes_with_linkdown\n            0x00, 0x00, 0x00, 0x00, // 30 drop_unicast_in_l2_multicast  (120 bytes)\n            0x00, 0x00, 0x00, 0x00, // 31 drop_gratuitous_arp\n\n        // AF_INET6 (L=612, T=10)\n        0x64, 0x02, 0x0a, 0x00,\n            // IFLA_INET6_FLAGS (L=8,T=1)\n            0x08, 0x00, 0x01, 0x00,\n            0x00, 0x00, 0x00, 0x80,\n\n            // IFLA_INET6_CACHEINFO (L=20, T=5)\n            0x14, 0x00, 0x05, 0x00,\n            0xff, 0xff, 0x00, 0x00, // max_reasm_len\n            0xaf, 0x00, 0x00, 0x00, // tstamp\n            0x82, 0x64, 0x00, 0x00, // reachable_time\n            0xe8, 0x03, 0x00, 0x00, // retrans_time\n\n            // IFLA_INET6_CONF (L=208, T=2)\n            0xd0, 0x00, 0x02, 0x00,\n            0x00, 0x00, 0x00, 0x00, // forwarding\n            0x40, 0x00, 0x00, 0x00, // hoplimit\n            0x00, 0x00, 0x01, 0x00, // mtu6\n            0x01, 0x00, 0x00, 0x00, // accept_ra\n            0x01, 0x00, 0x00, 0x00, // accept_redirects\n            0x01, 0x00, 0x00, 0x00, // autoconf\n            0x01, 0x00, 0x00, 0x00, // dad_transmits\n            0xff, 0xff, 0xff, 0xff, // rtr_solicits\n            0xa0, 0x0f, 0x00, 0x00, // rtr_solicit_interval\n            0xe8, 0x03, 0x00, 0x00, // rtr_solicit_delay\n            0xff, 0xff, 0xff, 0xff, // use_tempaddr\n            0x80, 0x3a, 0x09, 0x00, // temp_valid_lft\n            0x80, 0x51, 0x01, 0x00, // temp_prefered_lft\n            0x03, 0x00, 0x00, 0x00, // regen_max_retry\n            0x58, 0x02, 0x00, 0x00, // max_desync_factor\n            0x10, 0x00, 0x00, 0x00, // max_addresses\n            0x00, 0x00, 0x00, 0x00, // force_mld_version\n            0x01, 0x00, 0x00, 0x00, // accept_ra_defrtr\n            0x01, 0x00, 0x00, 0x00, // accept_ra_pinfo\n            0x01, 0x00, 0x00, 0x00, // accept_ra_rtr_pref\n            0x60, 0xea, 0x00, 0x00, // rtr_probe_interval\n            0x00, 0x00, 0x00, 0x00, // accept_ra_rt_info_max_plen\n            0x00, 0x00, 0x00, 0x00, // proxy_ndp\n            0x00, 0x00, 0x00, 0x00, // optimistic_dad\n            0x00, 0x00, 0x00, 0x00, // accept_source_route\n            0x00, 0x00, 0x00, 0x00, // mc_forwarding\n            0x00, 0x00, 0x00, 0x00, // disable_ipv6\n            0xff, 0xff, 0xff, 0xff, // accept_dad\n            0x00, 0x00, 0x00, 0x00, // force_tllao\n            0x00, 0x00, 0x00, 0x00, // ndisc_notify\n            0x10, 0x27, 0x00, 0x00, // mldv1_unsolicited_report_interval\n            0xe8, 0x03, 0x00, 0x00, // mldv2_unsolicited_report_interval\n            0x01, 0x00, 0x00, 0x00, // suppress_frag_ndisc\n            0x00, 0x00, 0x00, 0x00, // accept_ra_from_local\n            0x00, 0x00, 0x00, 0x00, // use_optimistic\n            0x01, 0x00, 0x00, 0x00, // accept_ra_mtu\n            0x00, 0x00, 0x00, 0x00, // stable_secret\n            0x00, 0x00, 0x00, 0x00, // use_oif_addrs_only\n            0x01, 0x00, 0x00, 0x00, // accept_ra_min_hop_limit\n            0x00, 0x00, 0x00, 0x00, // ignore_routes_with_linkdown\n            0x00, 0x00, 0x00, 0x00, // drop_unicast_in_l2_multicast\n            0x00, 0x00, 0x00, 0x00, // drop_unsolicited_na\n            0x00, 0x00, 0x00, 0x00, // keep_addr_on_down\n            0x80, 0xee, 0x36, 0x00, // rtr_solicit_max_interval\n            0x00, 0x00, 0x00, 0x00, // seg6_enabled\n            0x00, 0x00, 0x00, 0x00, // seg6_require_hmac\n            0x01, 0x00, 0x00, 0x00, // enhanced_dad\n            0x00, 0x00, 0x00, 0x00, // addr_gen_mode\n            0x00, 0x00, 0x00, 0x00, // disable_policy\n            0x00, 0x00, 0x00, 0x00, // accept_ra_rt_info_min_plen\n            0x00, 0x00, 0x00, 0x00, // ndisc_tclass\n\n            // IFLA_INET6_STATS (L=292, T=3)\n            0x24, 0x01, 0x03, 0x00,\n            0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1  num\n            0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2  in_pkts\n            0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3  in_octets\n            0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4  in_delivers\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 5  out_forw_datagrams\n            0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6  out_pkts\n            0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7  out_octets\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8  in_hdr_errors\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9  in_too_big_errors\n            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 10 in_no_routes      (40 bytes)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 11 in_addr_errors\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 12 in_unknown_protos\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 13 in_truncated_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 14 in_discards\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 15 out_discards\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 out_no_routes\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 17 reasm_timeout\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 18 reasm_reqds\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 19 reasm_oks\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 20 reasm_fails       (80 bytes)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 21 frag_oks\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 22 frag_fails\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 23 frag_creates\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 in_mcast_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 25 out_mcast_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 26 in_bcast_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 27 out_bcast_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 28 in_mcast_octets\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 29 out_mcast_octets\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 30 in_bcast_octets   (120 bytes)\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 31 out_bcast_octets\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 in_csum_errors\n            0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 33 in_no_ect_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 34 in_ect1_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 35 in_ect0_pkts\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 36 in_ce_pkts\n\n            // IFLA_INET6_ICMP6STATS (L=52, T=6)\n            0x34, 0x00, 0x06, 0x00,\n            0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // in_msgs\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // in_errors\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // out_msgs\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // out_errors\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // csum_errors\n\n            // IFLA_INET6_TOKEN (L=20, T=7)\n            0x14, 0x00, 0x07, 0x00,\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n            // IFLA_INET6_ADDR_GEN_MODE (L=5, T=8)\n            0x05, 0x00, 0x08, 0x00,\n            0x00, 0x00, 0x00, 0x00];\n\nlazy_static! {\n    static ref BUFFER: NlaBuffer<&'static [u8]> = NlaBuffer::new_checked(&BYTES[..]).unwrap();\n}\n\nfn get_nlas() -> impl Iterator<Item = Result<NlaBuffer<&'static [u8]>, DecodeError>> {\n    NlasIterator::new(&*BUFFER.value())\n}\n\nfn get_byte_buffer(nla: &dyn Emitable) -> Vec<u8> {\n    let mut buf = vec![0u8; nla.buffer_len()];\n    nla.emit(&mut buf);\n    buf\n}\n\nlazy_static! {\n    static ref PARSED_AF_INET6: AfSpecInet = AfSpecInet::Inet6(vec![\n        Inet6::Flags(2147483648),\n        Inet6::CacheInfo(get_byte_buffer(&Inet6CacheInfo {\n            max_reasm_len: 65535,\n            tstamp: 175,\n            reachable_time: 25730,\n            retrans_time: 1000,\n        })),\n        Inet6::DevConf(get_byte_buffer(&Inet6DevConf {\n            forwarding: 0,\n            hoplimit: 64,\n            mtu6: 65536,\n            accept_ra: 1,\n            accept_redirects: 1,\n            autoconf: 1,\n            dad_transmits: 1,\n            rtr_solicits: -1,\n            rtr_solicit_interval: 4000,\n            rtr_solicit_delay: 1000,\n            use_tempaddr: -1,\n            temp_valid_lft: 604800,\n            temp_prefered_lft: 86400,\n            regen_max_retry: 3,\n            max_desync_factor: 600,\n            max_addresses: 16,\n            force_mld_version: 0,\n            accept_ra_defrtr: 1,\n            accept_ra_pinfo: 1,\n            accept_ra_rtr_pref: 1,\n            rtr_probe_interval: 60000,\n            accept_ra_rt_info_max_plen: 0,\n            proxy_ndp: 0,\n            optimistic_dad: 0,\n            accept_source_route: 0,\n            mc_forwarding: 0,\n            disable_ipv6: 0,\n            accept_dad: -1,\n            force_tllao: 0,\n            ndisc_notify: 0,\n            mldv1_unsolicited_report_interval: 10000,\n            mldv2_unsolicited_report_interval: 1000,\n            suppress_frag_ndisc: 1,\n            accept_ra_from_local: 0,\n            use_optimistic: 0,\n            accept_ra_mtu: 1,\n            stable_secret: 0,\n            use_oif_addrs_only: 0,\n            accept_ra_min_hop_limit: 1,\n            ignore_routes_with_linkdown: 0,\n            drop_unicast_in_l2_multicast: 0,\n            drop_unsolicited_na: 0,\n            keep_addr_on_down: 0,\n            rtr_solicit_max_interval: 3600000,\n            seg6_enabled: 0,\n            seg6_require_hmac: 0,\n            enhanced_dad: 1,\n            addr_gen_mode: 0,\n            disable_policy: 0,\n            accept_ra_rt_info_min_plen: 0,\n            ndisc_tclass: 0,\n        })),\n        Inet6::Stats(get_byte_buffer(&Inet6Stats {\n            num: 36,\n            in_pkts: 6,\n            in_octets: 420,\n            in_delivers: 6,\n            out_forw_datagrams: 0,\n            out_pkts: 6,\n            out_octets: 420,\n            in_hdr_errors: 0,\n            in_too_big_errors: 0,\n            in_no_routes: 2,\n            in_addr_errors: 0,\n            in_unknown_protos: 0,\n            in_truncated_pkts: 0,\n            in_discards: 0,\n            out_discards: 0,\n            out_no_routes: 0,\n            reasm_timeout: 0,\n            reasm_reqds: 0,\n            reasm_oks: 0,\n            reasm_fails: 0,\n            frag_oks: 0,\n            frag_fails: 0,\n            frag_creates: 0,\n            in_mcast_pkts: 0,\n            out_mcast_pkts: 0,\n            in_bcast_pkts: 0,\n            out_bcast_pkts: 0,\n            in_mcast_octets: 0,\n            out_mcast_octets: 0,\n            in_bcast_octets: 0,\n            out_bcast_octets: 0,\n            in_csum_errors: 0,\n            in_no_ect_pkts: 6,\n            in_ect1_pkts: 0,\n            in_ect0_pkts: 0,\n            in_ce_pkts: 0,\n        })),\n        Inet6::IcmpStats(get_byte_buffer(&Icmp6Stats {\n            num: 6,\n            in_msgs: 0,\n            in_errors: 0,\n            out_msgs: 0,\n            out_errors: 0,\n            csum_errors: 0,\n        })),\n        Inet6::Token([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),\n        Inet6::AddrGenMode(0),\n    ]);\n}\n\nlazy_static! {\n    static ref PARSED_AF_INET: AfSpecInet =\n        AfSpecInet::Inet(vec![Inet::DevConf(get_byte_buffer(&InetDevConf {\n            forwarding: 1,\n            mc_forwarding: 0,\n            proxy_arp: 0,\n            accept_redirects: 1,\n            secure_redirects: 1,\n            send_redirects: 1,\n            shared_media: 1,\n            rp_filter: 0,\n            accept_source_route: 1,\n            bootp_relay: 0,\n            log_martians: 0,\n            tag: 0,\n            arpfilter: 0,\n            medium_id: 0,\n            noxfrm: 1,\n            nopolicy: 1,\n            force_igmp_version: 0,\n            arp_announce: 0,\n            arp_ignore: 0,\n            promote_secondaries: 0,\n            arp_accept: 0,\n            arp_notify: 0,\n            accept_local: 0,\n            src_vmark: 0,\n            proxy_arp_pvlan: 0,\n            route_localnet: 0,\n            igmpv2_unsolicited_report_interval: 10000,\n            igmpv3_unsolicited_report_interval: 1000,\n            ignore_routes_with_linkdown: 0,\n            drop_unicast_in_l2_multicast: 0,\n            drop_gratuitous_arp: 0,\n        }))]);\n}\n\n#[test]\nfn af_spec_header() {\n    assert_eq!(BUFFER.length(), 748);\n    assert_eq!(BUFFER.kind(), IFLA_AF_SPEC as u16);\n}\n\n#[test]\nfn parse_af_inet() {\n    let mut nlas = get_nlas();\n    // take the first nla\n    let inet_buf = nlas.next().unwrap().unwrap();\n\n    // buffer checks\n    assert_eq!(inet_buf.length(), 132);\n    assert_eq!(inet_buf.kind(), AF_INET);\n    assert_eq!(inet_buf.value().len(), 128);\n\n    // parsing check\n    let parsed = AfSpecInet::parse(&inet_buf).unwrap();\n    assert_eq!(parsed, *PARSED_AF_INET);\n}\n\n#[test]\nfn emit_af_inet() {\n    let mut bytes = vec![0xff; 132];\n\n    // Note: the value is a Vec of nlas, so the padding is automatically added for each nla.\n    assert_eq!(PARSED_AF_INET.value_len(), 128);\n    assert_eq!(PARSED_AF_INET.buffer_len(), 128 + 4);\n\n    PARSED_AF_INET.emit(&mut bytes[..]);\n\n    let buf = NlaBuffer::new_checked(&bytes[..]).unwrap();\n\n    let mut nlas = get_nlas();\n    let expected_buf = nlas.next().unwrap().unwrap();\n\n    assert_eq!(expected_buf.kind(), buf.kind());\n    assert_eq!(expected_buf.length(), buf.length());\n    assert_eq!(expected_buf.value(), buf.value());\n}\n\n#[test]\nfn emit_af_inet6() {\n    let mut bytes = vec![0xff; 612];\n\n    // Note: the value is a Vec of nlas, so the padding is automatically added for each nla.\n    assert_eq!(PARSED_AF_INET6.value_len(), 608);\n    assert_eq!(PARSED_AF_INET6.buffer_len(), 608 + 4);\n    PARSED_AF_INET6.emit(&mut bytes[..]);\n\n    let buf = NlaBuffer::new_checked(&bytes[..]).unwrap();\n\n    let mut nlas = get_nlas();\n    let _ = nlas.next();\n    let expected_buf = nlas.next().unwrap().unwrap();\n\n    assert_eq!(expected_buf.kind(), buf.kind());\n    assert_eq!(expected_buf.length(), buf.length());\n    assert_eq!(expected_buf.value(), buf.value());\n}\n\n#[test]\nfn parse_af_inet6() {\n    let mut nlas = get_nlas();\n    // take the first nla\n    let _ = nlas.next().unwrap();\n    let inet6_buf = nlas.next().unwrap().unwrap();\n\n    assert_eq!(inet6_buf.length(), 612);\n    assert_eq!(inet6_buf.kind(), AF_INET6);\n    assert_eq!(inet6_buf.value().len(), 608);\n    let parsed = AfSpecInet::parse(&inet6_buf).unwrap();\n\n    assert_eq!(parsed, *PARSED_AF_INET6);\n\n    // Normally this is the end of the nla iterator\n    assert!(nlas.next().is_none());\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, ParseableParametrized},\n    AddressMessage,\n    DecodeError,\n    LinkMessage,\n    NeighbourMessage,\n    NeighbourTableMessage,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n    NsidMessage,\n    RouteMessage,\n    RtnlMessageBuffer,\n    RuleMessage,\n    TcMessage,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum RtnlMessage {\n    NewLink(LinkMessage),\n    DelLink(LinkMessage),\n    GetLink(LinkMessage),\n    SetLink(LinkMessage),\n    NewLinkProp(LinkMessage),\n    DelLinkProp(LinkMessage),\n    NewAddress(AddressMessage),\n    DelAddress(AddressMessage),\n    GetAddress(AddressMessage),\n    NewNeighbour(NeighbourMessage),\n    GetNeighbour(NeighbourMessage),\n    DelNeighbour(NeighbourMessage),\n    NewNeighbourTable(NeighbourTableMessage),\n    GetNeighbourTable(NeighbourTableMessage),\n    SetNeighbourTable(NeighbourTableMessage),\n    NewRoute(RouteMessage),\n    DelRoute(RouteMessage),\n    GetRoute(RouteMessage),\n    NewQueueDiscipline(TcMessage),\n    DelQueueDiscipline(TcMessage),\n    GetQueueDiscipline(TcMessage),\n    NewTrafficClass(TcMessage),\n    DelTrafficClass(TcMessage),\n    GetTrafficClass(TcMessage),\n    NewTrafficFilter(TcMessage),\n    DelTrafficFilter(TcMessage),\n    GetTrafficFilter(TcMessage),\n    NewTrafficChain(TcMessage),\n    DelTrafficChain(TcMessage),\n    GetTrafficChain(TcMessage),\n    NewNsId(NsidMessage),\n    DelNsId(NsidMessage),\n    GetNsId(NsidMessage),\n    NewRule(RuleMessage),\n    DelRule(RuleMessage),\n    GetRule(RuleMessage),\n}\n\nimpl RtnlMessage {\n    pub fn is_new_link(&self) -> bool {\n        matches!(self, RtnlMessage::NewLink(_))\n    }\n\n    pub fn is_del_link(&self) -> bool {\n        matches!(self, RtnlMessage::DelLink(_))\n    }\n\n    pub fn is_get_link(&self) -> bool {\n        matches!(self, RtnlMessage::GetLink(_))\n    }\n\n    pub fn is_set_link(&self) -> bool {\n        matches!(self, RtnlMessage::SetLink(_))\n    }\n\n    pub fn is_new_address(&self) -> bool {\n        matches!(self, RtnlMessage::NewAddress(_))\n    }\n\n    pub fn is_del_address(&self) -> bool {\n        matches!(self, RtnlMessage::DelAddress(_))\n    }\n\n    pub fn is_get_address(&self) -> bool {\n        matches!(self, RtnlMessage::GetAddress(_))\n    }\n\n    pub fn is_get_neighbour(&self) -> bool {\n        matches!(self, RtnlMessage::GetNeighbour(_))\n    }\n\n    pub fn is_new_route(&self) -> bool {\n        matches!(self, RtnlMessage::NewRoute(_))\n    }\n\n    pub fn is_new_neighbour(&self) -> bool {\n        matches!(self, RtnlMessage::NewNeighbour(_))\n    }\n\n    pub fn is_get_route(&self) -> bool {\n        matches!(self, RtnlMessage::GetRoute(_))\n    }\n\n    pub fn is_del_neighbour(&self) -> bool {\n        matches!(self, RtnlMessage::DelNeighbour(_))\n    }\n\n    pub fn is_new_neighbour_table(&self) -> bool {\n        matches!(self, RtnlMessage::NewNeighbourTable(_))\n    }\n\n    pub fn is_get_neighbour_table(&self) -> bool {\n        matches!(self, RtnlMessage::GetNeighbourTable(_))\n    }\n\n    pub fn is_set_neighbour_table(&self) -> bool {\n        matches!(self, RtnlMessage::SetNeighbourTable(_))\n    }\n\n    pub fn is_del_route(&self) -> bool {\n        matches!(self, RtnlMessage::DelRoute(_))\n    }\n\n    pub fn is_new_qdisc(&self) -> bool {\n        matches!(self, RtnlMessage::NewQueueDiscipline(_))\n    }\n\n    pub fn is_del_qdisc(&self) -> bool {\n        matches!(self, RtnlMessage::DelQueueDiscipline(_))\n    }\n\n    pub fn is_get_qdisc(&self) -> bool {\n        matches!(self, RtnlMessage::GetQueueDiscipline(_))\n    }\n\n    pub fn is_new_class(&self) -> bool {\n        matches!(self, RtnlMessage::NewTrafficClass(_))\n    }\n\n    pub fn is_del_class(&self) -> bool {\n        matches!(self, RtnlMessage::DelTrafficClass(_))\n    }\n\n    pub fn is_get_class(&self) -> bool {\n        matches!(self, RtnlMessage::GetTrafficClass(_))\n    }\n\n    pub fn is_new_filter(&self) -> bool {\n        matches!(self, RtnlMessage::NewTrafficFilter(_))\n    }\n\n    pub fn is_del_filter(&self) -> bool {\n        matches!(self, RtnlMessage::DelTrafficFilter(_))\n    }\n\n    pub fn is_get_filter(&self) -> bool {\n        matches!(self, RtnlMessage::GetTrafficFilter(_))\n    }\n\n    pub fn is_new_chain(&self) -> bool {\n        matches!(self, RtnlMessage::NewTrafficChain(_))\n    }\n\n    pub fn is_del_chain(&self) -> bool {\n        matches!(self, RtnlMessage::DelTrafficChain(_))\n    }\n\n    pub fn is_get_chain(&self) -> bool {\n        matches!(self, RtnlMessage::GetTrafficChain(_))\n    }\n\n    pub fn is_new_nsid(&self) -> bool {\n        matches!(self, RtnlMessage::NewNsId(_))\n    }\n\n    pub fn is_get_nsid(&self) -> bool {\n        matches!(self, RtnlMessage::GetNsId(_))\n    }\n\n    pub fn is_del_nsid(&self) -> bool {\n        matches!(self, RtnlMessage::DelNsId(_))\n    }\n\n    pub fn is_get_rule(&self) -> bool {\n        matches!(self, RtnlMessage::GetRule(_))\n    }\n\n    pub fn is_new_rule(&self) -> bool {\n        matches!(self, RtnlMessage::NewRule(_))\n    }\n\n    pub fn is_del_rule(&self) -> bool {\n        matches!(self, RtnlMessage::DelRule(_))\n    }\n\n    pub fn message_type(&self) -> u16 {\n        use self::RtnlMessage::*;\n\n        match self {\n            NewLink(_) => RTM_NEWLINK,\n            DelLink(_) => RTM_DELLINK,\n            GetLink(_) => RTM_GETLINK,\n            SetLink(_) => RTM_SETLINK,\n            NewLinkProp(_) => RTM_NEWLINKPROP,\n            DelLinkProp(_) => RTM_DELLINKPROP,\n            NewAddress(_) => RTM_NEWADDR,\n            DelAddress(_) => RTM_DELADDR,\n            GetAddress(_) => RTM_GETADDR,\n            GetNeighbour(_) => RTM_GETNEIGH,\n            NewNeighbour(_) => RTM_NEWNEIGH,\n            DelNeighbour(_) => RTM_DELNEIGH,\n            GetNeighbourTable(_) => RTM_GETNEIGHTBL,\n            NewNeighbourTable(_) => RTM_NEWNEIGHTBL,\n            SetNeighbourTable(_) => RTM_SETNEIGHTBL,\n            NewRoute(_) => RTM_NEWROUTE,\n            DelRoute(_) => RTM_DELROUTE,\n            GetRoute(_) => RTM_GETROUTE,\n            NewQueueDiscipline(_) => RTM_NEWQDISC,\n            DelQueueDiscipline(_) => RTM_DELQDISC,\n            GetQueueDiscipline(_) => RTM_GETQDISC,\n            NewTrafficClass(_) => RTM_NEWTCLASS,\n            DelTrafficClass(_) => RTM_DELTCLASS,\n            GetTrafficClass(_) => RTM_GETTCLASS,\n            NewTrafficFilter(_) => RTM_NEWTFILTER,\n            DelTrafficFilter(_) => RTM_DELTFILTER,\n            GetTrafficFilter(_) => RTM_GETTFILTER,\n            NewTrafficChain(_) => RTM_NEWCHAIN,\n            DelTrafficChain(_) => RTM_DELCHAIN,\n            GetTrafficChain(_) => RTM_GETCHAIN,\n            GetNsId(_) => RTM_GETNSID,\n            NewNsId(_) => RTM_NEWNSID,\n            DelNsId(_) => RTM_DELNSID,\n            GetRule(_) => RTM_GETRULE,\n            NewRule(_) => RTM_NEWRULE,\n            DelRule(_) => RTM_DELRULE,\n        }\n    }\n}\n\nimpl Emitable for RtnlMessage {\n    #[rustfmt::skip]\n    fn buffer_len(&self) -> usize {\n        use self::RtnlMessage::*;\n        match self {\n            | NewLink(ref msg)\n            | DelLink(ref msg)\n            | GetLink(ref msg)\n            | SetLink(ref msg)\n            | NewLinkProp(ref msg)\n            | DelLinkProp(ref msg)\n            =>  msg.buffer_len(),\n\n            | NewAddress(ref msg)\n            | DelAddress(ref msg)\n            | GetAddress(ref msg)\n            => msg.buffer_len(),\n\n            | NewNeighbour(ref msg)\n            | GetNeighbour(ref msg)\n            | DelNeighbour(ref msg)\n            => msg.buffer_len(),\n\n            | NewNeighbourTable(ref msg)\n            | GetNeighbourTable(ref msg)\n            | SetNeighbourTable(ref msg)\n            => msg.buffer_len(),\n\n            | NewRoute(ref msg)\n            | DelRoute(ref msg)\n            | GetRoute(ref msg)\n            => msg.buffer_len(),\n\n            | NewQueueDiscipline(ref msg)\n            | DelQueueDiscipline(ref msg)\n            | GetQueueDiscipline(ref msg)\n            | NewTrafficClass(ref msg)\n            | DelTrafficClass(ref msg)\n            | GetTrafficClass(ref msg)\n            | NewTrafficFilter(ref msg)\n            | DelTrafficFilter(ref msg)\n            | GetTrafficFilter(ref msg)\n            | NewTrafficChain(ref msg)\n            | DelTrafficChain(ref msg)\n            | GetTrafficChain(ref msg)\n            => msg.buffer_len(),\n\n            | NewNsId(ref msg)\n            | DelNsId(ref msg)\n            | GetNsId(ref msg)\n            => msg.buffer_len(),\n\n            | NewRule(ref msg)\n            | DelRule(ref msg)\n            | GetRule(ref msg)\n            => msg.buffer_len()\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit(&self, buffer: &mut [u8]) {\n        use self::RtnlMessage::*;\n        match self {\n            | NewLink(ref msg)\n            | DelLink(ref msg)\n            | GetLink(ref msg)\n            | SetLink(ref msg)\n            | NewLinkProp(ref msg)\n            | DelLinkProp(ref msg)\n            => msg.emit(buffer),\n\n            | NewAddress(ref msg)\n            | DelAddress(ref msg)\n            | GetAddress(ref msg)\n            => msg.emit(buffer),\n\n            | GetNeighbour(ref msg)\n            | NewNeighbour(ref msg)\n            | DelNeighbour(ref msg)\n            => msg.emit(buffer),\n\n            | GetNeighbourTable(ref msg)\n            | NewNeighbourTable(ref msg)\n            | SetNeighbourTable(ref msg)\n            => msg.emit(buffer),\n\n            | NewRoute(ref msg)\n            | DelRoute(ref msg)\n            | GetRoute(ref msg)\n            => msg.emit(buffer),\n\n            | NewQueueDiscipline(ref msg)\n            | DelQueueDiscipline(ref msg)\n            | GetQueueDiscipline(ref msg)\n            | NewTrafficClass(ref msg)\n            | DelTrafficClass(ref msg)\n            | GetTrafficClass(ref msg)\n            | NewTrafficFilter(ref msg)\n            | DelTrafficFilter(ref msg)\n            | GetTrafficFilter(ref msg)\n            | NewTrafficChain(ref msg)\n            | DelTrafficChain(ref msg)\n            | GetTrafficChain(ref msg)\n            => msg.emit(buffer),\n\n            | NewNsId(ref msg)\n            | DelNsId(ref msg)\n            | GetNsId(ref msg)\n            => msg.emit(buffer),\n\n            | NewRule(ref msg)\n            | DelRule(ref msg)\n            | GetRule(ref msg)\n            => msg.emit(buffer)\n        }\n    }\n}\n\nimpl NetlinkSerializable for RtnlMessage {\n    fn message_type(&self) -> u16 {\n        self.message_type()\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl NetlinkDeserializable for RtnlMessage {\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        let buf = RtnlMessageBuffer::new(payload);\n        match RtnlMessage::parse_with_param(&buf, header.message_type) {\n            Err(e) => Err(e),\n            Ok(message) => Ok(message),\n        }\n    }\n}\n\nimpl From<RtnlMessage> for NetlinkPayload<RtnlMessage> {\n    fn from(message: RtnlMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod address;\npub use address::{AddressHeader, AddressMessage, AddressMessageBuffer, ADDRESS_HEADER_LEN};\n\npub mod link;\npub use link::{LinkHeader, LinkMessage, LinkMessageBuffer, LINK_HEADER_LEN};\n\npub mod neighbour;\npub use neighbour::{\n    NeighbourHeader,\n    NeighbourMessage,\n    NeighbourMessageBuffer,\n    NEIGHBOUR_HEADER_LEN,\n};\n\npub mod neighbour_table;\npub use neighbour_table::{\n    NeighbourTableHeader,\n    NeighbourTableMessage,\n    NeighbourTableMessageBuffer,\n    NEIGHBOUR_TABLE_HEADER_LEN,\n};\n\npub mod nsid;\npub use nsid::{NsidHeader, NsidMessage, NsidMessageBuffer, NSID_HEADER_LEN};\n\npub mod route;\npub use route::{RouteFlags, RouteHeader, RouteMessage, RouteMessageBuffer, ROUTE_HEADER_LEN};\n\npub mod rule;\npub use rule::{RuleHeader, RuleMessage, RuleMessageBuffer, RULE_HEADER_LEN};\n\npub mod tc;\npub use tc::{TcHeader, TcMessage, TcMessageBuffer, TC_HEADER_LEN};\n\npub mod constants;\npub use self::constants::*;\n\nmod buffer;\npub use self::buffer::*;\n\nmod message;\npub use self::message::*;\n\npub mod nlas {\n    pub use super::{\n        address::nlas as address,\n        link::nlas as link,\n        neighbour::nlas as neighbour,\n        neighbour_table::nlas as neighbour_table,\n        nsid::nlas as nsid,\n        route::nlas as route,\n        rule::nlas as rule,\n        tc::nlas as tc,\n    };\n    pub use crate::utils::nla::*;\n}\n\n#[cfg(test)]\nmod test;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const NEIGHBOUR_HEADER_LEN: usize = 12;\nbuffer!(NeighbourMessageBuffer(NEIGHBOUR_HEADER_LEN) {\n    family: (u8, 0),\n    ifindex: (u32, 4..8),\n    state: (u16, 8..10),\n    flags: (u8, 10),\n    ntype: (u8, 11),\n    payload:(slice, NEIGHBOUR_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NeighbourMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n    NeighbourMessageBuffer,\n    NEIGHBOUR_HEADER_LEN,\n};\n\n/// Neighbour headers have the following structure:\n///\n/// ```no_rust\n/// 0                8                16              24               32\n/// +----------------+----------------+----------------+----------------+\n/// |     family     |                     padding                      |\n/// +----------------+----------------+----------------+----------------+\n/// |                             link index                            |\n/// +----------------+----------------+----------------+----------------+\n/// |              state              |     flags      |     ntype      |\n/// +----------------+----------------+----------------+----------------+\n/// ```\n///\n/// `NeighbourHeader` exposes all these fields.\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct NeighbourHeader {\n    pub family: u8,\n    pub ifindex: u32,\n    /// Neighbour cache entry state. It should be set to one of the\n    /// `NUD_*` constants\n    pub state: u16,\n    /// Neighbour cache entry flags. It should be set to a combination\n    /// of the `NTF_*` constants\n    pub flags: u8,\n    /// Neighbour cache entry type. It should be set to one of the\n    /// `NDA_*` constants.\n    pub ntype: u8,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<NeighbourMessageBuffer<T>> for NeighbourHeader {\n    fn parse(buf: &NeighbourMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            family: buf.family(),\n            ifindex: buf.ifindex(),\n            state: buf.state(),\n            flags: buf.flags(),\n            ntype: buf.ntype(),\n        })\n    }\n}\n\nimpl Emitable for NeighbourHeader {\n    fn buffer_len(&self) -> usize {\n        NEIGHBOUR_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = NeighbourMessageBuffer::new(buffer);\n        packet.set_family(self.family);\n        packet.set_ifindex(self.ifindex);\n        packet.set_state(self.state);\n        packet.set_flags(self.flags);\n        packet.set_ntype(self.ntype);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    nlas::neighbour::Nla,\n    traits::{Emitable, Parseable},\n    DecodeError,\n    NeighbourHeader,\n    NeighbourMessageBuffer,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct NeighbourMessage {\n    pub header: NeighbourHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl Emitable for NeighbourMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for NeighbourMessage {\n    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(NeighbourMessage {\n            header: NeighbourHeader::parse(buf)\n                .context(\"failed to parse neighbour message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse neighbour message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::{\n        constants::*,\n        traits::Emitable,\n        NeighbourHeader,\n        NeighbourMessage,\n        NeighbourMessageBuffer,\n    };\n\n    // 0020   0a 00 00 00 02 00 00 00 02 00 80 01 14 00 01 00\n    // 0030   2a 02 80 10 66 d5 00 00 f6 90 ea ff fe 00 2d 83\n    // 0040   0a 00 02 00 f4 90 ea 00 2d 83 00 00 08 00 04 00\n    // 0050   01 00 00 00 14 00 03 00 00 00 00 00 00 00 00 00\n    // 0060   00 00 00 00 02 00 00 00\n\n    #[rustfmt::skip]\n    static HEADER: [u8; 12] = [\n        0x0a, // interface family (inet6)\n        0xff, 0xff, 0xff, // padding\n        0x01, 0x00, 0x00, 0x00, // interface index = 1\n        0x02, 0x00, // state NUD_REACHABLE\n        0x80, // flags NTF_PROXY\n        0x01  // ntype\n\n        // nlas\n        // will add some once I've got them parsed out.\n    ];\n\n    #[test]\n    fn packet_header_read() {\n        let packet = NeighbourMessageBuffer::new(&HEADER[0..12]);\n        assert_eq!(packet.family(), AF_INET6 as u8);\n        assert_eq!(packet.ifindex(), 1);\n        assert_eq!(packet.state(), NUD_REACHABLE);\n        assert_eq!(packet.flags(), NTF_ROUTER);\n        assert_eq!(packet.ntype(), NDA_DST as u8);\n    }\n\n    #[test]\n    fn packet_header_build() {\n        let mut buf = vec![0xff; 12];\n        {\n            let mut packet = NeighbourMessageBuffer::new(&mut buf);\n            packet.set_family(AF_INET6 as u8);\n            packet.set_ifindex(1);\n            packet.set_state(NUD_REACHABLE);\n            packet.set_flags(NTF_ROUTER);\n            packet.set_ntype(NDA_DST as u8);\n        }\n        assert_eq!(&buf[..], &HEADER[0..12]);\n    }\n\n    #[test]\n    fn emit() {\n        let header = NeighbourHeader {\n            family: AF_INET6 as u8,\n            ifindex: 1,\n            state: NUD_REACHABLE,\n            flags: NTF_ROUTER,\n            ntype: NDA_DST as u8,\n        };\n\n        let nlas = vec![];\n        let packet = NeighbourMessage { header, nlas };\n        let mut buf = vec![0; 12];\n\n        assert_eq!(packet.buffer_len(), 12);\n        packet.emit(&mut buf[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\nmod header;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, header::*, message::*, nlas::*};\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/nlas/cache_info.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct CacheInfo {\n    pub confirmed: u32,\n    pub used: u32,\n    pub updated: u32,\n    pub refcnt: u32,\n}\n\npub const NEIGHBOUR_CACHE_INFO_LEN: usize = 16;\n\nbuffer!(CacheInfoBuffer(NEIGHBOUR_CACHE_INFO_LEN) {\n    confirmed: (u32, 0..4),\n    used: (u32, 4..8),\n    updated: (u32, 8..12),\n    refcnt: (u32, 12..16),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<CacheInfoBuffer<T>> for CacheInfo {\n    fn parse(buf: &CacheInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            confirmed: buf.confirmed(),\n            used: buf.used(),\n            updated: buf.updated(),\n            refcnt: buf.refcnt(),\n        })\n    }\n}\n\nimpl Emitable for CacheInfo {\n    fn buffer_len(&self) -> usize {\n        NEIGHBOUR_CACHE_INFO_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = CacheInfoBuffer::new(buffer);\n        buffer.set_confirmed(self.confirmed);\n        buffer.set_used(self.used);\n        buffer.set_updated(self.updated);\n        buffer.set_refcnt(self.refcnt);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod cache_info;\npub use self::cache_info::*;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::{parse_u16, parse_u32},\n    traits::Parseable,\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    Destination(Vec<u8>),\n    LinkLocalAddress(Vec<u8>),\n    CacheInfo(Vec<u8>),\n    Probes(Vec<u8>),\n    Vlan(u16),\n    Port(Vec<u8>),\n    Vni(u32),\n    IfIndex(u32),\n    Master(Vec<u8>),\n    LinkNetNsId(Vec<u8>),\n    SourceVni(u32),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes)\n            | Destination(ref bytes)\n            | LinkLocalAddress(ref bytes)\n            | Probes(ref bytes)\n            | Port(ref bytes)\n            | Master(ref bytes)\n            | CacheInfo(ref bytes)\n            | LinkNetNsId(ref bytes) => bytes.len(),\n            Vlan(_) => 2,\n            Vni(_)\n            | IfIndex(_)\n            | SourceVni(_) => 4,\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes)\n            | Destination(ref bytes)\n            | LinkLocalAddress(ref bytes)\n            | Probes(ref bytes)\n            | Port(ref bytes)\n            | Master(ref bytes)\n            | CacheInfo(ref bytes)\n            | LinkNetNsId(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Vlan(ref value) => NativeEndian::write_u16(buffer, *value),\n            Vni(ref value)\n            | IfIndex(ref value)\n            | SourceVni(ref value) => NativeEndian::write_u32(buffer, *value),\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => NDA_UNSPEC,\n            Destination(_) => NDA_DST,\n            LinkLocalAddress(_) => NDA_LLADDR,\n            CacheInfo(_) => NDA_CACHEINFO,\n            Probes(_) => NDA_PROBES,\n            Vlan(_) => NDA_VLAN,\n            Port(_) => NDA_PORT,\n            Vni(_) => NDA_VNI,\n            IfIndex(_) => NDA_IFINDEX,\n            Master(_) => NDA_MASTER,\n            LinkNetNsId(_) => NDA_LINK_NETNSID,\n            SourceVni(_) => NDA_SRC_VNI,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            NDA_UNSPEC => Unspec(payload.to_vec()),\n            NDA_DST => Destination(payload.to_vec()),\n            NDA_LLADDR => LinkLocalAddress(payload.to_vec()),\n            NDA_CACHEINFO => CacheInfo(payload.to_vec()),\n            NDA_PROBES => Probes(payload.to_vec()),\n            NDA_VLAN => Vlan(parse_u16(payload)?),\n            NDA_PORT => Port(payload.to_vec()),\n            NDA_VNI => Vni(parse_u32(payload)?),\n            NDA_IFINDEX => IfIndex(parse_u32(payload)?),\n            NDA_MASTER => Master(payload.to_vec()),\n            NDA_LINK_NETNSID => LinkNetNsId(payload.to_vec()),\n            NDA_SRC_VNI => SourceVni(parse_u32(payload)?),\n            _ => Other(DefaultNla::parse(buf).context(\"invalid link NLA value (unknown type)\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const NEIGHBOUR_TABLE_HEADER_LEN: usize = 4;\n\nbuffer!(NeighbourTableMessageBuffer(NEIGHBOUR_TABLE_HEADER_LEN) {\n    family: (u8, 0),\n    payload: (slice, NEIGHBOUR_TABLE_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NeighbourTableMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\nuse super::buffer::{NeighbourTableMessageBuffer, NEIGHBOUR_TABLE_HEADER_LEN};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct NeighbourTableHeader {\n    pub family: u8,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<NeighbourTableMessageBuffer<T>> for NeighbourTableHeader {\n    fn parse(buf: &NeighbourTableMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            family: buf.family(),\n        })\n    }\n}\n\nimpl Emitable for NeighbourTableHeader {\n    fn buffer_len(&self) -> usize {\n        NEIGHBOUR_TABLE_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = NeighbourTableMessageBuffer::new(buffer);\n        packet.set_family(self.family);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::neighbour_table::Nla,\n    traits::{Emitable, Parseable},\n    DecodeError,\n    NeighbourTableHeader,\n    NeighbourTableMessageBuffer,\n};\nuse anyhow::Context;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct NeighbourTableMessage {\n    pub header: NeighbourTableHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl Emitable for NeighbourTableMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas.as_slice().emit(buffer);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourTableMessageBuffer<&'a T>>\n    for NeighbourTableMessage\n{\n    fn parse(buf: &NeighbourTableMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(NeighbourTableMessage {\n            header: NeighbourTableHeader::parse(buf)\n                .context(\"failed to parse neighbour table message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse neighbour table message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourTableMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &NeighbourTableMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\nmod header;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, header::*, message::*, nlas::*};\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/nlas/config.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct Config {\n    pub key_len: u16,\n    pub entry_size: u16,\n    pub entries: u32,\n    pub last_flush: u32,\n    pub last_rand: u32,\n    pub hash_rand: u32,\n    pub hash_mask: u32,\n    pub hash_chain_gc: u32,\n    pub proxy_qlen: u32,\n}\n\npub const CONFIG_LEN: usize = 32;\n\nbuffer!(ConfigBuffer(CONFIG_LEN) {\n    key_len: (u16, 0..2),\n    entry_size: (u16, 2..4),\n    entries: (u32, 4..8),\n    last_flush: (u32, 8..12),\n    last_rand: (u32, 12..16),\n    hash_rand: (u32, 16..20),\n    hash_mask: (u32, 20..24),\n    hash_chain_gc: (u32, 24..28),\n    proxy_qlen: (u32, 28..32),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<ConfigBuffer<T>> for Config {\n    fn parse(buf: &ConfigBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            key_len: buf.key_len(),\n            entry_size: buf.entry_size(),\n            entries: buf.entries(),\n            last_flush: buf.last_flush(),\n            last_rand: buf.last_rand(),\n            hash_rand: buf.hash_rand(),\n            hash_mask: buf.hash_mask(),\n            hash_chain_gc: buf.hash_chain_gc(),\n            proxy_qlen: buf.proxy_qlen(),\n        })\n    }\n}\n\nimpl Emitable for Config {\n    fn buffer_len(&self) -> usize {\n        CONFIG_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = ConfigBuffer::new(buffer);\n        buffer.set_key_len(self.key_len);\n        buffer.set_entry_size(self.entry_size);\n        buffer.set_entries(self.entries);\n        buffer.set_last_flush(self.last_flush);\n        buffer.set_last_rand(self.last_rand);\n        buffer.set_hash_rand(self.hash_rand);\n        buffer.set_hash_mask(self.hash_mask);\n        buffer.set_hash_chain_gc(self.hash_chain_gc);\n        buffer.set_proxy_qlen(self.proxy_qlen);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod config;\npub use config::*;\n\nmod stats;\npub use stats::*;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::{parse_string, parse_u32, parse_u64},\n    traits::Parseable,\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    // FIXME: parse this nla\n    Parms(Vec<u8>),\n    Name(String),\n    Threshold1(u32),\n    Threshold2(u32),\n    Threshold3(u32),\n    Config(Vec<u8>),\n    Stats(Vec<u8>),\n    GcInterval(u64),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes) | Parms(ref bytes) | Config(ref bytes) | Stats(ref bytes)=> bytes.len(),\n            // strings: +1 because we need to append a nul byte\n            Name(ref s) => s.len() + 1,\n            Threshold1(_) | Threshold2(_) | Threshold3(_) => 4,\n            GcInterval(_) => 8,\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes) | Parms(ref bytes) | Config(ref bytes) | Stats(ref bytes) => {\n                buffer.copy_from_slice(bytes.as_slice())\n            }\n            Name(ref string) => {\n                buffer[..string.len()].copy_from_slice(string.as_bytes());\n                buffer[string.len()] = 0;\n            }\n            GcInterval(ref value) => NativeEndian::write_u64(buffer, *value),\n            Threshold1(ref value) | Threshold2(ref value) | Threshold3(ref value) => {\n                NativeEndian::write_u32(buffer, *value)\n            }\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => NDTA_UNSPEC,\n            Name(_) => NDTA_NAME,\n            Config(_) => NDTA_CONFIG,\n            Stats(_) => NDTA_STATS,\n            Parms(_) => NDTA_PARMS,\n            GcInterval(_) => NDTA_GC_INTERVAL,\n            Threshold1(_) => NDTA_THRESH1,\n            Threshold2(_) => NDTA_THRESH2,\n            Threshold3(_) => NDTA_THRESH3,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            NDTA_UNSPEC => Unspec(payload.to_vec()),\n            NDTA_NAME => Name(parse_string(payload).context(\"invalid NDTA_NAME value\")?),\n            NDTA_CONFIG => Config(payload.to_vec()),\n            NDTA_STATS => Stats(payload.to_vec()),\n            NDTA_PARMS => Parms(payload.to_vec()),\n            NDTA_GC_INTERVAL => {\n                GcInterval(parse_u64(payload).context(\"invalid NDTA_GC_INTERVAL value\")?)\n            }\n            NDTA_THRESH1 => Threshold1(parse_u32(payload).context(\"invalid NDTA_THRESH1 value\")?),\n            NDTA_THRESH2 => Threshold2(parse_u32(payload).context(\"invalid NDTA_THRESH2 value\")?),\n            NDTA_THRESH3 => Threshold3(parse_u32(payload).context(\"invalid NDTA_THRESH3 value\")?),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/neighbour_table/nlas/stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct Stats {\n    pub allocs: u64,\n    pub destroys: u64,\n    pub hash_grows: u64,\n    pub res_failed: u64,\n    pub lookups: u64,\n    pub hits: u64,\n    pub multicast_probes_received: u64,\n    pub unicast_probes_received: u64,\n    pub periodic_gc_runs: u64,\n    pub forced_gc_runs: u64,\n}\n\npub const STATS_LEN: usize = 80;\nbuffer!(StatsBuffer(STATS_LEN) {\n    allocs: (u64, 0..8),\n    destroys: (u64, 8..16),\n    hash_grows: (u64, 16..24),\n    res_failed: (u64, 24..32),\n    lookups: (u64, 32..40),\n    hits: (u64, 40..48),\n    multicast_probes_received: (u64, 48..56),\n    unicast_probes_received: (u64, 56..64),\n    periodic_gc_runs: (u64, 64..72),\n    forced_gc_runs: (u64, 72..80),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<StatsBuffer<T>> for Stats {\n    fn parse(buf: &StatsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            allocs: buf.allocs(),\n            destroys: buf.destroys(),\n            hash_grows: buf.hash_grows(),\n            res_failed: buf.res_failed(),\n            lookups: buf.lookups(),\n            hits: buf.hits(),\n            multicast_probes_received: buf.multicast_probes_received(),\n            unicast_probes_received: buf.unicast_probes_received(),\n            periodic_gc_runs: buf.periodic_gc_runs(),\n            forced_gc_runs: buf.forced_gc_runs(),\n        })\n    }\n}\n\nimpl Emitable for Stats {\n    fn buffer_len(&self) -> usize {\n        STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatsBuffer::new(buffer);\n        buffer.set_allocs(self.allocs);\n        buffer.set_destroys(self.destroys);\n        buffer.set_hash_grows(self.hash_grows);\n        buffer.set_res_failed(self.res_failed);\n        buffer.set_lookups(self.lookups);\n        buffer.set_hits(self.hits);\n        buffer.set_multicast_probes_received(self.multicast_probes_received);\n        buffer.set_unicast_probes_received(self.unicast_probes_received);\n        buffer.set_periodic_gc_runs(self.periodic_gc_runs);\n        buffer.set_forced_gc_runs(self.forced_gc_runs);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/nsid/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const NSID_HEADER_LEN: usize = 4;\n\nbuffer!(NsidMessageBuffer(NSID_HEADER_LEN) {\n    rtgen_family: (u8, 0),\n    payload: (slice, NSID_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NsidMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/nsid/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::{NsidMessageBuffer, NSID_HEADER_LEN};\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct NsidHeader {\n    pub rtgen_family: u8,\n}\n\nimpl Emitable for NsidHeader {\n    fn buffer_len(&self) -> usize {\n        NSID_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = NsidMessageBuffer::new(buffer);\n        packet.set_rtgen_family(self.rtgen_family);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<NsidMessageBuffer<T>> for NsidHeader {\n    fn parse(buf: &NsidMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(NsidHeader {\n            rtgen_family: buf.rtgen_family(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/nsid/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    nlas::nsid::Nla,\n    traits::{Emitable, Parseable},\n    DecodeError,\n    NsidHeader,\n    NsidMessageBuffer,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct NsidMessage {\n    pub header: NsidHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NsidMessageBuffer<&'a T>> for NsidMessage {\n    fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            header: NsidHeader::parse(buf).context(\"failed to parse nsid message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse nsid message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NsidMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\nimpl Emitable for NsidMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::{\n        nlas::nsid::Nla,\n        traits::ParseableParametrized,\n        NetlinkBuffer,\n        NsidHeader,\n        NsidMessage,\n        RtnlMessage,\n        RtnlMessageBuffer,\n        NETNSA_NSID_NOT_ASSIGNED,\n        RTM_GETNSID,\n        RTM_NEWNSID,\n    };\n\n    #[rustfmt::skip]\n    #[test]\n    fn get_ns_id_request() {\n        let data = vec![\n            0x1c, 0x00, 0x00, 0x00, // length = 28\n            0x5a, 0x00, // message type = 90 = RTM_GETNSID\n            0x01, 0x00, // flags\n            0x00, 0x00, 0x00, 0x00, // seq number\n            0x00, 0x00, 0x00, 0x00, // pid\n\n            // GETNSID message\n            0x00, // rtgen family\n            0x00, 0x00, 0x00, // padding\n            // NLA\n            0x08, 0x00, // length = 8\n            0x03, 0x00, // type = 3 (Fd)\n            0x04, 0x00, 0x00, 0x00 // 4\n        ];\n        let expected = RtnlMessage::GetNsId(NsidMessage {\n            header: NsidHeader { rtgen_family: 0 },\n            nlas: vec![Nla::Fd(4)],\n        });\n        let actual = RtnlMessage::parse_with_param(&RtnlMessageBuffer::new(&NetlinkBuffer::new(&data).payload()), RTM_GETNSID).unwrap();\n        assert_eq!(expected, actual);\n    }\n\n    #[rustfmt::skip]\n    #[test]\n    fn get_ns_id_response() {\n        let data = vec![\n            0x1c, 0x00, 0x00, 0x00, // length = 28\n            0x58, 0x00, // message type = RTM_NEWNSID\n            0x00, 0x00, // flags\n            0x00, 0x00, 0x00, 0x00, // seq number\n            0x76, 0x12, 0x00, 0x00, // pid\n\n            // NETNSID message\n            0x00, // rtgen family\n            0x00, 0x00, 0x00, // padding\n            // NLA\n            0x08, 0x00, // length\n            0x01, 0x00, // type = NETNSA_NSID\n            0xff, 0xff, 0xff, 0xff // -1\n        ];\n        let expected = RtnlMessage::NewNsId(NsidMessage {\n            header: NsidHeader { rtgen_family: 0 },\n            nlas: vec![Nla::Id(NETNSA_NSID_NOT_ASSIGNED)],\n        });\n        let nl_buffer = NetlinkBuffer::new(&data).payload();\n        let rtnl_buffer = RtnlMessageBuffer::new(&nl_buffer);\n        let actual = RtnlMessage::parse_with_param(&rtnl_buffer, RTM_NEWNSID).unwrap();\n        assert_eq!(expected, actual);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/nsid/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\nmod header;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, header::*, message::*, nlas::*};\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/nsid/nlas.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::{parse_i32, parse_u32},\n    traits::Parseable,\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    Id(i32),\n    Pid(u32),\n    Fd(u32),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes) => bytes.len(),\n            Id(_) | Pid(_) | Fd(_) => 4,\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Fd(ref value) | Pid(ref value) => NativeEndian::write_u32(buffer, *value),\n            Id(ref value) => NativeEndian::write_i32(buffer, *value),\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => NETNSA_NONE,\n            Id(_) => NETNSA_NSID,\n            Pid(_) => NETNSA_PID,\n            Fd(_) => NETNSA_FD,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            NETNSA_NONE => Unspec(payload.to_vec()),\n            NETNSA_NSID => Id(parse_i32(payload).context(\"invalid NETNSA_NSID\")?),\n            NETNSA_PID => Pid(parse_u32(payload).context(\"invalid NETNSA_PID\")?),\n            NETNSA_FD => Fd(parse_u32(payload).context(\"invalid NETNSA_FD\")?),\n            kind => Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const ROUTE_HEADER_LEN: usize = 12;\n\nbuffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) {\n    address_family: (u8, 0),\n    destination_prefix_length: (u8, 1),\n    source_prefix_length: (u8, 2),\n    tos: (u8, 3),\n    table: (u8, 4),\n    protocol: (u8, 5),\n    scope: (u8, 6),\n    kind: (u8, 7),\n    flags: (u32, 8..ROUTE_HEADER_LEN),\n    payload: (slice, ROUTE_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, Parseable},\n    DecodeError,\n    RouteMessageBuffer,\n    ROUTE_HEADER_LEN,\n};\n\nbitflags! {\n    /// Flags that can be set in a `RTM_GETROUTE` ([`RtnlMessage::GetRoute`]) message.\n    pub struct RouteFlags: u32 {\n        /// If the route changes, notify the user via rtnetlink\n        const RTM_F_NOTIFY = RTM_F_NOTIFY;\n        /// This route is cloned. Cloned routes are routes coming from the cache instead of the\n        /// FIB. For IPv4, the cache was removed in Linux 3.6 (see [IPv4 route lookup on Linux] for\n        /// more information about IPv4 routing)\n        ///\n        /// [IPv4 route lookup on Linux]: https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux\n        const RTM_F_CLONED = RTM_F_CLONED;\n        /// Multipath equalizer (not yet implemented)\n        const RTM_F_EQUALIZE = RTM_F_EQUALIZE;\n        /// Prefix addresses\n        const RTM_F_PREFIX = RTM_F_PREFIX;\n        /// Show the table from which the lookup result comes. Note that before commit\n        /// `c36ba6603a11`, Linux would always hardcode [`RouteMessageHeader.table`] (known as\n        /// `rtmsg.rtm_table` in the kernel) to `RT_TABLE_MAIN`.\n        ///\n        /// [`RouteMessageHeader.table`]: ../struct.RouteMessageHeader.html#structfield.table\n        const RTM_F_LOOKUP_TABLE = RTM_F_LOOKUP_TABLE;\n        /// Return the full FIB lookup match (see commit `b61798130f1be5bff08712308126c2d7ebe390ef`)\n        const RTM_F_FIB_MATCH = RTM_F_FIB_MATCH;\n    }\n}\n\nimpl Default for RouteFlags {\n    fn default() -> Self {\n        Self::empty()\n    }\n}\n\n/// High level representation of `RTM_GETROUTE`, `RTM_ADDROUTE`, `RTM_DELROUTE`\n/// messages headers.\n///\n/// These headers have the following structure:\n///\n/// ```no_rust\n/// 0                8                16              24               32\n/// +----------------+----------------+----------------+----------------+\n/// | address family | dest. length   | source length  |      tos       |\n/// +----------------+----------------+----------------+----------------+\n/// |     table      |   protocol     |      scope     | type (kind)    |\n/// +----------------+----------------+----------------+----------------+\n/// |                               flags                               |\n/// +----------------+----------------+----------------+----------------+\n/// ```\n///\n/// # Example\n///\n/// ```rust\n/// extern crate netlink_packet_route;\n/// use netlink_packet_route::{constants::*, RouteFlags, RouteHeader};\n///\n/// fn main() {\n///     let mut hdr = RouteHeader::default();\n///     assert_eq!(hdr.address_family, 0u8);\n///     assert_eq!(hdr.destination_prefix_length, 0u8);\n///     assert_eq!(hdr.source_prefix_length, 0u8);\n///     assert_eq!(hdr.tos, 0u8);\n///     assert_eq!(hdr.table, RT_TABLE_UNSPEC);\n///     assert_eq!(hdr.protocol, RTPROT_UNSPEC);\n///     assert_eq!(hdr.scope, RT_SCOPE_UNIVERSE);\n///     assert_eq!(hdr.kind, RTN_UNSPEC);\n///     assert_eq!(hdr.flags.bits(), 0u32);\n///\n///     // set some values\n///     hdr.destination_prefix_length = 8;\n///     hdr.table = RT_TABLE_MAIN;\n///     hdr.protocol = RTPROT_KERNEL;\n///     hdr.scope = RT_SCOPE_NOWHERE;\n///\n///     // ...\n/// }\n/// ```\n#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]\npub struct RouteHeader {\n    /// Address family of the route: either [`AF_INET`] for IPv4 prefixes, or [`AF_INET6`] for IPv6\n    /// prefixes.\n    pub address_family: u8,\n    /// Prefix length of the destination subnet.\n    ///\n    /// Note that setting\n    pub destination_prefix_length: u8,\n    /// Prefix length of the source address.\n    ///\n    /// There could be multiple addresses from which a certain network is reachable. To decide which\n    /// source address to use to reach and address in that network, the kernel rely on the route's\n    /// source address for this destination.\n    ///\n    /// For instance, interface `if1` could have two addresses `10.0.0.1/24` and `10.0.0.128/24`,\n    /// and we could have the following routes:\n    ///\n    /// ```no_rust\n    /// 10.0.0.10/32 dev if1 scope link src 10.0.0.1\n    /// 10.0.0.11/32 dev if1 scope link src 10.0.0.1\n    /// 10.0.0.12/32 dev if1 scope link src 10.0.0.1\n    /// 10.0.0.0/24 dev if1 scope link src 10.0.0.128\n    /// ```\n    ///\n    /// It means that for `10.0.0.10`, `10.0.0.11` and `10.0.0.12` the packets will be sent with\n    /// `10.0.0.1` as source address, while for the rest of the `10.0.0.0/24` subnet, the source\n    /// address will be `10.0.0.128`\n    pub source_prefix_length: u8,\n    /// TOS filter\n    pub tos: u8,\n    /// Routing table ID. It can be one of the `RT_TABLE_*` constants or a custom table number\n    /// between 1 and 251 (included). Note that Linux supports routing table with an ID greater than\n    /// 255, in which case this attribute will be set to [`RT_TABLE_COMPAT`] and an [`Nla::Table`]\n    /// netlink attribute will be present in the message.\n    pub table: u8,\n    /// Protocol from which the route was learnt. It should be set to one of the `RTPROT_*`\n    /// constants.\n    pub protocol: u8,\n    /// The scope of the area where the addresses in the destination subnet are valid. Predefined\n    /// scope values are the `RT_SCOPE_*` constants.\n    pub scope: u8,\n    /// Route type. It should be set to one of the `RTN_*` constants.\n    pub kind: u8,\n    /// Flags when querying the kernel with a `RTM_GETROUTE` message. See [`RouteFlags`].\n    pub flags: RouteFlags,\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RouteMessageBuffer<&'a T>> for RouteHeader {\n    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(RouteHeader {\n            address_family: buf.address_family(),\n            destination_prefix_length: buf.destination_prefix_length(),\n            source_prefix_length: buf.source_prefix_length(),\n            tos: buf.tos(),\n            table: buf.table(),\n            protocol: buf.protocol(),\n            scope: buf.scope(),\n            kind: buf.kind(),\n            flags: RouteFlags::from_bits_truncate(buf.flags()),\n        })\n    }\n}\n\nimpl Emitable for RouteHeader {\n    fn buffer_len(&self) -> usize {\n        ROUTE_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = RouteMessageBuffer::new(buffer);\n        buffer.set_address_family(self.address_family);\n        buffer.set_destination_prefix_length(self.destination_prefix_length);\n        buffer.set_source_prefix_length(self.source_prefix_length);\n        buffer.set_tos(self.tos);\n        buffer.set_table(self.table);\n        buffer.set_protocol(self.protocol);\n        buffer.set_scope(self.scope);\n        buffer.set_kind(self.kind);\n        buffer.set_flags(self.flags.bits());\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::route::Nla,\n    traits::{Emitable, Parseable},\n    DecodeError,\n    RouteHeader,\n    RouteMessageBuffer,\n};\nuse anyhow::Context;\nuse std::net::IpAddr;\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct RouteMessage {\n    pub header: RouteHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl Emitable for RouteMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<RouteMessageBuffer<&'a T>> for RouteMessage {\n    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(RouteMessage {\n            header: RouteHeader::parse(buf).context(\"failed to parse route message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse route message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<RouteMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\nfn octets_to_addr(octets: &[u8]) -> Result<IpAddr, DecodeError> {\n    if octets.len() == 4 {\n        let mut ary: [u8; 4] = Default::default();\n        ary.copy_from_slice(octets);\n        Ok(IpAddr::from(ary))\n    } else if octets.len() == 16 {\n        let mut ary: [u8; 16] = Default::default();\n        ary.copy_from_slice(octets);\n        Ok(IpAddr::from(ary))\n    } else {\n        Err(DecodeError::from(\"Cannot decode IP address\"))\n    }\n}\n\nimpl RouteMessage {\n    /// Returns the input interface index, if present.\n    pub fn input_interface(&self) -> Option<u32> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Iif(v) = nla {\n                Some(*v)\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the output interface index, if present.\n    pub fn output_interface(&self) -> Option<u32> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Oif(v) = nla {\n                Some(*v)\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the source address prefix, if present.\n    pub fn source_prefix(&self) -> Option<(IpAddr, u8)> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Source(v) = nla {\n                octets_to_addr(v)\n                    .ok()\n                    .map(|addr| (addr, self.header.source_prefix_length))\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the destination subnet prefix, if present.\n    pub fn destination_prefix(&self) -> Option<(IpAddr, u8)> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Destination(v) = nla {\n                octets_to_addr(v)\n                    .ok()\n                    .map(|addr| (addr, self.header.destination_prefix_length))\n            } else {\n                None\n            }\n        })\n    }\n\n    /// Returns the gateway address, if present.\n    pub fn gateway(&self) -> Option<IpAddr> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Gateway(v) = nla {\n                octets_to_addr(v).ok()\n            } else {\n                None\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\nmod header;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, header::*, message::*, nlas::*};\n\n#[cfg(test)]\nmod test;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/cache_info.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct CacheInfo {\n    pub clntref: u32,\n    pub last_use: u32,\n    pub expires: u32,\n    pub error: u32,\n    pub used: u32,\n    pub id: u32,\n    pub ts: u32,\n    pub ts_age: u32,\n}\n\npub const CACHE_INFO_LEN: usize = 32;\n\nbuffer!(CacheInfoBuffer(CACHE_INFO_LEN) {\n    clntref: (u32, 0..4),\n    last_use: (u32, 4..8),\n    expires: (u32, 8..12),\n    error: (u32, 12..16),\n    used: (u32, 16..20),\n    id: (u32, 20..24),\n    ts: (u32, 24..28),\n    ts_age: (u32, 28..32),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<CacheInfoBuffer<T>> for CacheInfo {\n    fn parse(buf: &CacheInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            clntref: buf.clntref(),\n            last_use: buf.last_use(),\n            expires: buf.expires(),\n            error: buf.error(),\n            used: buf.used(),\n            id: buf.id(),\n            ts: buf.ts(),\n            ts_age: buf.ts_age(),\n        })\n    }\n}\n\nimpl Emitable for CacheInfo {\n    fn buffer_len(&self) -> usize {\n        CACHE_INFO_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = CacheInfoBuffer::new(buffer);\n        buffer.set_clntref(self.clntref);\n        buffer.set_last_use(self.last_use);\n        buffer.set_expires(self.expires);\n        buffer.set_error(self.error);\n        buffer.set_used(self.used);\n        buffer.set_id(self.id);\n        buffer.set_ts(self.ts);\n        buffer.set_ts_age(self.ts_age);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/metrics.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse std::mem::size_of;\n\nuse crate::{\n    constants::*,\n    nlas::{DefaultNla, Nla, NlaBuffer},\n    parsers::parse_u32,\n    traits::Parseable,\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Metrics {\n    Unspec(Vec<u8>),\n    Lock(u32),\n    Mtu(u32),\n    Window(u32),\n    Rtt(u32),\n    RttVar(u32),\n    SsThresh(u32),\n    Cwnd(u32),\n    Advmss(u32),\n    Reordering(u32),\n    Hoplimit(u32),\n    InitCwnd(u32),\n    Features(u32),\n    RtoMin(u32),\n    InitRwnd(u32),\n    QuickAck(u32),\n    CcAlgo(u32),\n    FastopenNoCookie(u32),\n    Other(DefaultNla),\n}\n\nimpl Nla for Metrics {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Metrics::*;\n        match *self {\n            Unspec(ref bytes) => bytes.len(),\n            Lock(_)\n                | Mtu(_)\n                | Window(_)\n                | Rtt(_)\n                | RttVar(_)\n                | SsThresh(_)\n                | Cwnd(_)\n                | Advmss(_)\n                | Reordering(_)\n                | Hoplimit(_)\n                | InitCwnd(_)\n                | Features(_)\n                | RtoMin(_)\n                | InitRwnd(_)\n                | QuickAck(_)\n                | CcAlgo(_)\n                | FastopenNoCookie(_)\n                => size_of::<u32>(),\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Metrics::*;\n        match *self {\n            Unspec(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n\n            Lock(value)\n                | Mtu(value)\n                | Window(value)\n                | Rtt(value)\n                | RttVar(value)\n                | SsThresh(value)\n                | Cwnd(value)\n                | Advmss(value)\n                | Reordering(value)\n                | Hoplimit(value)\n                | InitCwnd(value)\n                | Features(value)\n                | RtoMin(value)\n                | InitRwnd(value)\n                | QuickAck(value)\n                | CcAlgo(value)\n                | FastopenNoCookie(value)\n                => NativeEndian::write_u32(buffer, value),\n\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Metrics::*;\n        match *self {\n            Unspec(_) => RTAX_UNSPEC,\n            Lock(_) => RTAX_LOCK,\n            Mtu(_) => RTAX_MTU,\n            Window(_) => RTAX_WINDOW,\n            Rtt(_) => RTAX_RTT,\n            RttVar(_) => RTAX_RTTVAR,\n            SsThresh(_) => RTAX_SSTHRESH,\n            Cwnd(_) => RTAX_CWND,\n            Advmss(_) => RTAX_ADVMSS,\n            Reordering(_) => RTAX_REORDERING,\n            Hoplimit(_) => RTAX_HOPLIMIT,\n            InitCwnd(_) => RTAX_INITCWND,\n            Features(_) => RTAX_FEATURES,\n            RtoMin(_) => RTAX_RTO_MIN,\n            InitRwnd(_) => RTAX_INITRWND,\n            QuickAck(_) => RTAX_QUICKACK,\n            CcAlgo(_) => RTAX_CC_ALGO,\n            FastopenNoCookie(_) => RTAX_FASTOPEN_NO_COOKIE,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Metrics {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Metrics::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            RTAX_UNSPEC => Unspec(payload.to_vec()),\n            RTAX_LOCK => Lock(parse_u32(payload).context(\"invalid RTAX_LOCK value\")?),\n            RTAX_MTU => Mtu(parse_u32(payload).context(\"invalid RTAX_MTU value\")?),\n            RTAX_WINDOW => Window(parse_u32(payload).context(\"invalid RTAX_WINDOW value\")?),\n            RTAX_RTT => Rtt(parse_u32(payload).context(\"invalid RTAX_RTT value\")?),\n            RTAX_RTTVAR => RttVar(parse_u32(payload).context(\"invalid RTAX_RTTVAR value\")?),\n            RTAX_SSTHRESH => SsThresh(parse_u32(payload).context(\"invalid RTAX_SSTHRESH value\")?),\n            RTAX_CWND => Cwnd(parse_u32(payload).context(\"invalid RTAX_CWND value\")?),\n            RTAX_ADVMSS => Advmss(parse_u32(payload).context(\"invalid RTAX_ADVMSS value\")?),\n            RTAX_REORDERING => {\n                Reordering(parse_u32(payload).context(\"invalid RTAX_REORDERING value\")?)\n            }\n            RTAX_HOPLIMIT => Hoplimit(parse_u32(payload).context(\"invalid RTAX_HOPLIMIT value\")?),\n            RTAX_INITCWND => InitCwnd(parse_u32(payload).context(\"invalid RTAX_INITCWND value\")?),\n            RTAX_FEATURES => Features(parse_u32(payload).context(\"invalid RTAX_FEATURES value\")?),\n            RTAX_RTO_MIN => RtoMin(parse_u32(payload).context(\"invalid RTAX_RTO_MIN value\")?),\n            RTAX_INITRWND => InitRwnd(parse_u32(payload).context(\"invalid RTAX_INITRWND value\")?),\n            RTAX_QUICKACK => QuickAck(parse_u32(payload).context(\"invalid RTAX_QUICKACK value\")?),\n            RTAX_CC_ALGO => CcAlgo(parse_u32(payload).context(\"invalid RTAX_CC_ALGO value\")?),\n            RTAX_FASTOPEN_NO_COOKIE => FastopenNoCookie(\n                parse_u32(payload).context(\"invalid RTAX_FASTOPEN_NO_COOKIE value\")?,\n            ),\n            _ => Other(DefaultNla::parse(buf).context(\"invalid NLA value (unknown type) value\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/mfc_stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct MfcStats {\n    pub packets: u64,\n    pub bytes: u64,\n    pub wrong_if: u64,\n}\n\npub const MFC_STATS_LEN: usize = 24;\n\nbuffer!(MfcStatsBuffer(MFC_STATS_LEN) {\n    packets: (u64, 0..8),\n    bytes: (u64, 8..16),\n    wrong_if: (u64, 16..24),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<MfcStatsBuffer<T>> for MfcStats {\n    fn parse(buf: &MfcStatsBuffer<T>) -> Result<MfcStats, DecodeError> {\n        Ok(MfcStats {\n            packets: buf.packets(),\n            bytes: buf.bytes(),\n            wrong_if: buf.wrong_if(),\n        })\n    }\n}\n\nimpl Emitable for MfcStats {\n    fn buffer_len(&self) -> usize {\n        MFC_STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = MfcStatsBuffer::new(buffer);\n        buffer.set_packets(self.packets);\n        buffer.set_bytes(self.bytes);\n        buffer.set_wrong_if(self.wrong_if);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod cache_info;\npub use self::cache_info::*;\n\nmod metrics;\npub use self::metrics::*;\n\nmod mfc_stats;\npub use self::mfc_stats::*;\n\nmod mpls_ip_tunnel;\npub use self::mpls_ip_tunnel::*;\n\nmod next_hops;\npub use self::next_hops::*;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    parsers::{parse_u16, parse_u32},\n    traits::Parseable,\n    DecodeError,\n};\n\n#[cfg(feature = \"rich_nlas\")]\nuse crate::traits::Emitable;\n\n/// Netlink attributes for `RTM_NEWROUTE`, `RTM_DELROUTE`,\n/// `RTM_GETROUTE` messages.\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    #[cfg(not(feature = \"rich_nlas\"))]\n    Metrics(Vec<u8>),\n    #[cfg(feature = \"rich_nlas\")]\n    Metrics(Metrics),\n    #[cfg(not(feature = \"rich_nlas\"))]\n    MfcStats(Vec<u8>),\n    #[cfg(feature = \"rich_nlas\")]\n    MfcStats(MfcStats),\n    #[cfg(not(feature = \"rich_nlas\"))]\n    MultiPath(Vec<u8>),\n    #[cfg(feature = \"rich_nlas\")]\n    // See: https://codecave.cc/multipath-routing-in-linux-part-1.html\n    MultiPath(Vec<NextHop>),\n    #[cfg(not(feature = \"rich_nlas\"))]\n    CacheInfo(Vec<u8>),\n    #[cfg(feature = \"rich_nlas\")]\n    CacheInfo(CacheInfo),\n    Unspec(Vec<u8>),\n    Destination(Vec<u8>),\n    Source(Vec<u8>),\n    Gateway(Vec<u8>),\n    PrefSource(Vec<u8>),\n    Session(Vec<u8>),\n    MpAlgo(Vec<u8>),\n    Via(Vec<u8>),\n    NewDestination(Vec<u8>),\n    Pref(Vec<u8>),\n    Encap(Vec<u8>),\n    Expires(Vec<u8>),\n    Pad(Vec<u8>),\n    Uid(Vec<u8>),\n    TtlPropagate(Vec<u8>),\n    EncapType(u16),\n    Iif(u32),\n    Oif(u32),\n    Priority(u32),\n    ProtocolInfo(u32),\n    Flow(u32),\n    Table(u32),\n    Mark(u32),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes)\n                | Destination(ref bytes)\n                | Source(ref bytes)\n                | Gateway(ref bytes)\n                | PrefSource(ref bytes)\n                | Session(ref bytes)\n                | MpAlgo(ref bytes)\n                | Via(ref bytes)\n                | NewDestination(ref bytes)\n                | Pref(ref bytes)\n                | Encap(ref bytes)\n                | Expires(ref bytes)\n                | Pad(ref bytes)\n                | Uid(ref bytes)\n                | TtlPropagate(ref bytes)\n                => bytes.len(),\n\n            #[cfg(not(feature = \"rich_nlas\"))]\n            CacheInfo(ref bytes)\n                | MfcStats(ref bytes)\n                | Metrics(ref bytes)\n                | MultiPath(ref bytes)\n                => bytes.len(),\n\n            #[cfg(feature = \"rich_nlas\")]\n            CacheInfo(ref cache_info) => cache_info.buffer_len(),\n            #[cfg(feature = \"rich_nlas\")]\n            MfcStats(ref stats) => stats.buffer_len(),\n            #[cfg(feature = \"rich_nlas\")]\n            Metrics(ref metrics) => metrics.buffer_len(),\n            #[cfg(feature = \"rich_nlas\")]\n            MultiPath(ref next_hops) => next_hops.iter().map(|nh| nh.buffer_len()).sum(),\n\n            EncapType(_) => 2,\n            Iif(_)\n                | Oif(_)\n                | Priority(_)\n                | ProtocolInfo(_)\n                | Flow(_)\n                | Table(_)\n                | Mark(_)\n                => 4,\n\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    #[rustfmt::skip]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            Unspec(ref bytes)\n                | Destination(ref bytes)\n                | Source(ref bytes)\n                | Gateway(ref bytes)\n                | PrefSource(ref bytes)\n                | Session(ref bytes)\n                | MpAlgo(ref bytes)\n                | Via(ref bytes)\n                | NewDestination(ref bytes)\n                | Pref(ref bytes)\n                | Encap(ref bytes)\n                | Expires(ref bytes)\n                | Pad(ref bytes)\n                | Uid(ref bytes)\n                | TtlPropagate(ref bytes)\n                => buffer.copy_from_slice(bytes.as_slice()),\n\n            #[cfg(not(feature = \"rich_nlas\"))]\n                MultiPath(ref bytes)\n                | CacheInfo(ref bytes)\n                | MfcStats(ref bytes)\n                | Metrics(ref bytes)\n                => buffer.copy_from_slice(bytes.as_slice()),\n\n            #[cfg(feature = \"rich_nlas\")]\n            CacheInfo(ref cache_info) => cache_info.emit(buffer),\n            #[cfg(feature = \"rich_nlas\")]\n            MfcStats(ref stats) => stats.emit(buffer),\n            #[cfg(feature = \"rich_nlas\")]\n            Metrics(ref metrics) => metrics.emit(buffer),\n            #[cfg(feature = \"rich_nlas\")]\n            MultiPath(ref next_hops) => {\n                let mut offset = 0;\n                for nh in next_hops {\n                    let len = nh.buffer_len();\n                    nh.emit(&mut buffer[offset..offset+len]);\n                    offset += len\n                }\n            }\n\n            EncapType(value) => NativeEndian::write_u16(buffer, value),\n            Iif(value)\n                | Oif(value)\n                | Priority(value)\n                | ProtocolInfo(value)\n                | Flow(value)\n                | Table(value)\n                | Mark(value)\n                => NativeEndian::write_u32(buffer, value),\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => RTA_UNSPEC,\n            Destination(_) => RTA_DST,\n            Source(_) => RTA_SRC,\n            Iif(_) => RTA_IIF,\n            Oif(_) => RTA_OIF,\n            Gateway(_) => RTA_GATEWAY,\n            Priority(_) => RTA_PRIORITY,\n            PrefSource(_) => RTA_PREFSRC,\n            Metrics(_) => RTA_METRICS,\n            MultiPath(_) => RTA_MULTIPATH,\n            ProtocolInfo(_) => RTA_PROTOINFO,\n            Flow(_) => RTA_FLOW,\n            CacheInfo(_) => RTA_CACHEINFO,\n            Session(_) => RTA_SESSION,\n            MpAlgo(_) => RTA_MP_ALGO,\n            Table(_) => RTA_TABLE,\n            Mark(_) => RTA_MARK,\n            MfcStats(_) => RTA_MFC_STATS,\n            Via(_) => RTA_VIA,\n            NewDestination(_) => RTA_NEWDST,\n            Pref(_) => RTA_PREF,\n            EncapType(_) => RTA_ENCAP_TYPE,\n            Encap(_) => RTA_ENCAP,\n            Expires(_) => RTA_EXPIRES,\n            Pad(_) => RTA_PAD,\n            Uid(_) => RTA_UID,\n            TtlPropagate(_) => RTA_TTL_PROPAGATE,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            RTA_UNSPEC => Unspec(payload.to_vec()),\n            RTA_DST => Destination(payload.to_vec()),\n            RTA_SRC => Source(payload.to_vec()),\n            RTA_GATEWAY => Gateway(payload.to_vec()),\n            RTA_PREFSRC => PrefSource(payload.to_vec()),\n            RTA_SESSION => Session(payload.to_vec()),\n            RTA_MP_ALGO => MpAlgo(payload.to_vec()),\n            RTA_VIA => Via(payload.to_vec()),\n            RTA_NEWDST => NewDestination(payload.to_vec()),\n            RTA_PREF => Pref(payload.to_vec()),\n            RTA_ENCAP => Encap(payload.to_vec()),\n            RTA_EXPIRES => Expires(payload.to_vec()),\n            RTA_PAD => Pad(payload.to_vec()),\n            RTA_UID => Uid(payload.to_vec()),\n            RTA_TTL_PROPAGATE => TtlPropagate(payload.to_vec()),\n            RTA_ENCAP_TYPE => {\n                EncapType(parse_u16(payload).context(\"invalid RTA_ENCAP_TYPE value\")?)\n            }\n            RTA_IIF => Iif(parse_u32(payload).context(\"invalid RTA_IIF value\")?),\n            RTA_OIF => Oif(parse_u32(payload).context(\"invalid RTA_OIF value\")?),\n            RTA_PRIORITY => Priority(parse_u32(payload).context(\"invalid RTA_PRIORITY value\")?),\n            RTA_PROTOINFO => {\n                ProtocolInfo(parse_u32(payload).context(\"invalid RTA_PROTOINFO value\")?)\n            }\n            RTA_FLOW => Flow(parse_u32(payload).context(\"invalid RTA_FLOW value\")?),\n            RTA_TABLE => Table(parse_u32(payload).context(\"invalid RTA_TABLE value\")?),\n            RTA_MARK => Mark(parse_u32(payload).context(\"invalid RTA_MARK value\")?),\n\n            #[cfg(not(feature = \"rich_nlas\"))]\n            RTA_CACHEINFO => CacheInfo(payload.to_vec()),\n            #[cfg(feature = \"rich_nlas\")]\n            RTA_CACHEINFO => CacheInfo(\n                cache_info::CacheInfo::parse(\n                    &CacheInfoBuffer::new_checked(payload)\n                        .context(\"invalid RTA_CACHEINFO value\")?,\n                )\n                .context(\"invalid RTA_CACHEINFO value\")?,\n            ),\n            #[cfg(not(feature = \"rich_nlas\"))]\n            RTA_MFC_STATS => MfcStats(payload.to_vec()),\n            #[cfg(feature = \"rich_nlas\")]\n            RTA_MFC_STATS => MfcStats(\n                mfc_stats::MfcStats::parse(\n                    &MfcStatsBuffer::new_checked(payload).context(\"invalid RTA_MFC_STATS value\")?,\n                )\n                .context(\"invalid RTA_MFC_STATS value\")?,\n            ),\n            #[cfg(not(feature = \"rich_nlas\"))]\n            RTA_METRICS => Metrics(payload.to_vec()),\n            #[cfg(feature = \"rich_nlas\")]\n            RTA_METRICS => Metrics(\n                metrics::Metrics::parse(\n                    &NlaBuffer::new_checked(payload).context(\"invalid RTA_METRICS value\")?,\n                )\n                .context(\"invalid RTA_METRICS value\")?,\n            ),\n            #[cfg(not(feature = \"rich_nlas\"))]\n            RTA_MULTIPATH => MultiPath(payload.to_vec()),\n            #[cfg(feature = \"rich_nlas\")]\n            RTA_MULTIPATH => {\n                let mut next_hops = vec![];\n                let mut buf = payload;\n                loop {\n                    let nh_buf =\n                        NextHopBuffer::new_checked(&buf).context(\"invalid RTA_MULTIPATH value\")?;\n                    let len = nh_buf.length() as usize;\n                    let nh = NextHop::parse(&nh_buf).context(\"invalid RTA_MULTIPATH value\")?;\n                    next_hops.push(nh);\n                    if buf.len() == len {\n                        break;\n                    }\n                    buf = &buf[len..];\n                }\n                MultiPath(next_hops)\n            }\n            _ => Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/mpls_ip_tunnel.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    constants::*,\n    nlas::{DefaultNla, Nla, NlaBuffer},\n    parsers::parse_u8,\n    traits::Parseable,\n    DecodeError,\n};\n\n/// Netlink attributes for `RTA_ENCAP` with `RTA_ENCAP_TYPE` set to `LWTUNNEL_ENCAP_MPLS`.\npub enum MplsIpTunnel {\n    Destination(Vec<u8>),\n    Ttl(u8),\n    Other(DefaultNla),\n}\n\nimpl Nla for MplsIpTunnel {\n    fn value_len(&self) -> usize {\n        use self::MplsIpTunnel::*;\n        match self {\n            Destination(bytes) => bytes.len(),\n            Ttl(_) => 1,\n            Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::MplsIpTunnel::*;\n        match self {\n            Destination(_) => MPLS_IPTUNNEL_DST,\n            Ttl(_) => MPLS_IPTUNNEL_TTL,\n            Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::MplsIpTunnel::*;\n        match self {\n            Destination(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Ttl(ttl) => buffer[0] = *ttl,\n            Other(attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for MplsIpTunnel {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::MplsIpTunnel::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            MPLS_IPTUNNEL_DST => Destination(payload.to_vec()),\n            MPLS_IPTUNNEL_TTL => Ttl(parse_u8(payload).context(\"invalid MPLS_IPTUNNEL_TTL value\")?),\n            _ => Other(DefaultNla::parse(buf).context(\"invalid NLA value (unknown type) value\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/nlas/next_hops.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse std::net::IpAddr;\n\nuse crate::{\n    constants,\n    nlas::{NlaBuffer, NlasIterator},\n    parsers::parse_ip,\n    route::nlas::Nla,\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\nbitflags! {\n    pub struct NextHopFlags: u8 {\n        const RTNH_F_EMPTY = 0;\n        const RTNH_F_DEAD = constants::RTNH_F_DEAD as u8;\n        const RTNH_F_PERVASIVE = constants::RTNH_F_PERVASIVE as u8;\n        const RTNH_F_ONLINK = constants::RTNH_F_ONLINK as u8;\n        const RTNH_F_OFFLOAD = constants::RTNH_F_OFFLOAD as u8;\n        const RTNH_F_LINKDOWN = constants::RTNH_F_LINKDOWN as u8;\n        const RTNH_F_UNRESOLVED = constants::RTNH_F_UNRESOLVED as u8;\n    }\n}\n\nconst PAYLOAD_OFFSET: usize = 8;\n\nbuffer!(NextHopBuffer {\n    length: (u16, 0..2),\n    flags: (u8, 2),\n    hops: (u8, 3),\n    interface_id: (u32, 4..8),\n    payload: (slice, PAYLOAD_OFFSET..),\n});\n\nimpl<T: AsRef<[u8]>> NextHopBuffer<T> {\n    pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {\n        let packet = Self::new(buffer);\n        packet.check_buffer_length()?;\n        Ok(packet)\n    }\n\n    fn check_buffer_length(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < PAYLOAD_OFFSET {\n            return Err(\n                format!(\"invalid NextHopBuffer: length {} < {}\", len, PAYLOAD_OFFSET).into(),\n            );\n        }\n        if len < self.length() as usize {\n            return Err(format!(\n                \"invalid NextHopBuffer: length {} < {}\",\n                len,\n                8 + self.length()\n            )\n            .into());\n        }\n        Ok(())\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> NextHopBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(&self.payload()[..(self.length() as usize - PAYLOAD_OFFSET)])\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct NextHop {\n    /// Next-hop flags (see [`NextHopFlags`])\n    pub flags: NextHopFlags,\n    /// Next-hop priority\n    pub hops: u8,\n    /// Interface index for the next-hop\n    pub interface_id: u32,\n    /// Attributes\n    pub nlas: Vec<Nla>,\n}\n\nimpl<'a, T: AsRef<[u8]>> Parseable<NextHopBuffer<&'a T>> for NextHop {\n    fn parse(buf: &NextHopBuffer<&T>) -> Result<NextHop, DecodeError> {\n        let nlas = Vec::<Nla>::parse(\n            &NextHopBuffer::new_checked(buf.buffer)\n                .context(\"cannot parse route attributes in next-hop\")?,\n        )\n        .context(\"cannot parse route attributes in next-hop\")?;\n        Ok(NextHop {\n            flags: NextHopFlags::from_bits_truncate(buf.flags()),\n            hops: buf.hops(),\n            interface_id: buf.interface_id(),\n            nlas,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<NextHopBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &NextHopBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\nimpl Emitable for NextHop {\n    fn buffer_len(&self) -> usize {\n        // len, flags, hops and interface id fields\n        PAYLOAD_OFFSET + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut nh_buffer = NextHopBuffer::new(buffer);\n        nh_buffer.set_length(self.buffer_len() as u16);\n        nh_buffer.set_flags(self.flags.bits());\n        nh_buffer.set_hops(self.hops);\n        nh_buffer.set_interface_id(self.interface_id);\n        self.nlas.as_slice().emit(nh_buffer.payload_mut())\n    }\n}\n\nimpl NextHop {\n    /// Gateway address (it is actually encoded as an `RTA_GATEWAY` nla)\n    pub fn gateway(&self) -> Option<IpAddr> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Gateway(ip) = nla {\n                parse_ip(ip).ok()\n            } else {\n                None\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/route/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[cfg(feature = \"rich_nlas\")]\nmod test_rich_nlas {\n    use crate::{\n        rtnl::route::{\n            nlas::{NextHop, NextHopFlags, Nla},\n            RouteFlags,\n            RouteMessage,\n            RouteMessageBuffer,\n        },\n        utils::{Emitable, Parseable},\n    };\n    use std::net::Ipv6Addr;\n\n    #[rustfmt::skip]\n    static ROUTE_MSG: [u8; 100] = [\n        0x0a, // address family\n        0x40, // length of destination\n        0x00, // length of source\n        0x00, // TOS\n        0xfe, // routing table id\n        0x03, // routing protocol (boot)\n        0x00, // route origin (global)\n        0x01, // gateway or direct route\n        0x00, 0x00, 0x00, 0x00,\n\n            // Route destination address NLA\n            0x14, 0x00, // Length (20)\n            0x01, 0x00, // Type\n            // Value\n            0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\n            // RTA_MULTIPATH attribute\n            0x44, 0x00, // Length (68)\n            0x09, 0x00, // Type\n\n                // next-hop 1\n                0x1c, 0x00, // length (28)\n                0x00, // flags\n                0x00, // hops\n                0x00, 0x00, 0x00, 0x00, // interface ID\n                    // nested RTA_GATEWAY\n                    0x14, 0x00, // Length (14)\n                    0x05, 0x00, // Type\n                    // Value\n                    0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n\n                // next-hop 2\n                0x1c, 0x00, // length (28)\n                0x00, // flags\n                0x00, // hops\n                0x00, 0x00, 0x00, 0x00, // interface ID\n                    // nested RTA_GATEWAY\n                    0x14, 0x00, // Length (14)\n                    0x05, 0x00, // Type\n                    // Value\n                    0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\n\n                // next-hop 3\n                0x08, 0x00, // length (8)\n                0x00,  // flags\n                0x00, // hops\n                0x02, 0x00, 0x00, 0x00, // interface ID\n    ];\n\n    fn route_message() -> RouteMessage {\n        let mut msg = RouteMessage::default();\n        msg.header.address_family = 0x0a;\n        msg.header.destination_prefix_length = 0x40;\n        msg.header.source_prefix_length = 0;\n        msg.header.tos = 0;\n        msg.header.table = 0xfe;\n        msg.header.protocol = 0x03;\n        msg.header.scope = 0x00;\n        msg.header.kind = 0x01;\n        msg.header.flags = RouteFlags::empty();\n        msg.nlas = vec![\n            Nla::Destination(\"1001::\".parse::<Ipv6Addr>().unwrap().octets().to_vec()),\n            Nla::MultiPath(vec![\n                NextHop {\n                    flags: NextHopFlags::empty(),\n                    hops: 0,\n                    interface_id: 0,\n                    nlas: vec![Nla::Gateway(\n                        \"fc00::1\".parse::<Ipv6Addr>().unwrap().octets().to_vec(),\n                    )],\n                },\n                NextHop {\n                    flags: NextHopFlags::empty(),\n                    hops: 0,\n                    interface_id: 0,\n                    nlas: vec![Nla::Gateway(\n                        \"fc01::1\".parse::<Ipv6Addr>().unwrap().octets().to_vec(),\n                    )],\n                },\n                NextHop {\n                    flags: NextHopFlags::empty(),\n                    hops: 0,\n                    interface_id: 2,\n                    nlas: vec![],\n                },\n            ]),\n        ];\n        msg\n    }\n\n    #[test]\n    fn parse_message_with_multipath_nla() {\n        let expected = route_message();\n        let actual =\n            RouteMessage::parse(&RouteMessageBuffer::new_checked(&&ROUTE_MSG[..]).unwrap())\n                .unwrap();\n        assert_eq!(actual, expected);\n    }\n\n    #[test]\n    fn emit_message_with_multipath_nla() {\n        let msg = route_message();\n        let mut buf = vec![0; 100];\n        assert_eq!(msg.buffer_len(), 100);\n        msg.emit(&mut buf[..]);\n        assert_eq!(buf, ROUTE_MSG);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/rule/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const RULE_HEADER_LEN: usize = 12;\n\nbuffer!(RuleMessageBuffer(RULE_HEADER_LEN) {\n    family: (u8, 0),\n    dst_len: (u8, 1),\n    src_len: (u8, 2),\n    tos: (u8, 3),\n    table: (u8, 4),\n    reserve_1: (u8, 5),\n    reserve_2: (u8, 6),\n    action: (u8, 7),\n    flags: (u32, 8..RULE_HEADER_LEN),\n    payload: (slice, RULE_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> RuleMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/rule/header.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::{buffer::RuleMessageBuffer, RULE_HEADER_LEN};\nuse crate::{\n    constants::*,\n    utils::{Emitable, Parseable},\n    DecodeError,\n};\n\nbitflags! {\n    pub struct RuleFlags: u32 {\n        const FIB_RULE_PERMANENT = FIB_RULE_PERMANENT;\n        const FIB_RULE_INVERT = FIB_RULE_INVERT;\n        const FIB_RULE_UNRESOLVED = FIB_RULE_UNRESOLVED;\n        const FIB_RULE_IIF_DETACHED = FIB_RULE_IIF_DETACHED;\n        const FIB_RULE_DEV_DETACHED = FIB_RULE_DEV_DETACHED;\n        const FIB_RULE_OIF_DETACHED = FIB_RULE_OIF_DETACHED;\n        const FIB_RULE_FIND_SADDR = FIB_RULE_FIND_SADDR;\n    }\n}\n\nimpl Default for RuleFlags {\n    fn default() -> Self {\n        Self::empty()\n    }\n}\n\n// see https://github.com/torvalds/linux/blob/master/include/uapi/linux/fib_rules.h\n// see https://github.com/torvalds/linux/blob/master/include/net/fib_rules.h\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct RuleHeader {\n    /// Address family: one of the `AF_*` constants.\n    pub family: u8,\n    pub dst_len: u8,\n    pub src_len: u8,\n    pub tos: u8,\n    /// RT_TABLE_*\n    pub table: u8,\n    /// FR_ACT_*\n    pub action: u8,\n    /// fib rule flags\n    pub flags: u32,\n}\n\nimpl Emitable for RuleHeader {\n    fn buffer_len(&self) -> usize {\n        RULE_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = RuleMessageBuffer::new(buffer);\n        packet.set_family(self.family);\n        packet.set_dst_len(self.dst_len);\n        packet.set_src_len(self.src_len);\n        packet.set_flags(self.flags);\n        packet.set_table(self.table);\n        packet.set_tos(self.tos);\n        packet.set_action(self.action);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<RuleMessageBuffer<&'a T>> for RuleHeader {\n    fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(RuleHeader {\n            family: buf.family(),\n            dst_len: buf.dst_len(),\n            src_len: buf.src_len(),\n            tos: buf.tos(),\n            table: buf.table(),\n            action: buf.action(),\n            flags: buf.flags(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/rule/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::{buffer::RuleMessageBuffer, header::RuleHeader, nlas::Nla};\nuse crate::{\n    utils::{Emitable, Parseable},\n    DecodeError,\n};\nuse anyhow::Context;\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct RuleMessage {\n    pub header: RuleHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl Emitable for RuleMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<RuleMessageBuffer<&'a T>> for RuleMessage {\n    fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let header = RuleHeader::parse(buf).context(\"failed to parse link message header\")?;\n        let nlas = Vec::<Nla>::parse(buf).context(\"failed to parse link message NLAs\")?;\n        Ok(RuleMessage { header, nlas })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<RuleMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/rule/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod buffer;\npub mod header;\npub mod message;\npub mod nlas;\n\npub use buffer::*;\npub use header::*;\npub use message::*;\npub use nlas::*;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/rule/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas,\n    nlas::DefaultNla,\n    utils::{\n        byteorder::{ByteOrder, NativeEndian},\n        nla::NlaBuffer,\n        parsers::{parse_string, parse_u32, parse_u8},\n        Parseable,\n    },\n    DecodeError,\n    FRA_DPORT_RANGE,\n    FRA_DST,\n    FRA_FLOW,\n    FRA_FWMARK,\n    FRA_FWMASK,\n    FRA_GOTO,\n    FRA_IIFNAME,\n    FRA_IP_PROTO,\n    FRA_L3MDEV,\n    FRA_OIFNAME,\n    FRA_PAD,\n    FRA_PRIORITY,\n    FRA_PROTOCOL,\n    FRA_SPORT_RANGE,\n    FRA_SRC,\n    FRA_SUPPRESS_IFGROUP,\n    FRA_SUPPRESS_PREFIXLEN,\n    FRA_TABLE,\n    FRA_TUN_ID,\n    FRA_UID_RANGE,\n    FRA_UNSPEC,\n};\nuse anyhow::Context;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    /// destination address\n    Destination(Vec<u8>),\n    /// source address\n    Source(Vec<u8>),\n    /// input interface name\n    Iifname(String),\n    /// target to jump to when used with rule action `FR_ACT_GOTO`\n    Goto(u32),\n    Priority(u32),\n    FwMark(u32),\n    FwMask(u32),\n    /// flow class id,\n    Flow(u32),\n    TunId(u32),\n    SuppressIfGroup(u32),\n    SuppressPrefixLen(u32),\n    Table(u32),\n    /// output interface name\n    OifName(String),\n    Pad(Vec<u8>),\n    /// iif or oif is l3mdev goto its table\n    L3MDev(u8),\n    UidRange(Vec<u8>),\n    /// RTPROT_*\n    Protocol(u8),\n    /// AF_*\n    IpProto(u8),\n    SourcePortRange(Vec<u8>),\n    DestinationPortRange(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match self {\n            Unspec(ref bytes)\n            | Destination(ref bytes)\n            | Source(ref bytes)\n            | Pad(ref bytes)\n            | UidRange(ref bytes)\n            | SourcePortRange(ref bytes)\n            | DestinationPortRange(ref bytes) => bytes.len(),\n            Iifname(ref s) | OifName(ref s) => s.as_bytes().len() + 1,\n            Priority(_) | FwMark(_) | FwMask(_) | Flow(_) | TunId(_) | Goto(_)\n            | SuppressIfGroup(_) | SuppressPrefixLen(_) | Table(_) => 4,\n            L3MDev(_) | Protocol(_) | IpProto(_) => 1,\n            Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match self {\n            Unspec(_) => FRA_UNSPEC,\n            Destination(_) => FRA_DST,\n            Source(_) => FRA_SRC,\n            Iifname(_) => FRA_IIFNAME,\n            Goto(_) => FRA_GOTO,\n            Priority(_) => FRA_PRIORITY,\n            FwMark(_) => FRA_FWMARK,\n            FwMask(_) => FRA_FWMASK,\n            Flow(_) => FRA_FLOW,\n            TunId(_) => FRA_TUN_ID,\n            SuppressIfGroup(_) => FRA_SUPPRESS_IFGROUP,\n            SuppressPrefixLen(_) => FRA_SUPPRESS_PREFIXLEN,\n            Table(_) => FRA_TABLE,\n            OifName(_) => FRA_OIFNAME,\n            Pad(_) => FRA_PAD,\n            L3MDev(_) => FRA_L3MDEV,\n            UidRange(_) => FRA_UID_RANGE,\n            Protocol(_) => FRA_PROTOCOL,\n            IpProto(_) => FRA_IP_PROTO,\n            SourcePortRange(_) => FRA_SPORT_RANGE,\n            DestinationPortRange(_) => FRA_DPORT_RANGE,\n            Other(attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match self {\n            Unspec(ref bytes)\n            | Destination(ref bytes)\n            | Source(ref bytes)\n            | Pad(ref bytes)\n            | UidRange(ref bytes)\n            | SourcePortRange(ref bytes)\n            | DestinationPortRange(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Iifname(ref s) | OifName(ref s) => buffer[..s.len()].copy_from_slice(s.as_bytes()),\n\n            Priority(value)\n            | FwMark(value)\n            | FwMask(value)\n            | Flow(value)\n            | TunId(value)\n            | Goto(value)\n            | SuppressIfGroup(value)\n            | SuppressPrefixLen(value)\n            | Table(value) => NativeEndian::write_u32(buffer, *value),\n            L3MDev(value) | Protocol(value) | IpProto(value) => buffer[0] = *value,\n            Other(attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use Nla::*;\n\n        let payload = buf.value();\n\n        Ok(match buf.kind() {\n            FRA_UNSPEC => Unspec(payload.to_vec()),\n            FRA_DST => Destination(payload.to_vec()),\n            FRA_SRC => Source(payload.to_vec()),\n            FRA_IIFNAME => Iifname(parse_string(payload).context(\"invalid FRA_IIFNAME value\")?),\n            FRA_GOTO => Goto(parse_u32(payload).context(\"invalid FRA_GOTO value\")?),\n            FRA_PRIORITY => Priority(parse_u32(payload).context(\"invalid FRA_PRIORITY value\")?),\n            FRA_FWMARK => FwMark(parse_u32(payload).context(\"invalid FRA_FWMARK value\")?),\n            FRA_FLOW => Flow(parse_u32(payload).context(\"invalid FRA_FLOW value\")?),\n            FRA_TUN_ID => TunId(parse_u32(payload).context(\"invalid FRA_TUN_ID value\")?),\n            FRA_SUPPRESS_IFGROUP => {\n                SuppressIfGroup(parse_u32(payload).context(\"invalid FRA_SUPPRESS_IFGROUP value\")?)\n            }\n            FRA_SUPPRESS_PREFIXLEN => SuppressPrefixLen(\n                parse_u32(payload).context(\"invalid FRA_SUPPRESS_PREFIXLEN value\")?,\n            ),\n            FRA_TABLE => Table(parse_u32(payload).context(\"invalid FRA_TABLE value\")?),\n            FRA_FWMASK => FwMask(parse_u32(payload).context(\"invalid FRA_FWMASK value\")?),\n            FRA_OIFNAME => OifName(parse_string(payload).context(\"invalid FRA_OIFNAME value\")?),\n            FRA_PAD => Pad(payload.to_vec()),\n            FRA_L3MDEV => L3MDev(parse_u8(payload).context(\"invalid FRA_L3MDEV value\")?),\n            FRA_UID_RANGE => UidRange(payload.to_vec()),\n            FRA_PROTOCOL => Protocol(parse_u8(payload).context(\"invalid FRA_PROTOCOL value\")?),\n            FRA_IP_PROTO => IpProto(parse_u8(payload).context(\"invalid FRA_IP_PROTO value\")?),\n            FRA_SPORT_RANGE => SourcePortRange(payload.to_vec()),\n            FRA_DPORT_RANGE => DestinationPortRange(payload.to_vec()),\n            _ => Other(DefaultNla::parse(buf).context(\"invalid NLA (unknown kind)\")?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    nlas::{NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const TC_HEADER_LEN: usize = 20;\n\nbuffer!(TcMessageBuffer(TC_HEADER_LEN) {\n    family: (u8, 0),\n    pad1: (u8, 1),\n    pad2: (u16, 2..4),\n    index: (i32, 4..8),\n    handle: (u32, 8..12),\n    parent: (u32, 12..16),\n    info: (u32, 16..TC_HEADER_LEN),\n    payload: (slice, TC_HEADER_LEN..),\n});\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> TcMessageBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n/// Handles\npub const TC_H_MAJ_MASK: u32 = 0xFFFF0000;\npub const TC_H_MIN_MASK: u32 = 0x0000FFFF;\n\n#[macro_export]\nmacro_rules! TC_H_MAKE {\n    ($maj: expr, $min: expr) => {\n        ($maj & TC_H_MAJ_MASK) | ($min & TC_H_MIN_MASK)\n    };\n}\n\npub const TC_H_UNSPEC: u32 = 0;\npub const TC_H_ROOT: u32 = 0xFFFFFFFF;\npub const TC_H_INGRESS: u32 = 0xFFFFFFF1;\npub const TC_H_CLSACT: u32 = TC_H_INGRESS;\n\npub const TC_H_MIN_PRIORITY: u32 = 0xFFE0;\npub const TC_H_MIN_INGRESS: u32 = 0xFFF2;\npub const TC_H_MIN_EGRESS: u32 = 0xFFF3;\n\n/// U32 filters\npub const TCA_U32_UNSPEC: u16 = 0;\npub const TCA_U32_CLASSID: u16 = 1;\npub const TCA_U32_HASH: u16 = 2;\npub const TCA_U32_LINK: u16 = 3;\npub const TCA_U32_DIVISOR: u16 = 4;\npub const TCA_U32_SEL: u16 = 5;\npub const TCA_U32_POLICE: u16 = 6;\npub const TCA_U32_ACT: u16 = 7;\npub const TCA_U32_INDEV: u16 = 8;\npub const TCA_U32_PCNT: u16 = 9;\npub const TCA_U32_MARK: u16 = 10;\npub const TCA_U32_FLAGS: u16 = 11;\npub const TCA_U32_PAD: u16 = 12;\npub const TCA_U32_MAX: u16 = TCA_U32_PAD;\n\n/// U32 Flags\npub const TC_U32_TERMINAL: u8 = 1;\npub const TC_U32_OFFSET: u8 = 2;\npub const TC_U32_VAROFFSET: u8 = 4;\npub const TC_U32_EAT: u8 = 8;\npub const TC_U32_MAXDEPTH: u8 = 8;\n\n/// Action attributes\npub const TCA_ACT_UNSPEC: u16 = 0;\npub const TCA_ACT_KIND: u16 = 1;\npub const TCA_ACT_OPTIONS: u16 = 2;\npub const TCA_ACT_INDEX: u16 = 3;\npub const TCA_ACT_STATS: u16 = 4;\npub const TCA_ACT_PAD: u16 = 5;\npub const TCA_ACT_COOKIE: u16 = 6;\n\n//TODO(wllenyj): Why not subtract 1? See `linux/pkt_cls.h` for original definition.\npub const TCA_ACT_MAX: u16 = 7;\npub const TCA_OLD_COMPAT: u16 = TCA_ACT_MAX + 1;\npub const TCA_ACT_MAX_PRIO: u16 = 32;\npub const TCA_ACT_BIND: u16 = 1;\npub const TCA_ACT_NOBIND: u16 = 0;\npub const TCA_ACT_UNBIND: u16 = 1;\npub const TCA_ACT_NOUNBIND: u16 = 0;\npub const TCA_ACT_REPLACE: u16 = 1;\npub const TCA_ACT_NOREPLACE: u16 = 0;\n\npub const TC_ACT_UNSPEC: i32 = -1;\npub const TC_ACT_OK: i32 = 0;\npub const TC_ACT_RECLASSIFY: i32 = 1;\npub const TC_ACT_SHOT: i32 = 2;\npub const TC_ACT_PIPE: i32 = 3;\npub const TC_ACT_STOLEN: i32 = 4;\npub const TC_ACT_QUEUED: i32 = 5;\npub const TC_ACT_REPEAT: i32 = 6;\npub const TC_ACT_REDIRECT: i32 = 7;\npub const TC_ACT_TRAP: i32 = 8;\n\npub const TC_ACT_VALUE_MAX: i32 = TC_ACT_TRAP;\n\npub const TC_ACT_JUMP: i32 = 0x10000000;\n\npub const TCA_ACT_TAB: u16 = 1; // TCA_ROOT_TAB\npub const TCAA_MAX: u16 = 1;\n\n/// Mirred action attr\npub const TCA_MIRRED_UNSPEC: u16 = 0;\npub const TCA_MIRRED_TM: u16 = 1;\npub const TCA_MIRRED_PARMS: u16 = 2;\npub const TCA_MIRRED_PAD: u16 = 3;\npub const TCA_MIRRED_MAX: u16 = TCA_MIRRED_PAD;\n\npub const TCA_EGRESS_REDIR: i32 = 1; /* packet redirect to EGRESS */\npub const TCA_EGRESS_MIRROR: i32 = 2; /* mirror packet to EGRESS */\npub const TCA_INGRESS_REDIR: i32 = 3; /* packet redirect to INGRESS */\npub const TCA_INGRESS_MIRROR: i32 = 4; /* mirror packet to INGRESS */\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    constants::*,\n    nlas::{\n        tc::{Nla, Stats, Stats2, StatsBuffer, TcOpt},\n        DefaultNla,\n        NlasIterator,\n    },\n    parsers::{parse_string, parse_u8},\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n    TcMessageBuffer,\n    TC_HEADER_LEN,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct TcMessage {\n    pub header: TcHeader,\n    pub nlas: Vec<Nla>,\n}\n\nimpl TcMessage {\n    pub fn into_parts(self) -> (TcHeader, Vec<Nla>) {\n        (self.header, self.nlas)\n    }\n\n    pub fn from_parts(header: TcHeader, nlas: Vec<Nla>) -> Self {\n        TcMessage { header, nlas }\n    }\n\n    /// Create a new `TcMessage` with the given index\n    pub fn with_index(index: i32) -> Self {\n        Self {\n            header: TcHeader {\n                index,\n                ..Default::default()\n            },\n            nlas: Vec::new(),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct TcHeader {\n    pub family: u8,\n    // Interface index\n    pub index: i32,\n    // Qdisc handle\n    pub handle: u32,\n    // Parent Qdisc\n    pub parent: u32,\n    pub info: u32,\n}\n\nimpl Emitable for TcHeader {\n    fn buffer_len(&self) -> usize {\n        TC_HEADER_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = TcMessageBuffer::new(buffer);\n        packet.set_family(self.family);\n        packet.set_index(self.index);\n        packet.set_handle(self.handle);\n        packet.set_parent(self.parent);\n        packet.set_info(self.info);\n    }\n}\n\nimpl Emitable for TcMessage {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<TcMessageBuffer<T>> for TcHeader {\n    fn parse(buf: &TcMessageBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            family: buf.family(),\n            index: buf.index(),\n            handle: buf.handle(),\n            parent: buf.parent(),\n            info: buf.info(),\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for TcMessage {\n    fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            header: TcHeader::parse(buf).context(\"failed to parse tc message header\")?,\n            nlas: Vec::<Nla>::parse(buf).context(\"failed to parse tc message NLAs\")?,\n        })\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for Vec<Nla> {\n    fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        let mut kind = String::new();\n\n        for nla_buf in buf.nlas() {\n            let buf = nla_buf.context(\"invalid tc nla\")?;\n            let payload = buf.value();\n            let nla = match buf.kind() {\n                TCA_UNSPEC => Nla::Unspec(payload.to_vec()),\n                TCA_KIND => {\n                    kind = parse_string(payload).context(\"invalid TCA_KIND\")?;\n                    Nla::Kind(kind.clone())\n                }\n                TCA_OPTIONS => {\n                    let mut nlas = vec![];\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(\"invalid TCA_OPTIONS\")?;\n                        nlas.push(\n                            TcOpt::parse_with_param(&nla, &kind)\n                                .context(\"failed to parse TCA_OPTIONS\")?,\n                        )\n                    }\n                    Nla::Options(nlas)\n                }\n                TCA_STATS => Nla::Stats(\n                    Stats::parse(&StatsBuffer::new_checked(payload).context(\"invalid TCA_STATS\")?)\n                        .context(\"failed to parse TCA_STATS\")?,\n                ),\n                TCA_XSTATS => Nla::XStats(payload.to_vec()),\n                TCA_RATE => Nla::Rate(payload.to_vec()),\n                TCA_FCNT => Nla::Fcnt(payload.to_vec()),\n                TCA_STATS2 => {\n                    let mut nlas = vec![];\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(\"invalid TCA_STATS2\")?;\n                        nlas.push(Stats2::parse(&nla).context(\"failed to parse TCA_STATS2\")?);\n                    }\n                    Nla::Stats2(nlas)\n                }\n                TCA_STAB => Nla::Stab(payload.to_vec()),\n                TCA_CHAIN => Nla::Chain(payload.to_vec()),\n                TCA_HW_OFFLOAD => {\n                    Nla::HwOffload(parse_u8(payload).context(\"failed to parse TCA_HW_OFFLOAD\")?)\n                }\n                _ => Nla::Other(DefaultNla::parse(&buf).context(\"failed to parse tc nla\")?),\n            };\n\n            nlas.push(nla);\n        }\n        Ok(nlas)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod buffer;\npub mod constants;\nmod message;\npub mod nlas;\n\npub use self::{buffer::*, message::*, nlas::*};\n\n#[cfg(test)]\nmod test;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/action/mirred.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n/// Mirred action\n///\n/// The mirred action allows packet mirroring (copying) or\n/// redirecting (stealing) the packet it receives. Mirroring is what\n/// is sometimes referred to as Switch Port Analyzer (SPAN) and is\n/// commonly used to analyze and/or debug flows.\nuse crate::{\n    nlas::{self, DefaultNla, NlaBuffer},\n    tc::{constants::*, TC_GEN_BUF_LEN},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const KIND: &str = \"mirred\";\npub const TC_MIRRED_BUF_LEN: usize = TC_GEN_BUF_LEN + 8;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    Tm(Vec<u8>),\n    Parms(TcMirred),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match self {\n            Unspec(bytes) | Tm(bytes) => bytes.len(),\n            Parms(_) => TC_MIRRED_BUF_LEN,\n            Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match self {\n            Unspec(bytes) | Tm(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Parms(p) => p.emit(buffer),\n            Other(attr) => attr.emit_value(buffer),\n        }\n    }\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match self {\n            Unspec(_) => TCA_MIRRED_UNSPEC,\n            Tm(_) => TCA_MIRRED_TM,\n            Parms(_) => TCA_MIRRED_PARMS,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            TCA_MIRRED_UNSPEC => Unspec(payload.to_vec()),\n            TCA_MIRRED_TM => Tm(payload.to_vec()),\n            TCA_MIRRED_PARMS => Parms(TcMirred::parse(&TcMirredBuffer::new_checked(payload)?)?),\n            _ => Other(DefaultNla::parse(buf)?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct TcMirred {\n    pub index: u32,\n    pub capab: u32,\n    pub action: i32,\n    pub refcnt: i32,\n    pub bindcnt: i32,\n\n    pub eaction: i32,\n    pub ifindex: u32,\n}\n\nbuffer!(TcMirredBuffer(TC_MIRRED_BUF_LEN) {\n    index: (u32, 0..4),\n    capab: (u32, 4..8),\n    action: (i32, 8..12),\n    refcnt: (i32, 12..16),\n    bindcnt: (i32, 16..20),\n    eaction: (i32, TC_GEN_BUF_LEN..(TC_GEN_BUF_LEN + 4)),\n    ifindex: (u32, (TC_GEN_BUF_LEN + 4)..TC_MIRRED_BUF_LEN),\n});\n\nimpl Emitable for TcMirred {\n    fn buffer_len(&self) -> usize {\n        TC_MIRRED_BUF_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = TcMirredBuffer::new(buffer);\n        packet.set_index(self.index);\n        packet.set_capab(self.capab);\n        packet.set_action(self.action);\n        packet.set_refcnt(self.refcnt);\n        packet.set_bindcnt(self.bindcnt);\n\n        packet.set_eaction(self.eaction);\n        packet.set_ifindex(self.ifindex);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<TcMirredBuffer<T>> for TcMirred {\n    fn parse(buf: &TcMirredBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            index: buf.index(),\n            capab: buf.capab(),\n            action: buf.action(),\n            refcnt: buf.refcnt(),\n            bindcnt: buf.bindcnt(),\n            eaction: buf.eaction(),\n            ifindex: buf.ifindex(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/action/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod mirred;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    nlas::{self, DefaultNla, NlaBuffer, NlasIterator},\n    parsers::{parse_string, parse_u32},\n    tc::{constants::*, Stats2},\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n};\n\npub const TC_GEN_BUF_LEN: usize = 20;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct Action {\n    pub tab: u16,\n    pub nlas: Vec<ActNla>,\n}\n\nimpl Default for Action {\n    fn default() -> Self {\n        Self {\n            tab: TCA_ACT_TAB,\n            nlas: Vec::new(),\n        }\n    }\n}\n\nimpl nlas::Nla for Action {\n    fn value_len(&self) -> usize {\n        self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.nlas.as_slice().emit(buffer)\n    }\n\n    fn kind(&self) -> u16 {\n        self.tab\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Action {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = vec![];\n        let mut kind = String::new();\n\n        for iter in NlasIterator::new(buf.value()) {\n            let buf = iter.context(\"invalid action nla\")?;\n            let payload = buf.value();\n            nlas.push(match buf.kind() {\n                TCA_ACT_UNSPEC => ActNla::Unspec(payload.to_vec()),\n                TCA_ACT_KIND => {\n                    kind = parse_string(payload).context(\"failed to parse TCA_ACT_KIND\")?;\n                    ActNla::Kind(kind.clone())\n                }\n                TCA_ACT_OPTIONS => {\n                    let mut nlas = vec![];\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(\"invalid TCA_ACT_OPTIONS\")?;\n                        nlas.push(\n                            ActOpt::parse_with_param(&nla, &kind)\n                                .context(\"failed to parse TCA_ACT_OPTIONS\")?,\n                        )\n                    }\n                    ActNla::Options(nlas)\n                }\n                TCA_ACT_INDEX => {\n                    ActNla::Index(parse_u32(payload).context(\"failed to parse TCA_ACT_INDEX\")?)\n                }\n                TCA_ACT_STATS => {\n                    let mut nlas = vec![];\n                    for nla in NlasIterator::new(payload) {\n                        let nla = nla.context(\"invalid TCA_ACT_STATS\")?;\n                        nlas.push(Stats2::parse(&nla).context(\"failed to parse TCA_ACT_STATS\")?);\n                    }\n                    ActNla::Stats(nlas)\n                }\n                TCA_ACT_COOKIE => ActNla::Cookie(payload.to_vec()),\n                _ => ActNla::Other(DefaultNla::parse(&buf).context(\"failed to parse action nla\")?),\n            });\n        }\n        Ok(Self {\n            tab: buf.kind(),\n            nlas,\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum ActNla {\n    Unspec(Vec<u8>),\n    Kind(String),\n    Options(Vec<ActOpt>),\n    Index(u32),\n    Stats(Vec<Stats2>),\n    Cookie(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for ActNla {\n    fn value_len(&self) -> usize {\n        use self::ActNla::*;\n        match self {\n            Unspec(bytes) | Cookie(bytes) => bytes.len(),\n            Kind(k) => k.len() + 1,\n            Options(opt) => opt.as_slice().buffer_len(),\n            Index(_) => 4,\n            Stats(s) => s.as_slice().buffer_len(),\n            Other(attr) => attr.value_len(),\n        }\n    }\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::ActNla::*;\n        match self {\n            Unspec(bytes) | Cookie(bytes) => buffer.copy_from_slice(bytes.as_slice()),\n            Kind(string) => {\n                buffer[..string.as_bytes().len()].copy_from_slice(string.as_bytes());\n                buffer[string.as_bytes().len()] = 0;\n            }\n            Options(opt) => opt.as_slice().emit(buffer),\n            Index(value) => NativeEndian::write_u32(buffer, *value),\n            Stats(s) => s.as_slice().emit(buffer),\n            Other(attr) => attr.emit_value(buffer),\n        }\n    }\n    fn kind(&self) -> u16 {\n        use self::ActNla::*;\n        match self {\n            Unspec(_) => TCA_ACT_UNSPEC,\n            Kind(_) => TCA_ACT_KIND,\n            Options(_) => TCA_ACT_OPTIONS,\n            Index(_) => TCA_ACT_INDEX,\n            Stats(_) => TCA_ACT_STATS,\n            Cookie(_) => TCA_ACT_COOKIE,\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum ActOpt {\n    Mirred(mirred::Nla),\n    // Other options\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for ActOpt {\n    fn value_len(&self) -> usize {\n        use self::ActOpt::*;\n        match self {\n            Mirred(nla) => nla.value_len(),\n            Other(nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::ActOpt::*;\n        match self {\n            Mirred(nla) => nla.emit_value(buffer),\n            Other(nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::ActOpt::*;\n        match self {\n            Mirred(nla) => nla.kind(),\n            Other(nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for ActOpt\nwhere\n    T: AsRef<[u8]> + ?Sized,\n    S: AsRef<str>,\n{\n    fn parse_with_param(buf: &NlaBuffer<&'a T>, kind: S) -> Result<Self, DecodeError> {\n        Ok(match kind.as_ref() {\n            mirred::KIND => {\n                Self::Mirred(mirred::Nla::parse(buf).context(\"failed to parse mirred action\")?)\n            }\n            _ => Self::Other(DefaultNla::parse(buf).context(\"failed to parse action options\")?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct TcGen {\n    pub index: u32,\n    pub capab: u32,\n    pub action: i32,\n    pub refcnt: i32,\n    pub bindcnt: i32,\n}\n\nbuffer!(TcGenBuffer(TC_GEN_BUF_LEN) {\n    index: (u32, 0..4),\n    capab: (u32, 4..8),\n    action: (i32, 8..12),\n    refcnt: (i32, 12..16),\n    bindcnt: (i32, 16..20),\n});\n\nimpl Emitable for TcGen {\n    fn buffer_len(&self) -> usize {\n        TC_GEN_BUF_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = TcGenBuffer::new(buffer);\n        packet.set_index(self.index);\n        packet.set_capab(self.capab);\n        packet.set_action(self.action);\n        packet.set_refcnt(self.refcnt);\n        packet.set_bindcnt(self.bindcnt);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<TcGenBuffer<T>> for TcGen {\n    fn parse(buf: &TcGenBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            index: buf.index(),\n            capab: buf.capab(),\n            action: buf.action(),\n            refcnt: buf.refcnt(),\n            bindcnt: buf.bindcnt(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/filter/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod u32;\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/filter/u32.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n/// U32 filter\n///\n/// In its simplest form the U32 filter is a list of records, each consisting\n/// of two fields: a selector and an action. The selectors, described below,\n/// are compared with the currently processed IP packet until the first match\n/// occurs, and then the associated action is performed.\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    nlas::{self, DefaultNla, NlaBuffer, NlasIterator},\n    parsers::parse_u32,\n    tc::{constants::*, Action},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const KIND: &str = \"u32\";\n\nconst U32_SEL_BUF_LEN: usize = 16;\nconst U32_KEY_BUF_LEN: usize = 16;\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    Unspec(Vec<u8>),\n    ClassId(u32),\n    Hash(u32),\n    Link(u32),\n    Divisor(u32),\n    Sel(Sel),\n    Police(Vec<u8>),\n    Act(Vec<Action>),\n    Indev(Vec<u8>),\n    Pcnt(Vec<u8>),\n    Mark(Vec<u8>),\n    Flags(u32),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match self {\n            Unspec(b) | Police(b) | Indev(b) | Pcnt(b) | Mark(b) => b.len(),\n            ClassId(_) | Hash(_) | Link(_) | Divisor(_) | Flags(_) => 4,\n            Sel(s) => s.buffer_len(),\n            Act(acts) => acts.as_slice().buffer_len(),\n            Other(attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match self {\n            Unspec(b) | Police(b) | Indev(b) | Pcnt(b) | Mark(b) => {\n                buffer.copy_from_slice(b.as_slice())\n            }\n            ClassId(i) | Hash(i) | Link(i) | Divisor(i) | Flags(i) => {\n                NativeEndian::write_u32(buffer, *i)\n            }\n            Sel(s) => s.emit(buffer),\n            Act(acts) => acts.as_slice().emit(buffer),\n            Other(attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match self {\n            Unspec(_) => TCA_U32_UNSPEC,\n            ClassId(_) => TCA_U32_CLASSID,\n            Hash(_) => TCA_U32_HASH,\n            Link(_) => TCA_U32_LINK,\n            Divisor(_) => TCA_U32_DIVISOR,\n            Sel(_) => TCA_U32_SEL,\n            Police(_) => TCA_U32_POLICE,\n            Act(_) => TCA_U32_ACT,\n            Indev(_) => TCA_U32_INDEV,\n            Pcnt(_) => TCA_U32_PCNT,\n            Mark(_) => TCA_U32_MARK,\n            Flags(_) => TCA_U32_FLAGS,\n            Other(attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        use self::Nla::*;\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            TCA_U32_UNSPEC => Unspec(payload.to_vec()),\n            TCA_U32_CLASSID => {\n                ClassId(parse_u32(payload).context(\"failed to parse TCA_U32_UNSPEC\")?)\n            }\n            TCA_U32_HASH => Hash(parse_u32(payload).context(\"failed to parse TCA_U32_HASH\")?),\n            TCA_U32_LINK => Link(parse_u32(payload).context(\"failed to parse TCA_U32_LINK\")?),\n            TCA_U32_DIVISOR => {\n                Divisor(parse_u32(payload).context(\"failed to parse TCA_U32_DIVISOR\")?)\n            }\n            TCA_U32_SEL => Sel(self::Sel::parse(\n                &SelBuffer::new_checked(payload).context(\"invalid TCA_U32_SEL\")?,\n            )\n            .context(\"failed to parse TCA_U32_SEL\")?),\n            TCA_U32_POLICE => Police(payload.to_vec()),\n            TCA_U32_ACT => {\n                let mut acts = vec![];\n                for act in NlasIterator::new(payload) {\n                    let act = act.context(\"invalid TCA_U32_ACT\")?;\n                    acts.push(Action::parse(&act).context(\"failed to parse TCA_U32_ACT\")?);\n                }\n                Act(acts)\n            }\n            TCA_U32_INDEV => Indev(payload.to_vec()),\n            TCA_U32_PCNT => Pcnt(payload.to_vec()),\n            TCA_U32_MARK => Mark(payload.to_vec()),\n            TCA_U32_FLAGS => Flags(parse_u32(payload).context(\"failed to parse TCA_U32_FLAGS\")?),\n            _ => Other(DefaultNla::parse(buf).context(\"failed to parse u32 nla\")?),\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct Sel {\n    pub flags: u8,\n    pub offshift: u8,\n    pub nkeys: u8,\n    pub offmask: u16,\n    pub off: u16,\n    pub offoff: u16,\n    pub hoff: u16,\n    pub hmask: u32,\n    pub keys: Vec<Key>,\n}\n\nbuffer!(SelBuffer(U32_SEL_BUF_LEN) {\n    flags: (u8, 0),\n    offshift: (u8, 1),\n    nkeys: (u8, 2),\n    //pad: (u8, 3),\n    offmask: (u16, 4..6),\n    off: (u16, 6..8),\n    offoff: (u16, 8..10),\n    hoff: (u16, 10..12),\n    hmask: (u32, 12..U32_SEL_BUF_LEN),\n    keys: (slice, U32_SEL_BUF_LEN..),\n});\n\nimpl Emitable for Sel {\n    fn buffer_len(&self) -> usize {\n        U32_SEL_BUF_LEN + (self.nkeys as usize * U32_KEY_BUF_LEN)\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = SelBuffer::new(buffer);\n        packet.set_flags(self.flags);\n        packet.set_offshift(self.offshift);\n        packet.set_offmask(self.offmask);\n        packet.set_off(self.off);\n        packet.set_offoff(self.offoff);\n        packet.set_hoff(self.hoff);\n        packet.set_hmask(self.hmask);\n        packet.set_nkeys(self.nkeys);\n        assert_eq!(self.nkeys as usize, self.keys.len());\n\n        let key_buf = packet.keys_mut();\n        for (i, k) in self.keys.iter().enumerate() {\n            k.emit(&mut key_buf[(i * U32_KEY_BUF_LEN)..((i + 1) * U32_KEY_BUF_LEN)]);\n        }\n    }\n}\n\nimpl<T: AsRef<[u8]> + ?Sized> Parseable<SelBuffer<&T>> for Sel {\n    fn parse(buf: &SelBuffer<&T>) -> Result<Self, DecodeError> {\n        let nkeys = buf.nkeys();\n        let mut keys = Vec::<Key>::with_capacity(nkeys.into());\n        let key_payload = buf.keys();\n        for i in 0..nkeys {\n            let i = i as usize;\n            let keybuf = KeyBuffer::new_checked(\n                &key_payload[(i * U32_KEY_BUF_LEN)..(i + 1) * U32_KEY_BUF_LEN],\n            )\n            .context(\"invalid u32 key\")?;\n            keys.push(Key::parse(&keybuf).context(\"failed to parse u32 key\")?);\n        }\n\n        Ok(Self {\n            flags: buf.flags(),\n            offshift: buf.offshift(),\n            nkeys,\n            offmask: buf.offmask(),\n            off: buf.off(),\n            offoff: buf.offoff(),\n            hoff: buf.hoff(),\n            hmask: buf.hmask(),\n            keys,\n        })\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Default)]\npub struct Key {\n    pub mask: u32,\n    pub val: u32,\n    pub off: i32,\n    pub offmask: i32,\n}\n\nbuffer!(KeyBuffer(U32_KEY_BUF_LEN) {\n    mask: (u32, 0..4),\n    val: (u32, 4..8),\n    off: (i32, 8..12),\n    offmask: (i32, 12..U32_KEY_BUF_LEN),\n});\n\nimpl Emitable for Key {\n    fn buffer_len(&self) -> usize {\n        U32_KEY_BUF_LEN\n    }\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut packet = KeyBuffer::new(buffer);\n        packet.set_mask(self.mask);\n        packet.set_val(self.val);\n        packet.set_off(self.off);\n        packet.set_offmask(self.offmask);\n    }\n}\n\nimpl<T: AsRef<[u8]>> Parseable<KeyBuffer<T>> for Key {\n    fn parse(buf: &KeyBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            mask: buf.mask(),\n            val: buf.val(),\n            off: buf.off(),\n            offmask: buf.offmask(),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod stats;\npub use self::stats::*;\n\nmod stats_queue;\npub use self::stats_queue::*;\n\nmod stats_basic;\npub use self::stats_basic::*;\n\nmod options;\npub use self::options::*;\n\nmod qdisc;\npub use self::qdisc::*;\n\nmod filter;\npub use self::filter::*;\n\nmod action;\npub use self::action::*;\n\n#[cfg(test)]\nmod test;\n\nuse crate::{\n    constants::*,\n    nlas::{self, DefaultNla, NlaBuffer},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    /// Unspecified\n    Unspec(Vec<u8>),\n    /// Name of queueing discipline\n    Kind(String),\n    /// Options follow\n    Options(Vec<TcOpt>),\n    /// Statistics\n    Stats(Stats),\n    /// Module-specific statistics\n    XStats(Vec<u8>),\n    /// Rate limit\n    Rate(Vec<u8>),\n    Fcnt(Vec<u8>),\n    Stats2(Vec<Stats2>),\n    Stab(Vec<u8>),\n    Chain(Vec<u8>),\n    HwOffload(u8),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Nla {\n    #[rustfmt::skip]\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes) | XStats(ref bytes) | Rate(ref bytes) | Fcnt(ref bytes)\n            | Stab(ref bytes) | Chain(ref bytes) => bytes.len(),\n            HwOffload(_) => 1,\n            Stats2(ref thing) => thing.as_slice().buffer_len(),\n            Stats(_) => STATS_LEN,\n            Kind(ref string) => string.as_bytes().len() + 1,\n            Options(ref opt) => opt.as_slice().buffer_len(),\n            // Defaults\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    #[cfg_attr(nightly, rustfmt::skip)]\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            // Vec<u8>\n            Unspec(ref bytes)\n                | XStats(ref bytes)\n                | Rate(ref bytes)\n                | Fcnt(ref bytes)\n                | Stab(ref bytes)\n                | Chain(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),\n\n            HwOffload(ref val) => buffer[0] = *val,\n            Stats2(ref stats) => stats.as_slice().emit(buffer),\n            Stats(ref stats) => stats.emit(buffer),\n\n            Kind(ref string) => {\n                buffer[..string.as_bytes().len()].copy_from_slice(string.as_bytes());\n                buffer[string.as_bytes().len()] = 0;\n            }\n            Options(ref opt) => opt.as_slice().emit(buffer),\n\n            // Default\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Unspec(_) => TCA_UNSPEC,\n            Kind(_) => TCA_KIND,\n            Options(_) => TCA_OPTIONS,\n            Stats(_) => TCA_STATS,\n            XStats(_) => TCA_XSTATS,\n            Rate(_) => TCA_RATE,\n            Fcnt(_) => TCA_FCNT,\n            Stats2(_) => TCA_STATS2,\n            Stab(_) => TCA_STAB,\n            Chain(_) => TCA_CHAIN,\n            HwOffload(_) => TCA_HW_OFFLOAD,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Stats2 {\n    StatsApp(Vec<u8>),\n    StatsBasic(Vec<u8>),\n    StatsQueue(Vec<u8>),\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for Stats2 {\n    fn value_len(&self) -> usize {\n        use self::Stats2::*;\n        match *self {\n            StatsBasic(ref bytes) | StatsQueue(ref bytes) | StatsApp(ref bytes) => bytes.len(),\n            Other(ref nla) => nla.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Stats2::*;\n        match *self {\n            StatsBasic(ref bytes) | StatsQueue(ref bytes) | StatsApp(ref bytes) => {\n                buffer.copy_from_slice(bytes.as_slice())\n            }\n            Other(ref nla) => nla.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Stats2::*;\n        match *self {\n            StatsApp(_) => TCA_STATS_APP,\n            StatsBasic(_) => TCA_STATS_BASIC,\n            StatsQueue(_) => TCA_STATS_QUEUE,\n            Other(ref nla) => nla.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Stats2 {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            TCA_STATS_APP => Self::StatsApp(payload.to_vec()),\n            TCA_STATS_BASIC => Self::StatsBasic(payload.to_vec()),\n            TCA_STATS_QUEUE => Self::StatsQueue(payload.to_vec()),\n            _ => Self::Other(DefaultNla::parse(buf)?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/options.rs",
    "content": "// SPDX-License-Identifier: MIT\nuse anyhow::Context;\n\nuse crate::{\n    nlas::{self, DefaultNla, NlaBuffer},\n    tc::{ingress, u32},\n    traits::{Parseable, ParseableParametrized},\n    DecodeError,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum TcOpt {\n    // Qdisc specific options\n    Ingress,\n    // Filter specific options\n    U32(u32::Nla),\n    // Other options\n    Other(DefaultNla),\n}\n\nimpl nlas::Nla for TcOpt {\n    fn value_len(&self) -> usize {\n        match self {\n            Self::Ingress => 0,\n            Self::U32(u) => u.value_len(),\n            Self::Other(o) => o.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            Self::Ingress => unreachable!(),\n            Self::U32(u) => u.emit_value(buffer),\n            Self::Other(o) => o.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            Self::Ingress => unreachable!(),\n            Self::U32(u) => u.kind(),\n            Self::Other(o) => o.kind(),\n        }\n    }\n}\n\nimpl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for TcOpt\nwhere\n    T: AsRef<[u8]> + ?Sized,\n    S: AsRef<str>,\n{\n    fn parse_with_param(buf: &NlaBuffer<&'a T>, kind: S) -> Result<Self, DecodeError> {\n        Ok(match kind.as_ref() {\n            ingress::KIND => TcOpt::Ingress,\n            u32::KIND => Self::U32(u32::Nla::parse(buf).context(\"failed to parse u32 nlas\")?),\n            _ => Self::Other(DefaultNla::parse(buf)?),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/qdisc/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod ingress {\n    pub const KIND: &str = \"ingress\";\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/stats.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n/// Generic queue statistics\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct Stats {\n    /// Number of enqueued bytes\n    pub bytes: u64,\n    /// Number of enqueued packets\n    pub packets: u32,\n    /// Packets dropped because of lack of resources\n    pub drops: u32,\n    /// Number of throttle events when this flow goes out of allocated bandwidth\n    pub overlimits: u32,\n    /// Current flow byte rate\n    pub bps: u32,\n    /// Current flow packet rate\n    pub pps: u32,\n    pub qlen: u32,\n    pub backlog: u32,\n}\n\npub const STATS_LEN: usize = 36;\n\nbuffer!(StatsBuffer(STATS_LEN) {\n    bytes: (u64, 0..8),\n    packets: (u32, 8..12),\n    drops: (u32, 12..16),\n    overlimits: (u32, 16..20),\n    bps: (u32, 20..24),\n    pps: (u32, 24..28),\n    qlen: (u32, 28..32),\n    backlog: (u32, 32..36),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<StatsBuffer<T>> for Stats {\n    fn parse(buf: &StatsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            bytes: buf.bytes(),\n            packets: buf.packets(),\n            drops: buf.drops(),\n            overlimits: buf.overlimits(),\n            bps: buf.bps(),\n            pps: buf.pps(),\n            qlen: buf.qlen(),\n            backlog: buf.backlog(),\n        })\n    }\n}\n\nimpl Emitable for Stats {\n    fn buffer_len(&self) -> usize {\n        STATS_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatsBuffer::new(buffer);\n        buffer.set_bytes(self.bytes);\n        buffer.set_packets(self.packets);\n        buffer.set_drops(self.drops);\n        buffer.set_overlimits(self.overlimits);\n        buffer.set_bps(self.bps);\n        buffer.set_pps(self.pps);\n        buffer.set_qlen(self.qlen);\n        buffer.set_backlog(self.backlog);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/stats_basic.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n/// Byte/Packet throughput statistics\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct StatsBasic {\n    /// number of seen bytes\n    pub bytes: u64,\n    /// number of seen packets\n    pub packets: u32,\n}\n\npub const STATS_BASIC_LEN: usize = 12;\n\nbuffer!(StatsBasicBuffer(STATS_BASIC_LEN) {\n    bytes: (u64, 0..8),\n    packets: (u32, 8..12),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<StatsBasicBuffer<T>> for StatsBasic {\n    fn parse(buf: &StatsBasicBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(StatsBasic {\n            bytes: buf.bytes(),\n            packets: buf.packets(),\n        })\n    }\n}\n\nimpl Emitable for StatsBasic {\n    fn buffer_len(&self) -> usize {\n        STATS_BASIC_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatsBasicBuffer::new(buffer);\n        buffer.set_bytes(self.bytes);\n        buffer.set_packets(self.packets);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/stats_queue.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n/// Queuing statistics\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct StatsQueue {\n    /// queue length\n    pub qlen: u32,\n    /// backlog size of queue\n    pub backlog: u32,\n    /// number of dropped packets\n    pub drops: u32,\n    /// number of requeues\n    pub requeues: u32,\n    /// number of enqueues over the limit\n    pub overlimits: u32,\n}\n\npub const STATS_QUEUE_LEN: usize = 20;\n\nbuffer!(StatsQueueBuffer( STATS_QUEUE_LEN) {\n    qlen: (u32, 0..4),\n    backlog: (u32, 4..8),\n    drops: (u32, 8..12),\n    requeues: (u32, 12..16),\n    overlimits: (u32, 16..20),\n});\n\nimpl<T: AsRef<[u8]>> Parseable<StatsQueueBuffer<T>> for StatsQueue {\n    fn parse(buf: &StatsQueueBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            qlen: buf.qlen(),\n            backlog: buf.backlog(),\n            drops: buf.drops(),\n            requeues: buf.requeues(),\n            overlimits: buf.overlimits(),\n        })\n    }\n}\n\nimpl Emitable for StatsQueue {\n    fn buffer_len(&self) -> usize {\n        STATS_QUEUE_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = StatsQueueBuffer::new(buffer);\n        buffer.set_qlen(self.qlen);\n        buffer.set_backlog(self.backlog);\n        buffer.set_drops(self.drops);\n        buffer.set_requeues(self.requeues);\n        buffer.set_overlimits(self.overlimits);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/nlas/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#![cfg(test)]\n\nuse crate::{\n    constants::*,\n    nlas::Nla,\n    parsers::parse_u32,\n    tc::{self, constants::*, mirred, u32, ActNla, ActOpt, Action, Stats2, TcOpt},\n    traits::{Emitable, Parseable},\n    TcHeader,\n    TcMessage,\n    TcMessageBuffer,\n};\n\n#[rustfmt::skip]\n    static FILTER_U32_ACTION_PACKET: [u8; 260] = [\n        0, 0, 0, 0, // family, pad1, pad2\n        3, 0, 0, 0, // Interface index\n        0, 8, 0, 128, // handle: 0x800_00_800 => htid | hash | nodeid\n        255, 255, 255, 255, // parent: TC_H_ROOT\n        0, 3, 0, 192, // info: 0xc000_0300 => pref | protocol\n        // nlas\n        8, 0, // length\n        1, 0, // type: TCA_KIND\n        117, 51, 50, 0, // u32\\0\n\n        8, 0,\n        11, 0, // type: TCA_CHAIN\n        0, 0, 0, 0,\n\n        224, 0,\n        2, 0, // type: TCA_OPTIONS\n\n            36, 0,\n            5, 0, // type: TCA_U32_SEL\n                1, 0, 1, 0,\n                0, 0,\n                0, 0,\n                0, 0,\n                0, 0,\n                0, 0, 0, 0,\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\n            8, 0,\n            2, 0, // TCA_U32_HASH\n            0, 0, 0, 128,\n\n            8, 0,\n            11, 0, // TCA_U32_FLAGS\n            8, 0, 0, 0,\n\n            140, 0,\n            7, 0, // TCA_U32_ACT\n                136, 0,\n                1, 0, // TCA_ACT_TAB\n                    11, 0,\n                    1, 0, // TCA_ACT_KIND\n                        109, 105, 114, 114, 101, 100, 0, 0, // \"mirred\\0\"\n                    48, 0,\n                    4, 0, // TCA_ACT_STATS\n                        20, 0,\n                        1, 0, // TCA_STATS_BASIC\n                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                        24, 0,\n                        3, 0, // TCA_STATS_QUEUE\n                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                    72, 0,\n                    2, 0, // TCA_ACT_OPTIONS\n                        32, 0,\n                        2, 0, // TCA_MIRRED_PARMS\n                            1, 0, 0, 0,\n                            0, 0, 0, 0,\n                            4, 0, 0, 0,\n                            1, 0, 0, 0,\n                            1, 0, 0, 0,\n                            1, 0, 0, 0,\n                            3, 0, 0, 0,\n                        36, 0,\n                        1, 0, // TCA_MIRRED_TM\n                            189, 117, 195, 9, 0, 0, 0, 0,\n                            189, 117, 195, 9, 0, 0, 0, 0,\n                            0, 0, 0, 0, 0, 0, 0, 0,\n                            109, 226, 238, 72, 0, 0, 0, 0,\n            28, 0,\n            9, 0, // TCA_U32_PCNT\n            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    ];\n\n#[test]\n#[allow(clippy::unusual_byte_groupings)]\nfn tc_filter_u32_read() {\n    let packet = TcMessageBuffer::new(&FILTER_U32_ACTION_PACKET);\n    assert_eq!(packet.family(), 0);\n    assert_eq!(packet.index(), 3);\n    assert_eq!(packet.handle(), 0x800_00_800);\n    assert_eq!(packet.parent(), 0xffffffff);\n    assert_eq!(packet.info(), 0xc000_0300);\n\n    assert_eq!(packet.nlas().count(), 3);\n\n    let mut nlas = packet.nlas();\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 8);\n    assert_eq!(nla.kind(), TCA_KIND);\n    assert_eq!(nla.value(), \"u32\\0\".as_bytes());\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 8);\n    assert_eq!(nla.kind(), TCA_CHAIN);\n    assert_eq!(parse_u32(nla.value()).unwrap(), 0);\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 224);\n    assert_eq!(nla.kind(), TCA_OPTIONS);\n}\n\n#[test]\nfn tc_filter_u32_parse() {\n    let packet = TcMessageBuffer::new_checked(&FILTER_U32_ACTION_PACKET).unwrap();\n\n    // TcMessage\n    let msg = TcMessage::parse(&packet).unwrap();\n    assert_eq!(msg.header.index, 3);\n    assert_eq!(msg.header.info, 0xc000_0300);\n    assert_eq!(msg.nlas.len(), 3);\n\n    // Nlas\n    let mut iter = msg.nlas.iter();\n\n    // TCA_KIND\n    assert_eq!(\n        iter.next().unwrap(),\n        &tc::Nla::Kind(String::from(u32::KIND))\n    );\n\n    // TCA_CHAIN\n    assert!(matches!(iter.next().unwrap(), &tc::Nla::Chain(_)));\n\n    // TCA_OPTIONS\n    let nla = iter.next().unwrap();\n    let filter = if let tc::Nla::Options(f) = nla {\n        assert_eq!(f.len(), 5);\n        f\n    } else {\n        panic!(\"expect options nla\");\n    };\n\n    // u32 option\n    let mut fi = filter.iter();\n    let fa = fi.next().unwrap();\n    let ua = if let TcOpt::U32(u) = fa {\n        u\n    } else {\n        panic!(\"expect u32 nla\");\n    };\n\n    // TCA_U32_SEL\n    let sel = if let u32::Nla::Sel(s) = ua {\n        s\n    } else {\n        panic!(\"expect sel nla\");\n    };\n    assert_eq!(sel.flags, TC_U32_TERMINAL);\n    assert_eq!(sel.nkeys, 1);\n    assert_eq!(sel.keys.len(), 1);\n    assert_eq!(sel.keys[0], u32::Key::default());\n\n    // TCA_U32_HASH\n    assert_eq!(fi.next().unwrap(), &TcOpt::U32(u32::Nla::Hash(0x80000000)));\n    // TCA_U32_FLAGS\n    assert_eq!(fi.next().unwrap(), &TcOpt::U32(u32::Nla::Flags(0x00000008)));\n\n    // TCA_U32_ACT\n    let fa = fi.next().unwrap();\n    let acts = if let TcOpt::U32(u) = fa {\n        if let u32::Nla::Act(a) = u {\n            a\n        } else {\n            panic!(\"expect u32 action\");\n        }\n    } else {\n        panic!(\"expect u32 nla\");\n    };\n\n    // TCA_ACT_TAB\n    let mut act_iter = acts.iter();\n\n    let act = act_iter.next().unwrap();\n    assert_eq!(act.kind(), 1); // TCA_ACT_TAB\n    assert_eq!(act.buffer_len(), 136); // TCA_ACT_TAB\n    assert_eq!(act.tab, 1);\n\n    let mut act_nlas_iter = act.nlas.iter();\n\n    // TCA_ACT_KIND\n    assert_eq!(\n        act_nlas_iter.next().unwrap(),\n        &ActNla::Kind(\"mirred\".to_string())\n    );\n\n    // TCA_ACT_STATS\n    assert!(matches!(act_nlas_iter.next().unwrap(), ActNla::Stats(_)));\n\n    // TCA_ACT_OPTIONS\n    let act_nla = act_nlas_iter.next().unwrap();\n    let act_opts = if let ActNla::Options(opts) = act_nla {\n        opts\n    } else {\n        panic!(\"expect action options\");\n    };\n\n    let mut act_opts_iter = act_opts.iter();\n\n    // TCA_MIRRED_PARMS\n    let act_opt = act_opts_iter.next().unwrap();\n    if let ActOpt::Mirred(mirred::Nla::Parms(p)) = act_opt {\n        assert_eq!(p.index, 1);\n        assert_eq!(p.capab, 0);\n        assert_eq!(p.action, 4);\n        assert_eq!(p.refcnt, 1);\n        assert_eq!(p.bindcnt, 1);\n        assert_eq!(p.eaction, 1);\n        assert_eq!(p.ifindex, 3);\n    } else {\n        panic!(\"expect action mirred\");\n    }\n    // TCA_MIRRED_TM\n    let act_opt = act_opts_iter.next().unwrap();\n    assert_eq!(act_opt.kind(), TCA_MIRRED_TM);\n    assert_eq!(act_opt.buffer_len(), 36);\n\n    // TCA_U32_PCNT\n    let fa = fi.next().unwrap();\n    assert_eq!(fa.kind(), TCA_U32_PCNT);\n    assert_eq!(fa.buffer_len(), 28);\n}\n\n#[test]\n#[allow(clippy::unusual_byte_groupings)]\nfn tc_filter_u32_emit() {\n    // TcHeader\n    let header = TcHeader {\n        index: 3,\n        handle: 0x800_00_800,\n        parent: 0xffffffff,\n        info: 0xc000_0300,\n        ..Default::default()\n    };\n\n    // Tc Nlas\n    let nlas = vec![\n        tc::Nla::Kind(u32::KIND.to_string()),\n        tc::Nla::Chain(vec![0, 0, 0, 0]),\n        tc::Nla::Options(vec![\n            TcOpt::U32(u32::Nla::Sel(u32::Sel {\n                flags: TC_U32_TERMINAL,\n                offshift: 0,\n                nkeys: 1,\n                offmask: 0,\n                off: 0,\n                offoff: 0,\n                hoff: 0,\n                hmask: 0,\n                keys: vec![u32::Key::default()],\n            })),\n            TcOpt::U32(u32::Nla::Hash(0x80000000)),\n            TcOpt::U32(u32::Nla::Flags(0x00000008)),\n            TcOpt::U32(u32::Nla::Act(vec![Action {\n                tab: TCA_ACT_TAB,\n                nlas: vec![\n                    ActNla::Kind(mirred::KIND.to_string()),\n                    ActNla::Stats(vec![\n                        Stats2::StatsBasic(vec![0u8; 16]),\n                        Stats2::StatsQueue(vec![0u8; 20]),\n                    ]),\n                    ActNla::Options(vec![\n                        ActOpt::Mirred(mirred::Nla::Parms(mirred::TcMirred {\n                            index: 1,\n                            capab: 0,\n                            action: 4,\n                            refcnt: 1,\n                            bindcnt: 1,\n                            eaction: 1,\n                            ifindex: 3,\n                        })),\n                        ActOpt::Mirred(mirred::Nla::Tm(\n                            FILTER_U32_ACTION_PACKET[200..232].to_vec(),\n                        )),\n                    ]),\n                ],\n            }])),\n            TcOpt::U32(u32::Nla::Pcnt(vec![0u8; 24])),\n        ]),\n    ];\n\n    let msg = TcMessage::from_parts(header, nlas);\n    let mut buf = vec![0; 260];\n    assert_eq!(msg.buffer_len(), 260);\n    msg.emit(&mut buf[..]);\n    assert_eq!(&buf, &FILTER_U32_ACTION_PACKET);\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/tc/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#![cfg(test)]\n\nuse crate::{\n    constants::*,\n    nlas::NlasIterator,\n    tc::{ingress, Nla, Stats, Stats2, StatsBuffer, TC_HEADER_LEN},\n    traits::{Emitable, Parseable},\n    TcHeader,\n    TcMessage,\n    TcMessageBuffer,\n};\n\n#[rustfmt::skip]\n    static QDISC_INGRESS_PACKET: [u8; 136] = [\n        0,       // family\n        0, 0, 0, // pad1 + pad2\n        84, 0, 0, 0, // Interface index = 84\n        0, 0, 255, 255, // handle:  0xffff0000\n        241, 255, 255, 255, // parent: 0xfffffff1\n        1, 0, 0, 0, // info: refcnt: 1\n\n        // nlas\n        12, 0, // length\n        1, 0,  // type: TCA_KIND\n        105, 110, 103, 114, 101, 115, 115, 0, // ingress\\0\n\n        4, 0, // length\n        2, 0, // type: TCA_OPTIONS\n\n        5, 0, // length\n        12, 0,// type: TCA_HW_OFFLOAD\n        0,    // data: 0\n        0, 0, 0,// padding\n\n        48, 0, // length\n        7, 0,  // type: TCA_STATS2\n            20, 0, // length\n            1, 0, // type: TCA_STATS_BASIC\n            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n            24, 0,\n            3, 0, // type: TCA_STATS_QUEUE\n            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\n        44, 0, // length\n        3, 0,  // type: TCA_STATS\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n    ];\n\n#[test]\nfn tc_packet_header_read() {\n    let packet = TcMessageBuffer::new(QDISC_INGRESS_PACKET);\n    assert_eq!(packet.family(), 0);\n    assert_eq!(packet.index(), 84);\n    assert_eq!(packet.handle(), 0xffff0000);\n    assert_eq!(packet.parent(), 0xfffffff1);\n    assert_eq!(packet.info(), 1);\n}\n\n#[test]\nfn tc_packet_header_build() {\n    let mut buf = vec![0xff; TC_HEADER_LEN];\n    {\n        let mut packet = TcMessageBuffer::new(&mut buf);\n        packet.set_family(0);\n        packet.set_pad1(0);\n        packet.set_pad2(0);\n        packet.set_index(84);\n        packet.set_handle(0xffff0000);\n        packet.set_parent(0xfffffff1);\n        packet.set_info(1);\n    }\n    assert_eq!(&buf[..], &QDISC_INGRESS_PACKET[0..TC_HEADER_LEN]);\n}\n\n#[test]\nfn tc_packet_nlas_read() {\n    let packet = TcMessageBuffer::new(&QDISC_INGRESS_PACKET[..]);\n    assert_eq!(packet.nlas().count(), 5);\n    let mut nlas = packet.nlas();\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 12);\n    assert_eq!(nla.kind(), TCA_KIND);\n    assert_eq!(nla.value(), \"ingress\\0\".as_bytes());\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 4);\n    assert_eq!(nla.kind(), TCA_OPTIONS);\n    assert_eq!(nla.value(), []);\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 5);\n    assert_eq!(nla.kind(), TCA_HW_OFFLOAD);\n    assert_eq!(nla.value(), [0]);\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 48);\n    assert_eq!(nla.kind(), TCA_STATS2);\n\n    let mut stats2_iter = NlasIterator::new(nla.value());\n    let stats2_nla = stats2_iter.next().unwrap().unwrap();\n    stats2_nla.check_buffer_length().unwrap();\n    assert_eq!(stats2_nla.length(), 20);\n    assert_eq!(stats2_nla.kind(), TCA_STATS_BASIC);\n    assert_eq!(stats2_nla.value(), [0; 16]);\n    let s2 = Stats2::parse(&stats2_nla).unwrap();\n    assert!(matches!(s2, Stats2::StatsBasic(_)));\n\n    let stats2_nla = stats2_iter.next().unwrap().unwrap();\n    stats2_nla.check_buffer_length().unwrap();\n    assert_eq!(stats2_nla.length(), 24);\n    assert_eq!(stats2_nla.kind(), TCA_STATS_QUEUE);\n    assert_eq!(stats2_nla.value(), [0; 20]);\n    let s2 = Stats2::parse(&stats2_nla).unwrap();\n    assert!(matches!(s2, Stats2::StatsQueue(_)));\n\n    let nla = nlas.next().unwrap().unwrap();\n    nla.check_buffer_length().unwrap();\n    assert_eq!(nla.length(), 44);\n    assert_eq!(nla.kind(), TCA_STATS);\n    assert_eq!(nla.value(), [0; 40]);\n    let s = Stats::parse(&StatsBuffer::new(nla.value())).unwrap();\n    assert_eq!(s.packets, 0);\n    assert_eq!(s.backlog, 0);\n}\n\n#[test]\nfn tc_qdisc_ingress_emit() {\n    let header = TcHeader {\n        index: 84,\n        handle: 0xffff0000,\n        parent: 0xfffffff1,\n        info: 1,\n        ..Default::default()\n    };\n\n    let nlas = vec![Nla::Kind(ingress::KIND.into()), Nla::Options(vec![])];\n\n    let msg = TcMessage::from_parts(header, nlas);\n    let mut buf = vec![0; 36];\n    assert_eq!(msg.buffer_len(), 36);\n    msg.emit(&mut buf[..]);\n    assert_eq!(&buf, &QDISC_INGRESS_PACKET[..36]);\n}\n\n#[test]\nfn tc_qdisc_ingress_read() {\n    let packet = TcMessageBuffer::new_checked(&QDISC_INGRESS_PACKET).unwrap();\n\n    let msg = TcMessage::parse(&packet).unwrap();\n    assert_eq!(msg.header.index, 84);\n    assert_eq!(msg.nlas.len(), 5);\n\n    let mut iter = msg.nlas.iter();\n\n    let nla = iter.next().unwrap();\n    assert_eq!(nla, &Nla::Kind(String::from(ingress::KIND)));\n\n    let nla = iter.next().unwrap();\n    assert_eq!(nla, &Nla::Options(vec![]));\n\n    let nla = iter.next().unwrap();\n    assert_eq!(nla, &Nla::HwOffload(0));\n}\n"
  },
  {
    "path": "netlink-packet-route/src/rtnl/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#![cfg(test)]\n\nuse crate::{\n    nlas::link::{Info, InfoKind, Nla},\n    traits::ParseableParametrized,\n    LinkHeader,\n    LinkMessage,\n    NetlinkBuffer,\n    RtnlMessage,\n    RtnlMessageBuffer,\n    RTM_NEWLINK,\n};\n\n// This test was added because one of the NLA's payload is a string that is not null\n// terminated. I'm not sure if we missed something in the IFLA_LINK_INFO spec, or if\n// linux/iproute2 is being a bit inconsistent here.\n//\n// This message was created using `ip link add qemu-br1 type bridge`.\n#[rustfmt::skip]\n#[test]\nfn test_non_null_terminated_string() {\n    let data = vec![\n        0x40, 0x00, 0x00, 0x00, // length = 64\n        0x10, 0x00, // message type = 16 = (create network interface)\n        0x05, 0x06, // flags\n        0x81, 0x74, 0x57, 0x5c, // seq id\n        0x00, 0x00, 0x00, 0x00, // pid\n        0x00, // interface family\n        0x00, // padding\n        0x00, 0x00, // device type (NET/ROM pseudo)\n        0x00, 0x00, 0x00, 0x00, // interface index\n        0x00, 0x00, 0x00, 0x00, // device flags\n        0x00, 0x00, 0x00, 0x00, // device change flags\n        // NLA: device name\n        0x0d, 0x00, // length = 13\n        0x03, 0x00, // type = 3\n        // value=qemu-br1 NOTE THAT THIS IS NULL-TERMINATED\n        0x71, 0x65, 0x6d, 0x75, 0x2d, 0x62, 0x72, 0x31, 0x00,\n        0x00, 0x00, 0x00, // padding\n        // NLA: Link info\n        0x10, 0x00, // length = 16\n        0x12, 0x00, // type = link info\n        // nested NLA:\n        0x0a, 0x00, // length = 10\n        0x01, 0x00, // type = 1 = IFLA_INFO_KIND\n        // \"bridge\" NOTE THAT THIS IS NOT NULL-TERMINATED!\n        0x62, 0x72, 0x69, 0x64, 0x67, 0x65,\n        0x00, 0x00, // padding\n        ];\n    let expected = RtnlMessage::NewLink(LinkMessage {\n        header: LinkHeader::default(),\n        nlas: vec![\n            Nla::IfName(String::from(\"qemu-br1\")),\n            Nla::Info(vec![Info::Kind(InfoKind::Bridge)]),\n        ],\n    });\n    let nl_buffer = NetlinkBuffer::new(&data).payload();\n    let rtnl_buffer = RtnlMessageBuffer::new(&nl_buffer);\n    let actual = RtnlMessage::parse_with_param(&rtnl_buffer, RTM_NEWLINK).unwrap();\n    assert_eq!(expected, actual);\n}\n\n#[rustfmt::skip]\n#[test]\nfn test_attach_to_bridge() {\n    use crate::*;\n    let data = vec![\n        0x28, 0x00, 0x00, 0x00, // length\n        0x10, 0x00, // type\n        0x05, 0x00, // flags\n        0x9c, 0x9d, 0x57, 0x5c, // seq id\n        0x00, 0x00, 0x00, 0x00, // pid\n        0x00, // interface family\n        0x00, // padding\n        0x00, 0x00, // device type\n        0x06, 0x00, 0x00, 0x00, // interface index\n        0x00, 0x00, 0x00, 0x00, // device flags\n        0x00, 0x00, 0x00, 0x00, // device change flags\n        // NLA (set master)\n        0x08, 0x00, // length\n        0x0a, 0x00, // type\n        0x05, 0x00, 0x00, 0x00 // index of the master interface\n    ];\n    let nl_buffer = NetlinkBuffer::new(&data).payload();\n    let rtnl_buffer = RtnlMessageBuffer::new(&nl_buffer);\n    let actual = RtnlMessage::parse_with_param(&rtnl_buffer, RTM_NEWLINK).unwrap();\n    let expected = RtnlMessage::NewLink(LinkMessage {\n        header: LinkHeader {\n            interface_family: 0,\n            index: 6,\n            link_layer_type: 0,\n            flags: 0,\n            change_mask: 0,\n        },\n        nlas: vec![Nla::Master(5)],\n    });\n    assert_eq!(expected, actual);\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/Cargo.toml",
    "content": "[package]\nauthors = [\"Flier Lu <flier.lu@gmail.com>\", \"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-packet-sock-diag\"\nversion = \"0.3.1\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\", \"sock_diag\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink packet types for the sock_diag subprotocol\"\n\n[features]\nrich_nlas = []\n\n[dependencies]\nanyhow = \"1.0.32\"\nbyteorder = \"1.3.4\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\nbitflags = \"1.2.1\"\nlibc = \"0.2.77\"\nsmallvec = \"1.4.2\"\n\n[dev-dependencies]\nlazy_static = \"1.4.0\"\nnetlink-sys = { version = \"0.8.3\", path = \"../netlink-sys\" }\n"
  },
  {
    "path": "netlink-packet-sock-diag/examples/dump_ipv4.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse netlink_packet_sock_diag::{\n    constants::*,\n    inet::{ExtensionFlags, InetRequest, SocketId, StateFlags},\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n    SockDiagMessage,\n};\nuse netlink_sys::{protocols::NETLINK_SOCK_DIAG, Socket, SocketAddr};\n\nfn main() {\n    let mut socket = Socket::new(NETLINK_SOCK_DIAG).unwrap();\n    let _port_number = socket.bind_auto().unwrap().port_number();\n    socket.connect(&SocketAddr::new(0, 0)).unwrap();\n\n    let mut packet = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_REQUEST | NLM_F_DUMP,\n            ..Default::default()\n        },\n        payload: SockDiagMessage::InetRequest(InetRequest {\n            family: AF_INET,\n            protocol: IPPROTO_TCP,\n            extensions: ExtensionFlags::empty(),\n            states: StateFlags::all(),\n            socket_id: SocketId::new_v4(),\n        })\n        .into(),\n    };\n\n    packet.finalize();\n\n    let mut buf = vec![0; packet.header.length as usize];\n\n    // Before calling serialize, it is important to check that the buffer in which we're emitting is big\n    // enough for the packet, other `serialize()` panics.\n    assert_eq!(buf.len(), packet.buffer_len());\n\n    packet.serialize(&mut buf[..]);\n\n    println!(\">>> {:?}\", packet);\n    if let Err(e) = socket.send(&buf[..], 0) {\n        println!(\"SEND ERROR {}\", e);\n        return;\n    }\n\n    let mut receive_buffer = vec![0; 4096];\n    let mut offset = 0;\n    while let Ok(size) = socket.recv(&mut &mut receive_buffer[..], 0) {\n        loop {\n            let bytes = &receive_buffer[offset..];\n            let rx_packet = <NetlinkMessage<SockDiagMessage>>::deserialize(bytes).unwrap();\n            println!(\"<<< {:?}\", rx_packet);\n\n            match rx_packet.payload {\n                NetlinkPayload::Noop | NetlinkPayload::Ack(_) => {}\n                NetlinkPayload::InnerMessage(SockDiagMessage::InetResponse(response)) => {\n                    println!(\"{:#?}\", response);\n                }\n                NetlinkPayload::Done => {\n                    println!(\"Done!\");\n                    return;\n                }\n                NetlinkPayload::Error(_) | NetlinkPayload::Overrun(_) | _ => return,\n            }\n\n            offset += rx_packet.header.length as usize;\n            if offset == size || rx_packet.header.length == 0 {\n                offset = 0;\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/buffer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    inet,\n    traits::{Parseable, ParseableParametrized},\n    unix,\n    DecodeError,\n    SockDiagMessage,\n};\nuse anyhow::Context;\n\nconst BUF_MIN_LEN: usize = 2;\n\npub struct SockDiagBuffer<T> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> SockDiagBuffer<T> {\n    pub fn new(buffer: T) -> SockDiagBuffer<T> {\n        SockDiagBuffer { buffer }\n    }\n\n    pub fn length(&self) -> usize {\n        self.buffer.as_ref().len()\n    }\n\n    pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {\n        let packet = Self::new(buffer);\n        packet.check_len()?;\n        Ok(packet)\n    }\n\n    pub(crate) fn check_len(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < BUF_MIN_LEN {\n            return Err(format!(\n                \"invalid buffer: length is {} but packets are at least {} bytes\",\n                len, BUF_MIN_LEN\n            )\n            .into());\n        }\n        Ok(())\n    }\n\n    pub(crate) fn family(&self) -> u8 {\n        self.buffer.as_ref()[0]\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> SockDiagBuffer<&'a T> {\n    pub fn inner(&self) -> &'a [u8] {\n        self.buffer.as_ref()\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> SockDiagBuffer<&'a mut T> {\n    pub fn inner_mut(&mut self) -> &mut [u8] {\n        self.buffer.as_mut()\n    }\n}\n\nimpl<'a, T: AsRef<[u8]>> ParseableParametrized<SockDiagBuffer<&'a T>, u16> for SockDiagMessage {\n    fn parse_with_param(\n        buf: &SockDiagBuffer<&'a T>,\n        message_type: u16,\n    ) -> Result<Self, DecodeError> {\n        use self::SockDiagMessage::*;\n        buf.check_len()?;\n        let message = match (message_type, buf.family()) {\n            (SOCK_DIAG_BY_FAMILY, AF_INET) => {\n                let err = \"invalid AF_INET response\";\n                let buf = inet::InetResponseBuffer::new_checked(buf.inner()).context(err)?;\n                InetResponse(Box::new(inet::InetResponse::parse(&buf).context(err)?))\n            }\n            (SOCK_DIAG_BY_FAMILY, AF_INET6) => {\n                let err = \"invalid AF_INET6 response\";\n                let buf = inet::InetResponseBuffer::new_checked(buf.inner()).context(err)?;\n                InetResponse(Box::new(inet::InetResponse::parse(&buf).context(err)?))\n            }\n            (SOCK_DIAG_BY_FAMILY, AF_UNIX) => {\n                let err = \"invalid AF_UNIX response\";\n                let buf = unix::UnixResponseBuffer::new_checked(buf.inner()).context(err)?;\n                UnixResponse(Box::new(unix::UnixResponse::parse(&buf).context(err)?))\n            }\n            (SOCK_DIAG_BY_FAMILY, af) => {\n                return Err(format!(\"unknown address family {}\", af).into())\n            }\n            _ => return Err(format!(\"unknown message type {}\", message_type).into()),\n        };\n        Ok(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub use netlink_packet_core::constants::*;\n\npub const SOCK_DIAG_BY_FAMILY: u16 = 20;\npub const SOCK_DESTROY: u16 = 21;\n\npub const AF_UNSPEC: u8 = libc::AF_UNSPEC as u8;\npub const AF_UNIX: u8 = libc::AF_UNIX as u8;\n// pub const AF_LOCAL: u8 = libc::AF_LOCAL as u8;\npub const AF_INET: u8 = libc::AF_INET as u8;\npub const AF_AX25: u8 = libc::AF_AX25 as u8;\npub const AF_IPX: u8 = libc::AF_IPX as u8;\npub const AF_APPLETALK: u8 = libc::AF_APPLETALK as u8;\npub const AF_NETROM: u8 = libc::AF_NETROM as u8;\npub const AF_BRIDGE: u8 = libc::AF_BRIDGE as u8;\npub const AF_ATMPVC: u8 = libc::AF_ATMPVC as u8;\npub const AF_X25: u8 = libc::AF_X25 as u8;\npub const AF_INET6: u8 = libc::AF_INET6 as u8;\npub const AF_ROSE: u8 = libc::AF_ROSE as u8;\npub const AF_DECNET: u8 = libc::AF_DECnet as u8;\npub const AF_NETBEUI: u8 = libc::AF_NETBEUI as u8;\npub const AF_SECURITY: u8 = libc::AF_SECURITY as u8;\npub const AF_KEY: u8 = libc::AF_KEY as u8;\npub const AF_NETLINK: u8 = libc::AF_NETLINK as u8;\n// pub const AF_ROUTE: u8 = libc::AF_ROUTE as u8;\npub const AF_PACKET: u8 = libc::AF_PACKET as u8;\npub const AF_ASH: u8 = libc::AF_ASH as u8;\npub const AF_ECONET: u8 = libc::AF_ECONET as u8;\npub const AF_ATMSVC: u8 = libc::AF_ATMSVC as u8;\npub const AF_RDS: u8 = libc::AF_RDS as u8;\npub const AF_SNA: u8 = libc::AF_SNA as u8;\npub const AF_IRDA: u8 = libc::AF_IRDA as u8;\npub const AF_PPPOX: u8 = libc::AF_PPPOX as u8;\npub const AF_WANPIPE: u8 = libc::AF_WANPIPE as u8;\npub const AF_LLC: u8 = libc::AF_LLC as u8;\npub const AF_CAN: u8 = libc::AF_CAN as u8;\npub const AF_TIPC: u8 = libc::AF_TIPC as u8;\npub const AF_BLUETOOTH: u8 = libc::AF_BLUETOOTH as u8;\npub const AF_IUCV: u8 = libc::AF_IUCV as u8;\npub const AF_RXRPC: u8 = libc::AF_RXRPC as u8;\npub const AF_ISDN: u8 = libc::AF_ISDN as u8;\npub const AF_PHONET: u8 = libc::AF_PHONET as u8;\npub const AF_IEEE802154: u8 = libc::AF_IEEE802154 as u8;\npub const AF_CAIF: u8 = libc::AF_CAIF as u8;\npub const AF_ALG: u8 = libc::AF_ALG as u8;\n\n/// Dummy protocol for TCP\npub const IPPROTO_IP: u8 = 0;\n/// Internet Control Message Protocol\npub const IPPROTO_ICMP: u8 = 1;\n/// Internet Group Management Protocol\npub const IPPROTO_IGMP: u8 = 2;\n/// IPIP tunnels (older KA9Q tunnels use 94)\npub const IPPROTO_IPIP: u8 = 4;\n/// Transmission Control Protocol\npub const IPPROTO_TCP: u8 = 6;\n/// Exterior Gateway Protocol\npub const IPPROTO_EGP: u8 = 8;\n/// PUP protocol\npub const IPPROTO_PUP: u8 = 12;\n/// User Datagram Protocol\npub const IPPROTO_UDP: u8 = 17;\n/// XNS IDP protocol\npub const IPPROTO_IDP: u8 = 22;\n/// SO Transport Protocol Class 4\npub const IPPROTO_TP: u8 = 29;\n/// Datagram Congestion Control Protocol\npub const IPPROTO_DCCP: u8 = 33;\n/// IPv6 header\npub const IPPROTO_IPV6: u8 = 41;\n/// Reservation Protocol\npub const IPPROTO_RSVP: u8 = 46;\n/// General Routing Encapsulation\npub const IPPROTO_GRE: u8 = 47;\n/// encapsulating security payload\npub const IPPROTO_ESP: u8 = 50;\n/// authentication header\npub const IPPROTO_AH: u8 = 51;\n/// Multicast Transport Protocol\npub const IPPROTO_MTP: u8 = 92;\n/// IP option pseudo header for BEET\npub const IPPROTO_BEETPH: u8 = 94;\n/// Encapsulation Header\npub const IPPROTO_ENCAP: u8 = 98;\n/// Protocol Independent Multicast\npub const IPPROTO_PIM: u8 = 103;\n/// Compression Header Protocol\npub const IPPROTO_COMP: u8 = 108;\n/// Stream Control Transmission Protocol\npub const IPPROTO_SCTP: u8 = 132;\n/// UDP-Lite protocol\npub const IPPROTO_UDPLITE: u8 = 136;\n/// MPLS in IP\npub const IPPROTO_MPLS: u8 = 137;\n/// Raw IP packets\npub const IPPROTO_RAW: u8 = 255;\n/// IPv6 Hop-by-Hop options\npub const IPPROTO_HOPOPTS: u8 = 0;\n/// IPv6 routing header\npub const IPPROTO_ROUTING: u8 = 43;\n/// IPv6 fragmentation header\npub const IPPROTO_FRAGMENT: u8 = 44;\n/// ICMPv6\npub const IPPROTO_ICMPV6: u8 = 58;\n/// IPv6 no next header\npub const IPPROTO_NONE: u8 = 59;\n/// IPv6 destination options\npub const IPPROTO_DSTOPTS: u8 = 60;\n/// IPv6 mobility header\npub const IPPROTO_MH: u8 = 135;\n\n// Extensions for inet\npub const INET_DIAG_NONE: u16 = 0;\npub const INET_DIAG_MEMINFO: u16 = 1;\npub const INET_DIAG_INFO: u16 = 2;\npub const INET_DIAG_VEGASINFO: u16 = 3;\npub const INET_DIAG_CONG: u16 = 4;\npub const INET_DIAG_TOS: u16 = 5;\npub const INET_DIAG_TCLASS: u16 = 6;\npub const INET_DIAG_SKMEMINFO: u16 = 7;\npub const INET_DIAG_SHUTDOWN: u16 = 8;\n\npub const INET_DIAG_DCTCPINFO: u16 = 9;\npub const INET_DIAG_PROTOCOL: u16 = 10;\npub const INET_DIAG_SKV6ONLY: u16 = 11;\npub const INET_DIAG_LOCALS: u16 = 12;\npub const INET_DIAG_PEERS: u16 = 13;\npub const INET_DIAG_PAD: u16 = 14;\npub const INET_DIAG_MARK: u16 = 15;\npub const INET_DIAG_BBRINFO: u16 = 16;\npub const INET_DIAG_CLASS_ID: u16 = 17;\npub const INET_DIAG_MD5SIG: u16 = 18;\n\n/// (both server and client) represents an open connection, data\n/// received can be delivered to the user. The normal state for the\n/// data transfer phase of the connection.\npub const TCP_ESTABLISHED: u8 = 1;\n/// (client) represents waiting for a matching connection request\n/// after having sent a connection request.\npub const TCP_SYN_SENT: u8 = 2;\n/// (server) represents waiting for a confirming connection request\n/// acknowledgment after having both received and sent a connection\n/// request.\npub const TCP_SYN_RECV: u8 = 3;\n/// (both server and client) represents waiting for a connection\n/// termination request from the remote TCP, or an acknowledgment of\n/// the connection termination request previously sent.\npub const TCP_FIN_WAIT1: u8 = 4;\n/// (both server and client) represents waiting for a connection\n/// termination request from the remote TCP.\npub const TCP_FIN_WAIT2: u8 = 5;\n/// (either server or client) represents waiting for enough time to\n/// pass to be sure the remote TCP received the acknowledgment of its\n/// connection termination request.\npub const TCP_TIME_WAIT: u8 = 6;\n/// (both server and client) represents no connection state at all.\npub const TCP_CLOSE: u8 = 7;\n/// (both server and client) represents waiting for a connection\n/// termination request from the local user.\npub const TCP_CLOSE_WAIT: u8 = 8;\n/// (both server and client) represents waiting for an acknowledgment\n/// of the connection termination request previously sent to the\n/// remote TCP (which includes an acknowledgment of its connection\n/// termination request).\npub const TCP_LAST_ACK: u8 = 9;\n/// (server) represents waiting for a connection request from any\n/// remote TCP and port.\npub const TCP_LISTEN: u8 = 10;\n/// (both server and client) represents waiting for a connection termination request acknowledgment from the remote TCP.\npub const TCP_CLOSING: u8 = 11;\n\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_NAME`. The payload associated with this attribute is\n/// the pathname to which the socket was bound (a se quence of bytes\n/// up to `UNIX_PATH_MAX` length).\npub const UDIAG_SHOW_NAME: u32 = 1 << UNIX_DIAG_NAME;\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_VFS`, which returns VFS information associated to the\n/// inode.\npub const UDIAG_SHOW_VFS: u32 = 1 << UNIX_DIAG_VFS;\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_PEER`, which carries the peer's inode number. This\n/// attribute is reported for connected sockets only.\npub const UDIAG_SHOW_PEER: u32 = 1 << UNIX_DIAG_PEER;\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_ICONS`, which information about pending\n/// connections. Specifically, it contains the inode numbers of the\n/// sockets that have passed the `connect(2)` call, but hasn't been\n/// processed with `accept(2) yet`. This attribute is reported for\n/// listening sockets only.\npub const UDIAG_SHOW_ICONS: u32 = 1 << UNIX_DIAG_ICONS;\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_RQLEN`, which reports:\n///\n/// - for listening socket: the number of pending connections, and the\n///   backlog length (which equals to the value passed as the second\n///   argument to `listen(2)`).\n/// - for established sockets: the amount of data in incoming queue,\n///   and the amount of memory available for sending\npub const UDIAG_SHOW_RQLEN: u32 = 1 << UNIX_DIAG_RQLEN;\n/// The attribute reported in answer to this request is\n/// `UNIX_DIAG_MEMINFO` which shows memory information about the\n/// socket\npub const UDIAG_SHOW_MEMINFO: u32 = 1 << UNIX_DIAG_MEMINFO;\n\npub const UNIX_DIAG_NAME: u16 = 0;\npub const UNIX_DIAG_VFS: u16 = 1;\npub const UNIX_DIAG_PEER: u16 = 2;\npub const UNIX_DIAG_ICONS: u16 = 3;\npub const UNIX_DIAG_RQLEN: u16 = 4;\npub const UNIX_DIAG_MEMINFO: u16 = 5;\npub const UNIX_DIAG_SHUTDOWN: u16 = 6;\n\n/// Provides sequenced, reliable, two-way, connection-based byte\n/// streams. An out-of-band data transmission mechanism may be\n/// supported.\npub const SOCK_STREAM: u8 = libc::SOCK_STREAM as u8;\n/// Supports datagrams (connectionless, unreliable messages of a fixed\n/// maximum length).\npub const SOCK_DGRAM: u8 = libc::SOCK_DGRAM as u8;\n/// Provides a sequenced, reliable, two-way connection-based data\n/// transmission path for datagrams of fixed maximum length; a\n/// consumer is required to read an entire packet with each input\n/// system call.\npub const SOCK_SEQPACKET: u8 = libc::SOCK_SEQPACKET as u8;\n/// Provides raw network protocol access.\npub const SOCK_RAW: u8 = libc::SOCK_RAW as u8;\n/// Provides a reliable datagram layer that does not guarantee\n/// ordering.\npub const SOCK_RDM: u8 = libc::SOCK_RDM as u8;\n/// Obsolete and should not be used in new programs; see `packet(7)`.\npub const SOCK_PACKET: u8 = libc::SOCK_PACKET as u8;\n\n/// Nothing bad has been observed recently. No apparent reordering, packet loss, or ECN marks.\npub const TCP_CA_OPEN: u8 = 0;\npub const TCPF_CA_OPEN: u32 = 1 << TCP_CA_OPEN;\n\n/// The sender enters disordered state when it has received DUPACKs or\n/// SACKs in the last round of packets sent. This could be due to\n/// packet loss or reordering but needs further information to confirm\n/// packets have been lost.\npub const TCP_CA_DISORDER: u8 = 1;\npub const TCPF_CA_DISORDER: u32 = 1 << TCP_CA_DISORDER;\n/// The sender enters Congestion Window Reduction (CWR) state when it\n/// has received ACKs with ECN-ECE marks, or has experienced\n/// congestion or packet discard on the sender host (e.g. qdisc).\npub const TCP_CA_CWR: u8 = 2;\npub const TCPF_CA_CWR: u32 = 1 << TCP_CA_CWR;\n/// The sender is in fast recovery and retransmitting lost packets, typically triggered by ACK events.\npub const TCP_CA_RECOVERY: u8 = 3;\npub const TCPF_CA_RECOVERY: u32 = 1 << TCP_CA_RECOVERY;\n/// The sender is in loss recovery triggered by retransmission timeout.\npub const TCP_CA_LOSS: u8 = 4;\npub const TCPF_CA_LOSS: u32 = 1 << TCP_CA_LOSS;\n\npub const TCPI_OPT_TIMESTAMPS: u8 = 1;\npub const TCPI_OPT_SACK: u8 = 2;\npub const TCPI_OPT_WSCALE: u8 = 4;\n/// ECN was negociated at TCP session init\npub const TCPI_OPT_ECN: u8 = 8;\n/// We received at least one packet with ECT\npub const TCPI_OPT_ECN_SEEN: u8 = 16;\n/// SYN-ACK acked data in SYN sent or rcvd\npub const TCPI_OPT_SYN_DATA: u8 = 32;\n\n/// Shutdown state of a socket. A socket shut down with `SHUT_RD` can\n/// no longer receive data. See also `man 2 shutdown`.\npub const SHUT_RD: u8 = 0;\n/// Shutdown state of a socket. A socket shut down with `SHUT_WR` can\n/// no longer send data. See also `man 2 shutdown`.\npub const SHUT_WR: u8 = 1;\n/// Shutdown state of a socket. A socket shut down with `SHUT_RDWR`\n/// can no longer receive nor send data. See also `man 2 shutdown`.\npub const SHUT_RDWR: u8 = 2;\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod socket_id;\npub use self::socket_id::*;\n\nmod request;\npub use self::request::*;\n\nmod response;\npub use self::response::*;\n\npub mod nlas;\n\n#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/nlas.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\npub use crate::utils::nla::{DefaultNla, NlaBuffer, NlasIterator};\n\nuse crate::{\n    constants::*,\n    parsers::{parse_string, parse_u32, parse_u8},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const LEGACY_MEM_INFO_LEN: usize = 16;\n\nbuffer!(LegacyMemInfoBuffer(LEGACY_MEM_INFO_LEN) {\n    receive_queue: (u32, 0..4),\n    bottom_send_queue: (u32, 4..8),\n    cache: (u32, 8..12),\n    send_queue: (u32, 12..16)\n});\n\n/// In recent Linux kernels, this NLA is not used anymore to report\n/// AF_INET and AF_INET6 sockets memory information. See [`MemInfo`]\n/// instead.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct LegacyMemInfo {\n    /// Amount of data in the receive queue.\n    pub receive_queue: u32,\n    /// Amount of data that is queued by TCP but not yet sent.\n    pub bottom_send_queue: u32,\n    /// Amount of memory scheduled for future use (TCP only).\n    pub cache: u32,\n    /// Amount of data in the send queue.\n    pub send_queue: u32,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<LegacyMemInfoBuffer<T>> for LegacyMemInfo {\n    fn parse(buf: &LegacyMemInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            receive_queue: buf.receive_queue(),\n            bottom_send_queue: buf.bottom_send_queue(),\n            cache: buf.cache(),\n            send_queue: buf.send_queue(),\n        })\n    }\n}\n\nimpl Emitable for LegacyMemInfo {\n    fn buffer_len(&self) -> usize {\n        LEGACY_MEM_INFO_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = LegacyMemInfoBuffer::new(buf);\n        buf.set_receive_queue(self.receive_queue);\n        buf.set_bottom_send_queue(self.bottom_send_queue);\n        buf.set_cache(self.cache);\n        buf.set_send_queue(self.send_queue);\n    }\n}\n\npub const MEM_INFO_LEN: usize = 36;\n\n// FIXME: the last 2 fields are not present on old linux kernels. We\n// should support optional fields in the `buffer!` macro.\nbuffer!(MemInfoBuffer(MEM_INFO_LEN) {\n    receive_queue: (u32, 0..4),\n    receive_queue_max: (u32, 4..8),\n    bottom_send_queues: (u32, 8..12),\n    send_queue_max: (u32, 12..16),\n    cache: (u32, 16..20),\n    send_queue: (u32, 20..24),\n    options: (u32, 24..28),\n    backlog_queue_length: (u32, 28..32),\n    drops: (u32, 32..36),\n});\n\n/// Socket memory information. To understand this information, one\n/// must understand how the memory allocated for the send and receive\n/// queues of a socket is managed.\n///\n/// # Warning\n///\n/// This data structure is not well documented. The explanations given\n/// here are the results of my personal research on this topic, but I\n/// am by no mean an expert in Linux networking, so take this\n/// documentation with a huge grain of salt. Please report any error\n/// you may notice. Here are the references I used:\n///\n/// - [https://wiki.linuxfoundation.org/networking/sk_buff](a short introduction to `sk_buff`, the struct used in the kernel to store packets)\n/// - [vger.kernel.org has a lot of documentation about the low level network stack APIs](http://vger.kernel.org/~davem/skb_data.html)\n/// - [thorough high level explanation of buffering in the network stack](https://www.coverfire.com/articles/queueing-in-the-linux-network-stack/)\n/// - [understanding the backlog queue](http://veithen.io/2014/01/01/how-tcp-backlog-works-in-linux.html)\n/// - [high level explanation of packet reception](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/performance_tuning_guide/s-network-packet-reception)\n/// - [a StackExchange question about the different send queues used by a socket](https://unix.stackexchange.com/questions/551444/what-is-the-difference-between-sock-sk-wmem-alloc-and-sock-sk-wmem-queued)\n/// - other useful resources: [here](https://www.cl.cam.ac.uk/~pes20/Netsem/linuxnet.pdf) and [here](https://people.cs.clemson.edu/~westall/853/notes/skbuff.pdf)\n/// - [explanation of the socket backlog queue](https://medium.com/@c0ngwang/the-design-of-lock-sock-in-linux-kernel-69c3406e504b)\n///\n/// # Linux networking in a nutshell\n///\n/// The network stack uses multiple queues, both for sending an\n/// receiving data. Let's start with the simplest case: packet\n/// receptions.\n///\n/// When data is received, it is first handled by the device driver\n/// and put in the device driver queue. The kernel then move the\n/// packet to the socket receive queue (also called _receive\n/// buffer_). Finally, this application reads it (with `recv`, `read`\n/// or `recvfrom`) and the packet is dequeued.\n///\n/// Sending packet it slightly more complicated and the exact workflow\n/// may differ from one protocol to the other so we'll just give a\n/// high level overview. When an application sends data, a packet is\n/// created and stored in the socket send queue (also called _send\n/// buffer_). It is then passed down to the QDisc (Queuing\n/// Disciplines) queue. The QDisc facility enables quality of service:\n/// if some data is more urgent to transmit than other, QDisc will\n/// make sure it is sent in priority. Finally, the data is put on the\n/// device driver queue to be sent out.\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct MemInfo {\n    /// Memory currently allocated for the socket's receive\n    /// queue. This attribute is known as `sk_rmem_alloc` in the\n    /// kernel.\n    pub receive_queue: u32,\n    /// Maximum amount of memory that can be allocated for the\n    /// socket's receive queue. This is set by `SO_RCVBUF`. This is\n    /// _not_ the amount of memory currently allocated. This attribute\n    /// is known as `sk_rcvbuf` in the kernel.\n    pub receive_queue_max: u32,\n    /// Memory currently allocated for the socket send queue. This\n    /// attribute is known as `sk_wmem_queued` in the kernel. This\n    /// does does not account for data that have been passed down the\n    /// network stack (i.e. to the QDisc and device driver queues),\n    /// which is reported by the `bottow_send_queue` (known as\n    /// `sk_wmem_alloc` in the kernel).\n    ///\n    /// For a TCP socket, if the congestion window is small, the\n    /// kernel will move the data fron the socket send queue to the\n    /// QDisc queues more slowly. Thus, if the process sends of lot of\n    /// data, the socket send queue (which memory is tracked by\n    /// `sk_wmem_queued`) will grow while `sk_wmem_alloc` will remain\n    /// small.\n    pub send_queue: u32,\n    /// Maximum amount of memory (in bytes) that can be allocated for\n    /// this socket's send queue. This is set by `SO_SNDBUF`. This is\n    /// _not_ the amount of memory currently allocated. This attribute\n    /// is known as `sk_sndbuf` in the kernel.\n    pub send_queue_max: u32,\n    /// Memory used for packets that have been passed down the network\n    /// stack, i.e. that are either in the QDisc or device driver\n    /// queues. This attribute is known as `sk_wmem_alloc` in the\n    /// kernel. See also [`send_queue`].\n    pub bottom_send_queues: u32,\n    /// The amount of memory already allocated for this socket but\n    /// currently unused. When more memory is needed either for\n    /// sending or for receiving data, it will be taken from this\n    /// pool. This attribute is known as `sk_fwd_alloc` in the kernel.\n    pub cache: u32,\n    /// The amount of memory allocated for storing socket options, for\n    /// instance the key for TCP MD5 signature. This attribute is\n    /// known as `sk_optmem` in the kernel.\n    pub options: u32,\n    /// The length of the backlog queue. When the process is using the\n    /// socket, the socket is locked so the kernel cannot enqueue new\n    /// packets in the receive queue. To avoid blocking the bottom\n    /// half of network stack waiting for the process to release the\n    /// socket, the packets are enqueued in the backlog queue. Upon\n    /// releasing the socket, those packets are processed and put in\n    /// the regular receive queue.\n    // FIXME: this should be an Option because it's not present on old\n    // linux kernels.\n    pub backlog_queue_length: u32,\n    /// The amount of packets dropped. Depending on the kernel\n    /// version, this field may not be present.\n    // FIXME: this should be an Option because it's not present on old\n    // linux kernels.\n    pub drops: u32,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<MemInfoBuffer<T>> for MemInfo {\n    fn parse(buf: &MemInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            receive_queue: buf.receive_queue(),\n            receive_queue_max: buf.receive_queue_max(),\n            bottom_send_queues: buf.bottom_send_queues(),\n            send_queue_max: buf.send_queue_max(),\n            cache: buf.cache(),\n            send_queue: buf.send_queue(),\n            options: buf.options(),\n            backlog_queue_length: buf.backlog_queue_length(),\n            drops: buf.drops(),\n        })\n    }\n}\n\nimpl Emitable for MemInfo {\n    fn buffer_len(&self) -> usize {\n        MEM_INFO_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = MemInfoBuffer::new(buf);\n        buf.set_receive_queue(self.receive_queue);\n        buf.set_receive_queue_max(self.receive_queue_max);\n        buf.set_bottom_send_queues(self.bottom_send_queues);\n        buf.set_send_queue_max(self.send_queue_max);\n        buf.set_cache(self.cache);\n        buf.set_send_queue(self.send_queue);\n        buf.set_options(self.options);\n        buf.set_backlog_queue_length(self.backlog_queue_length);\n        buf.set_drops(self.drops);\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Nla {\n    /// The memory information of the socket. This attribute is\n    /// similar to `Nla::MemInfo` but provides less information. On\n    /// recent kernels, `Nla::MemInfo` is used instead.\n    // ref: https://patchwork.ozlabs.org/patch/154816/\n    LegacyMemInfo(LegacyMemInfo),\n    /// the TCP information\n    #[cfg(feature = \"rich_nlas\")]\n    TcpInfo(TcpInfo),\n    #[cfg(not(feature = \"rich_nlas\"))]\n    TcpInfo(Vec<u8>),\n    /// the congestion control algorithm used\n    Congestion(String),\n    /// the TOS of the socket.\n    Tos(u8),\n    /// the traffic class of the socket.\n    Tc(u8),\n    /// The memory information of the socket\n    MemInfo(MemInfo),\n    /// Shutown state: one of [`SHUT_RD`], [`SHUT_WR`] or [`SHUT_RDWR`]\n    Shutdown(u8),\n    /// The protocol\n    Protocol(u8),\n    /// Whether the socket is IPv6 only\n    SkV6Only(bool),\n    /// The mark of the socket.\n    Mark(u32),\n    /// The class ID of the socket.\n    ClassId(u32),\n    /// other attribute\n    Other(DefaultNla),\n}\n\nimpl crate::utils::nla::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            LegacyMemInfo(_) => LEGACY_MEM_INFO_LEN,\n            #[cfg(feature = \"rich_nlas\")]\n            TcpInfo(_) => TCP_INFO_LEN,\n            #[cfg(not(feature = \"rich_nlas\"))]\n            TcpInfo(ref bytes) => bytes.len(),\n            // +1 because we need to append a null byte\n            Congestion(ref s) => s.as_bytes().len() + 1,\n            Tos(_) | Tc(_) | Shutdown(_) | Protocol(_) | SkV6Only(_) => 1,\n            MemInfo(_) => MEM_INFO_LEN,\n            Mark(_) | ClassId(_) => 4,\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            LegacyMemInfo(_) => INET_DIAG_MEMINFO,\n            TcpInfo(_) => INET_DIAG_INFO,\n            Congestion(_) => INET_DIAG_CONG,\n            Tos(_) => INET_DIAG_TOS,\n            Tc(_) => INET_DIAG_TCLASS,\n            MemInfo(_) => INET_DIAG_SKMEMINFO,\n            Shutdown(_) => INET_DIAG_SHUTDOWN,\n            Protocol(_) => INET_DIAG_PROTOCOL,\n            SkV6Only(_) => INET_DIAG_SKV6ONLY,\n            Mark(_) => INET_DIAG_MARK,\n            ClassId(_) => INET_DIAG_CLASS_ID,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            LegacyMemInfo(ref value) => value.emit(buffer),\n            #[cfg(feature = \"rich_nlas\")]\n            TcpInfo(ref value) => value.emit(buffer),\n            #[cfg(not(feature = \"rich_nlas\"))]\n            TcpInfo(ref bytes) => buffer[..bytes.len()].copy_from_slice(&bytes[..]),\n            Congestion(ref s) => {\n                buffer[..s.len()].copy_from_slice(s.as_bytes());\n                buffer[s.len()] = 0;\n            }\n            Tos(b) | Tc(b) | Shutdown(b) | Protocol(b) => buffer[0] = b,\n            SkV6Only(value) => buffer[0] = value.into(),\n            MemInfo(ref value) => value.emit(buffer),\n            Mark(value) | ClassId(value) => NativeEndian::write_u32(buffer, value),\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            INET_DIAG_MEMINFO => {\n                let err = \"invalid INET_DIAG_MEMINFO value\";\n                let buf = LegacyMemInfoBuffer::new_checked(payload).context(err)?;\n                Self::LegacyMemInfo(LegacyMemInfo::parse(&buf).context(err)?)\n            }\n            #[cfg(feature = \"rich_nlas\")]\n            INET_DIAG_INFO => {\n                let err = \"invalid INET_DIAG_INFO value\";\n                let buf = TcpInfoBuffer::new_checked(payload).context(err)?;\n                Self::TcpInfo(TcpInfo::parse(&buf).context(err)?)\n            }\n            #[cfg(not(feature = \"rich_nlas\"))]\n            INET_DIAG_INFO => Self::TcpInfo(payload.to_vec()),\n            INET_DIAG_CONG => {\n                Self::Congestion(parse_string(payload).context(\"invalid INET_DIAG_CONG value\")?)\n            }\n            INET_DIAG_TOS => Self::Tos(parse_u8(payload).context(\"invalid INET_DIAG_TOS value\")?),\n            INET_DIAG_TCLASS => {\n                Self::Tc(parse_u8(payload).context(\"invalid INET_DIAG_TCLASS value\")?)\n            }\n            INET_DIAG_SKMEMINFO => {\n                let err = \"invalid INET_DIAG_SKMEMINFO value\";\n                let buf = MemInfoBuffer::new_checked(payload).context(err)?;\n                Self::MemInfo(MemInfo::parse(&buf).context(err)?)\n            }\n            INET_DIAG_SHUTDOWN => {\n                Self::Shutdown(parse_u8(payload).context(\"invalid INET_DIAG_SHUTDOWN value\")?)\n            }\n            INET_DIAG_PROTOCOL => {\n                Self::Protocol(parse_u8(payload).context(\"invalid INET_DIAG_PROTOCOL value\")?)\n            }\n            INET_DIAG_SKV6ONLY => {\n                Self::SkV6Only(parse_u8(payload).context(\"invalid INET_DIAG_SKV6ONLY value\")? != 0)\n            }\n            INET_DIAG_MARK => {\n                Self::Mark(parse_u32(payload).context(\"invalid INET_DIAG_MARK value\")?)\n            }\n            INET_DIAG_CLASS_ID => {\n                Self::ClassId(parse_u32(payload).context(\"invalid INET_DIAG_CLASS_ID value\")?)\n            }\n            kind => {\n                Self::Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?)\n            }\n        })\n    }\n}\n\n#[cfg(feature = \"rich_nlas\")]\npub const TCP_INFO_LEN: usize = 232;\n\n#[cfg(feature = \"rich_nlas\")]\nbuffer!(TcpInfoBuffer(TCP_INFO_LEN) {\n    // State of the TCP connection. This should be set to one of the\n    // `TCP_*` constants: `TCP_ESTABLISHED`, `TCP_SYN_SENT`, etc. This\n    // attribute is known as `tcpi_state` in the kernel.\n    state: (u8, 0),\n    // State of congestion avoidance. Sender's congestion state\n    // indicating normal or abnormal situations in the last round of\n    // packets sent. The state is driven by the ACK information and\n    // timer events. This should be set to one of the `TCP_CA_*`\n    // constants. This attribute is known as `tcpi_ca_state` in the\n    // kernel.\n    congestion_avoidance_state: (u8, 1),\n    // Number of retranmissions on timeout invoked. This attribute is\n    // known as `tcpi_retransmits` in the kernel.\n    retransmits: (u8, 2),\n    // Number of window or keep alive probes sent. This attribute is\n    // known as `tcpi_probes`.\n    probes: (u8, 3),\n    // Number of times the retransmission backoff timer invoked\n    backoff: (u8, 4),\n    options: (u8, 5),\n    wscale: (u8, 6),\n    delivery_rate_app_limited: (u8, 7),\n\n    rto: (u32, 8..12),\n    ato: (u32, 12..16),\n    snd_mss: (u32, 16..20),\n    rcv_mss: (u32, 20..24),\n\n    unacked: (u32, 24..28),\n    sacked: (u32, 28..32),\n    lost: (u32, 32..36),\n    retrans: (u32, 36..40),\n    fackets: (u32, 40..44),\n\n    // Times\n    last_data_sent: (u32, 44..48),\n    last_ack_sent: (u32, 48..52),\n    last_data_recv: (u32, 52..56),\n    last_ack_recv: (u32, 56..60),\n\n    // Metrics\n    pmtu: (u32, 60..64),\n    rcv_ssthresh: (u32, 64..68),\n    rtt: (u32, 68..72),\n    rttvar: (u32, 72..76),\n    snd_ssthresh: (u32, 76..80),\n    snd_cwnd: (u32, 80..84),\n    advmss: (u32, 84..88),\n    reordering: (u32, 88..92),\n\n    rcv_rtt: (u32, 92..96),\n    rcv_space: (u32, 96..100),\n\n    total_retrans: (u32, 100..104),\n\n    pacing_rate: (u64, 104..112),\n    max_pacing_rate: (u64, 112..120),\n    bytes_acked: (u64, 120..128),       // RFC4898 tcpEStatsAppHCThruOctetsAcked\n    bytes_received: (u64, 128..136),    // RFC4898 tcpEStatsAppHCThruOctetsReceived\n    segs_out: (u32, 136..140),          // RFC4898 tcpEStatsPerfSegsOut\n    segs_in: (u32, 140..144),           // RFC4898 tcpEStatsPerfSegsIn\n\n    notsent_bytes: (u32, 144..148),\n    min_rtt: (u32, 148..152),\n    data_segs_in: (u32, 152..156),      // RFC4898 tcpEStatsDataSegsIn\n    data_segs_out: (u32, 156..160),     // RFC4898 tcpEStatsDataSegsOut\n\n    delivery_rate: (u64, 160..168),\n\n    busy_time: (u64, 168..176),         // Time (usec) busy sending data\n    rwnd_limited: (u64, 176..184),      // Time (usec) limited by receive window\n    sndbuf_limited: (u64, 184..192),    // Time (usec) limited by send buffer\n\n    delivered: (u32, 192..196),\n    delivered_ce: (u32, 196..200),\n\n    bytes_sent: (u64, 200..208),       // RFC4898 tcpEStatsPerfHCDataOctetsOut\n    bytes_retrans: (u64, 208..216),    // RFC4898 tcpEStatsPerfOctetsRetrans\n    dsack_dups: (u32,   216..220),     // RFC4898 tcpEStatsStackDSACKDups\n    reord_seen: (u32,   220..224),     // reordering events seen\n    rcv_ooopack: (u32, 224..228),      // Out-of-order packets received\n    snd_wnd: (u32, 228..232),          // peer's advertised receive window after scaling (bytes)\n});\n\n// https://unix.stackexchange.com/questions/542712/detailed-output-of-ss-command\n\n#[cfg(feature = \"rich_nlas\")]\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct TcpInfo {\n    /// State of the TCP connection: one of `TCP_ESTABLISHED`,\n    /// `TCP_SYN_SENT`, `TP_SYN_RECV`, `TCP_FIN_WAIT1`,\n    /// `TCP_FIN_WAIT2` `TCP_TIME_WAIT`, `TCP_CLOSE`,\n    /// `TCP_CLOSE_WAIT`, `TCP_LAST_ACK` `TCP_LISTEN`, `TCP_CLOSING`.\n    pub state: u8,\n    /// Congestion algorithm state: one of `TCP_CA_OPEN`,\n    /// `TCP_CA_DISORDER`, `TCP_CA_CWR`, `TCP_CA_RECOVERY`,\n    /// `TCP_CA_LOSS`\n    pub ca_state: u8,\n    ///\n    pub retransmits: u8,\n    pub probes: u8,\n    pub backoff: u8,\n    pub options: u8,\n    // First 4 bits are snd_wscale, last 4 bits rcv_wscale\n    pub wscale: u8,\n    /// A boolean indicating if the goodput was measured when the\n    /// socket's throughput was limited by the sending application.\n    /// tcpi_delivery_rate_app_limited:1, tcpi_fastopen_client_fail:2\n    pub delivery_rate_app_limited: u8,\n\n    /// Value of the RTO (Retransmission TimeOut) timer. This value is\n    /// calculated using the RTT.\n    pub rto: u32,\n    /// Value of the ATO (ACK TimeOut) timer.\n    pub ato: u32,\n    /// MSS (Maximum Segment Size). Not shure how it differs from\n    /// `advmss`.\n    pub snd_mss: u32,\n    /// MSS (Maximum Segment Size) advertised by peer\n    pub rcv_mss: u32,\n\n    /// Number of segments that have not been ACKnowledged yet, ie the\n    /// number of in-flight segments.\n    pub unacked: u32,\n    /// Number of segments that have been SACKed\n    pub sacked: u32,\n    /// Number of segments that have been lost\n    pub lost: u32,\n    /// Number of segments that have been retransmitted\n    pub retrans: u32,\n    /// Number of segments that have been FACKed\n    pub fackets: u32,\n\n    pub last_data_sent: u32,\n    pub last_ack_sent: u32,\n    pub last_data_recv: u32,\n    pub last_ack_recv: u32,\n\n    pub pmtu: u32,\n    pub rcv_ssthresh: u32,\n    /// RTT (Round Trip Time). There RTT is the time between the\n    /// moment a segment is sent out and the moment it is\n    /// acknowledged. There are different kinds of RTT values, and I\n    /// don't know which one this value corresponds to: mRTT (measured\n    /// RTT), sRTT (smoothed RTT), RTTd (deviated RTT), etc.\n    pub rtt: u32,\n    /// RTT variance (or variation?)\n    pub rttvar: u32,\n    /// Slow-Start Threshold\n    pub snd_ssthresh: u32,\n    /// Size of the congestion window\n    pub snd_cwnd: u32,\n    /// MSS advertised by this peer\n    pub advmss: u32,\n\n    pub reordering: u32,\n\n    pub rcv_rtt: u32,\n    pub rcv_space: u32,\n\n    pub total_retrans: u32,\n\n    pub pacing_rate: u64,\n    pub max_pacing_rate: u64,\n    pub bytes_acked: u64,    // RFC4898 tcpEStatsAppHCThruOctetsAcked\n    pub bytes_received: u64, // RFC4898 tcpEStatsAppHCThruOctetsReceived\n    pub segs_out: u32,       // RFC4898 tcpEStatsPerfSegsOut\n    pub segs_in: u32,        // RFC4898 tcpEStatsPerfSegsIn\n\n    pub notsent_bytes: u32,\n    pub min_rtt: u32,\n    pub data_segs_in: u32,  // RFC4898 tcpEStatsDataSegsIn\n    pub data_segs_out: u32, // RFC4898 tcpEStatsDataSegsOut\n\n    /// The most recent goodput, as measured by tcp_rate_gen(). If the\n    /// socket is limited by the sending application (e.g., no data to\n    /// send), it reports the highest measurement instead of the most\n    /// recent. The unit is bytes per second (like other rate fields\n    /// in tcp_info).\n    pub delivery_rate: u64,\n\n    pub busy_time: u64,      // Time (usec) busy sending data\n    pub rwnd_limited: u64,   // Time (usec) limited by receive window\n    pub sndbuf_limited: u64, // Time (usec) limited by send buffer\n\n    pub delivered: u32,\n    pub delivered_ce: u32,\n\n    pub bytes_sent: u64,    // RFC4898 tcpEStatsPerfHCDataOctetsOut\n    pub bytes_retrans: u64, // RFC4898 tcpEStatsPerfOctetsRetrans\n    pub dsack_dups: u32,    // RFC4898 tcpEStatsStackDSACKDups\n    /// reordering events seen\n    pub reord_seen: u32,\n\n    /// Out-of-order packets received\n    pub rcv_ooopack: u32,\n    /// peer's advertised receive window after scaling (bytes)\n    pub snd_wnd: u32,\n}\n\n#[cfg(feature = \"rich_nlas\")]\nimpl<T: AsRef<[u8]>> Parseable<TcpInfoBuffer<T>> for TcpInfo {\n    fn parse(buf: &TcpInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            state: buf.state(),\n            ca_state: buf.congestion_avoidance_state(),\n            retransmits: buf.retransmits(),\n            probes: buf.probes(),\n            backoff: buf.backoff(),\n            options: buf.options(),\n            wscale: buf.wscale(),\n            delivery_rate_app_limited: buf.delivery_rate_app_limited(),\n            rto: buf.rto(),\n            ato: buf.ato(),\n            snd_mss: buf.snd_mss(),\n            rcv_mss: buf.rcv_mss(),\n            unacked: buf.unacked(),\n            sacked: buf.sacked(),\n            lost: buf.lost(),\n            retrans: buf.retrans(),\n            fackets: buf.fackets(),\n            last_data_sent: buf.last_data_sent(),\n            last_ack_sent: buf.last_ack_sent(),\n            last_data_recv: buf.last_data_recv(),\n            last_ack_recv: buf.last_ack_recv(),\n            pmtu: buf.pmtu(),\n            rcv_ssthresh: buf.rcv_ssthresh(),\n            rtt: buf.rtt(),\n            rttvar: buf.rttvar(),\n            snd_ssthresh: buf.snd_ssthresh(),\n            snd_cwnd: buf.snd_cwnd(),\n            advmss: buf.advmss(),\n            reordering: buf.reordering(),\n            rcv_rtt: buf.rcv_rtt(),\n            rcv_space: buf.rcv_space(),\n            total_retrans: buf.total_retrans(),\n            pacing_rate: buf.pacing_rate(),\n            max_pacing_rate: buf.max_pacing_rate(),\n            bytes_acked: buf.bytes_acked(),\n            bytes_received: buf.bytes_received(),\n            segs_out: buf.segs_out(),\n            segs_in: buf.segs_in(),\n            notsent_bytes: buf.notsent_bytes(),\n            min_rtt: buf.min_rtt(),\n            data_segs_in: buf.data_segs_in(),\n            data_segs_out: buf.data_segs_out(),\n            delivery_rate: buf.delivery_rate(),\n            busy_time: buf.busy_time(),\n            rwnd_limited: buf.rwnd_limited(),\n            sndbuf_limited: buf.sndbuf_limited(),\n            delivered: buf.delivered(),\n            delivered_ce: buf.delivered_ce(),\n            bytes_sent: buf.bytes_sent(),\n            bytes_retrans: buf.bytes_retrans(),\n            dsack_dups: buf.dsack_dups(),\n            reord_seen: buf.reord_seen(),\n            rcv_ooopack: buf.rcv_ooopack(),\n            snd_wnd: buf.snd_wnd(),\n        })\n    }\n}\n\n#[cfg(feature = \"rich_nlas\")]\nimpl Emitable for TcpInfo {\n    fn buffer_len(&self) -> usize {\n        TCP_INFO_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = TcpInfoBuffer::new(buf);\n        buf.set_state(self.state);\n        buf.set_congestion_avoidance_state(self.ca_state);\n        buf.set_retransmits(self.retransmits);\n        buf.set_probes(self.probes);\n        buf.set_backoff(self.backoff);\n        buf.set_options(self.options);\n        buf.set_wscale(self.wscale);\n        buf.set_delivery_rate_app_limited(self.delivery_rate_app_limited);\n        buf.set_rto(self.rto);\n        buf.set_ato(self.ato);\n        buf.set_snd_mss(self.snd_mss);\n        buf.set_rcv_mss(self.rcv_mss);\n        buf.set_unacked(self.unacked);\n        buf.set_sacked(self.sacked);\n        buf.set_lost(self.lost);\n        buf.set_retrans(self.retrans);\n        buf.set_fackets(self.fackets);\n        buf.set_last_data_sent(self.last_data_sent);\n        buf.set_last_ack_sent(self.last_ack_sent);\n        buf.set_last_data_recv(self.last_data_recv);\n        buf.set_last_ack_recv(self.last_ack_recv);\n        buf.set_pmtu(self.pmtu);\n        buf.set_rcv_ssthresh(self.rcv_ssthresh);\n        buf.set_rtt(self.rtt);\n        buf.set_rttvar(self.rttvar);\n        buf.set_snd_ssthresh(self.snd_ssthresh);\n        buf.set_snd_cwnd(self.snd_cwnd);\n        buf.set_advmss(self.advmss);\n        buf.set_reordering(self.reordering);\n        buf.set_rcv_rtt(self.rcv_rtt);\n        buf.set_rcv_space(self.rcv_space);\n        buf.set_total_retrans(self.total_retrans);\n        buf.set_pacing_rate(self.pacing_rate);\n        buf.set_max_pacing_rate(self.max_pacing_rate);\n        buf.set_bytes_acked(self.bytes_acked);\n        buf.set_bytes_received(self.bytes_received);\n        buf.set_segs_out(self.segs_out);\n        buf.set_segs_in(self.segs_in);\n        buf.set_notsent_bytes(self.notsent_bytes);\n        buf.set_min_rtt(self.min_rtt);\n        buf.set_data_segs_in(self.data_segs_in);\n        buf.set_data_segs_out(self.data_segs_out);\n        buf.set_delivery_rate(self.delivery_rate);\n        buf.set_busy_time(self.busy_time);\n        buf.set_rwnd_limited(self.rwnd_limited);\n        buf.set_sndbuf_limited(self.sndbuf_limited);\n        buf.set_delivered(self.delivered);\n        buf.set_delivered_ce(self.delivered_ce);\n        buf.set_bytes_sent(self.bytes_sent);\n        buf.set_bytes_retrans(self.bytes_retrans);\n        buf.set_dsack_dups(self.dsack_dups);\n        buf.set_reord_seen(self.reord_seen);\n        buf.set_rcv_ooopack(self.rcv_ooopack);\n        buf.set_snd_wnd(self.snd_wnd);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/request.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\n\nuse crate::{\n    constants::*,\n    inet::{SocketId, SocketIdBuffer},\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n};\n\npub const REQUEST_LEN: usize = 56;\n\nbuffer!(InetRequestBuffer(REQUEST_LEN) {\n    family: (u8, 0),\n    protocol: (u8, 1),\n    extensions: (u8, 2),\n    pad: (u8, 3),\n    states: (u32, 4..8),\n    socket_id: (slice, 8..56),\n});\n\n/// A request for Ipv4 and Ipv6 sockets\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct InetRequest {\n    /// The address family, either `AF_INET` or `AF_INET6`\n    pub family: u8,\n    /// The IP protocol. This field should be set to one of the\n    /// `IPPROTO_*` constants\n    pub protocol: u8,\n    /// Set of flags defining what kind of extended information to\n    /// report. Each requested kind of information is reported back as\n    /// a netlink attribute.\n    pub extensions: ExtensionFlags,\n    /// Bitmask that defines a filter of TCP socket states\n    pub states: StateFlags,\n    /// A socket ID object that is used in dump requests, in queries\n    /// about individual sockets, and is reported back in each\n    /// response.\n    ///\n    /// Unlike UNIX domain sockets, IPv4 and IPv6 sockets are\n    /// identified using addresses and ports.\n    pub socket_id: SocketId,\n}\n\nbitflags! {\n    /// Bitmask that defines a filter of TCP socket states\n    pub struct StateFlags: u32 {\n        /// (server and client) represents an open connection,\n        /// data received can be delivered to the user. The normal\n        /// state for the data transfer phase of the connection.\n        const ESTABLISHED = 1 << TCP_ESTABLISHED ;\n        /// (client) represents waiting for a matching connection\n        /// request after having sent a connection request.\n        const SYN_SENT = 1 <<TCP_SYN_SENT ;\n        /// (server) represents waiting for a confirming connection\n        /// request acknowledgment after having both received and sent\n        /// a connection request.\n        const SYN_RECV = 1 << TCP_SYN_RECV ;\n        /// (both server and client) represents waiting for a\n        /// connection termination request from the remote TCP, or an\n        /// acknowledgment of the connection termination request\n        /// previously sent.\n        const FIN_WAIT1 = 1 << TCP_FIN_WAIT1 ;\n        /// (both server and client) represents waiting for a\n        /// connection termination request from the remote TCP.\n        const FIN_WAIT2 = 1 << TCP_FIN_WAIT2 ;\n        /// (either server or client) represents waiting for enough\n        /// time to pass to be sure the remote TCP received the\n        /// acknowledgment of its connection termination request.\n        const TIME_WAIT = 1 << TCP_TIME_WAIT ;\n        /// (both server and client) represents no connection state at\n        /// all.\n        const CLOSE = 1 << TCP_CLOSE ;\n        /// (both server and client) represents waiting for a\n        /// connection termination request from the local user.\n        const CLOSE_WAIT = 1 << TCP_CLOSE_WAIT ;\n        /// (both server and client) represents waiting for an\n        /// acknowledgment of the connection termination request\n        /// previously sent to the remote TCP (which includes an\n        /// acknowledgment of its connection termination request).\n        const LAST_ACK = 1 << TCP_LAST_ACK ;\n        /// (server) represents waiting for a connection request from\n        /// any remote TCP and port.\n        const LISTEN = 1 << TCP_LISTEN ;\n        /// (both server and client) represents waiting for a\n        /// connection termination request acknowledgment from the\n        /// remote TCP.\n        const CLOSING = 1 << TCP_CLOSING ;\n    }\n}\n\nbitflags! {\n    /// This is a set of flags defining what kind of extended\n    /// information to report.\n    pub struct ExtensionFlags: u8 {\n        const MEMINFO = 1 << (INET_DIAG_MEMINFO as u16 - 1);\n        const INFO = 1 << (INET_DIAG_INFO as u16 - 1);\n        const VEGASINFO = 1 << (INET_DIAG_VEGASINFO as u16 - 1);\n        const CONG = 1 << (INET_DIAG_CONG as u16 - 1);\n        const TOS = 1 << (INET_DIAG_TOS as u16 - 1);\n        const TCLASS = 1 << (INET_DIAG_TCLASS as u16 - 1);\n        const SKMEMINFO = 1 << (INET_DIAG_SKMEMINFO as u16 - 1);\n        const SHUTDOWN = 1 << (INET_DIAG_SHUTDOWN as u16 - 1);\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<InetRequestBuffer<&'a T>> for InetRequest {\n    fn parse(buf: &InetRequestBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let err = \"invalid socket_id value\";\n        let socket_id = SocketId::parse_with_param(\n            &SocketIdBuffer::new_checked(&buf.socket_id()).context(err)?,\n            buf.family(),\n        )\n        .context(err)?;\n\n        Ok(Self {\n            family: buf.family(),\n            protocol: buf.protocol(),\n            extensions: ExtensionFlags::from_bits_truncate(buf.extensions()),\n            states: StateFlags::from_bits_truncate(buf.states()),\n            socket_id,\n        })\n    }\n}\n\nimpl Emitable for InetRequest {\n    fn buffer_len(&self) -> usize {\n        REQUEST_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = InetRequestBuffer::new(buf);\n        buf.set_family(self.family);\n        buf.set_protocol(self.protocol);\n        buf.set_extensions(self.extensions.bits());\n        buf.set_pad(0);\n        buf.set_states(self.states.bits());\n        self.socket_id.emit(buf.socket_id_mut())\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/response.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse smallvec::SmallVec;\nuse std::time::Duration;\n\nuse crate::{\n    inet::{\n        nlas::{Nla, NlaBuffer, NlasIterator},\n        SocketId,\n        SocketIdBuffer,\n    },\n    traits::{Emitable, Parseable, ParseableParametrized},\n    DecodeError,\n};\n\n/// The type of timer that is currently active for a TCP socket.\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum Timer {\n    /// A retransmit timer\n    Retransmit(Duration, u8),\n    /// A keep-alive timer\n    KeepAlive(Duration),\n    /// A `TIME_WAIT` timer\n    TimeWait,\n    /// A zero window probe timer\n    Probe(Duration),\n}\n\npub const RESPONSE_LEN: usize = 72;\n\nbuffer!(InetResponseBuffer(RESPONSE_LEN) {\n    family: (u8, 0),\n    state: (u8, 1),\n    timer: (u8, 2),\n    retransmits: (u8, 3),\n    socket_id: (slice, 4..52),\n    expires: (u32, 52..56),\n    recv_queue: (u32, 56..60),\n    send_queue: (u32, 60..64),\n    uid: (u32, 64..68),\n    inode: (u32, 68..72),\n    payload: (slice, RESPONSE_LEN..),\n});\n\n/// The response to a query for IPv4 or IPv6 sockets\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct InetResponseHeader {\n    /// This should be set to either `AF_INET` or `AF_INET6` for IPv4\n    /// or IPv6 sockets respectively.\n    pub family: u8,\n\n    /// The socket state.\n    pub state: u8,\n\n    /// For TCP sockets, this field describes the type of timer\n    /// that is currently active for the socket.\n    pub timer: Option<Timer>,\n\n    /// The socket ID object.\n    pub socket_id: SocketId,\n\n    /// For listening sockets: the number of pending connections. For\n    /// other sockets: the amount of data in the incoming queue.\n    pub recv_queue: u32,\n\n    /// For listening sockets: the backlog length. For other sockets:\n    /// the amount of memory available for sending.\n    pub send_queue: u32,\n\n    /// Socket owner UID.\n    pub uid: u32,\n\n    /// Socket inode number.\n    pub inode: u32,\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<InetResponseBuffer<&'a T>> for InetResponseHeader {\n    fn parse(buf: &InetResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let err = \"invalid socket_id value\";\n        let socket_id = SocketId::parse_with_param(\n            &SocketIdBuffer::new_checked(&buf.socket_id()).context(err)?,\n            buf.family(),\n        )\n        .context(err)?;\n\n        let timer = match buf.timer() {\n            1 => {\n                let expires = Duration::from_millis(buf.expires() as u64);\n                let retransmits = buf.retransmits();\n                Some(Timer::Retransmit(expires, retransmits))\n            }\n            2 => {\n                let expires = Duration::from_millis(buf.expires() as u64);\n                Some(Timer::KeepAlive(expires))\n            }\n            3 => Some(Timer::TimeWait),\n            4 => {\n                let expires = Duration::from_millis(buf.expires() as u64);\n                Some(Timer::Probe(expires))\n            }\n            _ => None,\n        };\n\n        Ok(Self {\n            family: buf.family(),\n            state: buf.state(),\n            timer,\n            socket_id,\n            recv_queue: buf.recv_queue(),\n            send_queue: buf.send_queue(),\n            uid: buf.uid(),\n            inode: buf.inode(),\n        })\n    }\n}\n\nimpl Emitable for InetResponseHeader {\n    fn buffer_len(&self) -> usize {\n        RESPONSE_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = InetResponseBuffer::new(buf);\n        buf.set_family(self.family);\n        buf.set_state(self.state);\n        match self.timer {\n            Some(Timer::Retransmit(expires, retransmits)) => {\n                buf.set_timer(1);\n                buf.set_expires((expires.as_millis() & 0xffff_ffff) as u32);\n                buf.set_retransmits(retransmits);\n            }\n            Some(Timer::KeepAlive(expires)) => {\n                buf.set_timer(2);\n                buf.set_expires((expires.as_millis() & 0xffff_ffff) as u32);\n                buf.set_retransmits(0);\n            }\n            Some(Timer::TimeWait) => {\n                buf.set_timer(3);\n                buf.set_expires(0);\n                buf.set_retransmits(0);\n            }\n            Some(Timer::Probe(expires)) => {\n                buf.set_timer(4);\n                buf.set_expires((expires.as_millis() & 0xffff_ffff) as u32);\n                buf.set_retransmits(0);\n            }\n            None => {\n                buf.set_timer(0);\n                buf.set_expires(0);\n                buf.set_retransmits(0);\n            }\n        }\n        buf.set_recv_queue(self.recv_queue);\n        buf.set_send_queue(self.send_queue);\n        buf.set_uid(self.uid);\n        buf.set_inode(self.inode);\n        self.socket_id.emit(buf.socket_id_mut())\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct InetResponse {\n    pub header: InetResponseHeader,\n    pub nlas: SmallVec<[Nla; 8]>,\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> InetResponseBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<InetResponseBuffer<&'a T>> for SmallVec<[Nla; 8]> {\n    fn parse(buf: &InetResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = smallvec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<InetResponseBuffer<&'a T>> for InetResponse {\n    fn parse(buf: &InetResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let header =\n            InetResponseHeader::parse(buf).context(\"failed to parse inet response header\")?;\n        let nlas =\n            SmallVec::<[Nla; 8]>::parse(buf).context(\"failed to parse inet response NLAs\")?;\n        Ok(InetResponse { header, nlas })\n    }\n}\n\nimpl Emitable for InetResponse {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/socket_id.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse byteorder::{BigEndian, ByteOrder};\nuse std::{\n    convert::{TryFrom, TryInto},\n    net::{IpAddr, Ipv4Addr, Ipv6Addr},\n};\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, ParseableParametrized},\n    DecodeError,\n};\n\npub const SOCKET_ID_LEN: usize = 48;\n\nbuffer!(SocketIdBuffer(SOCKET_ID_LEN) {\n    source_port: (slice, 0..2),\n    destination_port: (slice, 2..4),\n    source_address: (slice, 4..20),\n    destination_address: (slice, 20..36),\n    interface_id: (u32, 36..40),\n    cookie: (slice, 40..48),\n});\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct SocketId {\n    pub source_port: u16,\n    pub destination_port: u16,\n    pub source_address: IpAddr,\n    pub destination_address: IpAddr,\n    pub interface_id: u32,\n    /// An array of opaque identifiers that could be used along with\n    /// other fields of this structure to specify an individual\n    /// socket. It is ignored when querying for a list of sockets, as\n    /// well as when all its elements are set to `0xff`.\n    pub cookie: [u8; 8],\n}\n\nimpl SocketId {\n    pub fn new_v4() -> Self {\n        Self {\n            source_port: 0,\n            destination_port: 0,\n            source_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),\n            destination_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),\n            interface_id: 0,\n            cookie: [0; 8],\n        }\n    }\n    pub fn new_v6() -> Self {\n        Self {\n            source_port: 0,\n            destination_port: 0,\n            source_address: IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),\n            destination_address: IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),\n            interface_id: 0,\n            cookie: [0; 8],\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<SocketIdBuffer<&'a T>, u8> for SocketId {\n    fn parse_with_param(buf: &SocketIdBuffer<&'a T>, af: u8) -> Result<Self, DecodeError> {\n        let (source_address, destination_address) = match af {\n            AF_INET => {\n                let s = &buf.source_address()[..4];\n                let source = IpAddr::V4(Ipv4Addr::new(s[0], s[1], s[2], s[3]));\n\n                let s = &buf.destination_address()[..4];\n                let destination = IpAddr::V4(Ipv4Addr::new(s[0], s[1], s[2], s[3]));\n\n                (source, destination)\n            }\n            AF_INET6 => {\n                let bytes: [u8; 16] = buf.source_address().try_into().unwrap();\n                let source = IpAddr::V6(Ipv6Addr::from(bytes));\n\n                let bytes: [u8; 16] = buf.destination_address().try_into().unwrap();\n                let destination = IpAddr::V6(Ipv6Addr::from(bytes));\n                (source, destination)\n            }\n            _ => {\n                return Err(DecodeError::from(format!(\n                    \"unsupported address family {}: expected AF_INET ({}) or AF_INET6 ({})\",\n                    af, AF_INET, AF_INET6\n                )));\n            }\n        };\n\n        Ok(Self {\n            source_port: BigEndian::read_u16(buf.source_port()),\n            destination_port: BigEndian::read_u16(buf.destination_port()),\n            source_address,\n            destination_address,\n            interface_id: buf.interface_id(),\n            // Unwrapping is safe because SocketIdBuffer::cookie()\n            // returns a slice of exactly 8 bytes.\n            cookie: TryFrom::try_from(buf.cookie()).unwrap(),\n        })\n    }\n}\n\nimpl Emitable for SocketId {\n    fn buffer_len(&self) -> usize {\n        SOCKET_ID_LEN\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = SocketIdBuffer::new(buffer);\n\n        BigEndian::write_u16(buffer.source_port_mut(), self.source_port);\n        BigEndian::write_u16(buffer.destination_port_mut(), self.destination_port);\n\n        let mut address_buf: [u8; 16] = [0; 16];\n        match self.source_address {\n            IpAddr::V4(ip) => address_buf[0..4].copy_from_slice(&ip.octets()[..]),\n            IpAddr::V6(ip) => address_buf.copy_from_slice(&ip.octets()[..]),\n        }\n\n        buffer\n            .source_address_mut()\n            .copy_from_slice(&address_buf[..]);\n\n        address_buf = [0; 16];\n        match self.destination_address {\n            IpAddr::V4(ip) => address_buf[0..4].copy_from_slice(&ip.octets()[..]),\n            IpAddr::V6(ip) => address_buf.copy_from_slice(&ip.octets()[..]),\n        }\n\n        buffer\n            .destination_address_mut()\n            .copy_from_slice(&address_buf[..]);\n\n        buffer.set_interface_id(self.interface_id);\n        buffer.cookie_mut().copy_from_slice(&self.cookie[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/inet/tests.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    net::{IpAddr, Ipv4Addr},\n    time::Duration,\n};\n\nuse crate::{\n    constants::*,\n    inet::{\n        nlas::Nla,\n        ExtensionFlags,\n        InetRequest,\n        InetRequestBuffer,\n        InetResponse,\n        InetResponseBuffer,\n        InetResponseHeader,\n        SocketId,\n        StateFlags,\n        Timer,\n    },\n    traits::{Emitable, Parseable},\n};\n\nlazy_static! {\n    static ref REQ_UDP: InetRequest = InetRequest {\n        family: AF_INET as u8,\n        protocol: IPPROTO_UDP,\n        extensions: ExtensionFlags::empty(),\n        states: StateFlags::ESTABLISHED,\n        socket_id: SocketId::new_v4(),\n    };\n}\n\n#[rustfmt::skip]\nstatic REQ_UDP_BUF: [u8; 56] = [\n    0x02, // family (AF_INET)\n    0x11, // protocol (IPPROTO_UDP)\n    0x00, // extensions\n    0x00, // padding\n    0x02, 0x00, 0x00, 0x00, // states\n\n    // socket id\n    0x00, 0x00, // source port\n    0x00, 0x00, // destination port\n    // source address\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    // destination address\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, // interface id\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cookie\n];\n\n#[test]\nfn parse_udp_req() {\n    let parsed =\n        InetRequest::parse(&InetRequestBuffer::new_checked(&&REQ_UDP_BUF[..]).unwrap()).unwrap();\n    assert_eq!(parsed, *REQ_UDP);\n}\n\n#[test]\nfn emit_udp_req() {\n    assert_eq!(REQ_UDP.buffer_len(), 56);\n    let mut buf = vec![0; REQ_UDP.buffer_len()];\n    REQ_UDP.emit(&mut buf);\n    assert_eq!(&buf[..], &REQ_UDP_BUF[..]);\n}\n\nlazy_static! {\n    static ref RESP_TCP: InetResponse = InetResponse {\n        header: InetResponseHeader {\n            family: AF_INET as u8,\n            state: TCP_ESTABLISHED,\n            timer: Some(Timer::KeepAlive(Duration::from_millis(0x0000_6080))),\n            recv_queue: 0,\n            send_queue: 0,\n            uid: 1000,\n            inode: 0x0029_daa8,\n            socket_id: SocketId {\n                source_port: 60180,\n                destination_port: 443,\n                source_address: IpAddr::V4(Ipv4Addr::new(192, 168, 178, 60)),\n                destination_address: IpAddr::V4(Ipv4Addr::new(172, 217, 23, 131)),\n                interface_id: 0,\n                cookie: [0x52, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],\n            },\n        },\n        nlas: smallvec![Nla::Shutdown(0)],\n    };\n}\n\n#[rustfmt::skip]\nstatic RESP_TCP_BUF: [u8; 80] = [\n    0x02, // family (AF_INET)\n    0x01, // state (ESTABLISHED)\n    0x02, // timer\n    0x00, // retransmits\n\n    // socket id\n    0xeb, 0x14, // source port (60180)\n    0x01, 0xbb, // destination port (443)\n    // source ip (192.168.178.60)\n    0xc0, 0xa8, 0xb2, 0x3c, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    // destination ip (172.217.23.131)\n    0xac, 0xd9, 0x17, 0x83, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, // interface id\n    0x52, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cookie\n\n    0x80, 0x60, 0x00, 0x00, // expires\n    0x00, 0x00, 0x00, 0x00, // receive queue\n    0x00, 0x00, 0x00, 0x00, // send queue\n    0xe8, 0x03, 0x00, 0x00, // uid\n    0xa8, 0xda, 0x29, 0x00, // inode\n\n    // nlas\n    0x05, 0x00, // length = 5\n    0x08, 0x00, // type = 8\n    0x00, // value (0)\n    0x00, 0x00, 0x00\n];\n\n#[test]\nfn parse_tcp_resp() {\n    let parsed =\n        InetResponse::parse(&InetResponseBuffer::new_checked(&&RESP_TCP_BUF[..]).unwrap()).unwrap();\n    assert_eq!(parsed, *RESP_TCP);\n}\n\n#[test]\nfn emit_tcp_resp() {\n    assert_eq!(RESP_TCP.buffer_len(), 80);\n    let mut buf = vec![0; RESP_TCP.buffer_len()];\n    RESP_TCP.emit(&mut buf);\n    assert_eq!(&buf[..], &RESP_TCP_BUF[..]);\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_use]\nextern crate bitflags;\n\n#[macro_use]\npub(crate) extern crate netlink_packet_utils as utils;\npub(crate) use self::utils::parsers;\npub use self::utils::{traits, DecodeError};\npub use netlink_packet_core::{\n    ErrorMessage,\n    NetlinkBuffer,\n    NetlinkHeader,\n    NetlinkMessage,\n    NetlinkPayload,\n};\npub(crate) use netlink_packet_core::{NetlinkDeserializable, NetlinkSerializable};\n\n#[cfg(test)]\n#[macro_use]\nextern crate lazy_static;\n\n#[macro_use]\nextern crate smallvec;\n\npub mod buffer;\npub mod constants;\npub mod inet;\npub mod message;\npub mod unix;\npub use self::{buffer::*, constants::*, message::*};\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/message.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    inet,\n    traits::{Emitable, ParseableParametrized},\n    unix,\n    DecodeError,\n    NetlinkDeserializable,\n    NetlinkHeader,\n    NetlinkPayload,\n    NetlinkSerializable,\n    SockDiagBuffer,\n    SOCK_DIAG_BY_FAMILY,\n};\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum SockDiagMessage {\n    InetRequest(inet::InetRequest),\n    InetResponse(Box<inet::InetResponse>),\n    UnixRequest(unix::UnixRequest),\n    UnixResponse(Box<unix::UnixResponse>),\n}\n\nimpl SockDiagMessage {\n    pub fn is_inet_request(&self) -> bool {\n        matches!(self, SockDiagMessage::InetRequest(_))\n    }\n\n    pub fn is_inet_response(&self) -> bool {\n        matches!(self, SockDiagMessage::InetResponse(_))\n    }\n    pub fn is_unix_request(&self) -> bool {\n        matches!(self, SockDiagMessage::UnixRequest(_))\n    }\n\n    pub fn is_unix_response(&self) -> bool {\n        matches!(self, SockDiagMessage::UnixResponse(_))\n    }\n\n    pub fn message_type(&self) -> u16 {\n        SOCK_DIAG_BY_FAMILY\n    }\n}\n\nimpl Emitable for SockDiagMessage {\n    fn buffer_len(&self) -> usize {\n        use SockDiagMessage::*;\n\n        match self {\n            InetRequest(ref msg) => msg.buffer_len(),\n            InetResponse(ref msg) => msg.buffer_len(),\n            UnixRequest(ref msg) => msg.buffer_len(),\n            UnixResponse(ref msg) => msg.buffer_len(),\n        }\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        use SockDiagMessage::*;\n\n        match self {\n            InetRequest(ref msg) => msg.emit(buffer),\n            InetResponse(ref msg) => msg.emit(buffer),\n            UnixRequest(ref msg) => msg.emit(buffer),\n            UnixResponse(ref msg) => msg.emit(buffer),\n        }\n    }\n}\n\nimpl NetlinkSerializable for SockDiagMessage {\n    fn message_type(&self) -> u16 {\n        self.message_type()\n    }\n\n    fn buffer_len(&self) -> usize {\n        <Self as Emitable>::buffer_len(self)\n    }\n\n    fn serialize(&self, buffer: &mut [u8]) {\n        self.emit(buffer)\n    }\n}\n\nimpl NetlinkDeserializable for SockDiagMessage {\n    type Error = DecodeError;\n    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {\n        let buffer = SockDiagBuffer::new_checked(&payload)?;\n        SockDiagMessage::parse_with_param(&buffer, header.message_type)\n    }\n}\n\nimpl From<SockDiagMessage> for NetlinkPayload<SockDiagMessage> {\n    fn from(message: SockDiagMessage) -> Self {\n        NetlinkPayload::InnerMessage(message)\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/unix/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod request;\npub use self::request::*;\n\nmod response;\npub use self::response::*;\n\npub mod nlas;\n\n#[cfg(test)]\nmod tests;\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/unix/nlas.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\npub use crate::utils::nla::{DefaultNla, NlaBuffer, NlasIterator};\n\nuse crate::{\n    constants::*,\n    parsers::{parse_string, parse_u32, parse_u8},\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub enum Nla {\n    /// Path to which the socket was bound. This attribute is known as\n    /// `UNIX_DIAG_NAME` in the kernel.\n    Name(String),\n    /// VFS information for this socket. This attribute is known as\n    /// `UNIX_DIAG_VFS` in the kernel.\n    Vfs(Vfs),\n    /// Inode number of the socket's peer. This attribute is reported\n    /// for connected socket only. This attribute is known as\n    /// `UNIX_DIAG_PEER` in the kernel.\n    Peer(u32),\n    /// The payload associated with this attribute is an array of\n    /// inode numbers of sockets that have passed the `connect(2)`\n    /// call, but haven't been processed with `accept(2)` yet. This\n    /// attribute is reported for listening sockets only. This\n    /// attribute is known as `UNIX_DIAG_ICONS` in the kernel.\n    PendingConnections(Vec<u32>),\n    /// This attribute corresponds to the `UNIX_DIAG_RQLEN`. It\n    /// reports the length of the socket receive queue, and the queue\n    /// size limit. Note that for **listening** sockets the receive\n    /// queue is used to store actual data sent by other sockets. It\n    /// is used to store pending connections. So the meaning of this\n    /// attribute differs for listening sockets.\n    ///\n    /// For **listening** sockets:\n    ///\n    /// - the first the number is the number of pending\n    ///   connections. It should be equal to `Nla::PendingConnections`\n    ///   value's length.\n    /// - the second number is the backlog queue maximum length, which\n    ///   equals to the value passed as the second argument to\n    ///   `listen(2)`\n    ///\n    /// For other sockets:\n    ///\n    /// - the first number is the amount of data in receive queue\n    ///   (**note**: I am not sure if it is the actual amount of data\n    ///   or the amount of memory allocated. The two might differ\n    ///   because of memory allocation strategies: more memory than\n    ///   strictly necessary may be allocated for a given `sk_buff`)\n    /// - the second number is the memory used by outgoing data. Note\n    ///   that strictly UNIX sockets don't have a send queue, since\n    ///   the data they send is directly written into the destination\n    ///   socket receive queue. But the memory allocated for this data\n    ///   is still counted from the sender point of view.\n    ReceiveQueueLength(u32, u32),\n    /// Socket memory information. See [`MemInfo`] for more details.\n    MemInfo(MemInfo),\n    /// Shutown state: one of [`SHUT_RD`], [`SHUT_WR`] or [`SHUT_RDWR`]\n    Shutdown(u8),\n    /// Unknown attribute\n    Other(DefaultNla),\n}\n\npub const VFS_LEN: usize = 8;\n\nbuffer!(VfsBuffer(8) {\n    inode: (u32, 0..4),\n    device: (u32, 4..8),\n});\n\n#[derive(Debug, Eq, PartialEq, Clone)]\npub struct Vfs {\n    /// Inode number\n    inode: u32,\n    /// Device number\n    device: u32,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<VfsBuffer<T>> for Vfs {\n    fn parse(buf: &VfsBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            inode: buf.inode(),\n            device: buf.device(),\n        })\n    }\n}\n\nimpl Emitable for Vfs {\n    fn buffer_len(&self) -> usize {\n        VFS_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = VfsBuffer::new(buf);\n        buf.set_inode(self.inode);\n        buf.set_device(self.device);\n    }\n}\n\npub const MEM_INFO_LEN: usize = 36;\n\nbuffer!(MemInfoBuffer(MEM_INFO_LEN) {\n    unused_sk_rmem_alloc: (u32, 0..4),\n    so_rcvbuf: (u32, 4..8),\n    unused_sk_wmem_queued: (u32, 8..12),\n    max_datagram_size: (u32, 12..16),\n    unused_sk_fwd_alloc: (u32, 16..20),\n    alloc: (u32, 20..24),\n    unused_sk_optmem: (u32, 24..28),\n    unused_backlog: (u32, 28..32),\n    unused_drops: (u32, 32..36),\n});\n\n/// # Warning\n///\n/// I don't have a good understanding of the Unix Domain Sockets, thus\n/// take the following documentation with a *huge* grain of salt.\n///\n/// # Documentation\n///\n/// ## `UNIX_DIAG_MEMINFO` vs `INET_DIAG_SK_MEMINFO`\n///\n/// `MemInfo` represent an `UNIX_DIAG_MEMINFO` NLA. This NLA has the\n/// same structure than `INET_DIAG_SKMEMINFO`, but since Unix sockets\n/// don't actually use the network stack, many fields are not relevant\n/// and are always set to 0. According to iproute2 commit\n/// [51ff9f2453d066933f24170f0106a7deeefa02d9](https://patchwork.ozlabs.org/patch/222700/), only three attributes can have non-zero values.\n///\n/// ## Particularities of UNIX sockets\n///\n/// One particularity of UNIX sockets is that they don't really have a\n/// send queue: when sending data, the kernel finds the destination\n/// socket and enqueues the data directly in its receive queue (which\n/// [see also this StackOverflow\n/// answer](https://stackoverflow.com/questions/9644251/how-do-unix-domain-sockets-differentiate-between-multiple-clients)). For\n/// instance in `unix_dgram_sendmsg()` in `net/unix/af_unix.c` we\n/// have:\n///\n/// ```c\n/// // `other` refers to the peer socket here\n/// skb_queue_tail(&other->sk_receive_queue, skb);\n/// ```\n///\n/// Another particularity is that the kernel keeps track of the memory\n/// using the sender's `sock.sk_wmem_alloc` attribute. The receiver's\n/// `sock.sk_rmem_alloc` is always zero. Memory is allocated when data\n/// is written to a socket, and is reclaimed when the data is read\n/// from the peer's socket.\n///\n/// Last but not least, the way unix sockets handle incoming\n/// connection differs from the TCP sockets. For TCP sockets, the\n/// queue used to store pending connections is\n/// `sock.sk_ack_backlog`. But UNIX sockets use the receive queue to\n/// store them. They can do that because a listening socket only\n/// receive connections, they do not receive actual data from other\n/// socket, so there is no ambiguity about the nature of the data\n/// stored in the receive queue.\n// /// We can see that in `unix_stream_sendmsg()` for instance we have\n// /// the follownig function calls:\n// ///\n// /// ```\n// /// unix_stream_sendmsg()\n// ///     -> sock_alloc_send_pskb()\n// ///     -> skb_set_owner_w()\n// ///     -> refcount_add(size, &sk->sk_wmem_alloc);\n/// ```\n#[derive(Debug, PartialEq, Eq, Copy, Clone)]\npub struct MemInfo {\n    /// Value of `SO_RCVBUF`, although it does not have any effect on\n    /// Unix Domain Sockets. As per `man unix(7)`:\n    ///\n    /// > The `SO_SNDBUF` socket option does have an effect for UNIX\n    /// > domain sockets, but the `SO_RCVBUF` option does not.\n    ///\n    /// This attribute corresponds to `sock.sk_rcvbuf` in the kernel.\n    pub so_rcvbuf: u32,\n    /// Maximum size in in bytes of a datagram, as set by\n    /// `SO_SNDBUF`. As per `man unix(7)`:\n    ///\n    /// > For datagram sockets, the `SO_SNDBUF` value imposes an upper\n    /// > limit on the size of outgoing datagrams. This limit is\n    /// > calculated as the doubled (see `socket(7)`) option value\n    /// > less 32 bytes used for overhead.\n    ///\n    /// This attribute corresponds to `sock.sk_sndbuf` in the kernel.\n    pub max_datagram_size: u32,\n    /// Memory currently allocated for the data sent but not yet read\n    /// from the receiving socket(s). The memory is tracked using the\n    /// sending socket `sock.sk_wmem_queued` attribute in the kernel.\n    ///\n    /// Note that this quantity is a little larger than the actual\n    /// data being sent because it takes into account the overhead of\n    /// the `sk_buff`s used internally:\n    ///\n    /// ```c\n    /// /* in net/core/sock.c, sk_wmem_alloc is set in\n    ///    skb_set_owner_w() with: */\n    /// refcount_add(skb->truesize, &sk->sk_wmem_alloc);\n    ///\n    /// /* truesize is set by __alloc_skb() in net/core/skbuff.c\n    ///    by: */\n    /// skb->truesize = SKB_TRUESIZE(size);\n    ///\n    /// /* and SKB_TRUESIZE is defined as: */\n    /// #define SKB_TRUESIZE(X) ((X) +                        \\\n    ///     SKB_DATA_ALIGN(sizeof(struct sk_buff)) +          \\\n    ///     SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))\n    /// ```\n    pub alloc: u32,\n}\n\nimpl<T: AsRef<[u8]>> Parseable<MemInfoBuffer<T>> for MemInfo {\n    fn parse(buf: &MemInfoBuffer<T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            so_rcvbuf: buf.so_rcvbuf(),\n            max_datagram_size: buf.max_datagram_size(),\n            alloc: buf.alloc(),\n        })\n    }\n}\n\nimpl Emitable for MemInfo {\n    fn buffer_len(&self) -> usize {\n        MEM_INFO_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = MemInfoBuffer::new(buf);\n        buf.set_unused_sk_rmem_alloc(0);\n        buf.set_so_rcvbuf(self.so_rcvbuf);\n        buf.set_unused_sk_wmem_queued(0);\n        buf.set_max_datagram_size(self.max_datagram_size);\n        buf.set_unused_sk_fwd_alloc(0);\n        buf.set_alloc(self.alloc);\n        buf.set_unused_sk_optmem(0);\n        buf.set_unused_backlog(0);\n        buf.set_unused_drops(0);\n    }\n}\n\nimpl crate::utils::nla::Nla for Nla {\n    fn value_len(&self) -> usize {\n        use self::Nla::*;\n        match *self {\n            // +1 because we need to append a null byte\n            Name(ref s) => s.as_bytes().len() + 1,\n            Vfs(_) => VFS_LEN,\n            Peer(_) => 4,\n            PendingConnections(ref v) => 4 * v.len(),\n            ReceiveQueueLength(_, _) => 8,\n            MemInfo(_) => MEM_INFO_LEN,\n            Shutdown(_) => 1,\n            Other(ref attr) => attr.value_len(),\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        use self::Nla::*;\n        match *self {\n            Name(ref s) => {\n                buffer[..s.len()].copy_from_slice(s.as_bytes());\n                buffer[s.len()] = 0;\n            }\n            Vfs(ref value) => value.emit(buffer),\n            Peer(value) => NativeEndian::write_u32(buffer, value),\n            PendingConnections(ref values) => {\n                for (i, v) in values.iter().enumerate() {\n                    NativeEndian::write_u32(&mut buffer[i * 4..], *v);\n                }\n            }\n            ReceiveQueueLength(v1, v2) => {\n                NativeEndian::write_u32(buffer, v1);\n                NativeEndian::write_u32(&mut buffer[4..], v2);\n            }\n            MemInfo(ref value) => value.emit(buffer),\n            Shutdown(value) => buffer[0] = value,\n            Other(ref attr) => attr.emit_value(buffer),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        use self::Nla::*;\n        match *self {\n            Name(_) => UNIX_DIAG_NAME,\n            Vfs(_) => UNIX_DIAG_VFS,\n            Peer(_) => UNIX_DIAG_PEER,\n            PendingConnections(_) => UNIX_DIAG_ICONS,\n            ReceiveQueueLength(_, _) => UNIX_DIAG_RQLEN,\n            MemInfo(_) => UNIX_DIAG_MEMINFO,\n            Shutdown(_) => UNIX_DIAG_SHUTDOWN,\n            Other(ref attr) => attr.kind(),\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            UNIX_DIAG_NAME => {\n                let err = \"invalid UNIX_DIAG_NAME value\";\n                Self::Name(parse_string(payload).context(err)?)\n            }\n            UNIX_DIAG_VFS => {\n                let err = \"invalid UNIX_DIAG_VFS value\";\n                let buf = VfsBuffer::new_checked(payload).context(err)?;\n                Self::Vfs(Vfs::parse(&buf).context(err)?)\n            }\n            UNIX_DIAG_PEER => {\n                Self::Peer(parse_u32(payload).context(\"invalid UNIX_DIAG_PEER value\")?)\n            }\n            UNIX_DIAG_ICONS => {\n                if payload.len() % 4 != 0 {\n                    return Err(DecodeError::from(\"invalid UNIX_DIAG_ICONS\"));\n                }\n                Self::PendingConnections(payload.chunks(4).map(NativeEndian::read_u32).collect())\n            }\n            UNIX_DIAG_RQLEN => {\n                if payload.len() != 8 {\n                    return Err(DecodeError::from(\"invalid UNIX_DIAG_RQLEN\"));\n                }\n                Self::ReceiveQueueLength(\n                    NativeEndian::read_u32(&payload[..4]),\n                    NativeEndian::read_u32(&payload[4..]),\n                )\n            }\n            UNIX_DIAG_MEMINFO => {\n                let err = \"invalid UNIX_DIAG_MEMINFO value\";\n                let buf = MemInfoBuffer::new_checked(payload).context(err)?;\n                Self::MemInfo(MemInfo::parse(&buf).context(err)?)\n            }\n            UNIX_DIAG_SHUTDOWN => {\n                Self::Shutdown(parse_u8(payload).context(\"invalid UNIX_DIAG_SHUTDOWN value\")?)\n            }\n            kind => {\n                Self::Other(DefaultNla::parse(buf).context(format!(\"unknown NLA type {}\", kind))?)\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/unix/request.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::convert::TryFrom;\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\npub const UNIX_REQUEST_LEN: usize = 24;\n\nbuffer!(UnixRequestBuffer(UNIX_REQUEST_LEN) {\n    // The address family; it should be set to `AF_UNIX`\n    family: (u8, 0),\n    // This field should be set to `0`\n    protocol: (u8, 1),\n    // This field should be set to `0`\n    pad: (u16, 2..4),\n    // This is a bit mask that defines a filter of sockets\n    // states. Only those sockets whose states are in this mask will\n    // be reported. Ignored when querying for an individual\n    // socket. Supported values are:\n    //\n    // ```no_rust\n    // 1 << UNIX_ESTABLISHED\n    // 1 << UNIX_LISTEN\n    // ```\n    state_flags: (u32, 4..8),\n    // This is an inode number when querying for an individual\n    // socket. Ignored when querying for a list of sockets.\n    inode: (u32, 8..12),\n    // This is a set of flags defining what kind of information to\n    // report. Supported values are the `UDIAG_SHOW_*` constants.\n    show_flags: (u32, 12..16),\n    // This is an array of opaque identifiers that could be used\n    // along with udiag_ino to specify an individual socket. It is\n    // ignored when querying for a list of sockets, as well as when\n    // all its elements are set to `0xff`.\n    cookie: (slice, 16..UNIX_REQUEST_LEN),\n});\n\n/// The request for UNIX domain sockets\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct UnixRequest {\n    /// This is a bit mask that defines a filter of sockets states.\n    ///\n    /// Only those sockets whose states are in this mask will be reported.\n    /// Ignored when querying for an individual socket.\n    pub state_flags: StateFlags,\n    /// This is an inode number when querying for an individual socket.\n    ///\n    /// Ignored when querying for a list of sockets.\n    pub inode: u32,\n    /// This is a set of flags defining what kind of information to report.\n    ///\n    /// Each requested kind of information is reported back as a netlink attribute\n    pub show_flags: ShowFlags,\n    /// This is an opaque identifiers that could be used to specify an individual socket.\n    pub cookie: [u8; 8],\n}\n\nbitflags! {\n    /// Bitmask that defines a filter of UNIX socket states\n    pub struct StateFlags: u32 {\n        const ESTABLISHED = 1 << TCP_ESTABLISHED;\n        const LISTEN = 1 << TCP_LISTEN;\n    }\n}\n\nbitflags! {\n    /// Bitmask that defines what kind of information to\n    /// report. Supported values are the `UDIAG_SHOW_*` constants.\n    pub struct ShowFlags: u32 {\n        const NAME = UDIAG_SHOW_NAME;\n        const VFS = UDIAG_SHOW_VFS;\n        const PEER = UDIAG_SHOW_PEER;\n        const ICONS = UDIAG_SHOW_ICONS;\n        const RQLEN = UDIAG_SHOW_RQLEN;\n        const MEMINFO = UDIAG_SHOW_MEMINFO;\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + 'a> Parseable<UnixRequestBuffer<&'a T>> for UnixRequest {\n    fn parse(buf: &UnixRequestBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            state_flags: StateFlags::from_bits_truncate(buf.state_flags()),\n            inode: buf.inode(),\n            show_flags: ShowFlags::from_bits_truncate(buf.show_flags()),\n            // Unwrapping is safe because UnixRequestBuffer::cookie()\n            // returns a slice of exactly 8 bytes.\n            cookie: TryFrom::try_from(buf.cookie()).unwrap(),\n        })\n    }\n}\n\nimpl Emitable for UnixRequest {\n    fn buffer_len(&self) -> usize {\n        UNIX_REQUEST_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buffer = UnixRequestBuffer::new(buf);\n        buffer.set_family(AF_UNIX);\n        buffer.set_protocol(0);\n        buffer.set_state_flags(self.state_flags.bits());\n        buffer.set_inode(self.inode);\n        buffer.set_pad(0);\n        buffer.set_show_flags(self.show_flags.bits());\n        buffer.cookie_mut().copy_from_slice(&self.cookie[..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/unix/response.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::Context;\nuse smallvec::SmallVec;\nuse std::convert::TryFrom;\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, Parseable},\n    unix::nlas::{MemInfo, Nla, NlaBuffer, NlasIterator},\n    DecodeError,\n};\n\npub const UNIX_RESPONSE_HEADER_LEN: usize = 16;\n\nbuffer!(UnixResponseBuffer(UNIX_RESPONSE_HEADER_LEN) {\n    family: (u8, 0),\n    kind: (u8, 1),\n    state: (u8, 2),\n    pad: (u8, 3),\n    inode: (u32, 4..8),\n    cookie: (slice, 8..UNIX_RESPONSE_HEADER_LEN),\n    payload: (slice, UNIX_RESPONSE_HEADER_LEN..),\n});\n\n/// The response to a query for IPv4 or IPv6 sockets\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct UnixResponseHeader {\n    /// One of `SOCK_PACKET`, `SOCK_STREAM`, or `SOCK_SEQPACKET`\n    pub kind: u8,\n    /// State of the socket. According to `man 7 sock_diag` it can be\n    /// either `TCP_ESTABLISHED` or `TCP_LISTEN`. However datagram\n    /// UNIX sockets are not connection oriented so I would assume\n    /// that this field can also take other value (maybe `0`) for\n    /// these sockets.\n    pub state: u8,\n    /// Socket inode number.\n    pub inode: u32,\n    pub cookie: [u8; 8],\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for UnixResponseHeader {\n    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        Ok(Self {\n            kind: buf.kind(),\n            state: buf.state(),\n            inode: buf.inode(),\n            // Unwrapping is safe because UnixResponseBuffer::cookie()\n            // returns a slice of exactly 8 bytes.\n            cookie: TryFrom::try_from(buf.cookie()).unwrap(),\n        })\n    }\n}\n\nimpl Emitable for UnixResponseHeader {\n    fn buffer_len(&self) -> usize {\n        UNIX_RESPONSE_HEADER_LEN\n    }\n\n    fn emit(&self, buf: &mut [u8]) {\n        let mut buf = UnixResponseBuffer::new(buf);\n        buf.set_family(AF_UNIX as u8);\n        buf.set_kind(self.kind);\n        buf.set_state(self.state);\n        buf.set_pad(0);\n        buf.set_inode(self.inode);\n        buf.cookie_mut().copy_from_slice(&self.cookie[..]);\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct UnixResponse {\n    pub header: UnixResponseHeader,\n    pub nlas: SmallVec<[Nla; 8]>,\n}\n\nimpl UnixResponse {\n    pub fn peer(&self) -> Option<u32> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Peer(inode) = nla {\n                Some(*inode)\n            } else {\n                None\n            }\n        })\n    }\n\n    pub fn name(&self) -> Option<&String> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Name(name) = nla {\n                Some(name)\n            } else {\n                None\n            }\n        })\n    }\n\n    pub fn pending_connections(&self) -> Option<&[u32]> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::PendingConnections(connections) = nla {\n                Some(&connections[..])\n            } else {\n                None\n            }\n        })\n    }\n\n    fn mem_info(&self) -> Option<MemInfo> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::MemInfo(mem_info) = nla {\n                Some(*mem_info)\n            } else {\n                None\n            }\n        })\n    }\n\n    pub fn shutdown_state(&self) -> Option<u8> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::Shutdown(shutdown_state) = nla {\n                Some(*shutdown_state)\n            } else {\n                None\n            }\n        })\n    }\n\n    fn receive_queue_length(&self) -> Option<(u32, u32)> {\n        self.nlas.iter().find_map(|nla| {\n            if let Nla::ReceiveQueueLength(x, y) = nla {\n                Some((*x, *y))\n            } else {\n                None\n            }\n        })\n    }\n\n    pub fn number_of_pending_connection(&self) -> Option<u32> {\n        if self.header.state == TCP_LISTEN {\n            self.receive_queue_length().map(|(n, _)| n)\n        } else {\n            None\n        }\n    }\n\n    pub fn max_number_of_pending_connection(&self) -> Option<u32> {\n        if self.header.state == TCP_LISTEN {\n            self.receive_queue_length().map(|(_, n)| n)\n        } else {\n            None\n        }\n    }\n\n    pub fn receive_queue_size(&self) -> Option<u32> {\n        if self.header.state == TCP_LISTEN {\n            None\n        } else {\n            self.receive_queue_length().map(|(n, _)| n)\n        }\n    }\n\n    pub fn send_queue_size(&self) -> Option<u32> {\n        if self.header.state == TCP_LISTEN {\n            self.receive_queue_length().map(|(n, _)| n)\n        } else {\n            None\n        }\n    }\n\n    pub fn max_datagram_size(&self) -> Option<u32> {\n        self.mem_info().map(|mem_info| mem_info.max_datagram_size)\n    }\n\n    pub fn memory_used_for_outgoing_data(&self) -> Option<u32> {\n        self.mem_info().map(|mem_info| mem_info.alloc)\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> UnixResponseBuffer<&'a T> {\n    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {\n        NlasIterator::new(self.payload())\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for SmallVec<[Nla; 8]> {\n    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let mut nlas = smallvec![];\n        for nla_buf in buf.nlas() {\n            nlas.push(Nla::parse(&nla_buf?)?);\n        }\n        Ok(nlas)\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for UnixResponse {\n    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let header =\n            UnixResponseHeader::parse(buf).context(\"failed to parse inet response header\")?;\n        let nlas =\n            SmallVec::<[Nla; 8]>::parse(buf).context(\"failed to parse inet response NLAs\")?;\n        Ok(UnixResponse { header, nlas })\n    }\n}\n\nimpl Emitable for UnixResponse {\n    fn buffer_len(&self) -> usize {\n        self.header.buffer_len() + self.nlas.as_slice().buffer_len()\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        self.header.emit(buffer);\n        self.nlas\n            .as_slice()\n            .emit(&mut buffer[self.header.buffer_len()..]);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-sock-diag/src/unix/tests.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    traits::{Emitable, Parseable},\n    unix::{\n        nlas::Nla,\n        ShowFlags,\n        StateFlags,\n        UnixRequest,\n        UnixResponse,\n        UnixResponseBuffer,\n        UnixResponseHeader,\n    },\n};\n\nlazy_static! {\n    static ref SOCKET_INFO: UnixRequest = UnixRequest {\n        state_flags: StateFlags::all(),\n        inode: 0x1234,\n        show_flags: ShowFlags::PEER,\n        cookie: [0xff; 8]\n    };\n}\n\n#[rustfmt::skip]\nstatic SOCKET_INFO_BUF: [u8; 24] = [\n    0x01, // family: AF_UNIX\n    0x00, // protocol\n    0x00, 0x00, // padding\n    0x02, 0x04, 0x00, 0x00, // state_flags - 1 << TCP_ESTABLISHED | 1 << TCP_LISTEN\n    0x34, 0x12, 0x00, 0x00, // inode number\n    0x04, 0x00, 0x00, 0x00, // show_flags - UDIAG_SHOW_PEER\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // cookie\n];\n\nlazy_static! {\n    static ref LISTENING: UnixResponse = UnixResponse {\n        header: UnixResponseHeader {\n            kind: SOCK_STREAM,\n            state: TCP_LISTEN,\n            inode: 20238,\n            cookie: [0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],\n        },\n        nlas: smallvec![\n            Nla::Name(\"/tmp/.ICE-unix/1151\".to_string()),\n            Nla::ReceiveQueueLength(0, 128),\n            Nla::Shutdown(0),\n        ]\n    };\n}\n\n#[rustfmt::skip]\nstatic LISTENING_BUF: [u8; 60] = [\n    0x01, // family: AF_UNIX\n    0x01, // type: SOCK_STREAM\n    0x0a, // state: TCP_LISTEN\n    0x00, // padding\n    0x0e, 0x4f, 0x00, 0x00, // inode number\n    0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cookie\n\n    // NLAs\n    0x18, 0x00, // length: 24\n    0x00, 0x00, // type: UNIX_DIAG_NAME\n    // value: /tmp/.ICE-unix/1151\n    0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x2e, 0x49, 0x43, 0x45, 0x2d, 0x75, 0x6e, 0x69, 0x78, 0x2f, 0x31, 0x31, 0x35, 0x31, 0x00,\n\n    0x0c, 0x00, // length: 12\n    0x04, 0x00, // type: UNIX_DIAG_RQLEN\n    // value: ReceiveQueueLength(0, 128)\n    0x00, 0x00, 0x00, 0x00,\n    0x80, 0x00, 0x00, 0x00,\n\n    0x05, 0x00, // length: 5\n    0x06, 0x00, // type: UNIX_DIAG_SHUTDOWN\n    0x00, // value: 0\n    0x00, 0x00, 0x00 // padding\n];\n\n#[test]\nfn parse_listening() {\n    let parsed =\n        UnixResponse::parse(&UnixResponseBuffer::new_checked(&&LISTENING_BUF[..]).unwrap())\n            .unwrap();\n    assert_eq!(parsed, *LISTENING);\n}\n\n#[test]\nfn emit_listening() {\n    assert_eq!(LISTENING.buffer_len(), 60);\n    // Initialize the buffer with 0xff to check that padding bytes are\n    // set to 0\n    let mut buf = vec![0xff; LISTENING.buffer_len()];\n    LISTENING.emit(&mut buf);\n    assert_eq!(&buf[..], &LISTENING_BUF[..]);\n}\n\nlazy_static! {\n    static ref ESTABLISHED: UnixResponse = UnixResponse {\n        header: UnixResponseHeader {\n            kind: SOCK_STREAM,\n            state: TCP_ESTABLISHED,\n            inode: 31927,\n            cookie: [0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]\n        },\n        nlas: smallvec![\n            Nla::Name(\"/run/user/1000/bus\".to_string()),\n            Nla::Peer(31062),\n            Nla::ReceiveQueueLength(0, 0),\n            Nla::Shutdown(0),\n        ]\n    };\n}\n\n#[rustfmt::skip]\nstatic ESTABLISHED_BUF: [u8; 68] = [\n    0x01, // family: AF_LOCAL\n    0x01, // kind: SOCK_STREAM,\n    0x01, // state: TCP_ESTABLISHED\n    0x00, // padding\n    0xb7, 0x7c, 0x00, 0x00, // inode: 31927\n    0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cookie\n\n    // NLAs\n\n    0x17, 0x00, // length: 23\n    0x00, 0x00, // type: UNIX_DIAG_NAME\n    // value: /run/user/1000/bus\n    0x2f, 0x72, 0x75, 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x31, 0x30, 0x30, 0x30, 0x2f, 0x62, 0x75, 0x73, 0x00,\n    0x00, // padding\n\n    0x08, 0x00, // length: 8\n    0x02, 0x00, // type: UNIX_DIAG_PEER\n    0x56, 0x79, 0x00, 0x00, // value: 31062\n\n    0x0c, 0x00, // length: 12\n    0x04, 0x00, // type: UNIX_DIAG_RQLEN\n    // value: ReceiveQueueLength(0, 0)\n    0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00,\n\n    0x05, 0x00, // length: 5\n    0x06, 0x00, // type: UNIX_DIAG_SHUTDOWN\n    0x00, 0x00, 0x00, 0x00 // value: 0\n];\n\n#[test]\nfn parse_established() {\n    let parsed =\n        UnixResponse::parse(&UnixResponseBuffer::new_checked(&&ESTABLISHED_BUF[..]).unwrap())\n            .unwrap();\n    assert_eq!(parsed, *ESTABLISHED);\n}\n\n#[test]\nfn emit_established() {\n    assert_eq!(ESTABLISHED.buffer_len(), 68);\n    let mut buf = vec![0xff; ESTABLISHED.buffer_len()];\n    ESTABLISHED.emit(&mut buf);\n    assert_eq!(&buf[..], &ESTABLISHED_BUF[..]);\n}\n\n#[test]\nfn emit_socket_info() {\n    assert_eq!(SOCKET_INFO.buffer_len(), 24);\n    let mut buf = vec![0xff; SOCKET_INFO.buffer_len()];\n    SOCKET_INFO.emit(&mut buf);\n    assert_eq!(&buf[..], &SOCKET_INFO_BUF[..]);\n}\n"
  },
  {
    "path": "netlink-packet-utils/Cargo.toml",
    "content": "[package]\nname = \"netlink-packet-utils\"\nversion = \"0.5.1\"\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nedition = \"2018\"\nhomepage = \"https://github.com/little-dude/netlink\"\nrepository = \"https://github.com/little-dude/netlink\"\nlicense = \"MIT\"\ndescription = \"macros and helpers for parsing netlink messages\"\n\n\n[dependencies]\nanyhow = \"1.0.31\"\nbyteorder = \"1.3.2\"\npaste = \"1.0\"\nthiserror = \"1\"\n"
  },
  {
    "path": "netlink-packet-utils/src/errors.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse anyhow::anyhow;\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\n#[error(\"Encode error occurred: {inner}\")]\npub struct EncodeError {\n    inner: anyhow::Error,\n}\n\nimpl From<&'static str> for EncodeError {\n    fn from(msg: &'static str) -> Self {\n        EncodeError {\n            inner: anyhow!(msg),\n        }\n    }\n}\n\nimpl From<String> for EncodeError {\n    fn from(msg: String) -> Self {\n        EncodeError {\n            inner: anyhow!(msg),\n        }\n    }\n}\n\nimpl From<anyhow::Error> for EncodeError {\n    fn from(inner: anyhow::Error) -> EncodeError {\n        EncodeError { inner }\n    }\n}\n\n#[derive(Debug, Error)]\n#[error(\"Decode error occurred: {inner}\")]\npub struct DecodeError {\n    inner: anyhow::Error,\n}\n\nimpl From<&'static str> for DecodeError {\n    fn from(msg: &'static str) -> Self {\n        DecodeError {\n            inner: anyhow!(msg),\n        }\n    }\n}\n\nimpl From<String> for DecodeError {\n    fn from(msg: String) -> Self {\n        DecodeError {\n            inner: anyhow!(msg),\n        }\n    }\n}\n\nimpl From<anyhow::Error> for DecodeError {\n    fn from(inner: anyhow::Error) -> DecodeError {\n        DecodeError { inner }\n    }\n}\n"
  },
  {
    "path": "netlink-packet-utils/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub extern crate byteorder;\npub extern crate paste;\n\n#[macro_use]\nmod macros;\n\npub mod errors;\npub use self::errors::{DecodeError, EncodeError};\n\npub mod parsers;\n\npub mod traits;\npub use self::traits::*;\n\npub mod nla;\n"
  },
  {
    "path": "netlink-packet-utils/src/macros.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_export(local_inner_macros)]\nmacro_rules! getter {\n    ($buffer: ident, $name:ident, slice, $offset:expr) => {\n        impl<'a, T: AsRef<[u8]> + ?Sized> $buffer<&'a T> {\n            pub fn $name(&self) -> &'a [u8] {\n                &self.buffer.as_ref()[$offset]\n            }\n        }\n    };\n    ($buffer: ident, $name:ident, $ty:tt, $offset:expr) => {\n        impl<'a, T: AsRef<[u8]>> $buffer<T> {\n            getter!($name, $ty, $offset);\n        }\n    };\n    ($name:ident, u8, $offset:expr) => {\n        pub fn $name(&self) -> u8 {\n            self.buffer.as_ref()[$offset]\n        }\n    };\n    ($name:ident, u16, $offset:expr) => {\n        pub fn $name(&self) -> u16 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_u16(&self.buffer.as_ref()[$offset])\n        }\n    };\n    ($name:ident, u32, $offset:expr) => {\n        pub fn $name(&self) -> u32 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_u32(&self.buffer.as_ref()[$offset])\n        }\n    };\n    ($name:ident, u64, $offset:expr) => {\n        pub fn $name(&self) -> u64 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_u64(&self.buffer.as_ref()[$offset])\n        }\n    };\n    ($name:ident, i8, $offset:expr) => {\n        pub fn $name(&self) -> i8 {\n            self.buffer.as_ref()[$offset]\n        }\n    };\n    ($name:ident, i16, $offset:expr) => {\n        pub fn $name(&self) -> i16 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_i16(&self.buffer.as_ref()[$offset])\n        }\n    };\n    ($name:ident, i32, $offset:expr) => {\n        pub fn $name(&self) -> i32 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_i32(&self.buffer.as_ref()[$offset])\n        }\n    };\n    ($name:ident, i64, $offset:expr) => {\n        pub fn $name(&self) -> i64 {\n            use $crate::byteorder::{ByteOrder, NativeEndian};\n            NativeEndian::read_i64(&self.buffer.as_ref()[$offset])\n        }\n    };\n}\n\n#[macro_export(local_inner_macros)]\nmacro_rules! setter {\n    ($buffer: ident, $name:ident, slice, $offset:expr) => {\n        impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $buffer<&'a mut T> {\n            $crate::paste::item! {\n                pub fn [<$name _mut>](&mut self) -> &mut [u8] {\n                    &mut self.buffer.as_mut()[$offset]\n                }\n            }\n        }\n    };\n    ($buffer: ident, $name:ident, $ty:tt, $offset:expr) => {\n        impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> $buffer<T> {\n            setter!($name, $ty, $offset);\n        }\n    };\n    ($name:ident, u8, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: u8) {\n                self.buffer.as_mut()[$offset] = value;\n            }\n        }\n    };\n    ($name:ident, u16, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: u16) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_u16(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n    ($name:ident, u32, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: u32) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_u32(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n    ($name:ident, u64, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: u64) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_u64(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n    ($name:ident, i8, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: i8) {\n                self.buffer.as_mut()[$offset] = value;\n            }\n        }\n    };\n    ($name:ident, i16, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: i16) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_i16(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n    ($name:ident, i32, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: i32) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_i32(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n    ($name:ident, i64, $offset:expr) => {\n        $crate::paste::item! {\n            pub fn [<set_ $name>](&mut self, value: i64) {\n                use $crate::byteorder::{ByteOrder, NativeEndian};\n                NativeEndian::write_i64(&mut self.buffer.as_mut()[$offset], value)\n            }\n        }\n    };\n}\n\n#[macro_export(local_inner_macros)]\nmacro_rules! buffer {\n    ($name:ident($buffer_len:expr) { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {\n        buffer!($name { $($field: ($ty, $offset),)* });\n        buffer_check_length!($name($buffer_len));\n    };\n\n    ($name:ident { $($field:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {\n        buffer_common!($name);\n        fields!($name {\n            $($field: ($ty, $offset),)*\n        });\n    };\n\n    ($name:ident, $buffer_len:expr) => {\n        buffer_common!($name);\n        buffer_check_length!($name($buffer_len));\n    };\n\n    ($name:ident) => {\n        buffer_common!($name);\n    };\n}\n\n#[macro_export(local_inner_macros)]\nmacro_rules! fields {\n    ($buffer:ident { $($name:ident : ($ty:tt, $offset:expr)),* $(,)? }) => {\n        $(\n            getter!($buffer, $name, $ty, $offset);\n        )*\n\n            $(\n                setter!($buffer, $name, $ty, $offset);\n            )*\n    }\n}\n\n#[macro_export]\nmacro_rules! buffer_check_length {\n    ($name:ident($buffer_len:expr)) => {\n        impl<T: AsRef<[u8]>> $name<T> {\n            pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {\n                let packet = Self::new(buffer);\n                packet.check_buffer_length()?;\n                Ok(packet)\n            }\n\n            fn check_buffer_length(&self) -> Result<(), DecodeError> {\n                let len = self.buffer.as_ref().len();\n                if len < $buffer_len {\n                    Err(format!(\n                        concat!(\"invalid \", stringify!($name), \": length {} < {}\"),\n                        len, $buffer_len\n                    )\n                    .into())\n                } else {\n                    Ok(())\n                }\n            }\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! buffer_common {\n    ($name:ident) => {\n        #[derive(Debug, PartialEq, Eq, Clone, Copy)]\n        pub struct $name<T> {\n            buffer: T,\n        }\n\n        impl<T: AsRef<[u8]>> $name<T> {\n            pub fn new(buffer: T) -> Self {\n                Self { buffer }\n            }\n\n            pub fn into_inner(self) -> T {\n                self.buffer\n            }\n        }\n\n        impl<'a, T: AsRef<[u8]> + ?Sized> $name<&'a T> {\n            pub fn inner(&self) -> &'a [u8] {\n                &self.buffer.as_ref()[..]\n            }\n        }\n\n        impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> $name<&'a mut T> {\n            pub fn inner_mut(&mut self) -> &mut [u8] {\n                &mut self.buffer.as_mut()[..]\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "netlink-packet-utils/src/nla.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse core::ops::Range;\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\n\nuse crate::{\n    traits::{Emitable, Parseable},\n    DecodeError,\n};\n\n/// Represent a multi-bytes field with a fixed size in a packet\ntype Field = Range<usize>;\n\n/// Identify the bits that represent the \"nested\" flag of a netlink attribute.\npub const NLA_F_NESTED: u16 = 0x8000;\n/// Identify the bits that represent the \"byte order\" flag of a netlink attribute.\npub const NLA_F_NET_BYTEORDER: u16 = 0x4000;\n/// Identify the bits that represent the type of a netlink attribute.\npub const NLA_TYPE_MASK: u16 = !(NLA_F_NET_BYTEORDER | NLA_F_NESTED);\n/// NlA(RTA) align size\npub const NLA_ALIGNTO: usize = 4;\n/// NlA(RTA) header size. (unsigned short rta_len) + (unsigned short rta_type)\npub const NLA_HEADER_SIZE: usize = 4;\n\n#[macro_export]\nmacro_rules! nla_align {\n    ($len: expr) => {\n        ($len + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)\n    };\n}\n\nconst LENGTH: Field = 0..2;\nconst TYPE: Field = 2..4;\n#[allow(non_snake_case)]\nfn VALUE(length: usize) -> Field {\n    TYPE.end..TYPE.end + length\n}\n\n// with Copy, NlaBuffer<&'buffer T> can be copied, which turns out to be pretty conveninent. And since it's\n// boils down to copying a reference it's pretty cheap\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct NlaBuffer<T: AsRef<[u8]>> {\n    buffer: T,\n}\n\nimpl<T: AsRef<[u8]>> NlaBuffer<T> {\n    pub fn new(buffer: T) -> NlaBuffer<T> {\n        NlaBuffer { buffer }\n    }\n\n    pub fn new_checked(buffer: T) -> Result<NlaBuffer<T>, DecodeError> {\n        let buffer = Self::new(buffer);\n        buffer.check_buffer_length().context(\"invalid NLA buffer\")?;\n        Ok(buffer)\n    }\n\n    pub fn check_buffer_length(&self) -> Result<(), DecodeError> {\n        let len = self.buffer.as_ref().len();\n        if len < TYPE.end {\n            Err(format!(\n                \"buffer has length {}, but an NLA header is {} bytes\",\n                len, TYPE.end\n            )\n            .into())\n        } else if len < self.length() as usize {\n            Err(format!(\n                \"buffer has length: {}, but the NLA is {} bytes\",\n                len,\n                self.length()\n            )\n            .into())\n        } else if (self.length() as usize) < TYPE.end {\n            Err(format!(\n                \"NLA has invalid length: {} (should be at least {} bytes\",\n                self.length(),\n                TYPE.end,\n            )\n            .into())\n        } else {\n            Ok(())\n        }\n    }\n\n    /// Consume the buffer, returning the underlying buffer.\n    pub fn into_inner(self) -> T {\n        self.buffer\n    }\n\n    /// Return a reference to the underlying buffer\n    pub fn inner(&mut self) -> &T {\n        &self.buffer\n    }\n\n    /// Return a mutable reference to the underlying buffer\n    pub fn inner_mut(&mut self) -> &mut T {\n        &mut self.buffer\n    }\n\n    /// Return the `type` field\n    pub fn kind(&self) -> u16 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u16(&data[TYPE]) & NLA_TYPE_MASK\n    }\n\n    pub fn nested_flag(&self) -> bool {\n        let data = self.buffer.as_ref();\n        (NativeEndian::read_u16(&data[TYPE]) & NLA_F_NESTED) != 0\n    }\n\n    pub fn network_byte_order_flag(&self) -> bool {\n        let data = self.buffer.as_ref();\n        (NativeEndian::read_u16(&data[TYPE]) & NLA_F_NET_BYTEORDER) != 0\n    }\n\n    /// Return the `length` field. The `length` field corresponds to the length of the nla\n    /// header (type and length fields, and the value field). However, it does not account for the\n    /// potential padding that follows the value field.\n    pub fn length(&self) -> u16 {\n        let data = self.buffer.as_ref();\n        NativeEndian::read_u16(&data[LENGTH])\n    }\n\n    /// Return the length of the `value` field\n    ///\n    /// # Panic\n    ///\n    /// This panics if the length field value is less than the attribut header size.\n    pub fn value_length(&self) -> usize {\n        self.length() as usize - TYPE.end\n    }\n}\n\nimpl<T: AsRef<[u8]> + AsMut<[u8]>> NlaBuffer<T> {\n    /// Set the `type` field\n    pub fn set_kind(&mut self, kind: u16) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[TYPE], kind & NLA_TYPE_MASK)\n    }\n\n    pub fn set_nested_flag(&mut self) {\n        let kind = self.kind();\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[TYPE], kind | NLA_F_NESTED)\n    }\n\n    pub fn set_network_byte_order_flag(&mut self) {\n        let kind = self.kind();\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[TYPE], kind | NLA_F_NET_BYTEORDER)\n    }\n\n    /// Set the `length` field\n    pub fn set_length(&mut self, length: u16) {\n        let data = self.buffer.as_mut();\n        NativeEndian::write_u16(&mut data[LENGTH], length)\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + ?Sized> NlaBuffer<&'buffer T> {\n    /// Return the `value` field\n    pub fn value(&self) -> &[u8] {\n        &self.buffer.as_ref()[VALUE(self.value_length())]\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> NlaBuffer<&'buffer mut T> {\n    /// Return the `value` field\n    pub fn value_mut(&mut self) -> &mut [u8] {\n        let length = VALUE(self.value_length());\n        &mut self.buffer.as_mut()[length]\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub struct DefaultNla {\n    kind: u16,\n    value: Vec<u8>,\n}\n\nimpl Nla for DefaultNla {\n    fn value_len(&self) -> usize {\n        self.value.len()\n    }\n    fn kind(&self) -> u16 {\n        self.kind\n    }\n    fn emit_value(&self, buffer: &mut [u8]) {\n        buffer.copy_from_slice(self.value.as_slice());\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>> for DefaultNla {\n    fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {\n        let mut kind = buf.kind();\n\n        if buf.network_byte_order_flag() {\n            kind |= NLA_F_NET_BYTEORDER;\n        }\n\n        if buf.nested_flag() {\n            kind |= NLA_F_NESTED;\n        }\n\n        Ok(DefaultNla {\n            kind,\n            value: buf.value().to_vec(),\n        })\n    }\n}\n\npub trait Nla {\n    fn value_len(&self) -> usize;\n    fn kind(&self) -> u16;\n    fn emit_value(&self, buffer: &mut [u8]);\n\n    #[inline]\n    fn is_nested(&self) -> bool {\n        (self.kind() & NLA_F_NESTED) != 0\n    }\n\n    #[inline]\n    fn is_network_byteorder(&self) -> bool {\n        (self.kind() & NLA_F_NET_BYTEORDER) != 0\n    }\n}\n\nimpl<T: Nla> Emitable for T {\n    fn buffer_len(&self) -> usize {\n        nla_align!(self.value_len()) + NLA_HEADER_SIZE\n    }\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut buffer = NlaBuffer::new(buffer);\n        buffer.set_kind(self.kind());\n\n        if self.is_network_byteorder() {\n            buffer.set_network_byte_order_flag()\n        }\n\n        if self.is_nested() {\n            buffer.set_nested_flag()\n        }\n\n        // do not include the padding here, but do include the header\n        buffer.set_length(self.value_len() as u16 + NLA_HEADER_SIZE as u16);\n\n        self.emit_value(buffer.value_mut());\n\n        let padding = nla_align!(self.value_len()) - self.value_len();\n        for i in 0..padding {\n            buffer.inner_mut()[NLA_HEADER_SIZE + self.value_len() + i] = 0;\n        }\n    }\n}\n\n// FIXME: whern specialization lands, why can actually have\n//\n// impl<'a, T: Nla, I: Iterator<Item=T>> Emitable for I { ...}\n//\n// The reason this does not work today is because it conflicts with\n//\n// impl<T: Nla> Emitable for T { ... }\nimpl<'a, T: Nla> Emitable for &'a [T] {\n    fn buffer_len(&self) -> usize {\n        self.iter().fold(0, |acc, nla| {\n            assert_eq!(nla.buffer_len() % NLA_ALIGNTO, 0);\n            acc + nla.buffer_len()\n        })\n    }\n\n    fn emit(&self, buffer: &mut [u8]) {\n        let mut start = 0;\n        let mut end: usize;\n        for nla in self.iter() {\n            let attr_len = nla.buffer_len();\n            assert_eq!(nla.buffer_len() % NLA_ALIGNTO, 0);\n            end = start + attr_len;\n            nla.emit(&mut buffer[start..end]);\n            start = end;\n        }\n    }\n}\n\n/// An iterator that iteratates over nlas without decoding them. This is useful when looking\n/// for specific nlas.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub struct NlasIterator<T> {\n    position: usize,\n    buffer: T,\n}\n\nimpl<T> NlasIterator<T> {\n    pub fn new(buffer: T) -> Self {\n        NlasIterator {\n            position: 0,\n            buffer,\n        }\n    }\n}\n\nimpl<'buffer, T: AsRef<[u8]> + ?Sized + 'buffer> Iterator for NlasIterator<&'buffer T> {\n    type Item = Result<NlaBuffer<&'buffer [u8]>, DecodeError>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if self.position >= self.buffer.as_ref().len() {\n            return None;\n        }\n\n        match NlaBuffer::new_checked(&self.buffer.as_ref()[self.position..]) {\n            Ok(nla_buffer) => {\n                self.position += nla_align!(nla_buffer.length() as usize);\n                Some(Ok(nla_buffer))\n            }\n            Err(e) => {\n                // Make sure next time we call `next()`, we return None. We don't try to continue\n                // iterating after we failed to return a buffer.\n                self.position = self.buffer.as_ref().len();\n                Some(Err(e))\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn network_byteorder() {\n        // The IPSET_ATTR_TIMEOUT attribute should have the network byte order flag set.\n        // IPSET_ATTR_TIMEOUT(3600)\n        static TEST_ATTRIBUTE: &[u8] = &[0x08, 0x00, 0x06, 0x40, 0x00, 0x00, 0x0e, 0x10];\n        let buffer = NlaBuffer::new(TEST_ATTRIBUTE);\n        let buffer_is_net = buffer.network_byte_order_flag();\n        let buffer_is_nest = buffer.nested_flag();\n\n        let nla = DefaultNla::parse(&buffer).unwrap();\n        let mut emitted_buffer = vec![0; nla.buffer_len()];\n\n        nla.emit(&mut emitted_buffer);\n\n        let attr_is_net = nla.is_network_byteorder();\n        let attr_is_nest = nla.is_nested();\n\n        let emit = NlaBuffer::new(emitted_buffer);\n        let emit_is_net = emit.network_byte_order_flag();\n        let emit_is_nest = emit.nested_flag();\n\n        assert_eq!([buffer_is_net, buffer_is_nest], [attr_is_net, attr_is_nest]);\n        assert_eq!([attr_is_net, attr_is_nest], [emit_is_net, emit_is_nest]);\n    }\n\n    fn get_len() -> usize {\n        // usize::MAX\n        18446744073709551615\n    }\n\n    #[test]\n    fn test_align() {\n        assert_eq!(nla_align!(13), 16);\n        assert_eq!(nla_align!(16), 16);\n        assert_eq!(nla_align!(0), 0);\n        assert_eq!(nla_align!(1), 4);\n        assert_eq!(nla_align!(get_len() - 4), usize::MAX - 3);\n    }\n    #[test]\n    #[should_panic]\n    fn test_align_overflow() {\n        assert_eq!(nla_align!(get_len() - 3), usize::MAX);\n    }\n}\n"
  },
  {
    "path": "netlink-packet-utils/src/parsers.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    mem::size_of,\n    net::{IpAddr, Ipv4Addr, Ipv6Addr},\n};\n\nuse anyhow::Context;\nuse byteorder::{BigEndian, ByteOrder, NativeEndian};\n\nuse crate::DecodeError;\n\npub fn parse_mac(payload: &[u8]) -> Result<[u8; 6], DecodeError> {\n    if payload.len() != 6 {\n        return Err(format!(\"invalid MAC address: {:?}\", payload).into());\n    }\n    let mut address: [u8; 6] = [0; 6];\n    for (i, byte) in payload.iter().enumerate() {\n        address[i] = *byte;\n    }\n    Ok(address)\n}\n\npub fn parse_ipv6(payload: &[u8]) -> Result<[u8; 16], DecodeError> {\n    if payload.len() != 16 {\n        return Err(format!(\"invalid IPv6 address: {:?}\", payload).into());\n    }\n    let mut address: [u8; 16] = [0; 16];\n    for (i, byte) in payload.iter().enumerate() {\n        address[i] = *byte;\n    }\n    Ok(address)\n}\n\npub fn parse_ip(payload: &[u8]) -> Result<IpAddr, DecodeError> {\n    match payload.len() {\n        4 => Ok(Ipv4Addr::new(payload[0], payload[1], payload[2], payload[3]).into()),\n        16 => Ok(Ipv6Addr::from([\n            payload[0],\n            payload[1],\n            payload[2],\n            payload[3],\n            payload[4],\n            payload[5],\n            payload[6],\n            payload[7],\n            payload[8],\n            payload[9],\n            payload[10],\n            payload[11],\n            payload[12],\n            payload[13],\n            payload[14],\n            payload[15],\n        ])\n        .into()),\n        _ => Err(format!(\"invalid IPv6 address: {:?}\", payload).into()),\n    }\n}\n\npub fn parse_string(payload: &[u8]) -> Result<String, DecodeError> {\n    if payload.is_empty() {\n        return Ok(String::new());\n    }\n    // iproute2 is a bit inconsistent with null-terminated strings.\n    let slice = if payload[payload.len() - 1] == 0 {\n        &payload[..payload.len() - 1]\n    } else {\n        &payload[..payload.len()]\n    };\n    let s = String::from_utf8(slice.to_vec()).context(\"invalid string\")?;\n    Ok(s)\n}\n\npub fn parse_u8(payload: &[u8]) -> Result<u8, DecodeError> {\n    if payload.len() != 1 {\n        return Err(format!(\"invalid u8: {:?}\", payload).into());\n    }\n    Ok(payload[0])\n}\n\npub fn parse_u32(payload: &[u8]) -> Result<u32, DecodeError> {\n    if payload.len() != size_of::<u32>() {\n        return Err(format!(\"invalid u32: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_u32(payload))\n}\n\npub fn parse_u64(payload: &[u8]) -> Result<u64, DecodeError> {\n    if payload.len() != size_of::<u64>() {\n        return Err(format!(\"invalid u64: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_u64(payload))\n}\n\npub fn parse_u128(payload: &[u8]) -> Result<u128, DecodeError> {\n    if payload.len() != size_of::<u128>() {\n        return Err(format!(\"invalid u128: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_u128(payload))\n}\n\npub fn parse_u16(payload: &[u8]) -> Result<u16, DecodeError> {\n    if payload.len() != size_of::<u16>() {\n        return Err(format!(\"invalid u16: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_u16(payload))\n}\n\npub fn parse_i32(payload: &[u8]) -> Result<i32, DecodeError> {\n    if payload.len() != 4 {\n        return Err(format!(\"invalid u32: {:?}\", payload).into());\n    }\n    Ok(NativeEndian::read_i32(payload))\n}\n\npub fn parse_u16_be(payload: &[u8]) -> Result<u16, DecodeError> {\n    if payload.len() != size_of::<u16>() {\n        return Err(format!(\"invalid u16: {:?}\", payload).into());\n    }\n    Ok(BigEndian::read_u16(payload))\n}\n\npub fn parse_u32_be(payload: &[u8]) -> Result<u32, DecodeError> {\n    if payload.len() != size_of::<u32>() {\n        return Err(format!(\"invalid u32: {:?}\", payload).into());\n    }\n    Ok(BigEndian::read_u32(payload))\n}\n"
  },
  {
    "path": "netlink-packet-utils/src/traits.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::DecodeError;\n\n/// A type that implements `Emitable` can be serialized.\npub trait Emitable {\n    /// Return the length of the serialized data.\n    fn buffer_len(&self) -> usize;\n\n    /// Serialize this types and write the serialized data into the given buffer.\n    ///\n    /// # Panic\n    ///\n    /// This method panic if the buffer is not big enough. You **must** make sure the buffer is big\n    /// enough before calling this method. You can use\n    /// [`buffer_len()`](trait.Emitable.html#method.buffer_len) to check how big the storage needs\n    /// to be.\n    fn emit(&self, buffer: &mut [u8]);\n}\n\n/// A `Parseable` type can be used to deserialize data from the type `T` for which it is\n/// implemented.\npub trait Parseable<T>\nwhere\n    Self: Sized,\n    T: ?Sized,\n{\n    /// Deserialize the current type.\n    fn parse(buf: &T) -> Result<Self, DecodeError>;\n}\n\n/// A `Parseable` type can be used to deserialize data from the type `T` for which it is\n/// implemented.\npub trait ParseableParametrized<T, P>\nwhere\n    Self: Sized,\n    T: ?Sized,\n{\n    /// Deserialize the current type.\n    fn parse_with_param(buf: &T, params: P) -> Result<Self, DecodeError>;\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/Cargo.toml",
    "content": "[package]\nname = \"netlink-packet-wireguard\"\nversion = \"0.2.2\"\nauthors = [\"Leo <leo881003@gmail.com>\", \"Jake McGinty <me@jake.su>\"]\nedition = \"2018\"\nhomepage = \"https://github.com/little-dude/netlink\"\nrepository = \"https://github.com/little-dude/netlink\"\nkeywords = [\"wireguard\", \"netlink\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\ndescription = \"Wireguard generic netlink packet definitions\"\n\n[dependencies]\nanyhow = \"1.0.42\"\nbyteorder = \"1.4.3\"\nlibc = \"0.2.98\"\nlog = \"0.4.14\"\nnetlink-packet-generic = { version = \"0.3.1\", path = \"../netlink-packet-generic\" }\nnetlink-packet-utils = { version = \"0.5.1\", path = \"../netlink-packet-utils\" }\n\n[dev-dependencies]\nbase64 = \"0.13.0\"\nenv_logger = \"0.9.0\"\nfutures = \"0.3.16\"\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-proto = { version = \"0.10\", path = \"../netlink-proto\" }\ngenetlink = { version = \"0.2.1\", path = \"../genetlink\" }\ntokio = { version = \"1.9.0\", features = [\"macros\", \"rt-multi-thread\"] }\n"
  },
  {
    "path": "netlink-packet-wireguard/examples/get_wireguard_info.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::StreamExt;\nuse genetlink::new_connection;\nuse netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST};\nuse netlink_packet_generic::GenlMessage;\nuse netlink_packet_wireguard::{\n    nlas::{WgAllowedIpAttrs, WgDeviceAttrs, WgPeerAttrs},\n    Wireguard,\n    WireguardCmd,\n};\nuse std::env::args;\n\n#[tokio::main]\nasync fn main() {\n    env_logger::init();\n\n    let argv: Vec<String> = args().collect();\n    if argv.len() < 2 {\n        eprintln!(\"Usage: get_wireguard_info <ifname>\");\n        return;\n    }\n\n    let (connection, mut handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let genlmsg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {\n        cmd: WireguardCmd::GetDevice,\n        nlas: vec![WgDeviceAttrs::IfName(argv[1].clone())],\n    });\n    let mut nlmsg = NetlinkMessage::from(genlmsg);\n    nlmsg.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n    let mut res = handle.request(nlmsg).await.unwrap();\n\n    while let Some(result) = res.next().await {\n        let rx_packet = result.unwrap();\n        match rx_packet.payload {\n            NetlinkPayload::InnerMessage(genlmsg) => {\n                print_wg_payload(genlmsg.payload);\n            }\n            NetlinkPayload::Error(e) => {\n                eprintln!(\"Error: {:?}\", e.to_io());\n            }\n            _ => (),\n        };\n    }\n}\n\nfn print_wg_payload(wg: Wireguard) {\n    for nla in &wg.nlas {\n        match nla {\n            WgDeviceAttrs::IfIndex(v) => println!(\"IfIndex: {}\", v),\n            WgDeviceAttrs::IfName(v) => println!(\"IfName: {}\", v),\n            WgDeviceAttrs::PrivateKey(_) => println!(\"PrivateKey: (hidden)\"),\n            WgDeviceAttrs::PublicKey(v) => println!(\"PublicKey: {}\", base64::encode(v)),\n            WgDeviceAttrs::ListenPort(v) => println!(\"ListenPort: {}\", v),\n            WgDeviceAttrs::Fwmark(v) => println!(\"Fwmark: {}\", v),\n            WgDeviceAttrs::Peers(nlas) => {\n                for peer in nlas {\n                    println!(\"Peer: \");\n                    print_wg_peer(peer);\n                }\n            }\n            _ => (),\n        }\n    }\n}\n\nfn print_wg_peer(nlas: &[WgPeerAttrs]) {\n    for nla in nlas {\n        match nla {\n            WgPeerAttrs::PublicKey(v) => println!(\"  PublicKey: {}\", base64::encode(v)),\n            WgPeerAttrs::PresharedKey(_) => println!(\"  PresharedKey: (hidden)\"),\n            WgPeerAttrs::Endpoint(v) => println!(\"  Endpoint: {}\", v),\n            WgPeerAttrs::PersistentKeepalive(v) => println!(\"  PersistentKeepalive: {}\", v),\n            WgPeerAttrs::LastHandshake(v) => println!(\"  LastHandshake: {:?}\", v),\n            WgPeerAttrs::RxBytes(v) => println!(\"  RxBytes: {}\", v),\n            WgPeerAttrs::TxBytes(v) => println!(\"  TxBytes: {}\", v),\n            WgPeerAttrs::AllowedIps(nlas) => {\n                for ip in nlas {\n                    print_wg_allowedip(ip);\n                }\n            }\n            _ => (),\n        }\n    }\n}\n\nfn print_wg_allowedip(nlas: &[WgAllowedIpAttrs]) -> Option<()> {\n    let ipaddr = nlas.iter().find_map(|nla| {\n        if let WgAllowedIpAttrs::IpAddr(addr) = nla {\n            Some(*addr)\n        } else {\n            None\n        }\n    })?;\n    let cidr = nlas.iter().find_map(|nla| {\n        if let WgAllowedIpAttrs::Cidr(cidr) = nla {\n            Some(*cidr)\n        } else {\n            None\n        }\n    })?;\n    println!(\"  AllowedIp: {}/{}\", ipaddr, cidr);\n    Some(())\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub const AF_INET: u16 = libc::AF_INET as u16;\npub const AF_INET6: u16 = libc::AF_INET6 as u16;\n\npub const WG_KEY_LEN: usize = 32;\n\npub const WG_CMD_GET_DEVICE: u8 = 0;\npub const WG_CMD_SET_DEVICE: u8 = 1;\n\npub const WGDEVICE_F_REPLACE_PEERS: u32 = 1 << 0;\n\npub const WGDEVICE_A_UNSPEC: u16 = 0;\npub const WGDEVICE_A_IFINDEX: u16 = 1;\npub const WGDEVICE_A_IFNAME: u16 = 2;\npub const WGDEVICE_A_PRIVATE_KEY: u16 = 3;\npub const WGDEVICE_A_PUBLIC_KEY: u16 = 4;\npub const WGDEVICE_A_FLAGS: u16 = 5;\npub const WGDEVICE_A_LISTEN_PORT: u16 = 6;\npub const WGDEVICE_A_FWMARK: u16 = 7;\npub const WGDEVICE_A_PEERS: u16 = 8;\n\npub const WGPEER_F_REMOVE_ME: u32 = 1 << 0;\npub const WGPEER_F_REPLACE_ALLOWEDIPS: u32 = 1 << 1;\npub const WGPEER_F_UPDATE_ONLY: u32 = 1 << 2;\n\npub const WGPEER_A_UNSPEC: u16 = 0;\npub const WGPEER_A_PUBLIC_KEY: u16 = 1;\npub const WGPEER_A_PRESHARED_KEY: u16 = 2;\npub const WGPEER_A_FLAGS: u16 = 3;\npub const WGPEER_A_ENDPOINT: u16 = 4;\npub const WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL: u16 = 5;\npub const WGPEER_A_LAST_HANDSHAKE_TIME: u16 = 6;\npub const WGPEER_A_RX_BYTES: u16 = 7;\npub const WGPEER_A_TX_BYTES: u16 = 8;\npub const WGPEER_A_ALLOWEDIPS: u16 = 9;\npub const WGPEER_A_PROTOCOL_VERSION: u16 = 10;\n\npub const WGALLOWEDIP_A_UNSPEC: u16 = 0;\npub const WGALLOWEDIP_A_FAMILY: u16 = 1;\npub const WGALLOWEDIP_A_IPADDR: u16 = 2;\npub const WGALLOWEDIP_A_CIDR_MASK: u16 = 3;\n"
  },
  {
    "path": "netlink-packet-wireguard/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_use]\nextern crate log;\n\nuse crate::constants::*;\nuse anyhow::Context;\nuse netlink_packet_generic::{GenlFamily, GenlHeader};\nuse netlink_packet_utils::{nla::NlasIterator, traits::*, DecodeError};\nuse nlas::WgDeviceAttrs;\nuse std::convert::{TryFrom, TryInto};\n\npub mod constants;\npub mod nlas;\nmod raw;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum WireguardCmd {\n    GetDevice,\n    SetDevice,\n}\n\nimpl From<WireguardCmd> for u8 {\n    fn from(cmd: WireguardCmd) -> Self {\n        use WireguardCmd::*;\n        match cmd {\n            GetDevice => WG_CMD_GET_DEVICE,\n            SetDevice => WG_CMD_SET_DEVICE,\n        }\n    }\n}\n\nimpl TryFrom<u8> for WireguardCmd {\n    type Error = DecodeError;\n\n    fn try_from(value: u8) -> Result<Self, Self::Error> {\n        use WireguardCmd::*;\n        Ok(match value {\n            WG_CMD_GET_DEVICE => GetDevice,\n            WG_CMD_SET_DEVICE => SetDevice,\n            cmd => {\n                return Err(DecodeError::from(format!(\n                    \"Unknown wireguard command: {}\",\n                    cmd\n                )))\n            }\n        })\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Wireguard {\n    pub cmd: WireguardCmd,\n    pub nlas: Vec<nlas::WgDeviceAttrs>,\n}\n\nimpl GenlFamily for Wireguard {\n    fn family_name() -> &'static str {\n        \"wireguard\"\n    }\n\n    fn version(&self) -> u8 {\n        1\n    }\n\n    fn command(&self) -> u8 {\n        self.cmd.into()\n    }\n}\n\nimpl Emitable for Wireguard {\n    fn emit(&self, buffer: &mut [u8]) {\n        self.nlas.as_slice().emit(buffer)\n    }\n\n    fn buffer_len(&self) -> usize {\n        self.nlas.as_slice().buffer_len()\n    }\n}\n\nimpl ParseableParametrized<[u8], GenlHeader> for Wireguard {\n    fn parse_with_param(buf: &[u8], header: GenlHeader) -> Result<Self, DecodeError> {\n        Ok(Self {\n            cmd: header.cmd.try_into()?,\n            nlas: parse_nlas(buf)?,\n        })\n    }\n}\n\nfn parse_nlas(buf: &[u8]) -> Result<Vec<WgDeviceAttrs>, DecodeError> {\n    let mut nlas = Vec::new();\n    let error_msg = \"failed to parse message attributes\";\n    for nla in NlasIterator::new(buf) {\n        let nla = &nla.context(error_msg)?;\n        let parsed = WgDeviceAttrs::parse(nla).context(error_msg)?;\n        nlas.push(parsed);\n    }\n    Ok(nlas)\n}\n\n#[cfg(test)]\n\nmod test {\n    use netlink_packet_core::{NetlinkMessage, NLM_F_ACK, NLM_F_REQUEST};\n    use netlink_packet_generic::GenlMessage;\n\n    use crate::nlas::{WgAllowedIp, WgAllowedIpAttrs, WgPeer, WgPeerAttrs};\n\n    use super::*;\n\n    const KNOWN_VALID_PACKET: &[u8] = &[\n        0x74, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, 0x38, 0x24, 0xd6, 0x61, 0x00, 0x00, 0x00,\n        0x00, 0x01, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x00, 0x66, 0x72, 0x61, 0x6e, 0x64, 0x73,\n        0x00, 0x00, 0x54, 0x00, 0x08, 0x80, 0x50, 0x00, 0x00, 0x80, 0x24, 0x00, 0x01, 0x00, 0x01,\n        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n        0x01, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x09, 0x80, 0x1c, 0x00,\n        0x00, 0x80, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x0a,\n        0x0a, 0x0a, 0x0a, 0x05, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,\n    ];\n\n    #[test]\n    fn test_parse_known_valid_packet() {\n        NetlinkMessage::<GenlMessage<Wireguard>>::deserialize(KNOWN_VALID_PACKET).unwrap();\n    }\n\n    #[test]\n    fn test_serialize_then_deserialize() {\n        let genlmsg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {\n            cmd: WireguardCmd::SetDevice,\n            nlas: vec![\n                WgDeviceAttrs::IfName(\"wg0\".to_string()),\n                WgDeviceAttrs::PrivateKey([0xaa; 32]),\n                WgDeviceAttrs::Peers(vec![\n                    WgPeer(vec![\n                        WgPeerAttrs::PublicKey([0x01; 32]),\n                        WgPeerAttrs::PresharedKey([0x01; 32]),\n                        WgPeerAttrs::AllowedIps(vec![WgAllowedIp(vec![\n                            WgAllowedIpAttrs::IpAddr([10, 0, 0, 0].into()),\n                            WgAllowedIpAttrs::Cidr(24),\n                            WgAllowedIpAttrs::Family(AF_INET),\n                        ])]),\n                    ]),\n                    WgPeer(vec![\n                        WgPeerAttrs::PublicKey([0x02; 32]),\n                        WgPeerAttrs::PresharedKey([0x01; 32]),\n                        WgPeerAttrs::AllowedIps(vec![WgAllowedIp(vec![\n                            WgAllowedIpAttrs::IpAddr([10, 0, 1, 0].into()),\n                            WgAllowedIpAttrs::Cidr(24),\n                            WgAllowedIpAttrs::Family(AF_INET),\n                        ])]),\n                    ]),\n                ]),\n            ],\n        });\n        let mut nlmsg = NetlinkMessage::from(genlmsg);\n        nlmsg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n\n        nlmsg.finalize();\n        let mut buf = [0; 4096];\n        nlmsg.serialize(&mut buf);\n        let len = nlmsg.buffer_len();\n        NetlinkMessage::<GenlMessage<Wireguard>>::deserialize(&buf[..len]).unwrap();\n    }\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/src/nlas/allowedip.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    raw::{emit_ip, parse_ip, IPV4_LEN, IPV6_LEN},\n};\n\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::{mem::size_of_val, net::IpAddr};\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum WgAllowedIpAttrs {\n    Unspec(Vec<u8>),\n    Family(u16),\n    IpAddr(IpAddr),\n    Cidr(u8),\n}\n\nimpl Nla for WgAllowedIpAttrs {\n    fn value_len(&self) -> usize {\n        match self {\n            WgAllowedIpAttrs::Unspec(bytes) => bytes.len(),\n            WgAllowedIpAttrs::Family(v) => size_of_val(v),\n            WgAllowedIpAttrs::IpAddr(v) => match *v {\n                IpAddr::V4(_) => IPV4_LEN,\n                IpAddr::V6(_) => IPV6_LEN,\n            },\n            WgAllowedIpAttrs::Cidr(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            WgAllowedIpAttrs::Unspec(_) => WGALLOWEDIP_A_UNSPEC,\n            WgAllowedIpAttrs::Family(_) => WGALLOWEDIP_A_FAMILY,\n            WgAllowedIpAttrs::IpAddr(_) => WGALLOWEDIP_A_IPADDR,\n            WgAllowedIpAttrs::Cidr(_) => WGALLOWEDIP_A_CIDR_MASK,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            WgAllowedIpAttrs::Unspec(bytes) => buffer.copy_from_slice(bytes),\n            WgAllowedIpAttrs::Family(v) => NativeEndian::write_u16(buffer, *v),\n            WgAllowedIpAttrs::IpAddr(v) => emit_ip(v, buffer),\n            WgAllowedIpAttrs::Cidr(v) => buffer[0] = *v,\n        }\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for WgAllowedIpAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            WGALLOWEDIP_A_UNSPEC => Self::Unspec(payload.to_vec()),\n            WGALLOWEDIP_A_FAMILY => {\n                Self::Family(parse_u16(payload).context(\"invalid WGALLOWEDIP_A_FAMILY value\")?)\n            }\n            WGALLOWEDIP_A_IPADDR => {\n                Self::IpAddr(parse_ip(payload).context(\"invalid WGALLOWEDIP_A_IPADDR value\")?)\n            }\n            WGALLOWEDIP_A_CIDR_MASK => Self::Cidr(payload[0]),\n            kind => return Err(DecodeError::from(format!(\"invalid NLA kind: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/src/nlas/device.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    constants::*,\n    nlas::{WgPeer, WgPeerAttrs},\n};\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer, NlasIterator},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::{convert::TryInto, mem::size_of_val};\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum WgDeviceAttrs {\n    Unspec(Vec<u8>),\n    IfIndex(u32),\n    IfName(String),\n    PrivateKey([u8; WG_KEY_LEN]),\n    PublicKey([u8; WG_KEY_LEN]),\n    ListenPort(u16),\n    Fwmark(u32),\n    Peers(Vec<WgPeer>),\n    Flags(u32),\n}\n\nimpl Nla for WgDeviceAttrs {\n    fn value_len(&self) -> usize {\n        match self {\n            WgDeviceAttrs::Unspec(bytes) => bytes.len(),\n            WgDeviceAttrs::IfIndex(v) => size_of_val(v),\n            WgDeviceAttrs::IfName(v) => v.as_bytes().len() + 1,\n            WgDeviceAttrs::PrivateKey(v) => size_of_val(v),\n            WgDeviceAttrs::PublicKey(v) => size_of_val(v),\n            WgDeviceAttrs::ListenPort(v) => size_of_val(v),\n            WgDeviceAttrs::Fwmark(v) => size_of_val(v),\n            WgDeviceAttrs::Peers(nlas) => nlas.iter().map(|op| op.buffer_len()).sum(),\n            WgDeviceAttrs::Flags(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            WgDeviceAttrs::Unspec(_) => WGDEVICE_A_UNSPEC,\n            WgDeviceAttrs::IfIndex(_) => WGDEVICE_A_IFINDEX,\n            WgDeviceAttrs::IfName(_) => WGDEVICE_A_IFNAME,\n            WgDeviceAttrs::PrivateKey(_) => WGDEVICE_A_PRIVATE_KEY,\n            WgDeviceAttrs::PublicKey(_) => WGDEVICE_A_PUBLIC_KEY,\n            WgDeviceAttrs::ListenPort(_) => WGDEVICE_A_LISTEN_PORT,\n            WgDeviceAttrs::Fwmark(_) => WGDEVICE_A_FWMARK,\n            WgDeviceAttrs::Peers(_) => WGDEVICE_A_PEERS,\n            WgDeviceAttrs::Flags(_) => WGDEVICE_A_FLAGS,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            WgDeviceAttrs::Unspec(bytes) => buffer.copy_from_slice(bytes),\n            WgDeviceAttrs::IfIndex(v) => NativeEndian::write_u32(buffer, *v),\n            WgDeviceAttrs::IfName(s) => {\n                buffer[..s.len()].copy_from_slice(s.as_bytes());\n                buffer[s.len()] = 0;\n            }\n            WgDeviceAttrs::PrivateKey(v) => buffer.copy_from_slice(v),\n            WgDeviceAttrs::PublicKey(v) => buffer.copy_from_slice(v),\n            WgDeviceAttrs::ListenPort(v) => NativeEndian::write_u16(buffer, *v),\n            WgDeviceAttrs::Fwmark(v) => NativeEndian::write_u32(buffer, *v),\n            WgDeviceAttrs::Peers(nlas) => {\n                let mut len = 0;\n                for op in nlas {\n                    op.emit(&mut buffer[len..]);\n                    len += op.buffer_len();\n                }\n            }\n            WgDeviceAttrs::Flags(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n\n    fn is_nested(&self) -> bool {\n        matches!(self, WgDeviceAttrs::Peers(_))\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for WgDeviceAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            WGDEVICE_A_UNSPEC => Self::Unspec(payload.to_vec()),\n            WGDEVICE_A_IFINDEX => {\n                Self::IfIndex(parse_u32(payload).context(\"invalid WGDEVICE_A_IFINDEX value\")?)\n            }\n            WGDEVICE_A_IFNAME => {\n                Self::IfName(parse_string(payload).context(\"invalid WGDEVICE_A_IFNAME value\")?)\n            }\n            WGDEVICE_A_PRIVATE_KEY => Self::PrivateKey(\n                payload\n                    .try_into()\n                    .context(\"invalid WGDEVICE_A_PRIVATE_KEY value\")?,\n            ),\n            WGDEVICE_A_PUBLIC_KEY => Self::PublicKey(\n                payload\n                    .try_into()\n                    .context(\"invalid WGDEVICE_A_PUBLIC_KEY value\")?,\n            ),\n            WGDEVICE_A_LISTEN_PORT => Self::ListenPort(\n                parse_u16(payload).context(\"invalid WGDEVICE_A_LISTEN_PORT value\")?,\n            ),\n            WGDEVICE_A_FWMARK => {\n                Self::Fwmark(parse_u32(payload).context(\"invalid WGDEVICE_A_FWMARK value\")?)\n            }\n            WGDEVICE_A_PEERS => {\n                let error_msg = \"failed to parse WGDEVICE_A_PEERS\";\n                let mut peers = Vec::new();\n                for nlas in NlasIterator::new(payload) {\n                    let nlas = &nlas.context(error_msg)?;\n                    let mut group = Vec::new();\n                    for nla in NlasIterator::new(nlas.value()) {\n                        let nla = &nla.context(error_msg)?;\n                        let parsed = WgPeerAttrs::parse(nla).context(error_msg)?;\n                        group.push(parsed);\n                    }\n                    peers.push(WgPeer(group));\n                }\n                Self::Peers(peers)\n            }\n            WGDEVICE_A_FLAGS => {\n                Self::Flags(parse_u32(payload).context(\"invalid WGDEVICE_A_FLAGS value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"invalid NLA kind: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/src/nlas/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod allowedip;\nmod device;\nmod peer;\n\npub use allowedip::WgAllowedIpAttrs;\npub use device::WgDeviceAttrs;\npub use peer::{WgAllowedIp, WgPeer, WgPeerAttrs};\n"
  },
  {
    "path": "netlink-packet-wireguard/src/nlas/peer.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::WgAllowedIpAttrs;\nuse crate::{\n    constants::*,\n    raw::{\n        emit_socket_addr,\n        emit_timespec,\n        parse_socket_addr,\n        parse_timespec,\n        SOCKET_ADDR_V4_LEN,\n        SOCKET_ADDR_V6_LEN,\n        TIMESPEC_LEN,\n    },\n};\nuse anyhow::Context;\nuse byteorder::{ByteOrder, NativeEndian};\nuse netlink_packet_utils::{\n    nla::{Nla, NlaBuffer, NlasIterator},\n    parsers::*,\n    traits::*,\n    DecodeError,\n};\nuse std::{convert::TryInto, mem::size_of_val, net::SocketAddr, ops::Deref, time::SystemTime};\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct WgPeer(pub Vec<WgPeerAttrs>);\n\nimpl Nla for WgPeer {\n    fn value_len(&self) -> usize {\n        self.0.as_slice().buffer_len()\n    }\n\n    fn kind(&self) -> u16 {\n        0\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.0.as_slice().emit(buffer);\n    }\n\n    fn is_nested(&self) -> bool {\n        true\n    }\n}\n\nimpl Deref for WgPeer {\n    type Target = Vec<WgPeerAttrs>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct WgAllowedIp(pub Vec<WgAllowedIpAttrs>);\n\nimpl Nla for WgAllowedIp {\n    fn value_len(&self) -> usize {\n        self.0.as_slice().buffer_len()\n    }\n\n    fn kind(&self) -> u16 {\n        0\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        self.0.as_slice().emit(buffer);\n    }\n\n    fn is_nested(&self) -> bool {\n        true\n    }\n}\n\nimpl Deref for WgAllowedIp {\n    type Target = Vec<WgAllowedIpAttrs>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum WgPeerAttrs {\n    Unspec(Vec<u8>),\n    PublicKey([u8; WG_KEY_LEN]),\n    PresharedKey([u8; WG_KEY_LEN]),\n    Endpoint(SocketAddr),\n    PersistentKeepalive(u16),\n    LastHandshake(SystemTime),\n    RxBytes(u64),\n    TxBytes(u64),\n    AllowedIps(Vec<WgAllowedIp>),\n    ProtocolVersion(u32),\n    Flags(u32),\n}\n\nimpl Nla for WgPeerAttrs {\n    fn value_len(&self) -> usize {\n        match self {\n            WgPeerAttrs::Unspec(bytes) => bytes.len(),\n            WgPeerAttrs::PublicKey(v) => size_of_val(v),\n            WgPeerAttrs::PresharedKey(v) => size_of_val(v),\n            WgPeerAttrs::Endpoint(v) => match *v {\n                SocketAddr::V4(_) => SOCKET_ADDR_V4_LEN,\n                SocketAddr::V6(_) => SOCKET_ADDR_V6_LEN,\n            },\n            WgPeerAttrs::PersistentKeepalive(v) => size_of_val(v),\n            WgPeerAttrs::LastHandshake(_) => TIMESPEC_LEN,\n            WgPeerAttrs::RxBytes(v) => size_of_val(v),\n            WgPeerAttrs::TxBytes(v) => size_of_val(v),\n            WgPeerAttrs::AllowedIps(nlas) => nlas.iter().map(|op| op.buffer_len()).sum(),\n            WgPeerAttrs::ProtocolVersion(v) => size_of_val(v),\n            WgPeerAttrs::Flags(v) => size_of_val(v),\n        }\n    }\n\n    fn kind(&self) -> u16 {\n        match self {\n            WgPeerAttrs::Unspec(_) => WGPEER_A_UNSPEC,\n            WgPeerAttrs::PublicKey(_) => WGPEER_A_PUBLIC_KEY,\n            WgPeerAttrs::PresharedKey(_) => WGPEER_A_PRESHARED_KEY,\n            WgPeerAttrs::Endpoint(_) => WGPEER_A_ENDPOINT,\n            WgPeerAttrs::PersistentKeepalive(_) => WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,\n            WgPeerAttrs::LastHandshake(_) => WGPEER_A_LAST_HANDSHAKE_TIME,\n            WgPeerAttrs::RxBytes(_) => WGPEER_A_RX_BYTES,\n            WgPeerAttrs::TxBytes(_) => WGPEER_A_TX_BYTES,\n            WgPeerAttrs::AllowedIps(_) => WGPEER_A_ALLOWEDIPS,\n            WgPeerAttrs::ProtocolVersion(_) => WGPEER_A_PROTOCOL_VERSION,\n            WgPeerAttrs::Flags(_) => WGPEER_A_FLAGS,\n        }\n    }\n\n    fn emit_value(&self, buffer: &mut [u8]) {\n        match self {\n            WgPeerAttrs::Unspec(bytes) => buffer.copy_from_slice(bytes),\n            WgPeerAttrs::PublicKey(v) => buffer.copy_from_slice(v),\n            WgPeerAttrs::PresharedKey(v) => buffer.copy_from_slice(v),\n            WgPeerAttrs::Endpoint(v) => emit_socket_addr(v, buffer),\n            WgPeerAttrs::PersistentKeepalive(v) => NativeEndian::write_u16(buffer, *v),\n            WgPeerAttrs::LastHandshake(v) => emit_timespec(v, buffer),\n            WgPeerAttrs::RxBytes(v) => NativeEndian::write_u64(buffer, *v),\n            WgPeerAttrs::TxBytes(v) => NativeEndian::write_u64(buffer, *v),\n            WgPeerAttrs::AllowedIps(nlas) => {\n                let mut len = 0;\n                for op in nlas {\n                    op.emit(&mut buffer[len..]);\n                    len += op.buffer_len();\n                }\n            }\n            WgPeerAttrs::ProtocolVersion(v) => NativeEndian::write_u32(buffer, *v),\n            WgPeerAttrs::Flags(v) => NativeEndian::write_u32(buffer, *v),\n        }\n    }\n\n    fn is_nested(&self) -> bool {\n        matches!(self, WgPeerAttrs::AllowedIps(_))\n    }\n}\n\nimpl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for WgPeerAttrs {\n    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {\n        let payload = buf.value();\n        Ok(match buf.kind() {\n            WGPEER_A_UNSPEC => Self::Unspec(payload.to_vec()),\n            WGPEER_A_PUBLIC_KEY => {\n                Self::PublicKey(payload.try_into().context(\"invalid WGPEER_A_PUBLIC_KEY\")?)\n            }\n            WGPEER_A_PRESHARED_KEY => Self::PresharedKey(\n                payload\n                    .try_into()\n                    .context(\"invalid WGPEER_A_PRESHARED_KEY\")?,\n            ),\n            WGPEER_A_ENDPOINT => {\n                Self::Endpoint(parse_socket_addr(payload).context(\"invalid WGPEER_A_ENDPOINT\")?)\n            }\n            WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL => Self::PersistentKeepalive(\n                parse_u16(payload)\n                    .context(\"invalid WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL value\")?,\n            ),\n            WGPEER_A_LAST_HANDSHAKE_TIME => Self::LastHandshake(\n                parse_timespec(payload).context(\"invalid WGPEER_A_LAST_HANDSHAKE_TIME\")?,\n            ),\n            WGPEER_A_RX_BYTES => {\n                Self::RxBytes(parse_u64(payload).context(\"invalid WGPEER_A_RX_BYTES value\")?)\n            }\n            WGPEER_A_TX_BYTES => {\n                Self::TxBytes(parse_u64(payload).context(\"invalid WGPEER_A_TX_BYTES value\")?)\n            }\n            WGPEER_A_ALLOWEDIPS => {\n                let error_msg = \"failed to parse WGPEER_A_ALLOWEDIPS\";\n                let mut ips = Vec::new();\n                for nlas in NlasIterator::new(payload) {\n                    let nlas = &nlas.context(error_msg)?;\n                    let mut group = Vec::new();\n                    for nla in NlasIterator::new(nlas.value()) {\n                        let nla = &nla.context(error_msg)?;\n                        let parsed = WgAllowedIpAttrs::parse(nla).context(error_msg)?;\n                        group.push(parsed);\n                    }\n                    ips.push(WgAllowedIp(group));\n                }\n                Self::AllowedIps(ips)\n            }\n            WGPEER_A_PROTOCOL_VERSION => Self::ProtocolVersion(\n                parse_u32(payload).context(\"invalid WGPEER_A_PROTOCOL_VERSION value\")?,\n            ),\n            WGPEER_A_FLAGS => {\n                Self::Flags(parse_u32(payload).context(\"invalid WGPEER_A_FLAGS value\")?)\n            }\n            kind => return Err(DecodeError::from(format!(\"invalid NLA kind: {}\", kind))),\n        })\n    }\n}\n"
  },
  {
    "path": "netlink-packet-wireguard/src/raw.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    convert::TryFrom,\n    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},\n    time::{Duration, SystemTime},\n};\n\nuse byteorder::{BigEndian, ByteOrder, NativeEndian};\nuse netlink_packet_utils::DecodeError;\n\nuse crate::constants::{AF_INET, AF_INET6};\n\npub const IPV4_LEN: usize = 4;\npub const IPV6_LEN: usize = 16;\npub const SOCKET_ADDR_V4_LEN: usize = 16;\npub const SOCKET_ADDR_V6_LEN: usize = 28;\npub const TIMESPEC_LEN: usize = 16;\n\n/// Parse an IPv6 socket address, defined as:\n/// ```c\n/// struct sockaddr_in6 {\n///     sa_family_t     sin6_family;   /* AF_INET6 */\n///     in_port_t       sin6_port;     /* port number */\n///     uint32_t        sin6_flowinfo; /* IPv6 flow information */\n///     struct in6_addr sin6_addr;     /* IPv6 address */\n///     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */\n/// };\n/// struct in6_addr {\n///     unsigned char   s6_addr[16];   /* IPv6 address */\n/// };\n/// ```\n/// `sockaddr_in6` is 4 bytes aligned (28 bytes) so there's no padding.\nfn parse_socket_addr_v6(payload: &[u8]) -> SocketAddrV6 {\n    assert_eq!(payload.len(), SOCKET_ADDR_V6_LEN);\n    // We don't need the address family to build a SocketAddrv6\n    // let address_family = NativeEndian::read_u16(&payload[..2]);\n    let port = BigEndian::read_u16(&payload[2..4]);\n    let flow_info = NativeEndian::read_u32(&payload[4..8]);\n    // We know we have exactly 16 bytes so this won't fail\n    let ip_bytes = <[u8; 16]>::try_from(&payload[8..24]).unwrap();\n    let ip = Ipv6Addr::from(ip_bytes);\n    let scope_id = NativeEndian::read_u32(&payload[24..28]);\n    SocketAddrV6::new(ip, port, flow_info, scope_id)\n}\n\n/// Parse an IPv4 socket address, defined as:\n/// ```c\n/// #if  __UAPI_DEF_SOCKADDR_IN\n/// #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */\n/// struct sockaddr_in {\n///   __kernel_sa_family_t sin_family; /* Address family   */\n///   __be16               sin_port;   /* Port number      */\n///   struct in_addr       sin_addr;   /* Internet address */\n///   /* Pad to size of `struct sockaddr'. */\n///   unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];\n/// };\nfn parse_socket_addr_v4(payload: &[u8]) -> SocketAddrV4 {\n    assert_eq!(payload.len(), 16);\n    // We don't need the address family to build a SocketAddr4v\n    // let address_family = NativeEndian::read_u16(&payload[..2]);\n    let port = BigEndian::read_u16(&payload[2..4]);\n    // We know we have exactly 4 bytes so this won't fail\n    let ip_bytes = <[u8; 4]>::try_from(&payload[4..8]).unwrap();\n    let ip = Ipv4Addr::from(ip_bytes);\n    SocketAddrV4::new(ip, port)\n}\n\npub fn parse_ip(payload: &[u8]) -> Result<IpAddr, DecodeError> {\n    match payload.len() {\n        IPV4_LEN => {\n            // This won't fail since we ensure the slice is 4 bytes long\n            let ip_bytes = <[u8; IPV4_LEN]>::try_from(payload).unwrap();\n            Ok(IpAddr::V4(Ipv4Addr::from(ip_bytes)))\n        }\n        IPV6_LEN => {\n            // This won't fail since we ensure the slice is 16 bytes long\n            let ip_bytes = <[u8; IPV6_LEN]>::try_from(payload).unwrap();\n            Ok(IpAddr::V6(Ipv6Addr::from(ip_bytes)))\n        }\n        _ => Err(DecodeError::from(format!(\n            \"invalid IP address: {:x?}\",\n            payload\n        ))),\n    }\n}\n\npub fn emit_ip(addr: &IpAddr, buf: &mut [u8]) {\n    match addr {\n        IpAddr::V4(ip) => {\n            buf[..IPV4_LEN].copy_from_slice(ip.octets().as_slice());\n        }\n        IpAddr::V6(ip) => {\n            buf[..IPV6_LEN].copy_from_slice(ip.octets().as_slice());\n        }\n    }\n}\n\n/// Emit an IPv4 socket address in the given buffer. An IPv4 socket\n/// address is defined as:\n/// ```c\n/// #if  __UAPI_DEF_SOCKADDR_IN\n/// #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */\n/// struct sockaddr_in {\n///   __kernel_sa_family_t sin_family; /* Address family   */\n///   __be16               sin_port;   /* Port number      */\n///   struct in_addr       sin_addr;   /* Internet address */\n///   /* Pad to size of `struct sockaddr'. */\n///   unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];\n/// };\n/// ```\n/// Note that this adds 8 bytes of padding so the buffer must be large\n/// enough to account for them.\nfn emit_socket_addr_v4(addr: &SocketAddrV4, buf: &mut [u8]) {\n    NativeEndian::write_u16(&mut buf[..2], AF_INET);\n    BigEndian::write_u16(&mut buf[2..4], addr.port());\n    buf[4..8].copy_from_slice(addr.ip().octets().as_slice());\n    // padding\n    buf[8..16].copy_from_slice([0; 8].as_slice());\n}\n\n/// Emit an IPv6 socket address.\n///\n/// An IPv6 socket address is defined as:\n/// ```c\n/// struct sockaddr_in6 {\n///     sa_family_t     sin6_family;   /* AF_INET6 */\n///     in_port_t       sin6_port;     /* port number */\n///     uint32_t        sin6_flowinfo; /* IPv6 flow information */\n///     struct in6_addr sin6_addr;     /* IPv6 address */\n///     uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */\n/// };\n/// struct in6_addr {\n///     unsigned char   s6_addr[16];   /* IPv6 address */\n/// };\n/// ```\n/// `sockaddr_in6` is 4 bytes aligned (28 bytes) so there's no padding.\nfn emit_socket_addr_v6(addr: &SocketAddrV6, buf: &mut [u8]) {\n    NativeEndian::write_u16(&mut buf[..2], AF_INET6);\n    BigEndian::write_u16(&mut buf[2..4], addr.port());\n    NativeEndian::write_u32(&mut buf[4..8], addr.flowinfo());\n    buf[8..24].copy_from_slice(addr.ip().octets().as_slice());\n    NativeEndian::write_u32(&mut buf[24..28], addr.scope_id());\n}\n\npub fn emit_socket_addr(addr: &SocketAddr, buf: &mut [u8]) {\n    match addr {\n        SocketAddr::V4(v4) => emit_socket_addr_v4(v4, buf),\n        SocketAddr::V6(v6) => emit_socket_addr_v6(v6, buf),\n    }\n}\n\npub fn parse_socket_addr(buf: &[u8]) -> Result<SocketAddr, DecodeError> {\n    match buf.len() {\n        SOCKET_ADDR_V4_LEN => Ok(SocketAddr::V4(parse_socket_addr_v4(buf))),\n        SOCKET_ADDR_V6_LEN => Ok(SocketAddr::V6(parse_socket_addr_v6(buf))),\n        _ => Err(format!(\n            \"invalid socket address (should be 16 or 28 bytes): {:x?}\",\n            buf\n        )\n        .into()),\n    }\n}\n\npub fn emit_timespec(time: &SystemTime, buf: &mut [u8]) {\n    match time.duration_since(SystemTime::UNIX_EPOCH) {\n        Ok(epoch_elapsed) => {\n            NativeEndian::write_i64(&mut buf[..8], epoch_elapsed.as_secs() as i64);\n            NativeEndian::write_i64(&mut buf[8..16], epoch_elapsed.subsec_nanos() as i64);\n        }\n        Err(e) => {\n            // This method is supposed to not fail so just log an\n            // error. If we want such errors to be handled by the\n            // caller, we shouldn't use `SystemTime`.\n            error!(\"error while emitting timespec: {:?}\", e);\n            NativeEndian::write_i64(&mut buf[..8], 0_i64);\n            NativeEndian::write_i64(&mut buf[8..16], 0_i64);\n        }\n    }\n}\n\npub fn parse_timespec(buf: &[u8]) -> Result<SystemTime, DecodeError> {\n    if buf.len() != TIMESPEC_LEN {\n        return Err(DecodeError::from(format!(\n            \"Invalid timespec buffer: {:x?}\",\n            buf\n        )));\n    }\n    let epoch_elapsed_s = Duration::from_secs(NativeEndian::read_u64(&buf[..8]));\n    let epoch_elapsed_ns = Duration::from_nanos(NativeEndian::read_u64(&buf[8..16]));\n    Ok(SystemTime::UNIX_EPOCH + epoch_elapsed_s + epoch_elapsed_ns)\n}\n\n#[cfg(test)]\n\nmod test {\n    use std::str::FromStr;\n\n    use super::*;\n\n    const SOCKADDR_IN_BYTES_1: &[u8] =\n        b\"\\x02\\x00\\x1c\\x7a\\x7f\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"; // 127.0.0.1:7290\n    const SOCKADDR_IN_BYTES_2: &[u8] =\n        b\"\\x02\\x00\\xca\\x6c\\xc0\\xa8\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"; // 192.168.1.1:51820\n    const SOCKADDR_IN6_BYTES_1: &[u8] =\n        b\"\\x0a\\x00\\xca\\x6c\\x10\\x00\\x00\\x00\\xfe\\x80\\x00\\x00\\x00\\x00\\x00\\x00\\xe4\\x58\\x8e\\xad\\x89\\xbb\\x8e\\x25\\x03\\x00\\x00\\x00\";\n    // fe80::e458:8ead:89bb:8e25%3:51820 (flow 16)\n\n    #[test]\n    fn test_parse_socket_addr_in_1() {\n        let ipaddr = parse_socket_addr(SOCKADDR_IN_BYTES_1).unwrap();\n        assert_eq!(ipaddr, SocketAddrV4::new(Ipv4Addr::LOCALHOST, 7290).into());\n    }\n\n    #[test]\n    fn test_parse_socket_addr_in_2() {\n        let ipaddr = parse_socket_addr(SOCKADDR_IN_BYTES_2).unwrap();\n        assert_eq!(\n            ipaddr,\n            SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 1), 51820).into()\n        );\n    }\n\n    #[test]\n    fn test_parse_socket_addr_in6_1() {\n        let ipaddr = parse_socket_addr(SOCKADDR_IN6_BYTES_1).unwrap();\n        assert_eq!(\n            ipaddr,\n            SocketAddrV6::new(\n                Ipv6Addr::from_str(\"fe80::e458:8ead:89bb:8e25\").unwrap(),\n                51820,\n                16,\n                3\n            )\n            .into()\n        );\n    }\n}\n"
  },
  {
    "path": "netlink-proto/Cargo.toml",
    "content": "[package]\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-proto\"\nversion = \"0.10.0\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"linux\", \"async\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"async netlink protocol\"\n\n[dependencies]\nbytes = \"1.0\"\nlog = \"0.4.8\"\nfutures = \"0.3\"\ntokio = { version = \"1.0\", default-features = false, features = [\"io-util\"] }\nnetlink-packet-core = { version = \"0.4.2\", path = \"../netlink-packet-core\" }\nnetlink-sys = { default-features = false, version = \"0.8.3\", path = \"../netlink-sys\" }\nthiserror = \"1.0.30\"\n\n[features]\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-sys/tokio_socket\"]\nsmol_socket = [\"netlink-sys/smol_socket\"]\n\n[dev-dependencies]\nenv_logger = \"0.8.2\"\ntokio = { version = \"1.0.1\", default-features = false, features = [\"macros\", \"rt-multi-thread\"] }\nnetlink-packet-route = { version = \"0.13.0\", path = \"../netlink-packet-route\" }\nnetlink-packet-audit = { version = \"0.4.1\", path = \"../netlink-packet-audit\" }\nasync-std = {version = \"1.9.0\", features = [\"attributes\"]}\n\n[[example]]\nname = \"dump_links\"\n\n[[example]]\nname = \"dump_links_async\"\nrequired-features = [\"smol_socket\"]\n\n[[example]]\nname = \"audit_netlink_events\"\n"
  },
  {
    "path": "netlink-proto/examples/audit_netlink_events.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n// This example shows how to use `netlink-proto` with the tokio runtime to print audit events.\n//\n// This example shows how the netlink socket can be accessed\n// `netlink_proto::Connection`, and configured (in this case to\n// register to a multicast group).\n//\n// Compilation:\n// ------------\n//\n// cargo build --example audit_events\n//\n// Usage:\n// ------\n//\n// Find the example binary in the target directory, and run it *as\n// root*. If you compiled in debug mode with the command above, the\n// binary should be under:\n// `<repo-root>/target/debug/examples/audit_events`. This example runs\n// forever, you must hit ^C to kill it.\n\nuse futures::stream::StreamExt;\nuse netlink_packet_audit::{\n    AuditMessage,\n    NetlinkMessage,\n    NetlinkPayload,\n    StatusMessage,\n    NLM_F_ACK,\n    NLM_F_REQUEST,\n};\nuse std::process;\n\nuse netlink_proto::{\n    new_connection,\n    sys::{protocols::NETLINK_AUDIT, SocketAddr},\n};\n\nconst AUDIT_STATUS_ENABLED: u32 = 1;\nconst AUDIT_STATUS_PID: u32 = 4;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    // Create a netlink socket. Here:\n    //\n    // - `conn` is a `Connection` that has the netlink socket. It's a\n    //   `Future` that keeps polling the socket and must be spawned an\n    //   the event loop.\n    //\n    // - `handle` is a `Handle` to the `Connection`. We use it to send\n    //   netlink messages and receive responses to these messages.\n    //\n    // - `messages` is a channel receiver through which we receive\n    //   messages that we have not sollicated, ie that are not\n    //   response to a request we made. In this example, we'll receive\n    //   the audit event through that channel.\n    let (conn, mut handle, mut messages) = new_connection(NETLINK_AUDIT)\n        .map_err(|e| format!(\"Failed to create a new netlink connection: {}\", e))?;\n\n    // Spawn the `Connection` so that it starts polling the netlink\n    // socket in the background.\n    tokio::spawn(conn);\n\n    // Use the `ConnectionHandle` to send a request to the kernel\n    // asking it to start multicasting audit event messages.\n    tokio::spawn(async move {\n        // Craft the packet to enable audit events\n        let mut status = StatusMessage::new();\n        status.enabled = 1;\n        status.pid = process::id();\n        status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n        let payload = AuditMessage::SetStatus(status);\n        let mut nl_msg = NetlinkMessage::from(payload);\n        nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n\n        // We'll send unicast messages to the kernel.\n        let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);\n        let mut response = match handle.request(nl_msg, kernel_unicast) {\n            Ok(response) => response,\n            Err(e) => {\n                eprintln!(\"{}\", e);\n                return;\n            }\n        };\n\n        while let Some(message) = response.next().await {\n            if let NetlinkPayload::Error(err_message) = message.payload {\n                eprintln!(\"Received an error message: {:?}\", err_message);\n                return;\n            }\n        }\n    });\n\n    // Finally, start receiving event through the `messages` channel.\n    println!(\"Starting to print audit events... press ^C to interrupt\");\n    while let Some((message, _addr)) = messages.next().await {\n        if let NetlinkPayload::Error(err_message) = message.payload {\n            eprintln!(\"received an error message: {:?}\", err_message);\n        } else {\n            println!(\"{:?}\", message);\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "netlink-proto/examples/dump_links.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::StreamExt;\nuse netlink_packet_route::{\n    LinkMessage,\n    NetlinkHeader,\n    NetlinkMessage,\n    RtnlMessage,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\nuse netlink_proto::{\n    new_connection,\n    sys::{protocols::NETLINK_ROUTE, SocketAddr},\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    // Create the netlink socket. Here, we won't use the channel that\n    // receives unsolicited messages.\n    let (conn, mut handle, _) = new_connection(NETLINK_ROUTE)\n        .map_err(|e| format!(\"Failed to create a new netlink connection: {}\", e))?;\n\n    // Spawn the `Connection` in the background\n    tokio::spawn(conn);\n\n    // Create the netlink message that requests the links to be dumped\n    let request = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_DUMP | NLM_F_REQUEST,\n            ..Default::default()\n        },\n        payload: RtnlMessage::GetLink(LinkMessage::default()).into(),\n    };\n\n    // Send the request\n    let mut response = handle\n        .request(request, SocketAddr::new(0, 0))\n        .map_err(|e| format!(\"Failed to send request: {}\", e))?;\n\n    // Print all the messages received in response\n    loop {\n        if let Some(packet) = response.next().await {\n            println!(\"<<< {:?}\", packet);\n        } else {\n            break;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "netlink-proto/examples/dump_links_async.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::StreamExt;\nuse netlink_packet_route::{\n    LinkMessage,\n    NetlinkHeader,\n    NetlinkMessage,\n    RtnlMessage,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\nuse netlink_proto::{\n    new_connection,\n    sys::{protocols::NETLINK_ROUTE, SocketAddr},\n};\n\n#[async_std::main]\nasync fn main() -> Result<(), String> {\n    // Create the netlink socket. Here, we won't use the channel that\n    // receives unsolicited messages.\n    let (conn, mut handle, _) = new_connection(NETLINK_ROUTE)\n        .map_err(|e| format!(\"Failed to create a new netlink connection: {}\", e))?;\n\n    // Spawn the `Connection` so that it starts polling the netlink\n    // socket in the background.\n    let _ = async_std::task::spawn(conn);\n\n    // Create the netlink message that requests the links to be dumped\n    let request = NetlinkMessage {\n        header: NetlinkHeader {\n            flags: NLM_F_DUMP | NLM_F_REQUEST,\n            ..Default::default()\n        },\n        payload: RtnlMessage::GetLink(LinkMessage::default()).into(),\n    };\n\n    // Send the request\n    let mut response = handle\n        .request(request, SocketAddr::new(0, 0))\n        .map_err(|e| format!(\"Failed to send request: {}\", e))?;\n\n    // Print all the messages received in response\n    loop {\n        if let Some(packet) = response.next().await {\n            println!(\"<<< {:?}\", packet);\n        } else {\n            break;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "netlink-proto/src/codecs.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{fmt::Debug, io};\n\nuse bytes::{BufMut, BytesMut};\nuse netlink_packet_core::{\n    NetlinkBuffer,\n    NetlinkDeserializable,\n    NetlinkMessage,\n    NetlinkSerializable,\n};\n\n/// Protocol to serialize and deserialize messages to and from datagrams\n///\n/// This is separate from `tokio_util::codec::{Decoder, Encoder}` as the implementations\n/// rely on the buffer containing full datagrams; they won't work well with simple\n/// bytestreams.\n///\n/// Officially there should be exactly one implementation of this, but the audit\n/// subsystem ignores way too many rules of the protocol, so they need a separate\n/// implementation.\n///\n/// Although one could make a tighter binding between `NetlinkMessageCodec` and\n/// the message types (NetlinkDeserializable+NetlinkSerializable) it can handle,\n/// this would put quite some overhead on subsystems that followed the spec - so\n/// we simply default to the proper implementation (in `Connection`) and the\n/// `audit` code needs to overwrite it.\npub trait NetlinkMessageCodec {\n    /// Decode message of given type from datagram payload\n    ///\n    /// There might be more than one message; this needs to be called until it\n    /// either returns `Ok(None)` or an error.\n    fn decode<T>(src: &mut BytesMut) -> io::Result<Option<NetlinkMessage<T>>>\n    where\n        T: NetlinkDeserializable + Debug;\n\n    /// Encode message to (datagram) buffer\n    fn encode<T>(msg: NetlinkMessage<T>, buf: &mut BytesMut) -> io::Result<()>\n    where\n        T: NetlinkSerializable + Debug;\n}\n\n/// Standard implementation of `NetlinkMessageCodec`\npub struct NetlinkCodec {\n    // we don't need an instance of this, just the type\n    _private: (),\n}\n\nimpl NetlinkMessageCodec for NetlinkCodec {\n    fn decode<T>(src: &mut BytesMut) -> io::Result<Option<NetlinkMessage<T>>>\n    where\n        T: NetlinkDeserializable + Debug,\n    {\n        debug!(\"NetlinkCodec: decoding next message\");\n\n        loop {\n            // If there's nothing to read, return Ok(None)\n            if src.is_empty() {\n                trace!(\"buffer is empty\");\n                return Ok(None);\n            }\n\n            // This is a bit hacky because we don't want to keep `src`\n            // borrowed, since we need to mutate it later.\n            let len = match NetlinkBuffer::new_checked(src.as_ref()) {\n                Ok(buf) => buf.length() as usize,\n                Err(e) => {\n                    // We either received a truncated packet, or the\n                    // packet if malformed (invalid length field). In\n                    // both case, we can't decode the datagram, and we\n                    // cannot find the start of the next one (if\n                    // any). The only solution is to clear the buffer\n                    // and potentially lose some datagrams.\n                    error!(\n                        \"failed to decode datagram, clearing buffer: {:?}: {:#x?}.\",\n                        e,\n                        src.as_ref()\n                    );\n                    src.clear();\n                    return Ok(None);\n                }\n            };\n\n            let bytes = src.split_to(len);\n\n            let parsed = NetlinkMessage::<T>::deserialize(&bytes);\n            match parsed {\n                Ok(packet) => {\n                    trace!(\"<<< {:?}\", packet);\n                    return Ok(Some(packet));\n                }\n                Err(e) => {\n                    error!(\"failed to decode packet {:#x?}: {}\", &bytes, e);\n                    // continue looping, there may be more datagrams in the buffer\n                }\n            }\n        }\n    }\n\n    fn encode<T>(msg: NetlinkMessage<T>, buf: &mut BytesMut) -> io::Result<()>\n    where\n        T: Debug + NetlinkSerializable,\n    {\n        let msg_len = msg.buffer_len();\n        if buf.remaining_mut() < msg_len {\n            // BytesMut can expand till usize::MAX... unlikely to hit this one.\n            return Err(io::Error::new(\n                io::ErrorKind::Other,\n                format!(\n                    \"message is {} bytes, but only {} bytes left in the buffer\",\n                    msg_len,\n                    buf.remaining_mut()\n                ),\n            ));\n        }\n\n        // As NetlinkMessage::serialize needs an initialized buffer anyway\n        // no need for any `unsafe` magic.\n        let old_len = buf.len();\n        let new_len = old_len + msg_len;\n        buf.resize(new_len, 0);\n        msg.serialize(&mut buf[old_len..][..msg_len]);\n        trace!(\">>> {:?}\", msg);\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "netlink-proto/src/connection.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    fmt::Debug,\n    io,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\nuse futures::{\n    channel::mpsc::{UnboundedReceiver, UnboundedSender},\n    Future,\n    Sink,\n    Stream,\n};\nuse log::{error, warn};\nuse netlink_packet_core::{\n    NetlinkDeserializable,\n    NetlinkMessage,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\n\nuse crate::{\n    codecs::{NetlinkCodec, NetlinkMessageCodec},\n    framed::NetlinkFramed,\n    sys::{AsyncSocket, SocketAddr},\n    Protocol,\n    Request,\n    Response,\n};\n\n#[cfg(feature = \"tokio_socket\")]\nuse netlink_sys::TokioSocket as DefaultSocket;\n#[cfg(not(feature = \"tokio_socket\"))]\ntype DefaultSocket = ();\n\n/// Connection to a Netlink socket, running in the background.\n///\n/// [`ConnectionHandle`](struct.ConnectionHandle.html) are used to pass new requests to the\n/// `Connection`, that in turn, sends them through the netlink socket.\npub struct Connection<T, S = DefaultSocket, C = NetlinkCodec>\nwhere\n    T: Debug + NetlinkSerializable + NetlinkDeserializable,\n{\n    socket: NetlinkFramed<T, S, C>,\n\n    protocol: Protocol<T, UnboundedSender<NetlinkMessage<T>>>,\n\n    /// Channel used by the user to pass requests to the connection.\n    requests_rx: Option<UnboundedReceiver<Request<T>>>,\n\n    /// Channel used to transmit to the ConnectionHandle the unsolicited messages received from the\n    /// socket (multicast messages for instance).\n    unsolicited_messages_tx: Option<UnboundedSender<(NetlinkMessage<T>, SocketAddr)>>,\n\n    socket_closed: bool,\n}\n\nimpl<T, S, C> Connection<T, S, C>\nwhere\n    T: Debug + NetlinkSerializable + NetlinkDeserializable + Unpin,\n    S: AsyncSocket,\n    C: NetlinkMessageCodec,\n{\n    pub(crate) fn new(\n        requests_rx: UnboundedReceiver<Request<T>>,\n        unsolicited_messages_tx: UnboundedSender<(NetlinkMessage<T>, SocketAddr)>,\n        protocol: isize,\n    ) -> io::Result<Self> {\n        let socket = S::new(protocol)?;\n        Ok(Connection {\n            socket: NetlinkFramed::new(socket),\n            protocol: Protocol::new(),\n            requests_rx: Some(requests_rx),\n            unsolicited_messages_tx: Some(unsolicited_messages_tx),\n            socket_closed: false,\n        })\n    }\n\n    pub fn socket_mut(&mut self) -> &mut S {\n        self.socket.get_mut()\n    }\n\n    pub fn poll_send_messages(&mut self, cx: &mut Context) {\n        trace!(\"poll_send_messages called\");\n        let Connection {\n            ref mut socket,\n            ref mut protocol,\n            ..\n        } = self;\n        let mut socket = Pin::new(socket);\n\n        while !protocol.outgoing_messages.is_empty() {\n            trace!(\"found outgoing message to send checking if socket is ready\");\n            if let Poll::Ready(Err(e)) = Pin::as_mut(&mut socket).poll_ready(cx) {\n                // Sink errors are usually not recoverable. The socket\n                // probably shut down.\n                warn!(\"netlink socket shut down: {:?}\", e);\n                self.socket_closed = true;\n                return;\n            }\n\n            let (mut message, addr) = protocol.outgoing_messages.pop_front().unwrap();\n            message.finalize();\n\n            trace!(\"sending outgoing message\");\n            if let Err(e) = Pin::as_mut(&mut socket).start_send((message, addr)) {\n                error!(\"failed to send message: {:?}\", e);\n                self.socket_closed = true;\n                return;\n            }\n        }\n\n        trace!(\"poll_send_messages done\");\n        self.poll_flush(cx)\n    }\n\n    pub fn poll_flush(&mut self, cx: &mut Context) {\n        trace!(\"poll_flush called\");\n        if let Poll::Ready(Err(e)) = Pin::new(&mut self.socket).poll_flush(cx) {\n            warn!(\"error flushing netlink socket: {:?}\", e);\n            self.socket_closed = true;\n        }\n    }\n\n    pub fn poll_read_messages(&mut self, cx: &mut Context) {\n        trace!(\"poll_read_messages called\");\n        let mut socket = Pin::new(&mut self.socket);\n\n        loop {\n            trace!(\"polling socket\");\n            match socket.as_mut().poll_next(cx) {\n                Poll::Ready(Some((message, addr))) => {\n                    trace!(\"read datagram from socket\");\n                    self.protocol.handle_message(message, addr);\n                }\n                Poll::Ready(None) => {\n                    warn!(\"netlink socket stream shut down\");\n                    self.socket_closed = true;\n                    return;\n                }\n                Poll::Pending => {\n                    trace!(\"no datagram read from socket\");\n                    return;\n                }\n            }\n        }\n    }\n\n    pub fn poll_requests(&mut self, cx: &mut Context) {\n        trace!(\"poll_requests called\");\n        if let Some(mut stream) = self.requests_rx.as_mut() {\n            loop {\n                match Pin::new(&mut stream).poll_next(cx) {\n                    Poll::Ready(Some(request)) => self.protocol.request(request),\n                    Poll::Ready(None) => break,\n                    Poll::Pending => return,\n                }\n            }\n            let _ = self.requests_rx.take();\n            trace!(\"no new requests to handle poll_requests done\");\n        }\n    }\n\n    pub fn forward_unsolicited_messages(&mut self) {\n        if self.unsolicited_messages_tx.is_none() {\n            while let Some((message, source)) = self.protocol.incoming_requests.pop_front() {\n                warn!(\n                    \"ignoring unsolicited message {:?} from {:?}\",\n                    message, source\n                );\n            }\n            return;\n        }\n\n        trace!(\"forward_unsolicited_messages called\");\n        let mut ready = false;\n\n        let Connection {\n            ref mut protocol,\n            ref mut unsolicited_messages_tx,\n            ..\n        } = self;\n\n        while let Some((message, source)) = protocol.incoming_requests.pop_front() {\n            if unsolicited_messages_tx\n                .as_mut()\n                .unwrap()\n                .unbounded_send((message, source))\n                .is_err()\n            {\n                // The channel is unbounded so the only error that can\n                // occur is that the channel is closed because the\n                // receiver was dropped\n                warn!(\"failed to forward message to connection handle: channel closed\");\n                ready = true;\n                break;\n            }\n        }\n\n        if ready {\n            // The channel is closed so we can drop the sender.\n            let _ = self.unsolicited_messages_tx.take();\n            // purge `protocol.incoming_requests`\n            self.forward_unsolicited_messages();\n        }\n\n        trace!(\"forward_unsolicited_messages done\");\n    }\n\n    pub fn forward_responses(&mut self) {\n        trace!(\"forward_responses called\");\n        let protocol = &mut self.protocol;\n\n        while let Some(response) = protocol.incoming_responses.pop_front() {\n            let Response {\n                message,\n                done,\n                metadata: tx,\n            } = response;\n            if done {\n                use NetlinkPayload::*;\n                match &message.payload {\n                    // Since `self.protocol` set the `done` flag here,\n                    // we know it has already dropped the request and\n                    // its associated metadata, ie the UnboundedSender\n                    // used to forward messages back to the\n                    // ConnectionHandle. By just continuing we're\n                    // dropping the last instance of that sender,\n                    // hence closing the channel and signaling the\n                    // handle that no more messages are expected.\n                    Noop | Done | Ack(_) => {\n                        trace!(\"not forwarding Noop/Ack/Done message to the handle\");\n                        continue;\n                    }\n                    // I'm not sure how we should handle overrun messages\n                    Overrun(_) => unimplemented!(\"overrun is not handled yet\"),\n                    // We need to forward error messages and messages\n                    // that are part of the netlink subprotocol,\n                    // because only the user knows how they want to\n                    // handle them.\n                    Error(_) | InnerMessage(_) => {}\n                }\n            }\n\n            trace!(\"forwarding response to the handle\");\n            if tx.unbounded_send(message).is_err() {\n                // With an unboundedsender, an error can\n                // only happen if the receiver is closed.\n                warn!(\"failed to forward response back to the handle\");\n            }\n        }\n        trace!(\"forward_responses done\");\n    }\n\n    pub fn should_shut_down(&self) -> bool {\n        self.socket_closed || (self.unsolicited_messages_tx.is_none() && self.requests_rx.is_none())\n    }\n}\n\nimpl<T, S, C> Future for Connection<T, S, C>\nwhere\n    T: Debug + NetlinkSerializable + NetlinkDeserializable + Unpin,\n    S: AsyncSocket,\n    C: NetlinkMessageCodec,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {\n        trace!(\"polling Connection\");\n        let pinned = self.get_mut();\n\n        debug!(\"reading incoming messages\");\n        pinned.poll_read_messages(cx);\n\n        debug!(\"forwarding unsolicited messages to the connection handle\");\n        pinned.forward_unsolicited_messages();\n\n        debug!(\"forwaring responses to previous requests to the connection handle\");\n        pinned.forward_responses();\n\n        debug!(\"handling requests\");\n        pinned.poll_requests(cx);\n\n        debug!(\"sending messages\");\n        pinned.poll_send_messages(cx);\n\n        trace!(\"done polling Connection\");\n\n        if pinned.should_shut_down() {\n            Poll::Ready(())\n        } else {\n            Poll::Pending\n        }\n    }\n}\n"
  },
  {
    "path": "netlink-proto/src/errors.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::io;\n\nuse netlink_packet_core::NetlinkMessage;\n\n#[derive(thiserror::Error, Debug)]\npub enum Error<T> {\n    /// The netlink connection is closed\n    #[error(\"the netlink connection is closed\")]\n    ConnectionClosed,\n\n    /// Received an error message as a response\n    #[error(\"received an error message as a response: {0:?}\")]\n    NetlinkError(NetlinkMessage<T>),\n\n    /// Error while reading from or writing to the netlink socket\n    #[error(\"error while reading from or writing to the netlink socket: {0}\")]\n    SocketIo(#[from] io::Error),\n}\n"
  },
  {
    "path": "netlink-proto/src/framed.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse bytes::BytesMut;\nuse std::{\n    fmt::Debug,\n    io,\n    marker::PhantomData,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\nuse futures::{Sink, Stream};\nuse log::error;\n\nuse crate::{\n    codecs::NetlinkMessageCodec,\n    sys::{AsyncSocket, SocketAddr},\n};\nuse netlink_packet_core::{NetlinkDeserializable, NetlinkMessage, NetlinkSerializable};\n\npub struct NetlinkFramed<T, S, C> {\n    socket: S,\n    // see https://doc.rust-lang.org/nomicon/phantom-data.html\n    // \"invariant\" seems like the safe choice; using `fn(T) -> T`\n    // should make it invariant but still Send+Sync.\n    msg_type: PhantomData<fn(T) -> T>, // invariant\n    codec: PhantomData<fn(C) -> C>,    // invariant\n    reader: BytesMut,\n    writer: BytesMut,\n    in_addr: SocketAddr,\n    out_addr: SocketAddr,\n    flushed: bool,\n}\n\nimpl<T, S, C> Stream for NetlinkFramed<T, S, C>\nwhere\n    T: NetlinkDeserializable + Debug,\n    S: AsyncSocket,\n    C: NetlinkMessageCodec,\n{\n    type Item = (NetlinkMessage<T>, SocketAddr);\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let Self {\n            ref mut socket,\n            ref mut in_addr,\n            ref mut reader,\n            ..\n        } = Pin::get_mut(self);\n\n        loop {\n            match C::decode::<T>(reader) {\n                Ok(Some(item)) => return Poll::Ready(Some((item, *in_addr))),\n                Ok(None) => {}\n                Err(e) => {\n                    error!(\"unrecoverable error in decoder: {:?}\", e);\n                    return Poll::Ready(None);\n                }\n            }\n\n            reader.clear();\n            reader.reserve(INITIAL_READER_CAPACITY);\n\n            *in_addr = match ready!(socket.poll_recv_from(cx, reader)) {\n                Ok(addr) => addr,\n                Err(e) => {\n                    error!(\"failed to read from netlink socket: {:?}\", e);\n                    return Poll::Ready(None);\n                }\n            };\n        }\n    }\n}\n\nimpl<T, S, C> Sink<(NetlinkMessage<T>, SocketAddr)> for NetlinkFramed<T, S, C>\nwhere\n    T: NetlinkSerializable + Debug,\n    S: AsyncSocket,\n    C: NetlinkMessageCodec,\n{\n    type Error = io::Error;\n\n    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        if !self.flushed {\n            match self.poll_flush(cx)? {\n                Poll::Ready(()) => {}\n                Poll::Pending => return Poll::Pending,\n            }\n        }\n\n        Poll::Ready(Ok(()))\n    }\n\n    fn start_send(\n        self: Pin<&mut Self>,\n        item: (NetlinkMessage<T>, SocketAddr),\n    ) -> Result<(), Self::Error> {\n        trace!(\"sending frame\");\n        let (frame, out_addr) = item;\n        let pin = self.get_mut();\n        C::encode(frame, &mut pin.writer)?;\n        pin.out_addr = out_addr;\n        pin.flushed = false;\n        trace!(\"frame encoded; length={}\", pin.writer.len());\n        Ok(())\n    }\n\n    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        if self.flushed {\n            return Poll::Ready(Ok(()));\n        }\n\n        trace!(\"flushing frame; length={}\", self.writer.len());\n        let Self {\n            ref mut socket,\n            ref mut out_addr,\n            ref mut writer,\n            ..\n        } = *self;\n\n        let n = ready!(socket.poll_send_to(cx, writer, out_addr))?;\n        trace!(\"written {}\", n);\n\n        let wrote_all = n == self.writer.len();\n        self.writer.clear();\n        self.flushed = true;\n\n        let res = if wrote_all {\n            Ok(())\n        } else {\n            Err(io::Error::new(\n                io::ErrorKind::Other,\n                \"failed to write entire datagram to socket\",\n            ))\n        };\n\n        Poll::Ready(res)\n    }\n\n    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        ready!(self.poll_flush(cx))?;\n        Poll::Ready(Ok(()))\n    }\n}\n\n// The theoritical max netlink packet size is 32KB for a netlink\n// message since Linux 4.9 (16KB before). See:\n// https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=d35c99ff77ecb2eb239731b799386f3b3637a31e\nconst INITIAL_READER_CAPACITY: usize = 64 * 1024;\nconst INITIAL_WRITER_CAPACITY: usize = 8 * 1024;\n\nimpl<T, S, C> NetlinkFramed<T, S, C> {\n    /// Create a new `NetlinkFramed` backed by the given socket and codec.\n    ///\n    /// See struct level documentation for more details.\n    pub fn new(socket: S) -> Self {\n        Self {\n            socket,\n            msg_type: PhantomData,\n            codec: PhantomData,\n            out_addr: SocketAddr::new(0, 0),\n            in_addr: SocketAddr::new(0, 0),\n            reader: BytesMut::with_capacity(INITIAL_READER_CAPACITY),\n            writer: BytesMut::with_capacity(INITIAL_WRITER_CAPACITY),\n            flushed: true,\n        }\n    }\n\n    /// Returns a reference to the underlying I/O stream wrapped by `Framed`.\n    ///\n    /// # Note\n    ///\n    /// Care should be taken to not tamper with the underlying stream of data\n    /// coming in as it may corrupt the stream of frames otherwise being worked\n    /// with.\n    pub fn get_ref(&self) -> &S {\n        &self.socket\n    }\n\n    /// Returns a mutable reference to the underlying I/O stream wrapped by\n    /// `Framed`.\n    ///\n    /// # Note\n    ///\n    /// Care should be taken to not tamper with the underlying stream of data\n    /// coming in as it may corrupt the stream of frames otherwise being worked\n    /// with.\n    pub fn get_mut(&mut self) -> &mut S {\n        &mut self.socket\n    }\n\n    /// Consumes the `Framed`, returning its underlying I/O stream.\n    pub fn into_inner(self) -> S {\n        self.socket\n    }\n}\n"
  },
  {
    "path": "netlink-proto/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    channel::mpsc::{unbounded, UnboundedSender},\n    Stream,\n};\nuse netlink_packet_core::NetlinkMessage;\nuse std::fmt::Debug;\n\nuse crate::{errors::Error, sys::SocketAddr, Request};\n\n/// A handle to pass requests to a [`Connection`](struct.Connection.html).\n#[derive(Clone, Debug)]\npub struct ConnectionHandle<T>\nwhere\n    T: Debug,\n{\n    requests_tx: UnboundedSender<Request<T>>,\n}\n\nimpl<T> ConnectionHandle<T>\nwhere\n    T: Debug,\n{\n    pub(crate) fn new(requests_tx: UnboundedSender<Request<T>>) -> Self {\n        ConnectionHandle { requests_tx }\n    }\n\n    /// Send a new request and get the response as a stream of messages. Note that some messages\n    /// are not part of the response stream:\n    ///\n    /// - **acknowledgements**: when an acknowledgement is received, the stream is closed\n    /// - **end of dump messages**: similarly, upon receiving an \"end of dump\" message, the stream is\n    /// closed\n    pub fn request(\n        &mut self,\n        message: NetlinkMessage<T>,\n        destination: SocketAddr,\n    ) -> Result<impl Stream<Item = NetlinkMessage<T>>, Error<T>> {\n        let (tx, rx) = unbounded::<NetlinkMessage<T>>();\n        let request = Request::from((message, destination, tx));\n        debug!(\"handle: forwarding new request to connection\");\n        UnboundedSender::unbounded_send(&self.requests_tx, request).map_err(|e| {\n            // the channel is unbounded, so it can't be full. If this\n            // failed, it means the Connection shut down.\n            if e.is_full() {\n                panic!(\"internal error: unbounded channel full?!\");\n            } else if e.is_disconnected() {\n                Error::ConnectionClosed\n            } else {\n                panic!(\"unknown error: {:?}\", e);\n            }\n        })?;\n        Ok(rx)\n    }\n\n    pub fn notify(\n        &mut self,\n        message: NetlinkMessage<T>,\n        destination: SocketAddr,\n    ) -> Result<(), Error<T>> {\n        let (tx, _rx) = unbounded::<NetlinkMessage<T>>();\n        let request = Request::from((message, destination, tx));\n        debug!(\"handle: forwarding new request to connection\");\n        UnboundedSender::unbounded_send(&self.requests_tx, request)\n            .map_err(|_| Error::ConnectionClosed)\n    }\n}\n"
  },
  {
    "path": "netlink-proto/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! `netlink-proto` is an asynchronous implementation of the Netlink\n//! protocol.\n//!\n//! # Example: listening for audit events\n//!\n//! This example shows how to use `netlink-proto` with the `tokio`\n//! runtime to print audit events. It requires extra external\n//! dependencies:\n//!\n//! - `futures = \"^0.3\"`\n//! - `tokio = \"^1.0\"`\n//! - `netlink-packet-audit = \"^0.1\"`\n//!\n//! ```rust,no_run\n//! use futures::stream::StreamExt;\n//! use netlink_packet_audit::{\n//!     AuditMessage,\n//!     NetlinkMessage,\n//!     NetlinkPayload,\n//!     StatusMessage,\n//!     NLM_F_ACK,\n//!     NLM_F_REQUEST,\n//! };\n//! use std::process;\n//!\n//! use netlink_proto::{\n//!     new_connection,\n//!     sys::{protocols::NETLINK_AUDIT, SocketAddr},\n//! };\n//!\n//! const AUDIT_STATUS_ENABLED: u32 = 1;\n//! const AUDIT_STATUS_PID: u32 = 4;\n//!\n//! #[tokio::main]\n//! async fn main() -> Result<(), String> {\n//!     // Create a netlink socket. Here:\n//!     //\n//!     // - `conn` is a `Connection` that has the netlink socket. It's a\n//!     //   `Future` that keeps polling the socket and must be spawned an\n//!     //   the event loop.\n//!     //\n//!     // - `handle` is a `Handle` to the `Connection`. We use it to send\n//!     //   netlink messages and receive responses to these messages.\n//!     //\n//!     // - `messages` is a channel receiver through which we receive\n//!     //   messages that we have not solicited, ie that are not\n//!     //   response to a request we made. In this example, we'll receive\n//!     //   the audit event through that channel.\n//!     let (conn, mut handle, mut messages) = new_connection(NETLINK_AUDIT)\n//!         .map_err(|e| format!(\"Failed to create a new netlink connection: {}\", e))?;\n//!\n//!     // Spawn the `Connection` so that it starts polling the netlink\n//!     // socket in the background.\n//!     tokio::spawn(conn);\n//!\n//!     // Use the `ConnectionHandle` to send a request to the kernel\n//!     // asking it to start multicasting audit event messages.\n//!     tokio::spawn(async move {\n//!         // Craft the packet to enable audit events\n//!         let mut status = StatusMessage::new();\n//!         status.enabled = 1;\n//!         status.pid = process::id();\n//!         status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n//!         let payload = AuditMessage::SetStatus(status);\n//!         let mut nl_msg = NetlinkMessage::from(payload);\n//!         nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n//!\n//!         // We'll send unicast messages to the kernel.\n//!         let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);\n//!         let mut response = match handle.request(nl_msg, kernel_unicast) {\n//!             Ok(response) => response,\n//!             Err(e) => {\n//!                 eprintln!(\"{}\", e);\n//!                 return;\n//!             }\n//!         };\n//!\n//!         while let Some(message) = response.next().await {\n//!             if let NetlinkPayload::Error(err_message) = message.payload {\n//!                 eprintln!(\"Received an error message: {:?}\", err_message);\n//!                 return;\n//!             }\n//!         }\n//!     });\n//!\n//!     // Finally, start receiving event through the `messages` channel.\n//!     println!(\"Starting to print audit events... press ^C to interrupt\");\n//!     while let Some((message, _addr)) = messages.next().await {\n//!         if let NetlinkPayload::Error(err_message) = message.payload {\n//!             eprintln!(\"received an error message: {:?}\", err_message);\n//!         } else {\n//!             println!(\"{:?}\", message);\n//!         }\n//!     }\n//!\n//!     Ok(())\n//! }\n//! ```\n//!\n//! # Example: dumping all the machine's links\n//!\n//! This example shows how to use `netlink-proto` with the ROUTE\n//! protocol.\n//!\n//! Here we do not use `netlink_proto::new_connection()`, and instead\n//! create the socket manually and use call `send()` and `receive()`\n//! directly. In the previous example, the `NetlinkFramed` was wrapped\n//! in a `Connection` which was polled automatically by the runtime.\n//!\n//! ```rust,no_run\n//! use futures::StreamExt;\n//!\n//! use netlink_packet_route::{\n//!     LinkMessage,\n//!     NetlinkHeader,\n//!     NetlinkMessage,\n//!     RtnlMessage,\n//!     NLM_F_DUMP,\n//!     NLM_F_REQUEST,\n//! };\n//!\n//! use netlink_proto::{\n//!     new_connection,\n//!     sys::{protocols::NETLINK_ROUTE, SocketAddr},\n//! };\n//!\n//! #[tokio::main]\n//! async fn main() -> Result<(), String> {\n//!     // Create the netlink socket. Here, we won't use the channel that\n//!     // receives unsolicited messages.\n//!     let (conn, mut handle, _) = new_connection(NETLINK_ROUTE)\n//!         .map_err(|e| format!(\"Failed to create a new netlink connection: {}\", e))?;\n//!\n//!     // Spawn the `Connection` in the background\n//!     tokio::spawn(conn);\n//!\n//!     // Create the netlink message that requests the links to be dumped\n//!     let msg = NetlinkMessage {\n//!         header: NetlinkHeader {\n//!             sequence_number: 1,\n//!             flags: NLM_F_DUMP | NLM_F_REQUEST,\n//!             ..Default::default()\n//!         },\n//!         payload: RtnlMessage::GetLink(LinkMessage::default()).into(),\n//!     };\n//!\n//!     // Send the request\n//!     let mut response = handle\n//!         .request(msg, SocketAddr::new(0, 0))\n//!         .map_err(|e| format!(\"Failed to send request: {}\", e))?;\n//!\n//!     // Print all the messages received in response\n//!     loop {\n//!         if let Some(packet) = response.next().await {\n//!             println!(\"<<< {:?}\", packet);\n//!         } else {\n//!             break;\n//!         }\n//!     }\n//!\n//!     Ok(())\n//! }\n//! ```\n#[macro_use]\nextern crate futures;\n#[macro_use]\nextern crate log;\n\nmod codecs;\npub use crate::codecs::*;\n\nmod framed;\npub use crate::framed::*;\n\nmod protocol;\npub(crate) use self::protocol::{Protocol, Response};\npub(crate) type Request<T> =\n    self::protocol::Request<T, UnboundedSender<crate::packet::NetlinkMessage<T>>>;\n\nmod connection;\npub use crate::connection::*;\n\nmod errors;\npub use crate::errors::*;\n\nmod handle;\npub use crate::handle::*;\n\nuse futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};\nuse std::{fmt::Debug, io};\n\npub use netlink_packet_core as packet;\n\npub mod sys {\n    pub use netlink_sys::{protocols, AsyncSocket, AsyncSocketExt, SocketAddr};\n\n    #[cfg(feature = \"tokio_socket\")]\n    pub use netlink_sys::TokioSocket;\n\n    #[cfg(feature = \"smol_socket\")]\n    pub use netlink_sys::SmolSocket;\n}\n\n/// Create a new Netlink connection for the given Netlink protocol, and returns a handle to that\n/// connection as well as a stream of unsolicited messages received by that connection (unsolicited\n/// here means messages that are not a response to a request made by the `Connection`).\n/// `Connection<T>` wraps a Netlink socket and implements the Netlink protocol.\n///\n/// `protocol` must be one of the [`crate::sys::protocols`][protos] constants.\n///\n/// `T` is the type of netlink messages used for this protocol. For instance, if you're using the\n/// `NETLINK_AUDIT` protocol with the `netlink-packet-audit` crate, `T` will be\n/// `netlink_packet_audit::AuditMessage`. More generally, `T` is anything that can be serialized\n/// and deserialized into a Netlink message. See the `netlink_packet_core` documentation for\n/// details about the `NetlinkSerializable` and `NetlinkDeserializable` traits.\n///\n/// Most of the time, users will want to spawn the `Connection` on an async runtime, and use the\n/// handle to send messages.\n///\n/// [protos]: crate::sys::protocols\n#[cfg(feature = \"tokio_socket\")]\n#[allow(clippy::type_complexity)]\npub fn new_connection<T>(\n    protocol: isize,\n) -> io::Result<(\n    Connection<T>,\n    ConnectionHandle<T>,\n    UnboundedReceiver<(packet::NetlinkMessage<T>, sys::SocketAddr)>,\n)>\nwhere\n    T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin,\n{\n    new_connection_with_codec(protocol)\n}\n\n/// Variant of [`new_connection`] that allows specifying a socket type to use for async handling\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<T, S>(\n    protocol: isize,\n) -> io::Result<(\n    Connection<T, S>,\n    ConnectionHandle<T>,\n    UnboundedReceiver<(packet::NetlinkMessage<T>, sys::SocketAddr)>,\n)>\nwhere\n    T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin,\n    S: sys::AsyncSocket,\n{\n    new_connection_with_codec(protocol)\n}\n\n/// Variant of [`new_connection`] that allows specifying a socket type to use for async handling and a special codec\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_codec<T, S, C>(\n    protocol: isize,\n) -> io::Result<(\n    Connection<T, S, C>,\n    ConnectionHandle<T>,\n    UnboundedReceiver<(packet::NetlinkMessage<T>, sys::SocketAddr)>,\n)>\nwhere\n    T: Debug + packet::NetlinkSerializable + packet::NetlinkDeserializable + Unpin,\n    S: sys::AsyncSocket,\n    C: NetlinkMessageCodec,\n{\n    let (requests_tx, requests_rx) = unbounded::<Request<T>>();\n    let (messages_tx, messages_rx) = unbounded::<(packet::NetlinkMessage<T>, sys::SocketAddr)>();\n    Ok((\n        Connection::new(requests_rx, messages_tx, protocol)?,\n        ConnectionHandle::new(requests_tx),\n        messages_rx,\n    ))\n}\n"
  },
  {
    "path": "netlink-proto/src/protocol/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[allow(clippy::module_inception)]\nmod protocol;\nmod request;\n\npub(crate) use protocol::{Protocol, Response};\npub(crate) use request::Request;\n"
  },
  {
    "path": "netlink-proto/src/protocol/protocol.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    collections::{hash_map, HashMap, VecDeque},\n    fmt::Debug,\n};\n\nuse netlink_packet_core::{\n    constants::*,\n    NetlinkDeserializable,\n    NetlinkMessage,\n    NetlinkPayload,\n    NetlinkSerializable,\n};\n\nuse super::Request;\nuse crate::sys::SocketAddr;\n\n#[derive(Debug, Eq, PartialEq, Hash)]\nstruct RequestId {\n    sequence_number: u32,\n    port: u32,\n}\n\nimpl RequestId {\n    fn new(sequence_number: u32, port: u32) -> Self {\n        Self {\n            sequence_number,\n            port,\n        }\n    }\n}\n\n#[derive(Debug, Eq, PartialEq)]\npub(crate) struct Response<T, M> {\n    pub done: bool,\n    pub message: NetlinkMessage<T>,\n    pub metadata: M,\n}\n\n#[derive(Debug)]\nstruct PendingRequest<M> {\n    expecting_ack: bool,\n    metadata: M,\n}\n\n#[derive(Debug, Default)]\npub(crate) struct Protocol<T, M> {\n    /// Counter that is incremented for each message sent\n    sequence_id: u32,\n\n    /// Requests for which we're awaiting a response. Metadata are\n    /// associated with each request.\n    pending_requests: HashMap<RequestId, PendingRequest<M>>,\n\n    /// Responses to pending requests\n    pub incoming_responses: VecDeque<Response<T, M>>,\n\n    /// Requests from remote peers\n    pub incoming_requests: VecDeque<(NetlinkMessage<T>, SocketAddr)>,\n\n    /// The messages to be sent out\n    pub outgoing_messages: VecDeque<(NetlinkMessage<T>, SocketAddr)>,\n}\n\nimpl<T, M> Protocol<T, M>\nwhere\n    T: Debug + NetlinkSerializable + NetlinkDeserializable,\n    M: Debug + Clone,\n{\n    pub fn new() -> Self {\n        Self {\n            sequence_id: 0,\n            pending_requests: HashMap::new(),\n            incoming_responses: VecDeque::new(),\n            incoming_requests: VecDeque::new(),\n            outgoing_messages: VecDeque::new(),\n        }\n    }\n\n    pub fn handle_message(&mut self, message: NetlinkMessage<T>, source: SocketAddr) {\n        let request_id = RequestId::new(message.header.sequence_number, source.port_number());\n        debug!(\"handling messages (request id = {:?})\", request_id);\n        if let hash_map::Entry::Occupied(entry) = self.pending_requests.entry(request_id) {\n            Self::handle_response(&mut self.incoming_responses, entry, message);\n        } else {\n            self.incoming_requests.push_back((message, source));\n        }\n    }\n\n    fn handle_response(\n        incoming_responses: &mut VecDeque<Response<T, M>>,\n        entry: hash_map::OccupiedEntry<RequestId, PendingRequest<M>>,\n        message: NetlinkMessage<T>,\n    ) {\n        let entry_key;\n        let mut request_id = entry.key();\n        debug!(\"handling response to request {:?}\", request_id);\n\n        // A request is processed if we receive an Ack, Error,\n        // Done, Overrun, or InnerMessage without the\n        // multipart flag and we were not expecting an Ack\n        let done = match message.payload {\n            NetlinkPayload::InnerMessage(_)\n                if message.header.flags & NLM_F_MULTIPART == NLM_F_MULTIPART =>\n            {\n                false\n            }\n            NetlinkPayload::InnerMessage(_) => !entry.get().expecting_ack,\n            _ => true,\n        };\n\n        let metadata = if done {\n            trace!(\"request {:?} fully processed\", request_id);\n            let (k, v) = entry.remove_entry();\n            entry_key = k;\n            request_id = &entry_key;\n            v.metadata\n        } else {\n            trace!(\"more responses to request {:?} may come\", request_id);\n            entry.get().metadata.clone()\n        };\n\n        let response = Response::<T, M> {\n            done,\n            message,\n            metadata,\n        };\n        incoming_responses.push_back(response);\n        debug!(\"done handling response to request {:?}\", request_id);\n    }\n\n    pub fn request(&mut self, request: Request<T, M>) {\n        let Request {\n            mut message,\n            metadata,\n            destination,\n        } = request;\n\n        self.set_sequence_id(&mut message);\n        let request_id = RequestId::new(self.sequence_id, destination.port_number());\n        let flags = message.header.flags;\n        self.outgoing_messages.push_back((message, destination));\n\n        // If we expect a response, we store the request id so that we\n        // can map the response to this specific request.\n        //\n        // Note that we expect responses in three cases only:\n        //  - when the request has the NLM_F_REQUEST flag\n        //  - when the request has the NLM_F_ACK flag\n        //  - when the request has the NLM_F_ECHO flag\n        let expecting_ack = flags & NLM_F_ACK == NLM_F_ACK;\n        if flags & NLM_F_REQUEST == NLM_F_REQUEST\n            || flags & NLM_F_ECHO == NLM_F_ECHO\n            || expecting_ack\n        {\n            self.pending_requests.insert(\n                request_id,\n                PendingRequest {\n                    expecting_ack,\n                    metadata,\n                },\n            );\n        }\n    }\n\n    fn set_sequence_id(&mut self, message: &mut NetlinkMessage<T>) {\n        self.sequence_id += 1;\n        message.header.sequence_number = self.sequence_id;\n    }\n}\n"
  },
  {
    "path": "netlink-proto/src/protocol/request.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::fmt::Debug;\n\nuse netlink_packet_core::NetlinkMessage;\n\nuse crate::sys::SocketAddr;\n\n#[derive(Debug)]\npub(crate) struct Request<T, M> {\n    pub metadata: M,\n    pub message: NetlinkMessage<T>,\n    pub destination: SocketAddr,\n}\n\nimpl<T, M> From<(NetlinkMessage<T>, SocketAddr, M)> for Request<T, M>\nwhere\n    T: Debug,\n    M: Debug,\n{\n    fn from(parts: (NetlinkMessage<T>, SocketAddr, M)) -> Self {\n        Request {\n            message: parts.0,\n            destination: parts.1,\n            metadata: parts.2,\n        }\n    }\n}\n\nimpl<T, M> From<Request<T, M>> for (NetlinkMessage<T>, SocketAddr, M)\nwhere\n    T: Debug,\n    M: Debug,\n{\n    fn from(req: Request<T, M>) -> (NetlinkMessage<T>, SocketAddr, M) {\n        (req.message, req.destination, req.metadata)\n    }\n}\n"
  },
  {
    "path": "netlink-sys/Cargo.toml",
    "content": "[package]\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nname = \"netlink-sys\"\nversion = \"0.8.3\"\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"ip\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"netlink sockets, with optional integration with tokio\"\n\n[dependencies]\nbytes = \"1.0\"\nlibc = \"0.2.66\"\nlog = \"0.4.8\"\n\n[dependencies.futures]\noptional = true\nversion = \"0.3.1\"\n\n[dependencies.tokio]\noptional = true\nversion = \"1.0.1\"\ndefault-features = false\n# We only depend on tokio for PollEvented\nfeatures = [\"net\"]\n\n[dependencies.mio]\noptional = true\nversion = \"0.8\"\nfeatures = [\"os-poll\", \"os-ext\"]\n\n[dependencies.async-io]\noptional = true\nversion = \"1.3\"\n\n[features]\ndefault = []\nmio_socket = [\"mio\"]\ntokio_socket = [\"tokio\", \"futures\"]\nsmol_socket = [\"async-io\",\"futures\"]\n\n[dev-dependencies]\nnetlink-packet-audit = { version = \"0.4.1\", path = \"../netlink-packet-audit\" }\n\n[dev-dependencies.tokio]\nversion = \"1.0.1\"\ndefault-features = false\n# We only depend on tokio for PollEvented\nfeatures = [\"net\", \"macros\", \"rt-multi-thread\"]\n\n[dev-dependencies.async-std]\nversion = \"1.9.0\"\nfeatures = [\"attributes\"]\n\n\n[[example]]\nname = \"audit_events\"\n\n[[example]]\nname = \"audit_events_tokio\"\nrequired-features = [\"tokio_socket\"]\n\n[[example]]\nname = \"audit_events_tokio_manual_thread_builder\"\nrequired-features = [\"tokio_socket\"]\n\n[[example]]\nname = \"audit_events_async_std\"\nrequired-features = [\"smol_socket\"]\n"
  },
  {
    "path": "netlink-sys/examples/audit_events.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n// Build:\n//\n// ```\n// cd netlink-sys\n// cargo build --example audit_events\n// ```\n//\n// Run *as root*:\n//\n// ```\n// ../target/debug/examples/audit_events\n// ```\n\nuse std::process;\n\nuse netlink_packet_audit::{\n    AuditMessage,\n    NetlinkBuffer,\n    NetlinkMessage,\n    StatusMessage,\n    NLM_F_ACK,\n    NLM_F_REQUEST,\n};\n\nuse netlink_sys::{protocols::NETLINK_AUDIT, Socket, SocketAddr};\n\npub const AUDIT_STATUS_ENABLED: u32 = 1;\npub const AUDIT_STATUS_PID: u32 = 4;\n\nfn main() {\n    let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);\n    let socket = Socket::new(NETLINK_AUDIT).unwrap();\n\n    let mut status = StatusMessage::new();\n    status.enabled = 1;\n    status.pid = process::id();\n    status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n    let payload = AuditMessage::SetStatus(status);\n    let mut nl_msg = NetlinkMessage::from(payload);\n    nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n    nl_msg.finalize();\n\n    let mut buf = vec![0; 1024 * 8];\n    nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]);\n\n    socket\n        .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast, 0)\n        .unwrap();\n    let mut buf = vec![0; 1024 * 8];\n    loop {\n        let (n, _addr) = socket.recv_from(&mut buf, 0).unwrap();\n        // This dance with the NetlinkBuffer should not be\n        // necessary. It is here to work around a netlink bug. See:\n        // https://github.com/mozilla/libaudit-go/issues/24\n        // https://github.com/linux-audit/audit-userspace/issues/78\n        {\n            let mut nl_buf = NetlinkBuffer::new(&mut buf[0..n]);\n            if n != nl_buf.length() as usize {\n                nl_buf.set_length(n as u32);\n            }\n        }\n        let parsed = NetlinkMessage::<AuditMessage>::deserialize(&buf[0..n]).unwrap();\n        println!(\"<<< {:?}\", parsed);\n    }\n}\n"
  },
  {
    "path": "netlink-sys/examples/audit_events_async_std.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n// Build:\n//\n// ```\n// cd netlink-sys\n// cargo build --example audit_events_async_std --features async_std_socket\n// ```\n//\n// Run *as root*:\n//\n// ```\n// ../target/debug/examples/audit_events_async_std\n// ```\n\nuse std::process;\n\nuse netlink_packet_audit::{\n    AuditMessage,\n    NetlinkBuffer,\n    NetlinkMessage,\n    StatusMessage,\n    NLM_F_ACK,\n    NLM_F_REQUEST,\n};\n\nuse netlink_sys::{protocols::NETLINK_AUDIT, AsyncSocket, AsyncSocketExt, SmolSocket, SocketAddr};\n\nconst AUDIT_STATUS_ENABLED: u32 = 1;\nconst AUDIT_STATUS_PID: u32 = 4;\n\n#[async_std::main]\nasync fn main() {\n    let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);\n    let mut socket = SmolSocket::new(NETLINK_AUDIT).unwrap();\n\n    let mut status = StatusMessage::new();\n    status.enabled = 1;\n    status.pid = process::id();\n    status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n    let payload = AuditMessage::SetStatus(status);\n    let mut nl_msg = NetlinkMessage::from(payload);\n    nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n    nl_msg.finalize();\n\n    let mut buf = vec![0; 1024 * 8];\n    nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]);\n\n    println!(\">>> {:?}\", nl_msg);\n    socket\n        .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast)\n        .await\n        .unwrap();\n\n    let mut buf = bytes::BytesMut::with_capacity(1024 * 8);\n    loop {\n        buf.clear();\n        let _addr = socket.recv_from(&mut buf).await.unwrap();\n        // This dance with the NetlinkBuffer should not be\n        // necessary. It is here to work around a netlink bug. See:\n        // https://github.com/mozilla/libaudit-go/issues/24\n        // https://github.com/linux-audit/audit-userspace/issues/78\n        {\n            let n = buf.len();\n            let mut nl_buf = NetlinkBuffer::new(&mut buf);\n            if n != nl_buf.length() as usize {\n                nl_buf.set_length(n as u32);\n            }\n        }\n        let parsed = NetlinkMessage::<AuditMessage>::deserialize(&buf).unwrap();\n        println!(\"<<< {:?}\", parsed);\n    }\n}\n"
  },
  {
    "path": "netlink-sys/examples/audit_events_tokio.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n// Build:\n//\n// ```\n// cd netlink-sys\n// cargo build --example audit_events_async --features tokio_socket\n// ```\n//\n// Run *as root*:\n//\n// ```\n// ../target/debug/examples/audit_events_async\n// ```\n\nuse std::process;\n\nuse netlink_packet_audit::{\n    AuditMessage,\n    NetlinkBuffer,\n    NetlinkMessage,\n    StatusMessage,\n    NLM_F_ACK,\n    NLM_F_REQUEST,\n};\n\nuse netlink_sys::{protocols::NETLINK_AUDIT, AsyncSocket, AsyncSocketExt, SocketAddr, TokioSocket};\n\nconst AUDIT_STATUS_ENABLED: u32 = 1;\nconst AUDIT_STATUS_PID: u32 = 4;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let kernel_unicast: SocketAddr = SocketAddr::new(0, 0);\n    let mut socket = TokioSocket::new(NETLINK_AUDIT).unwrap();\n\n    let mut status = StatusMessage::new();\n    status.enabled = 1;\n    status.pid = process::id();\n    status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;\n    let payload = AuditMessage::SetStatus(status);\n    let mut nl_msg = NetlinkMessage::from(payload);\n    nl_msg.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n    nl_msg.finalize();\n\n    let mut buf = vec![0; 1024 * 8];\n    nl_msg.serialize(&mut buf[..nl_msg.buffer_len()]);\n\n    println!(\">>> {:?}\", nl_msg);\n    socket\n        .send_to(&buf[..nl_msg.buffer_len()], &kernel_unicast)\n        .await\n        .unwrap();\n\n    let mut buf = bytes::BytesMut::with_capacity(1024 * 8);\n    loop {\n        buf.clear();\n        let _addr = socket.recv_from(&mut buf).await.unwrap();\n        // This dance with the NetlinkBuffer should not be\n        // necessary. It is here to work around a netlink bug. See:\n        // https://github.com/mozilla/libaudit-go/issues/24\n        // https://github.com/linux-audit/audit-userspace/issues/78\n        {\n            let n = buf.len();\n            let mut nl_buf = NetlinkBuffer::new(&mut buf);\n            if n != nl_buf.length() as usize {\n                nl_buf.set_length(n as u32);\n            }\n        }\n        let parsed = NetlinkMessage::<AuditMessage>::deserialize(&buf).unwrap();\n        println!(\"<<< {:?}\", parsed);\n    }\n}\n"
  },
  {
    "path": "netlink-sys/examples/audit_events_tokio_manual_thread_builder.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n/*\n * This example shows the mimimal manual tokio initialization required to be able\n * to use netlink.\n */\n\nuse netlink_sys::{protocols::NETLINK_AUDIT, AsyncSocket, TokioSocket};\n\nfn main() -> Result<(), String> {\n    let rt = tokio::runtime::Builder::new_multi_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n\n    let future = async {\n        TokioSocket::new(NETLINK_AUDIT).unwrap();\n    };\n    rt.handle().block_on(future);\n    Ok(())\n}\n"
  },
  {
    "path": "netlink-sys/src/addr.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    fmt,\n    hash::{Hash, Hasher},\n    mem,\n};\n\n/// The address of a netlink socket\n///\n/// A netlink address is made of two parts: the unicast address of the socket, called _port number_ or _PID_, and the\n/// multicast address called _group ID_. In this library, we've chosen to stick to the \"port number\" terminology, since\n/// PID can be confused with process ID. However, the netlink man page mostly uses PID.\n///\n/// ## Port number\n///\n/// Sockets in kernel space have 0 as a port number. For sockets opened by a user-space process, the port number can\n/// either be assigned by the process itself, or by the kernel. The only constraint is that this port number must be\n/// unique: two netlink sockets created by a given process must have a different port number. However, netlinks sockets\n/// created by different processes can have the same port number.\n///\n/// ### Port number assigned by the kernel\n///\n/// One way to set the port number is to let the kernel assign it, by calling [`Socket::bind`][bind] with a port number set to\n/// 0. The kernel will usually use the process ID as port number for the first netlink socket created by the process,\n/// which is why the socket port number is also called PID. For example:\n///\n/// ```rust\n/// use std::process;\n/// use netlink_sys::{\n///     protocols::NETLINK_ROUTE,\n///     SocketAddr, Socket,\n/// };\n///\n/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n/// // The first parameter is the port number. By setting it to 0 we ask the kernel to pick a port for us\n/// let mut addr = SocketAddr::new(0, 0);\n/// socket.bind(&addr).unwrap();\n/// // Retrieve the socket address\n/// socket.get_address(&mut addr).unwrap();\n/// // the socket port number should be equal to the process ID, but there is no guarantee\n/// println!(\"socket port number = {}, process ID = {}\", addr.port_number(), process::id());\n///\n/// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap();\n/// let mut addr2 = SocketAddr::new(0, 0);\n/// socket2.bind(&addr2).unwrap();\n/// socket2.get_address(&mut addr2).unwrap();\n/// // the unicast address picked by the kernel for the second socket should be different\n/// assert!(addr.port_number() != addr2.port_number());\n/// ```\n///\n/// Note that it's a little tedious to create a socket address, call `bind` and then retrive the address with\n/// [`Socket::get_address`][get_addr]. To avoid this boilerplate you can use [`Socket::bind_auto`][bind_auto]:\n///\n/// ```rust\n/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n/// use std::process;\n///\n/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n/// let addr = socket.bind_auto().unwrap();\n/// println!(\"socket port number = {}\", addr.port_number());\n/// ```\n///\n/// ### Setting the port number manually\n///\n/// The application can also pick the port number by calling Socket::bind with an address with a non-zero port\n/// number. However, it must ensure that this number is unique for each socket created. For instance:\n///\n/// ```rust\n/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n/// use std::process;\n///\n/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n/// // set the socket port number to 2\n/// let mut addr = SocketAddr::new(2, 0);\n/// socket.bind(&addr).unwrap();\n/// // Retrieve the socket address\n/// socket.get_address(&mut addr).unwrap();\n/// assert_eq!(2, addr.port_number());\n///\n/// // Creating a second socket with the same port number fails\n/// let mut socket2 = Socket::new(NETLINK_ROUTE).unwrap();\n/// let mut addr2 = SocketAddr::new(2, 0);\n/// socket2.bind(&addr2).unwrap_err();\n/// ```\n///\n/// [bind]: crate::Socket::bind\n/// [bind_auto]: crate::Socket::bind_auto\n/// [get_addr]: crate::Socket::get_address\n#[derive(Copy, Clone)]\npub struct SocketAddr(pub(crate) libc::sockaddr_nl);\n\nimpl Hash for SocketAddr {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.0.nl_family.hash(state);\n        self.0.nl_pid.hash(state);\n        self.0.nl_groups.hash(state);\n    }\n}\n\nimpl PartialEq for SocketAddr {\n    fn eq(&self, other: &SocketAddr) -> bool {\n        self.0.nl_family == other.0.nl_family\n            && self.0.nl_pid == other.0.nl_pid\n            && self.0.nl_groups == other.0.nl_groups\n    }\n}\n\nimpl fmt::Debug for SocketAddr {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(\n            f,\n            \"SocketAddr(nl_family={}, nl_pid={}, nl_groups={})\",\n            self.0.nl_family, self.0.nl_pid, self.0.nl_groups\n        )\n    }\n}\n\nimpl Eq for SocketAddr {}\n\nimpl fmt::Display for SocketAddr {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(\n            f,\n            \"address family: {}, pid: {}, multicast groups: {})\",\n            self.0.nl_family, self.0.nl_pid, self.0.nl_groups\n        )\n    }\n}\n\nimpl SocketAddr {\n    /// Create a new socket address for with th\n    pub fn new(port_number: u32, multicast_groups: u32) -> Self {\n        let mut addr: libc::sockaddr_nl = unsafe { mem::zeroed() };\n        addr.nl_family = libc::PF_NETLINK as libc::sa_family_t;\n        addr.nl_pid = port_number;\n        addr.nl_groups = multicast_groups;\n        SocketAddr(addr)\n    }\n\n    /// Get the unicast address of this socket\n    pub fn port_number(&self) -> u32 {\n        self.0.nl_pid\n    }\n\n    /// Get the multicast groups of this socket\n    pub fn multicast_groups(&self) -> u32 {\n        self.0.nl_groups\n    }\n\n    pub(crate) fn as_raw(&self) -> (*const libc::sockaddr, libc::socklen_t) {\n        let addr_ptr = &self.0 as *const libc::sockaddr_nl as *const libc::sockaddr;\n        //             \\                                 / \\                      /\n        //              +---------------+---------------+   +----------+---------+\n        //                               |                             |\n        //                               v                             |\n        //             create a raw pointer to the sockaddr_nl         |\n        //                                                             v\n        //                                                cast *sockaddr_nl -> *sockaddr\n        //\n        // This kind of things seems to be pretty usual when using C APIs from Rust. It could be\n        // written in a shorter way thank to type inference:\n        //\n        //      let addr_ptr: *const libc:sockaddr = &self.0 as *const _ as *const _;\n        //\n        // But since this is my first time dealing with this kind of things I chose the most\n        // explicit form.\n\n        let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;\n        (addr_ptr, addr_len)\n    }\n\n    pub(crate) fn as_raw_mut(&mut self) -> (*mut libc::sockaddr, libc::socklen_t) {\n        let addr_ptr = &mut self.0 as *mut libc::sockaddr_nl as *mut libc::sockaddr;\n        let addr_len = mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;\n        (addr_ptr, addr_len)\n    }\n}\n"
  },
  {
    "path": "netlink-sys/src/async_socket.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    io,\n    task::{Context, Poll},\n};\n\nuse crate::{Socket, SocketAddr};\n\n/// Trait to support different async backends\npub trait AsyncSocket: Sized + Unpin {\n    /// Access underyling [`Socket`]\n    fn socket_ref(&self) -> &Socket;\n\n    /// Mutable access to underyling [`Socket`]\n    fn socket_mut(&mut self) -> &mut Socket;\n\n    /// Wrapper for [`Socket::new`]\n    fn new(protocol: isize) -> io::Result<Self>;\n\n    /// Polling wrapper for [`Socket::send`]\n    fn poll_send(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>>;\n\n    /// Polling wrapper for [`Socket::send_to`]\n    fn poll_send_to(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n        addr: &SocketAddr,\n    ) -> Poll<io::Result<usize>>;\n\n    /// Polling wrapper for [`Socket::recv`]\n    ///\n    /// Passes 0 for flags, and ignores the returned length (the buffer will have advanced by the amount read).\n    fn poll_recv<B>(&mut self, cx: &mut Context<'_>, buf: &mut B) -> Poll<io::Result<()>>\n    where\n        B: bytes::BufMut;\n\n    /// Polling wrapper for [`Socket::recv_from`]\n    ///\n    /// Passes 0 for flags, and ignores the returned length - just returns the address (the buffer will have advanced by the amount read).\n    fn poll_recv_from<B>(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &mut B,\n    ) -> Poll<io::Result<SocketAddr>>\n    where\n        B: bytes::BufMut;\n\n    /// Polling wrapper for [`Socket::recv_from_full`]\n    ///\n    /// Passes 0 for flags, and ignores the returned length - just returns the address (the buffer will have advanced by the amount read).\n    fn poll_recv_from_full(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<io::Result<(Vec<u8>, SocketAddr)>>;\n}\n"
  },
  {
    "path": "netlink-sys/src/async_socket_ext.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    future::Future,\n    io,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\nuse crate::{AsyncSocket, SocketAddr};\n\n/// Support trait for [`AsyncSocket`]\n///\n/// Provides awaitable variants of the poll functions from [`AsyncSocket`].\npub trait AsyncSocketExt: AsyncSocket {\n    /// `async fn send(&mut self, buf: &[u8]) -> io::Result<usize>`\n    fn send<'a, 'b>(&'a mut self, buf: &'b [u8]) -> PollSend<'a, 'b, Self> {\n        PollSend { socket: self, buf }\n    }\n\n    /// `async fn send(&mut self, buf: &[u8]) -> io::Result<usize>`\n    fn send_to<'a, 'b>(\n        &'a mut self,\n        buf: &'b [u8],\n        addr: &'b SocketAddr,\n    ) -> PollSendTo<'a, 'b, Self> {\n        PollSendTo {\n            socket: self,\n            buf,\n            addr,\n        }\n    }\n\n    /// `async fn recv<B>(&mut self, buf: &mut [u8]) -> io::Result<()>`\n    fn recv<'a, 'b, B>(&'a mut self, buf: &'b mut B) -> PollRecv<'a, 'b, Self, B>\n    where\n        B: bytes::BufMut,\n    {\n        PollRecv { socket: self, buf }\n    }\n\n    /// `async fn recv<B>(&mut self, buf: &mut [u8]) -> io::Result<SocketAddr>`\n    fn recv_from<'a, 'b, B>(&'a mut self, buf: &'b mut B) -> PollRecvFrom<'a, 'b, Self, B>\n    where\n        B: bytes::BufMut,\n    {\n        PollRecvFrom { socket: self, buf }\n    }\n\n    /// `async fn recrecv_from_full(&mut self) -> io::Result<(Vec<u8>, SocketAddr)>`\n    fn recv_from_full(&mut self) -> PollRecvFromFull<'_, Self> {\n        PollRecvFromFull { socket: self }\n    }\n}\n\nimpl<S: AsyncSocket> AsyncSocketExt for S {}\n\npub struct PollSend<'a, 'b, S> {\n    socket: &'a mut S,\n    buf: &'b [u8],\n}\n\nimpl<S> Future for PollSend<'_, '_, S>\nwhere\n    S: AsyncSocket,\n{\n    type Output = io::Result<usize>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this: &mut Self = Pin::into_inner(self);\n        this.socket.poll_send(cx, this.buf)\n    }\n}\n\npub struct PollSendTo<'a, 'b, S> {\n    socket: &'a mut S,\n    buf: &'b [u8],\n    addr: &'b SocketAddr,\n}\n\nimpl<S> Future for PollSendTo<'_, '_, S>\nwhere\n    S: AsyncSocket,\n{\n    type Output = io::Result<usize>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this: &mut Self = Pin::into_inner(self);\n        this.socket.poll_send_to(cx, this.buf, this.addr)\n    }\n}\n\npub struct PollRecv<'a, 'b, S, B> {\n    socket: &'a mut S,\n    buf: &'b mut B,\n}\n\nimpl<S, B> Future for PollRecv<'_, '_, S, B>\nwhere\n    S: AsyncSocket,\n    B: bytes::BufMut,\n{\n    type Output = io::Result<()>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this: &mut Self = Pin::into_inner(self);\n        this.socket.poll_recv(cx, this.buf)\n    }\n}\n\npub struct PollRecvFrom<'a, 'b, S, B> {\n    socket: &'a mut S,\n    buf: &'b mut B,\n}\n\nimpl<S, B> Future for PollRecvFrom<'_, '_, S, B>\nwhere\n    S: AsyncSocket,\n    B: bytes::BufMut,\n{\n    type Output = io::Result<SocketAddr>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this: &mut Self = Pin::into_inner(self);\n        this.socket.poll_recv_from(cx, this.buf)\n    }\n}\n\npub struct PollRecvFromFull<'a, S> {\n    socket: &'a mut S,\n}\n\nimpl<S> Future for PollRecvFromFull<'_, S>\nwhere\n    S: AsyncSocket,\n{\n    type Output = io::Result<(Vec<u8>, SocketAddr)>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this: &mut Self = Pin::into_inner(self);\n        this.socket.poll_recv_from_full(cx)\n    }\n}\n"
  },
  {
    "path": "netlink-sys/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This module provides a lot of netlink constants for various protocol. As we add support for the\n//! various protocols, these constants will be moved to their own crate.\n\nuse libc::c_int as int;\n\n/// Receives routing and link updates and may be used to modify the routing tables (both IPv4\n/// and IPv6), IP addresses, link parameters, neighbor setups, queueing disciplines, traffic\n/// classes  and  packet  classifiers  (see rtnetlink(7)).\npub const NETLINK_ROUTE: isize = 0;\npub const NETLINK_UNUSED: isize = 1;\n/// Reserved for user-mode socket protocols.\npub const NETLINK_USERSOCK: isize = 2;\n/// Transport  IPv4  packets  from  netfilter  to  user  space.  Used by ip_queue kernel\n/// module.  After a long period of being declared obsolete (in favor of the more advanced\n/// nfnetlink_queue feature), it was  removed in Linux 3.5.\npub const NETLINK_FIREWALL: isize = 3;\n/// Query information about sockets of various protocol families from the kernel (see sock_diag(7)).\npub const NETLINK_SOCK_DIAG: isize = 4;\n/// Netfilter/iptables ULOG.\npub const NETLINK_NFLOG: isize = 5;\n/// IPsec.\npub const NETLINK_XFRM: isize = 6;\n/// SELinux event notifications.\npub const NETLINK_SELINUX: isize = 7;\n/// Open-iSCSI.\npub const NETLINK_ISCSI: isize = 8;\n/// Auditing.\npub const NETLINK_AUDIT: isize = 9;\n/// Access to FIB lookup from user space.\npub const NETLINK_FIB_LOOKUP: isize = 10;\n/// Kernel connector. See `Documentation/connector/*` in the Linux kernel source tree for further information.\npub const NETLINK_CONNECTOR: isize = 11;\n/// Netfilter subsystem.\npub const NETLINK_NETFILTER: isize = 12;\n/// Transport IPv6 packets from netfilter to user space.  Used by ip6_queue kernel module.\npub const NETLINK_IP6_FW: isize = 13;\n/// DECnet routing messages.\npub const NETLINK_DNRTMSG: isize = 14;\n/// Kernel messages to user space.\npub const NETLINK_KOBJECT_UEVENT: isize = 15;\n///  Generic netlink family for simplified netlink usage.\npub const NETLINK_GENERIC: isize = 16;\n/// SCSI transpots\npub const NETLINK_SCSITRANSPORT: isize = 18;\npub const NETLINK_ECRYPTFS: isize = 19;\n/// Infiniband RDMA.\npub const NETLINK_RDMA: isize = 20;\n/// Netlink interface to request information about ciphers registered with the kernel crypto\n/// API as well as allow configuration of the kernel crypto API.\npub const NETLINK_CRYPTO: isize = 21;\n\npub const TCA_ROOT_UNSPEC: int = 0;\npub const TCA_ROOT_TAB: int = 1;\npub const TCA_ROOT_FLAGS: int = 2;\npub const TCA_ROOT_COUNT: int = 3;\npub const TCA_ROOT_TIME_DELTA: int = 4;\n\npub const EM_NONE: u32 = 0;\npub const EM_M32: u32 = 1;\npub const EM_SPARC: u32 = 2;\npub const EM_386: u32 = 3;\npub const EM_68K: u32 = 4;\npub const EM_88K: u32 = 5;\npub const EM_486: u32 = 6;\npub const EM_860: u32 = 7;\npub const EM_MIPS: u32 = 8;\npub const EM_MIPS_RS3_LE: u32 = 10;\npub const EM_MIPS_RS4_BE: u32 = 10;\npub const EM_PARISC: u32 = 15;\npub const EM_SPARC32PLUS: u32 = 18;\npub const EM_PPC: u32 = 20;\npub const EM_PPC64: u32 = 21;\npub const EM_SPU: u32 = 23;\npub const EM_ARM: u32 = 40;\npub const EM_SH: u32 = 42;\npub const EM_SPARCV9: u32 = 43;\npub const EM_H8_300: u32 = 46;\npub const EM_IA_64: u32 = 50;\npub const EM_X86_64: u32 = 62;\npub const EM_S390: u32 = 22;\npub const EM_CRIS: u32 = 76;\npub const EM_M32R: u32 = 88;\npub const EM_MN10300: u32 = 89;\npub const EM_OPENRISC: u32 = 92;\npub const EM_BLACKFIN: u32 = 106;\npub const EM_ALTERA_NIOS2: u32 = 113;\npub const EM_TI_C6000: u32 = 140;\npub const EM_AARCH64: u32 = 183;\npub const EM_TILEPRO: u32 = 188;\npub const EM_MICROBLAZE: u32 = 189;\npub const EM_TILEGX: u32 = 191;\npub const EM_BPF: u32 = 247;\npub const EM_FRV: u32 = 21569;\npub const EM_ALPHA: u32 = 36902;\npub const EM_CYGNUS_M32R: u32 = 36929;\npub const EM_S390_OLD: u32 = 41872;\npub const EM_CYGNUS_MN10300: u32 = 48879;\n\npub const NLMSGERR_ATTR_UNUSED: int = 0;\npub const NLMSGERR_ATTR_MSG: int = 1;\npub const NLMSGERR_ATTR_OFFS: int = 2;\npub const NLMSGERR_ATTR_COOKIE: int = 3;\npub const NLMSGERR_ATTR_MAX: int = 3;\n\npub const NL_MMAP_STATUS_UNUSED: int = 0;\npub const NL_MMAP_STATUS_RESERVED: int = 1;\npub const NL_MMAP_STATUS_VALID: int = 2;\npub const NL_MMAP_STATUS_COPY: int = 3;\npub const NL_MMAP_STATUS_SKIP: int = 4;\n\npub const NETLINK_UNCONNECTED: int = 0;\npub const NETLINK_CONNECTED: int = 1;\n\npub const __BITS_PER_LONG: int = 64;\npub const __FD_SETSIZE: int = 1024;\npub const SI_LOAD_SHIFT: int = 16;\npub const _K_SS_MAXSIZE: int = 128;\npub const NETLINK_SMC: int = 22;\npub const NETLINK_INET_DIAG: int = 4;\npub const MAX_LINKS: int = 32;\n\npub const NLMSG_MIN_TYPE: int = 16;\npub const NETLINK_ADD_MEMBERSHIP: int = 1;\npub const NETLINK_DROP_MEMBERSHIP: int = 2;\npub const NETLINK_PKTINFO: int = 3;\npub const NETLINK_BROADCAST_ERROR: int = 4;\npub const NETLINK_NO_ENOBUFS: int = 5;\npub const NETLINK_RX_RING: int = 6;\npub const NETLINK_TX_RING: int = 7;\npub const NETLINK_LISTEN_ALL_NSID: int = 8;\npub const NETLINK_LIST_MEMBERSHIPS: int = 9;\npub const NETLINK_CAP_ACK: int = 10;\npub const NETLINK_EXT_ACK: int = 11;\npub const NL_MMAP_MSG_ALIGNMENT: int = 4;\npub const NET_MAJOR: int = 36;\n"
  },
  {
    "path": "netlink-sys/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub mod constants;\npub mod protocols {\n    pub use super::constants::{\n        NETLINK_AUDIT,\n        NETLINK_CONNECTOR,\n        NETLINK_CRYPTO,\n        NETLINK_DNRTMSG,\n        NETLINK_ECRYPTFS,\n        NETLINK_FIB_LOOKUP,\n        NETLINK_FIREWALL,\n        NETLINK_GENERIC,\n        NETLINK_IP6_FW,\n        NETLINK_ISCSI,\n        NETLINK_KOBJECT_UEVENT,\n        NETLINK_NETFILTER,\n        NETLINK_NFLOG,\n        NETLINK_RDMA,\n        NETLINK_ROUTE,\n        NETLINK_SCSITRANSPORT,\n        NETLINK_SELINUX,\n        NETLINK_SOCK_DIAG,\n        NETLINK_UNUSED,\n        NETLINK_USERSOCK,\n        NETLINK_XFRM,\n    };\n}\n\nmod socket;\npub use self::socket::Socket;\n\nmod addr;\npub use self::addr::SocketAddr;\n\nmod async_socket;\npub use self::async_socket::AsyncSocket;\n\npub mod async_socket_ext;\npub use self::async_socket_ext::AsyncSocketExt;\n\n#[cfg(feature = \"tokio_socket\")]\nmod tokio;\n#[cfg(feature = \"tokio_socket\")]\npub use self::tokio::TokioSocket;\n\n#[cfg(feature = \"smol_socket\")]\nmod smol;\n#[cfg(feature = \"smol_socket\")]\npub use self::smol::SmolSocket;\n\n#[cfg(feature = \"mio_socket\")]\nmod mio;\n"
  },
  {
    "path": "netlink-sys/src/mio.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::Socket;\nuse std::os::unix::io::AsRawFd;\n\nuse mio::{event::Source, unix::SourceFd};\n\nimpl Source for Socket {\n    fn register(\n        &mut self,\n        registry: &mio::Registry,\n        token: mio::Token,\n        interests: mio::Interest,\n    ) -> std::io::Result<()> {\n        let raw_fd = self.as_raw_fd();\n\n        SourceFd(&raw_fd).register(registry, token, interests)\n    }\n\n    fn reregister(\n        &mut self,\n        registry: &mio::Registry,\n        token: mio::Token,\n        interests: mio::Interest,\n    ) -> std::io::Result<()> {\n        let raw_fd = self.as_raw_fd();\n\n        SourceFd(&raw_fd).reregister(registry, token, interests)\n    }\n\n    fn deregister(&mut self, registry: &mio::Registry) -> std::io::Result<()> {\n        let raw_fd = self.as_raw_fd();\n\n        SourceFd(&raw_fd).deregister(registry)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn request_neighbour_dump(socket: &mut Socket) -> std::io::Result<()> {\n        // Buffer generated from:\n        // ```\n        // let mut neighbour_dump_request = NetlinkMessage {\n        //     header: NetlinkHeader {\n        //         flags: NLM_F_DUMP | NLM_F_REQUEST,\n        //         ..Default::default()\n        //     },\n        //     payload: NetlinkPayload::from(RtnlMessage::GetNeighbour(NeighbourMessage::default())),\n        // };\n        // ```\n        let buf = [\n            28, 0, 0, 0, 30, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        ];\n        socket.send(&buf[..], 0)?;\n\n        Ok(())\n    }\n\n    #[test]\n    fn test_event_loop() -> Result<(), Box<dyn std::error::Error>> {\n        use crate::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n        use mio::{Events, Interest, Poll, Token};\n        use std::time::Duration;\n\n        let mut poll = Poll::new()?;\n        let mut events = Events::with_capacity(128);\n\n        let mut socket = Socket::new(NETLINK_ROUTE)?;\n        socket.bind_auto()?;\n        socket.connect(&SocketAddr::new(0, 0))?;\n        poll.registry()\n            .register(&mut socket, Token(1), Interest::READABLE)?;\n\n        // Send neighbour query\n        request_neighbour_dump(&mut socket)?;\n\n        // Make sure that we got anything\n        poll.poll(&mut events, Some(Duration::from_secs(1)))?;\n        assert!(!events.is_empty());\n\n        // Make sure the we didn't get a thing after removing socket from loop\n        poll.registry().deregister(&mut socket)?;\n        poll.poll(&mut events, Some(Duration::from_secs(1)))?;\n        assert!(events.is_empty());\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "netlink-sys/src/smol.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    io,\n    os::unix::io::{AsRawFd, FromRawFd, RawFd},\n    task::{Context, Poll},\n};\n\nuse async_io::Async;\n\nuse futures::ready;\n\nuse log::trace;\n\nuse crate::{AsyncSocket, Socket, SocketAddr};\n\n/// An I/O object representing a Netlink socket.\npub struct SmolSocket(Async<Socket>);\n\nimpl FromRawFd for SmolSocket {\n    unsafe fn from_raw_fd(fd: RawFd) -> Self {\n        let socket = Socket::from_raw_fd(fd);\n        socket.set_non_blocking(true).unwrap();\n        SmolSocket(Async::new(socket).unwrap())\n    }\n}\n\nimpl AsRawFd for SmolSocket {\n    fn as_raw_fd(&self) -> RawFd {\n        self.0.get_ref().as_raw_fd()\n    }\n}\n\n// async_io::Async<..>::{read,write}_with[_mut] functions try IO first,\n// and only register context if it would block.\n// replicate this in these poll functions:\nimpl SmolSocket {\n    fn poll_write_with<F, R>(&mut self, cx: &mut Context<'_>, mut op: F) -> Poll<io::Result<R>>\n    where\n        F: FnMut(&mut Self) -> io::Result<R>,\n    {\n        loop {\n            match op(self) {\n                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}\n                res => return Poll::Ready(res),\n            }\n            // try again if writable now, otherwise come back later:\n            ready!(self.0.poll_writable(cx))?;\n        }\n    }\n\n    fn poll_read_with<F, R>(&mut self, cx: &mut Context<'_>, mut op: F) -> Poll<io::Result<R>>\n    where\n        F: FnMut(&mut Self) -> io::Result<R>,\n    {\n        loop {\n            match op(self) {\n                Err(err) if err.kind() == io::ErrorKind::WouldBlock => {}\n                res => return Poll::Ready(res),\n            }\n            // try again if readable now, otherwise come back later:\n            ready!(self.0.poll_readable(cx))?;\n        }\n    }\n}\n\nimpl AsyncSocket for SmolSocket {\n    fn socket_ref(&self) -> &Socket {\n        self.0.get_ref()\n    }\n\n    /// Mutable access to underyling [`Socket`]\n    fn socket_mut(&mut self) -> &mut Socket {\n        self.0.get_mut()\n    }\n\n    fn new(protocol: isize) -> io::Result<Self> {\n        let socket = Socket::new(protocol)?;\n        Ok(Self(Async::new(socket)?))\n    }\n\n    fn poll_send(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {\n        self.poll_write_with(cx, |this| this.0.get_mut().send(buf, 0))\n    }\n\n    fn poll_send_to(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n        addr: &SocketAddr,\n    ) -> Poll<io::Result<usize>> {\n        self.poll_write_with(cx, |this| this.0.get_mut().send_to(buf, addr, 0))\n    }\n\n    fn poll_recv<B>(&mut self, cx: &mut Context<'_>, buf: &mut B) -> Poll<io::Result<()>>\n    where\n        B: bytes::BufMut,\n    {\n        self.poll_read_with(cx, |this| this.0.get_mut().recv(buf, 0).map(|_len| ()))\n    }\n\n    fn poll_recv_from<B>(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &mut B,\n    ) -> Poll<io::Result<SocketAddr>>\n    where\n        B: bytes::BufMut,\n    {\n        self.poll_read_with(cx, |this| {\n            let x = this.0.get_mut().recv_from(buf, 0);\n            trace!(\"poll_recv_from: {:?}\", x);\n            x.map(|(_len, addr)| addr)\n        })\n    }\n\n    fn poll_recv_from_full(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<io::Result<(Vec<u8>, SocketAddr)>> {\n        self.poll_read_with(cx, |this| this.0.get_mut().recv_from_full())\n    }\n}\n"
  },
  {
    "path": "netlink-sys/src/socket.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    io::{Error, Result},\n    mem,\n    os::unix::io::{AsRawFd, FromRawFd, RawFd},\n};\n\nuse crate::SocketAddr;\n\n/// A netlink socket.\n///\n/// # Example\n///\n/// In this example we:\n///\n/// 1. open a new socket\n/// 2. send a message to the kernel\n/// 3. read the reponse\n///\n/// ```rust\n/// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n/// use std::process;\n///\n/// // open a new socket for the NETLINK_ROUTE subsystem (see \"man 7 rtnetlink\")\n/// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n/// // address of the remote peer we'll send a message to. This particular address is for the kernel\n/// let kernel_addr = SocketAddr::new(0, 0);\n/// // this is a valid message for listing the network links on the system\n/// let pkt = vec![\n///     0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00,\n///     0x00, 0x00, 0x00, 0x00, 0x00,\n/// ];\n/// // send the message to the kernel\n/// let n_sent = socket.send_to(&pkt[..], &kernel_addr, 0).unwrap();\n/// assert_eq!(n_sent, pkt.len());\n/// // buffer for receiving the response\n/// let mut buf = vec![0; 4096];\n/// loop {\n///     // receive a datagram\n///     let (n_received, sender_addr) = socket.recv_from(&mut &mut buf[..], 0).unwrap();\n///     assert_eq!(sender_addr, kernel_addr);\n///     println!(\"received datagram {:?}\", &buf[..n_received]);\n///     if buf[4] == 2 && buf[5] == 0 {\n///         println!(\"the kernel responded with an error\");\n///         return;\n///     }\n///     if buf[4] == 3 && buf[5] == 0 {\n///         println!(\"end of dump\");\n///         return;\n///     }\n/// }\n/// ```\n#[derive(Clone, Debug)]\npub struct Socket(RawFd);\n\nimpl AsRawFd for Socket {\n    fn as_raw_fd(&self) -> RawFd {\n        self.0\n    }\n}\n\nimpl FromRawFd for Socket {\n    unsafe fn from_raw_fd(fd: RawFd) -> Self {\n        Socket(fd)\n    }\n}\n\nimpl Drop for Socket {\n    fn drop(&mut self) {\n        unsafe { libc::close(self.0) };\n    }\n}\n\nimpl Socket {\n    /// Open a new socket for the given netlink subsystem. `protocol` must be one of the\n    /// [`netlink_sys::protocols`][protos] constants.\n    ///\n    /// [protos]: crate::protocols\n    pub fn new(protocol: isize) -> Result<Self> {\n        let res = unsafe {\n            libc::socket(\n                libc::PF_NETLINK,\n                libc::SOCK_DGRAM | libc::SOCK_CLOEXEC,\n                protocol as libc::c_int,\n            )\n        };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(Socket(res))\n    }\n\n    /// Bind the socket to the given address\n    pub fn bind(&mut self, addr: &SocketAddr) -> Result<()> {\n        let (addr_ptr, addr_len) = addr.as_raw();\n        let res = unsafe { libc::bind(self.0, addr_ptr, addr_len) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(())\n    }\n\n    /// Bind the socket to an address assigned by the kernel, and return that address.\n    pub fn bind_auto(&mut self) -> Result<SocketAddr> {\n        let mut addr = SocketAddr::new(0, 0);\n        self.bind(&addr)?;\n        self.get_address(&mut addr)?;\n        Ok(addr)\n    }\n\n    /// Get the socket address\n    pub fn get_address(&self, addr: &mut SocketAddr) -> Result<()> {\n        let (addr_ptr, mut addr_len) = addr.as_raw_mut();\n        let addr_len_copy = addr_len;\n        let addr_len_ptr = &mut addr_len as *mut libc::socklen_t;\n        let res = unsafe { libc::getsockname(self.0, addr_ptr, addr_len_ptr) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        assert_eq!(addr_len, addr_len_copy);\n        Ok(())\n    }\n\n    // when building with --features smol we don't need this\n    #[allow(dead_code)]\n    /// Make this socket non-blocking\n    pub fn set_non_blocking(&self, non_blocking: bool) -> Result<()> {\n        let mut non_blocking = non_blocking as libc::c_int;\n        let res = unsafe { libc::ioctl(self.0, libc::FIONBIO, &mut non_blocking) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(())\n    }\n\n    /// Connect the socket to the given address. Netlink is a connection-less protocol, so a socket can communicate with\n    /// multiple peers with the [`Socket::send_to`] and [`Socket::recv_from`] methods. However, if the socket only needs\n    /// to communicate with one peer, it is convenient not to have to bother with the peer address. This is what\n    /// `connect` is for. After calling `connect`, [`Socket::send`] and [`Socket::recv`] respectively send and receive\n    /// datagrams to and from `remote_addr`.\n    ///\n    /// # Examples\n    ///\n    /// In this example we:\n    ///\n    /// 1. open a socket\n    /// 2. connect it to the kernel with [`Socket::connect`]\n    /// 3. send a request to the kernel with [`Socket::send`]\n    /// 4. read the response (which can span over several messages) [`Socket::recv`]\n    ///\n    /// ```rust\n    /// use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};\n    /// use std::process;\n    ///\n    /// let mut socket = Socket::new(NETLINK_ROUTE).unwrap();\n    /// let _ = socket.bind_auto().unwrap();\n    /// let kernel_addr = SocketAddr::new(0, 0);\n    /// socket.connect(&kernel_addr).unwrap();\n    /// // This is a valid message for listing the network links on the system\n    /// let msg = vec![\n    ///     0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x03, 0xfd, 0xfe, 0x38, 0x5c, 0x00, 0x00, 0x00,\n    ///     0x00, 0x00, 0x00, 0x00, 0x00,\n    /// ];\n    /// let n_sent = socket.send(&msg[..], 0).unwrap();\n    /// assert_eq!(n_sent, msg.len());\n    /// // buffer for receiving the response\n    /// let mut buf = vec![0; 4096];\n    /// loop {\n    ///     let mut n_received = socket.recv(&mut &mut buf[..], 0).unwrap();\n    ///     println!(\"received {:?}\", &buf[..n_received]);\n    ///     if buf[4] == 2 && buf[5] == 0 {\n    ///         println!(\"the kernel responded with an error\");\n    ///         return;\n    ///     }\n    ///     if buf[4] == 3 && buf[5] == 0 {\n    ///         println!(\"end of dump\");\n    ///         return;\n    ///     }\n    /// }\n    /// ```\n    pub fn connect(&self, remote_addr: &SocketAddr) -> Result<()> {\n        // FIXME:\n        //\n        // Event though for SOCK_DGRAM sockets there's no IO, if our socket is non-blocking,\n        // connect() might return EINPROGRESS. In theory, the right way to treat EINPROGRESS would\n        // be to ignore the error, and let the user poll the socket to check when it becomes\n        // writable, indicating that the connection succeeded. The code already exists in mio for\n        // TcpStream:\n        //\n        // > pub fn connect(stream: net::TcpStream, addr: &SocketAddr) -> io::Result<TcpStream> {\n        // >     set_non_block(stream.as_raw_fd())?;\n        // >     match stream.connect(addr) {\n        // >         Ok(..) => {}\n        // >         Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}\n        // >         Err(e) => return Err(e),\n        // >     }\n        // >     Ok(TcpStream {  inner: stream })\n        // > }\n        //\n        // In practice, since the connection does not require any IO for SOCK_DGRAM sockets, it\n        // almost never returns EINPROGRESS and so for now, we just return whatever libc::connect\n        // returns. If it returns EINPROGRESS, the caller will have to handle the error themself\n        //\n        // Refs:\n        //\n        // - https://stackoverflow.com/a/14046386/1836144\n        // - https://lists.isc.org/pipermail/bind-users/2009-August/077527.html\n        let (addr, addr_len) = remote_addr.as_raw();\n        let res = unsafe { libc::connect(self.0, addr, addr_len) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(())\n    }\n\n    // Most of the comments in this method come from a discussion on rust users forum.\n    // [thread]: https://users.rust-lang.org/t/help-understanding-libc-call/17308/9\n    //\n    /// Read a datagram from the socket and return the number of bytes that have been read and the address of the\n    /// sender. The data being read is copied into `buf`. If `buf` is too small, the datagram is truncated. The\n    /// supported flags are the `MSG_*` described in `man 2 recvmsg`\n    ///\n    /// # Warning\n    ///\n    /// In datagram oriented protocols, `recv` and `recvfrom` receive normally only ONE datagram, but this seems not to\n    /// be always true for netlink sockets: with some protocols like `NETLINK_AUDIT`, multiple netlink packets can be\n    /// read with a single call.\n    pub fn recv_from<B>(&self, buf: &mut B, flags: libc::c_int) -> Result<(usize, SocketAddr)>\n    where\n        B: bytes::BufMut,\n    {\n        // Create an empty storage for the address. Note that Rust standard library create a\n        // sockaddr_storage so that it works for any address family, but here, we already know that\n        // we'll have a Netlink address, so we can create the appropriate storage.\n        let mut addr = unsafe { mem::zeroed::<libc::sockaddr_nl>() };\n\n        // recvfrom takes a *sockaddr as parameter so that it can accept any kind of address\n        // storage, so we need to create such a pointer for the sockaddr_nl we just initialized.\n        //\n        //                     Create a raw pointer to        Cast our raw pointer to a\n        //                     our storage. We cannot         generic pointer to *sockaddr\n        //                     pass it to recvfrom yet.       that recvfrom can use\n        //                                 ^                              ^\n        //                                 |                              |\n        //                  +--------------+---------------+    +---------+--------+\n        //                 /                                \\  /                    \\\n        let addr_ptr = &mut addr as *mut libc::sockaddr_nl as *mut libc::sockaddr;\n\n        // Why do we need to pass the address length? We're passing a generic *sockaddr to\n        // recvfrom. Somehow recvfrom needs to make sure that the address of the received packet\n        // would fit into the actual type that is behind *sockaddr: it could be a sockaddr_nl but\n        // also a sockaddr_in, a sockaddr_in6, or even the generic sockaddr_storage that can store\n        // any address.\n        let mut addrlen = mem::size_of_val(&addr);\n        // recvfrom does not take the address length by value (see [thread]), so we need to create\n        // a pointer to it.\n        let addrlen_ptr = &mut addrlen as *mut usize as *mut libc::socklen_t;\n\n        let chunk = buf.chunk_mut();\n        //                        Cast the *mut u8 into *mut void.\n        //                 This is equivalent to casting a *char into *void\n        //                                   See [thread]\n        //                                         ^\n        //             Create a *mut u8            |\n        //                    ^                    |\n        //                    |                    |\n        //             +------+-------+   +--------+-------+\n        //            /                \\ /                  \\\n        let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void;\n        let buf_len = chunk.len() as libc::size_t;\n\n        let res = unsafe { libc::recvfrom(self.0, buf_ptr, buf_len, flags, addr_ptr, addrlen_ptr) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        } else {\n            // with `MSG_TRUNC` `res` might exceed `buf_len`\n            let written = std::cmp::min(buf_len, res as usize);\n            unsafe {\n                buf.advance_mut(written);\n            }\n        }\n        Ok((res as usize, SocketAddr(addr)))\n    }\n\n    /// For a connected socket, `recv` reads a datagram from the socket. The sender is the remote peer the socket is\n    /// connected to (see [`Socket::connect`]). See also [`Socket::recv_from`]\n    pub fn recv<B>(&self, buf: &mut B, flags: libc::c_int) -> Result<usize>\n    where\n        B: bytes::BufMut,\n    {\n        let chunk = buf.chunk_mut();\n        let buf_ptr = chunk.as_mut_ptr() as *mut libc::c_void;\n        let buf_len = chunk.len() as libc::size_t;\n\n        let res = unsafe { libc::recv(self.0, buf_ptr, buf_len, flags) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        } else {\n            // with `MSG_TRUNC` `res` might exceed `buf_len`\n            let written = std::cmp::min(buf_len, res as usize);\n            unsafe {\n                buf.advance_mut(written);\n            }\n        }\n        Ok(res as usize)\n    }\n\n    /// Receive a full message. Unlike [`Socket::recv_from`], which truncates messages that exceed the length of the\n    /// buffer passed as argument, this method always reads a whole message, no matter its size.\n    pub fn recv_from_full(&self) -> Result<(Vec<u8>, SocketAddr)> {\n        // Peek\n        let mut buf: Vec<u8> = Vec::new();\n        let (peek_len, _) = self.recv_from(&mut buf, libc::MSG_PEEK | libc::MSG_TRUNC)?;\n\n        // Receive\n        buf.clear();\n        buf.reserve(peek_len);\n        let (rlen, addr) = self.recv_from(&mut buf, 0)?;\n        assert_eq!(rlen, peek_len);\n        Ok((buf, addr))\n    }\n\n    /// Send the given buffer `buf` to the remote peer with address `addr`. The supported flags are the `MSG_*` values\n    /// documented in `man 2 send`.\n    pub fn send_to(&self, buf: &[u8], addr: &SocketAddr, flags: libc::c_int) -> Result<usize> {\n        let (addr_ptr, addr_len) = addr.as_raw();\n        let buf_ptr = buf.as_ptr() as *const libc::c_void;\n        let buf_len = buf.len() as libc::size_t;\n\n        let res = unsafe { libc::sendto(self.0, buf_ptr, buf_len, flags, addr_ptr, addr_len) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(res as usize)\n    }\n\n    /// For a connected socket, `send` sends the given buffer `buf` to the remote peer the socket is connected to. See\n    /// also [`Socket::connect`] and [`Socket::send_to`].\n    pub fn send(&self, buf: &[u8], flags: libc::c_int) -> Result<usize> {\n        let buf_ptr = buf.as_ptr() as *const libc::c_void;\n        let buf_len = buf.len() as libc::size_t;\n\n        let res = unsafe { libc::send(self.0, buf_ptr, buf_len, flags) };\n        if res < 0 {\n            return Err(Error::last_os_error());\n        }\n        Ok(res as usize)\n    }\n\n    pub fn set_pktinfo(&mut self, value: bool) -> Result<()> {\n        let value: libc::c_int = if value { 1 } else { 0 };\n        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_PKTINFO, value)\n    }\n\n    pub fn get_pktinfo(&self) -> Result<bool> {\n        let res = getsockopt::<libc::c_int>(self.0, libc::SOL_NETLINK, libc::NETLINK_PKTINFO)?;\n        Ok(res == 1)\n    }\n\n    pub fn add_membership(&mut self, group: u32) -> Result<()> {\n        setsockopt(\n            self.0,\n            libc::SOL_NETLINK,\n            libc::NETLINK_ADD_MEMBERSHIP,\n            group,\n        )\n    }\n\n    pub fn drop_membership(&mut self, group: u32) -> Result<()> {\n        setsockopt(\n            self.0,\n            libc::SOL_NETLINK,\n            libc::NETLINK_DROP_MEMBERSHIP,\n            group,\n        )\n    }\n\n    // pub fn list_membership(&self) -> Vec<u32> {\n    //     unimplemented!();\n    //     // getsockopt won't be enough here, because we may need to perform 2 calls, and because the\n    //     // length of the list returned by libc::getsockopt is returned by mutating the length\n    //     // argument, which our implementation of getsockopt forbids.\n    // }\n\n    /// `NETLINK_BROADCAST_ERROR` (since Linux 2.6.30). When not set, `netlink_broadcast()` only\n    /// reports `ESRCH` errors and silently ignore `NOBUFS` errors.\n    pub fn set_broadcast_error(&mut self, value: bool) -> Result<()> {\n        let value: libc::c_int = if value { 1 } else { 0 };\n        setsockopt(\n            self.0,\n            libc::SOL_NETLINK,\n            libc::NETLINK_BROADCAST_ERROR,\n            value,\n        )\n    }\n\n    pub fn get_broadcast_error(&self) -> Result<bool> {\n        let res =\n            getsockopt::<libc::c_int>(self.0, libc::SOL_NETLINK, libc::NETLINK_BROADCAST_ERROR)?;\n        Ok(res == 1)\n    }\n\n    /// `NETLINK_NO_ENOBUFS` (since Linux 2.6.30). This flag can be used by unicast and broadcast\n    /// listeners to avoid receiving `ENOBUFS` errors.\n    pub fn set_no_enobufs(&mut self, value: bool) -> Result<()> {\n        let value: libc::c_int = if value { 1 } else { 0 };\n        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_NO_ENOBUFS, value)\n    }\n\n    pub fn get_no_enobufs(&self) -> Result<bool> {\n        let res = getsockopt::<libc::c_int>(self.0, libc::SOL_NETLINK, libc::NETLINK_NO_ENOBUFS)?;\n        Ok(res == 1)\n    }\n\n    /// `NETLINK_LISTEN_ALL_NSID` (since Linux 4.2). When set, this socket will receive netlink\n    /// notifications from  all  network  namespaces that have an nsid assigned into the network\n    /// namespace where the socket has been opened. The nsid is sent to user space via an ancillary\n    /// data.\n    pub fn set_listen_all_namespaces(&mut self, value: bool) -> Result<()> {\n        let value: libc::c_int = if value { 1 } else { 0 };\n        setsockopt(\n            self.0,\n            libc::SOL_NETLINK,\n            libc::NETLINK_LISTEN_ALL_NSID,\n            value,\n        )\n    }\n\n    pub fn get_listen_all_namespaces(&self) -> Result<bool> {\n        let res =\n            getsockopt::<libc::c_int>(self.0, libc::SOL_NETLINK, libc::NETLINK_LISTEN_ALL_NSID)?;\n        Ok(res == 1)\n    }\n\n    /// `NETLINK_CAP_ACK` (since Linux 4.2). The kernel may fail to allocate the necessary room\n    /// for the acknowledgment message back to user space.  This option trims off the payload of\n    /// the original netlink message. The netlink message header is still included, so the user can\n    /// guess from the sequence  number which message triggered the acknowledgment.\n    pub fn set_cap_ack(&mut self, value: bool) -> Result<()> {\n        let value: libc::c_int = if value { 1 } else { 0 };\n        setsockopt(self.0, libc::SOL_NETLINK, libc::NETLINK_CAP_ACK, value)\n    }\n\n    pub fn get_cap_ack(&self) -> Result<bool> {\n        let res = getsockopt::<libc::c_int>(self.0, libc::SOL_NETLINK, libc::NETLINK_CAP_ACK)?;\n        Ok(res == 1)\n    }\n}\n\n/// Wrapper around `getsockopt`:\n///\n/// ```no_rust\n/// int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len);\n/// ```\npub(crate) fn getsockopt<T: Copy>(fd: RawFd, level: libc::c_int, option: libc::c_int) -> Result<T> {\n    // Create storage for the options we're fetching\n    let mut slot: T = unsafe { mem::zeroed() };\n\n    // Create a mutable raw pointer to the storage so that getsockopt can fill the value\n    let slot_ptr = &mut slot as *mut T as *mut libc::c_void;\n\n    // Let getsockopt know how big our storage is\n    let mut slot_len = mem::size_of::<T>() as libc::socklen_t;\n\n    // getsockopt takes a mutable pointer to the length, because for some options like\n    // NETLINK_LIST_MEMBERSHIP where the option value is a list with arbitrary length,\n    // getsockopt uses this parameter to signal how big the storage needs to be.\n    let slot_len_ptr = &mut slot_len as *mut libc::socklen_t;\n\n    let res = unsafe { libc::getsockopt(fd, level, option, slot_ptr, slot_len_ptr) };\n    if res < 0 {\n        return Err(Error::last_os_error());\n    }\n\n    // Ignore the options that require the legnth to be set by getsockopt.\n    // We'll deal with them individually.\n    assert_eq!(slot_len as usize, mem::size_of::<T>());\n\n    Ok(slot)\n}\n\n// adapted from rust standard library\nfn setsockopt<T>(fd: RawFd, level: libc::c_int, option: libc::c_int, payload: T) -> Result<()> {\n    let payload = &payload as *const T as *const libc::c_void;\n    let payload_len = mem::size_of::<T>() as libc::socklen_t;\n\n    let res = unsafe { libc::setsockopt(fd, level, option, payload, payload_len) };\n    if res < 0 {\n        return Err(Error::last_os_error());\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::protocols::NETLINK_ROUTE;\n\n    #[test]\n    fn new() {\n        Socket::new(NETLINK_ROUTE).unwrap();\n    }\n\n    #[test]\n    fn connect() {\n        let sock = Socket::new(NETLINK_ROUTE).unwrap();\n        sock.connect(&SocketAddr::new(0, 0)).unwrap();\n    }\n\n    #[test]\n    fn bind() {\n        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();\n        sock.bind(&SocketAddr::new(4321, 0)).unwrap();\n    }\n\n    #[test]\n    fn bind_auto() {\n        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();\n        let addr = sock.bind_auto().unwrap();\n        // make sure that the address we got from the kernel is there\n        assert!(addr.port_number() != 0);\n    }\n\n    #[test]\n    fn set_non_blocking() {\n        let sock = Socket::new(NETLINK_ROUTE).unwrap();\n        sock.set_non_blocking(true).unwrap();\n        sock.set_non_blocking(false).unwrap();\n    }\n\n    #[test]\n    fn options() {\n        let mut sock = Socket::new(NETLINK_ROUTE).unwrap();\n\n        sock.set_cap_ack(true).unwrap();\n        assert!(sock.get_cap_ack().unwrap());\n        sock.set_cap_ack(false).unwrap();\n        assert!(!sock.get_cap_ack().unwrap());\n\n        sock.set_no_enobufs(true).unwrap();\n        assert!(sock.get_no_enobufs().unwrap());\n        sock.set_no_enobufs(false).unwrap();\n        assert!(!sock.get_no_enobufs().unwrap());\n\n        sock.set_broadcast_error(true).unwrap();\n        assert!(sock.get_broadcast_error().unwrap());\n        sock.set_broadcast_error(false).unwrap();\n        assert!(!sock.get_broadcast_error().unwrap());\n\n        // FIXME: these require root permissions\n        // sock.set_listen_all_namespaces(true).unwrap();\n        // assert!(sock.get_listen_all_namespaces().unwrap());\n        // sock.set_listen_all_namespaces(false).unwrap();\n        // assert!(!sock.get_listen_all_namespaces().unwrap());\n    }\n}\n"
  },
  {
    "path": "netlink-sys/src/tokio.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::{\n    io,\n    os::unix::io::{AsRawFd, FromRawFd, RawFd},\n    task::{Context, Poll},\n};\n\nuse futures::ready;\nuse log::trace;\nuse tokio::io::unix::AsyncFd;\n\nuse crate::{AsyncSocket, Socket, SocketAddr};\n\n/// An I/O object representing a Netlink socket.\npub struct TokioSocket(AsyncFd<Socket>);\n\nimpl FromRawFd for TokioSocket {\n    unsafe fn from_raw_fd(fd: RawFd) -> Self {\n        let socket = Socket::from_raw_fd(fd);\n        socket.set_non_blocking(true).unwrap();\n        TokioSocket(AsyncFd::new(socket).unwrap())\n    }\n}\n\nimpl AsRawFd for TokioSocket {\n    fn as_raw_fd(&self) -> RawFd {\n        self.0.get_ref().as_raw_fd()\n    }\n}\n\nimpl AsyncSocket for TokioSocket {\n    fn socket_ref(&self) -> &Socket {\n        self.0.get_ref()\n    }\n\n    /// Mutable access to underyling [`Socket`]\n    fn socket_mut(&mut self) -> &mut Socket {\n        self.0.get_mut()\n    }\n\n    fn new(protocol: isize) -> io::Result<Self> {\n        let socket = Socket::new(protocol)?;\n        socket.set_non_blocking(true)?;\n        Ok(Self(AsyncFd::new(socket)?))\n    }\n\n    fn poll_send(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {\n        loop {\n            // Check if the socket it writable. If\n            // AsyncFd::poll_write_ready returns NotReady, it will\n            // already have arranged for the current task to be\n            // notified when the socket becomes writable, so we can\n            // just return Pending\n            let mut guard = ready!(self.0.poll_write_ready(cx))?;\n\n            match guard.try_io(|inner| inner.get_ref().send(buf, 0)) {\n                Ok(x) => return Poll::Ready(x),\n                Err(_would_block) => continue,\n            }\n        }\n    }\n\n    fn poll_send_to(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &[u8],\n        addr: &SocketAddr,\n    ) -> Poll<io::Result<usize>> {\n        loop {\n            let mut guard = ready!(self.0.poll_write_ready(cx))?;\n\n            match guard.try_io(|inner| inner.get_ref().send_to(buf, addr, 0)) {\n                Ok(x) => return Poll::Ready(x),\n                Err(_would_block) => continue,\n            }\n        }\n    }\n\n    fn poll_recv<B>(&mut self, cx: &mut Context<'_>, buf: &mut B) -> Poll<io::Result<()>>\n    where\n        B: bytes::BufMut,\n    {\n        loop {\n            // Check if the socket is readable. If not,\n            // AsyncFd::poll_read_ready would have arranged for the\n            // current task to be polled again when the socket becomes\n            // readable, so we can just return Pending\n            let mut guard = ready!(self.0.poll_read_ready(cx))?;\n\n            match guard.try_io(|inner| inner.get_ref().recv(buf, 0)) {\n                Ok(x) => return Poll::Ready(x.map(|_len| ())),\n                Err(_would_block) => continue,\n            }\n        }\n    }\n\n    fn poll_recv_from<B>(\n        &mut self,\n        cx: &mut Context<'_>,\n        buf: &mut B,\n    ) -> Poll<io::Result<SocketAddr>>\n    where\n        B: bytes::BufMut,\n    {\n        loop {\n            trace!(\"poll_recv_from called\");\n            let mut guard = ready!(self.0.poll_read_ready(cx))?;\n            trace!(\"poll_recv_from socket is ready for reading\");\n\n            match guard.try_io(|inner| inner.get_ref().recv_from(buf, 0)) {\n                Ok(x) => {\n                    trace!(\"poll_recv_from {:?} bytes read\", x);\n                    return Poll::Ready(x.map(|(_len, addr)| addr));\n                }\n                Err(_would_block) => {\n                    trace!(\"poll_recv_from socket would block\");\n                    continue;\n                }\n            }\n        }\n    }\n\n    fn poll_recv_from_full(\n        &mut self,\n        cx: &mut Context<'_>,\n    ) -> Poll<io::Result<(Vec<u8>, SocketAddr)>> {\n        loop {\n            trace!(\"poll_recv_from_full called\");\n            let mut guard = ready!(self.0.poll_read_ready(cx))?;\n            trace!(\"poll_recv_from_full socket is ready for reading\");\n\n            match guard.try_io(|inner| inner.get_ref().recv_from_full()) {\n                Ok(x) => {\n                    trace!(\"poll_recv_from_full {:?} bytes read\", x);\n                    return Poll::Ready(x);\n                }\n                Err(_would_block) => {\n                    trace!(\"poll_recv_from_full socket would block\");\n                    continue;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "rtnetlink/Cargo.toml",
    "content": "[package]\nname = \"rtnetlink\"\nversion = \"0.11.0\"\nauthors = [\"Corentin Henry <corentinhenry@gmail.com>\"]\nedition = \"2018\"\n\nhomepage = \"https://github.com/little-dude/netlink\"\nkeywords = [\"netlink\", \"ip\", \"linux\"]\nlicense = \"MIT\"\nreadme = \"../README.md\"\nrepository = \"https://github.com/little-dude/netlink\"\ndescription = \"manipulate linux networking resources via netlink\"\n\n[features]\ntest_as_root = []\ndefault = [\"tokio_socket\"]\ntokio_socket = [\"netlink-proto/tokio_socket\", \"tokio\"]\nsmol_socket = [\"netlink-proto/smol_socket\", \"async-global-executor\"]\n\n[dependencies]\nfutures = \"0.3.11\"\nlog = \"0.4.8\"\nthiserror = \"1\"\nnetlink-packet-route = { version = \"0.13.0\", path = \"../netlink-packet-route\" }\nnetlink-proto = { default-features = false, version = \"0.10\", path = \"../netlink-proto\" }\nnix = { version = \"0.24.1\" , default-features = false, features = [\"fs\", \"mount\", \"sched\", \"signal\"] }\ntokio = { version = \"1.0.1\", features = [\"rt\"], optional = true}\nasync-global-executor = { version = \"2.0.2\", optional = true }\n\n[dev-dependencies]\nenv_logger = \"0.8.2\"\nipnetwork = \"0.18.0\"\ntokio = { version = \"1.0.1\", features = [\"macros\", \"rt\", \"rt-multi-thread\"] }\nasync-std = { version = \"1.9.0\", features = [\"attributes\"]}\n"
  },
  {
    "path": "rtnetlink/examples/add_address.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse std::env;\n\nuse ipnetwork::IpNetwork;\nuse rtnetlink::{new_connection, Error, Handle};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 3 {\n        usage();\n        return Ok(());\n    }\n\n    let link_name = &args[1];\n    let ip: IpNetwork = args[2].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid address\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = add_address(link_name, ip, handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    Ok(())\n}\n\nasync fn add_address(link_name: &str, ip: IpNetwork, handle: Handle) -> Result<(), Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .match_name(link_name.to_string())\n        .execute();\n    if let Some(link) = links.try_next().await? {\n        handle\n            .address()\n            .add(link.header.index, ip.ip(), ip.prefix())\n            .execute()\n            .await?\n    }\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_address -- <link_name> <ip_address>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_address\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_address <link_name> <ip_address>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_neighbour.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::{env, net::IpAddr};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 3 {\n        usage();\n        return Ok(());\n    }\n\n    let link_name = &args[1];\n    let ip: IpAddr = args[2].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid IP address\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = add_neighbour(link_name, ip, handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    Ok(())\n}\n\nasync fn add_neighbour(link_name: &str, ip: IpAddr, handle: Handle) -> Result<(), Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .match_name(link_name.to_string())\n        .execute();\n    if let Some(link) = links.try_next().await? {\n        handle\n            .neighbours()\n            .add(link.header.index, ip)\n            .execute()\n            .await?;\n        println!(\"Done\");\n    }\n\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_neighbour -- <link_name> <ip_address>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_neighbour\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_neighbour <link_name> <ip_address>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_netns.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::NetworkNamespace;\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    env_logger::init();\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let ns_name = &args[1];\n\n    NetworkNamespace::add(ns_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_netns -- <ns_name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example add_netns\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_netns <ns_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_netns_async.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::NetworkNamespace;\nuse std::env;\n\n#[async_std::main]\nasync fn main() -> Result<(), String> {\n    env_logger::init();\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let ns_name = &args[1];\n\n    NetworkNamespace::add(ns_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_netns -- <ns_name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example add_netns\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_netns <ns_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_route.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::env;\n\nuse ipnetwork::Ipv4Network;\nuse rtnetlink::{new_connection, Error, Handle};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 3 {\n        usage();\n        return Ok(());\n    }\n\n    let dest: Ipv4Network = args[1].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid destination\");\n        std::process::exit(1);\n    });\n    let gateway: Ipv4Network = args[2].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid gateway\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = add_route(&dest, &gateway, handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    Ok(())\n}\n\nasync fn add_route(dest: &Ipv4Network, gateway: &Ipv4Network, handle: Handle) -> Result<(), Error> {\n    let route = handle.route();\n    route\n        .add()\n        .v4()\n        .destination_prefix(dest.ip(), dest.prefix())\n        .gateway(gateway.ip())\n        .execute()\n        .await?;\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_route -- <destination>/<prefix_length> <gateway>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_route\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_route <destination>/<prefix_length> <gateway>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_route_pref_src.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::TryStreamExt;\nuse std::{env, net::Ipv4Addr};\n\nuse ipnetwork::Ipv4Network;\nuse rtnetlink::{new_connection, Error, Handle};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 4 {\n        usage();\n        return Ok(());\n    }\n\n    let dest: Ipv4Network = args[1].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid destination\");\n        std::process::exit(1);\n    });\n    let iface: String = args[2].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid interface\");\n        std::process::exit(1);\n    });\n    let source: Ipv4Addr = args[3].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid source\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = add_route(&dest, iface, source, handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    Ok(())\n}\n\nasync fn add_route(\n    dest: &Ipv4Network,\n    iface: String,\n    source: Ipv4Addr,\n    handle: Handle,\n) -> Result<(), Error> {\n    let iface_idx = handle\n        .link()\n        .get()\n        .match_name(iface)\n        .execute()\n        .try_next()\n        .await?\n        .unwrap()\n        .header\n        .index;\n\n    let route = handle.route();\n    route\n        .add()\n        .v4()\n        .destination_prefix(dest.ip(), dest.prefix())\n        .output_interface(iface_idx)\n        .pref_source(source)\n        .execute()\n        .await?;\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_route_pref_src -- <destination>/<prefix_length> <interface> <source>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_route_pref_src\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_route_pref_src <destination>/<prefix_length> <interface> <source>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_rule.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::env;\n\nuse ipnetwork::Ipv4Network;\nuse rtnetlink::{new_connection, Error, Handle};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n\n    let dest: Ipv4Network = args[1].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid destination\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = add_rule(&dest, handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    Ok(())\n}\n\nasync fn add_rule(dest: &Ipv4Network, handle: Handle) -> Result<(), Error> {\n    let rule = handle.rule();\n    rule.add()\n        .v4()\n        .destination_prefix(dest.ip(), dest.prefix())\n        .execute()\n        .await?;\n\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_rule -- <destination>/<prefix_length> <gateway>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_rule\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_rule <destination>/<prefix_length> <gateway>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/add_tc_qdisc_ingress.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::env;\n\nuse rtnetlink::new_connection;\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    env_logger::init();\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n\n    let index: u32 = args[1].parse().unwrap_or_else(|_| {\n        eprintln!(\"invalid index\");\n        std::process::exit(1);\n    });\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = handle.qdisc().add(index as i32).ingress().execute().await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example add_tc_qdisc_ingress -- <index>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example add_tc_qdisc_ingress \n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./add_tc_qdisc_ingress <index>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_bond.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::new_connection;\nuse std::net::{Ipv4Addr, Ipv6Addr};\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    handle\n        .link()\n        .add()\n        .bond(\"my-bond\".into())\n        .mode(1)\n        .miimon(100)\n        .updelay(100)\n        .downdelay(100)\n        .min_links(2)\n        .arp_ip_target(vec![Ipv4Addr::new(6, 6, 7, 7), Ipv4Addr::new(8, 8, 9, 10)])\n        .ns_ip6_target(vec![\n            Ipv6Addr::new(0xfd01, 0, 0, 0, 0, 0, 0, 1),\n            Ipv6Addr::new(0xfd02, 0, 0, 0, 0, 0, 0, 2),\n        ])\n        .up()\n        .execute()\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_bridge.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::new_connection;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    handle\n        .link()\n        .add()\n        .bridge(\"my-bridge-1\".into())\n        .execute()\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_macvlan.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    create_macvlan(handle, link_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nasync fn create_macvlan(handle: Handle, veth_name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(veth_name.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        // hard code mode: 4u32 i.e bridge mode\n        let request = handle\n            .link()\n            .add()\n            .macvlan(\"test_macvlan\".into(), link.header.index, 4u32);\n        request.execute().await?\n    } else {\n        println!(\"no link link {} found\", veth_name);\n    }\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example create_macvlan -- <link name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example create_macvlan\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./create_macvlan <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_macvtap.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    create_macvtap(handle, link_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nasync fn create_macvtap(handle: Handle, veth_name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(veth_name.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        // hard code mode: 4u32 i.e bridge mode\n        let request = handle\n            .link()\n            .add()\n            .macvtap(\"test_macvtap\".into(), link.header.index, 4u32);\n        request.execute().await?\n    } else {\n        println!(\"no link link {} found\", veth_name);\n    }\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example create_macvtap -- <link name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink; cargo build --example create_macvtap\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./create_macvtap <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_veth.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::new_connection;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    handle\n        .link()\n        .add()\n        .veth(\"veth-rs-1\".into(), \"veth-rs-2\".into())\n        .execute()\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n"
  },
  {
    "path": "rtnetlink/examples/create_vxlan.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    create_vxlan(handle, link_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nasync fn create_vxlan(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        handle\n            .link()\n            .add()\n            .vxlan(\"vxlan0\".into(), 10u32)\n            .link(link.header.index)\n            .port(4789)\n            .up()\n            .execute()\n            .await?\n    } else {\n        println!(\"no link link {} found\", name);\n    }\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example create_vxlan -- <link name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example create_vxlan\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./create_vxlan <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/del_link.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = del_link(handle, link_name.to_string()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn del_link(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        handle.link().del(link.header.index).execute().await\n    } else {\n        eprintln!(\"link {} not found\", name);\n        Ok(())\n    }\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example del_link -- <link name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example del_link\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./del_link <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/del_netns.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::NetworkNamespace;\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let ns_name = &args[1];\n\n    NetworkNamespace::del(ns_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example del_netns -- <ns_name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example del_netns\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./del_netns <ns_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/del_netns_async.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse rtnetlink::NetworkNamespace;\nuse std::env;\n\n#[async_std::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let ns_name = &args[1];\n\n    NetworkNamespace::del(ns_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example del_netns -- <ns_name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example del_netns\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./del_netns <ns_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/flush_addresses.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    if let Err(e) = flush_addresses(handle, link_name.to_string()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn flush_addresses(handle: Handle, link: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(link.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        // We should have received only one message\n        assert!(links.try_next().await?.is_none());\n\n        let mut addresses = handle\n            .address()\n            .get()\n            .set_link_index_filter(link.header.index)\n            .execute();\n        while let Some(addr) = addresses.try_next().await? {\n            handle.address().del(addr).execute().await?;\n        }\n        Ok(())\n    } else {\n        eprintln!(\"link {} not found\", link);\n        Ok(())\n    }\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example flush_addresses -- <link_name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example flush_addresses\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./flush_addresses <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_address.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    let link = \"lo\".to_string();\n    println!(\"dumping address for link \\\"{}\\\"\", link);\n\n    if let Err(e) = dump_addresses(handle, link).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn dump_addresses(handle: Handle, link: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(link.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        let mut addresses = handle\n            .address()\n            .get()\n            .set_link_index_filter(link.header.index)\n            .execute();\n        while let Some(msg) = addresses.try_next().await? {\n            println!(\"{:?}\", msg);\n        }\n        Ok(())\n    } else {\n        eprintln!(\"link {} not found\", link);\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_links.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{\n    new_connection,\n    packet::rtnl::{\n        constants::{AF_BRIDGE, RTEXT_FILTER_BRVLAN},\n        link::nlas::Nla,\n    },\n    Error,\n    Handle,\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    env_logger::init();\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    // Fetch a link by its index\n    let index = 1;\n    println!(\"*** retrieving link with index {} ***\", index);\n    if let Err(e) = get_link_by_index(handle.clone(), index).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Fetch a link by its name\n    let name = \"lo\";\n    println!(\"*** retrieving link named \\\"{}\\\" ***\", name);\n    if let Err(e) = get_link_by_name(handle.clone(), name.to_string()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the links and print their index and name\n    println!(\"*** dumping links ***\");\n    if let Err(e) = dump_links(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the bridge vlan information\n    if let Err(e) = dump_bridge_filter_info(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn get_link_by_index(handle: Handle, index: u32) -> Result<(), Error> {\n    let mut links = handle.link().get().match_index(index).execute();\n    let msg = if let Some(msg) = links.try_next().await? {\n        msg\n    } else {\n        eprintln!(\"no link with index {} found\", index);\n        return Ok(());\n    };\n    // We should have received only one message\n    assert!(links.try_next().await?.is_none());\n\n    for nla in msg.nlas.into_iter() {\n        if let Nla::IfName(name) = nla {\n            println!(\"found link with index {} (name = {})\", index, name);\n            return Ok(());\n        }\n    }\n    eprintln!(\n        \"found link with index {}, but this link does not have a name\",\n        index\n    );\n    Ok(())\n}\n\nasync fn get_link_by_name(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if (links.try_next().await?).is_some() {\n        println!(\"found link {}\", name);\n        // We should only have one link with that name\n        assert!(links.try_next().await?.is_none());\n    } else {\n        println!(\"no link link {} found\", name);\n    }\n    Ok(())\n}\n\nasync fn dump_links(handle: Handle) -> Result<(), Error> {\n    let mut links = handle.link().get().execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::IfName(name) = nla {\n                println!(\"found link {} ({})\", msg.header.index, name);\n                continue 'outer;\n            }\n        }\n        eprintln!(\"found link {}, but the link has no name\", msg.header.index);\n    }\n    Ok(())\n}\n\nasync fn dump_bridge_filter_info(handle: Handle) -> Result<(), Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .set_filter_mask(AF_BRIDGE as u8, RTEXT_FILTER_BRVLAN)\n        .execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::AfSpecBridge(data) = nla {\n                println!(\n                    \"found interface {} with AfSpecBridge data {:?})\",\n                    msg.header.index, data\n                );\n                continue 'outer;\n            }\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_links_async.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{\n    new_connection,\n    packet::rtnl::{\n        constants::{AF_BRIDGE, RTEXT_FILTER_BRVLAN},\n        link::nlas::Nla,\n    },\n    Error,\n    Handle,\n};\n\n#[async_std::main]\nasync fn main() -> Result<(), ()> {\n    env_logger::init();\n    let (connection, handle, _) = new_connection().unwrap();\n    async_std::task::spawn(connection);\n\n    // Fetch a link by its index\n    let index = 1;\n    println!(\"*** retrieving link with index {} ***\", index);\n    if let Err(e) = get_link_by_index(handle.clone(), index).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Fetch a link by its name\n    let name = \"lo\";\n    println!(\"*** retrieving link named \\\"{}\\\" ***\", name);\n    if let Err(e) = get_link_by_name(handle.clone(), name.to_string()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the links and print their index and name\n    println!(\"*** dumping links ***\");\n    if let Err(e) = dump_links(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the bridge vlan information\n    if let Err(e) = dump_bridge_filter_info(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn get_link_by_index(handle: Handle, index: u32) -> Result<(), Error> {\n    let mut links = handle.link().get().match_index(index).execute();\n    let msg = if let Some(msg) = links.try_next().await? {\n        msg\n    } else {\n        eprintln!(\"no link with index {} found\", index);\n        return Ok(());\n    };\n    // We should have received only one message\n    assert!(links.try_next().await?.is_none());\n\n    for nla in msg.nlas.into_iter() {\n        if let Nla::IfName(name) = nla {\n            println!(\"found link with index {} (name = {})\", index, name);\n            return Ok(());\n        }\n    }\n    eprintln!(\n        \"found link with index {}, but this link does not have a name\",\n        index\n    );\n    Ok(())\n}\n\nasync fn get_link_by_name(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if (links.try_next().await?).is_some() {\n        println!(\"found link {}\", name);\n        // We should only have one link with that name\n        assert!(links.try_next().await?.is_none());\n    } else {\n        println!(\"no link link {} found\", name);\n    }\n    Ok(())\n}\n\nasync fn dump_links(handle: Handle) -> Result<(), Error> {\n    let mut links = handle.link().get().execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::IfName(name) = nla {\n                println!(\"found link {} ({})\", msg.header.index, name);\n                continue 'outer;\n            }\n        }\n        eprintln!(\"found link {}, but the link has no name\", msg.header.index);\n    }\n    Ok(())\n}\n\nasync fn dump_bridge_filter_info(handle: Handle) -> Result<(), Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .set_filter_mask(AF_BRIDGE as u8, RTEXT_FILTER_BRVLAN)\n        .execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::AfSpecBridge(data) = nla {\n                println!(\n                    \"found interface {} with AfSpecBridge data {:?})\",\n                    msg.header.index, data\n                );\n                continue 'outer;\n            }\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_links_thread_builder.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\n\nuse rtnetlink::{\n    new_connection,\n    packet::rtnl::{\n        constants::{AF_BRIDGE, RTEXT_FILTER_BRVLAN},\n        link::nlas::Nla,\n    },\n    Error,\n    Handle,\n};\n\nasync fn do_it(rt: &tokio::runtime::Runtime) -> Result<(), ()> {\n    env_logger::init();\n    let (connection, handle, _) = new_connection().unwrap();\n    rt.spawn(connection);\n\n    // Fetch a link by its index\n    let index = 1;\n    println!(\"*** retrieving link with index {} ***\", index);\n    if let Err(e) = get_link_by_index(handle.clone(), index).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Fetch a link by its name\n    let name = \"lo\";\n    println!(\"*** retrieving link named \\\"{}\\\" ***\", name);\n    if let Err(e) = get_link_by_name(handle.clone(), name.to_string()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the links and print their index and name\n    println!(\"*** dumping links ***\");\n    if let Err(e) = dump_links(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    // Dump all the bridge vlan information\n    if let Err(e) = dump_bridge_filter_info(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n\n    Ok(())\n}\n\nasync fn get_link_by_index(handle: Handle, index: u32) -> Result<(), Error> {\n    let mut links = handle.link().get().match_index(index).execute();\n    let msg = if let Some(msg) = links.try_next().await? {\n        msg\n    } else {\n        eprintln!(\"no link with index {} found\", index);\n        return Ok(());\n    };\n    // We should have received only one message\n    assert!(links.try_next().await?.is_none());\n\n    for nla in msg.nlas.into_iter() {\n        if let Nla::IfName(name) = nla {\n            println!(\"found link with index {} (name = {})\", index, name);\n            return Ok(());\n        }\n    }\n    eprintln!(\n        \"found link with index {}, but this link does not have a name\",\n        index\n    );\n    Ok(())\n}\n\nasync fn get_link_by_name(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if (links.try_next().await?).is_some() {\n        println!(\"found link {}\", name);\n        // We should only have one link with that name\n        assert!(links.try_next().await?.is_none());\n    } else {\n        println!(\"no link link {} found\", name);\n    }\n    Ok(())\n}\n\nasync fn dump_links(handle: Handle) -> Result<(), Error> {\n    let mut links = handle.link().get().execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::IfName(name) = nla {\n                println!(\"found link {} ({})\", msg.header.index, name);\n                continue 'outer;\n            }\n        }\n        eprintln!(\"found link {}, but the link has no name\", msg.header.index);\n    }\n    Ok(())\n}\n\nasync fn dump_bridge_filter_info(handle: Handle) -> Result<(), Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .set_filter_mask(AF_BRIDGE as u8, RTEXT_FILTER_BRVLAN)\n        .execute();\n    'outer: while let Some(msg) = links.try_next().await? {\n        for nla in msg.nlas.into_iter() {\n            if let Nla::AfSpecBridge(data) = nla {\n                println!(\n                    \"found interface {} with AfSpecBridge data {:?})\",\n                    msg.header.index, data\n                );\n                continue 'outer;\n            }\n        }\n    }\n    Ok(())\n}\n\nfn main() -> Result<(), String> {\n    let rt = tokio::runtime::Builder::new_multi_thread()\n        .enable_io()\n        .build()\n        .unwrap();\n\n    let future = do_it(&rt);\n    println!(\"blocking in main\");\n    rt.handle().block_on(future).unwrap();\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_neighbours.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle, IpVersion};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    println!(\"dumping neighbours\");\n    if let Err(e) = dump_neighbours(handle.clone()).await {\n        eprintln!(\"{}\", e);\n    }\n    println!();\n\n    Ok(())\n}\n\nasync fn dump_neighbours(handle: Handle) -> Result<(), Error> {\n    let mut neighbours = handle\n        .neighbours()\n        .get()\n        .set_family(IpVersion::V4)\n        .execute();\n    while let Some(route) = neighbours.try_next().await? {\n        println!(\"{:?}\", route);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_route.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle, IpVersion};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    println!(\"dumping routes for IPv4\");\n    if let Err(e) = dump_addresses(handle.clone(), IpVersion::V4).await {\n        eprintln!(\"{}\", e);\n    }\n    println!();\n\n    println!(\"dumping routes for IPv6\");\n    if let Err(e) = dump_addresses(handle.clone(), IpVersion::V6).await {\n        eprintln!(\"{}\", e);\n    }\n    println!();\n\n    Ok(())\n}\n\nasync fn dump_addresses(handle: Handle, ip_version: IpVersion) -> Result<(), Error> {\n    let mut routes = handle.route().get(ip_version).execute();\n    while let Some(route) = routes.try_next().await? {\n        println!(\"{:?}\", route);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/get_rule.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle, IpVersion};\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    println!(\"dumping rules for IPv4\");\n    if let Err(e) = dump_addresses(handle.clone(), IpVersion::V4).await {\n        eprintln!(\"{}\", e);\n    }\n    println!();\n\n    println!(\"dumping rules for IPv6\");\n    if let Err(e) = dump_addresses(handle.clone(), IpVersion::V6).await {\n        eprintln!(\"{}\", e);\n    }\n    println!();\n\n    Ok(())\n}\n\nasync fn dump_addresses(handle: Handle, ip_version: IpVersion) -> Result<(), Error> {\n    let mut rules = handle.rule().get(ip_version).execute();\n    while let Some(rule) = rules.try_next().await? {\n        println!(\"{:?}\", rule);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/ip_monitor.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse netlink_packet_route::constants::*;\nuse rtnetlink::{\n    new_connection,\n    sys::{AsyncSocket, SocketAddr},\n};\n\nconst fn nl_mgrp(group: u32) -> u32 {\n    if group > 31 {\n        panic!(\"use netlink_sys::Socket::add_membership() for this group\");\n    }\n    if group == 0 {\n        0\n    } else {\n        1 << (group - 1)\n    }\n}\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    // conn - `Connection` that has a netlink socket which is a `Future` that polls the socket\n    // and thus must have an event loop\n    //\n    // handle - `Handle` to the `Connection`. Used to send/recv netlink messages.\n    //\n    // messages - A channel receiver.\n    let (mut conn, mut _handle, mut messages) = new_connection().map_err(|e| format!(\"{}\", e))?;\n\n    // These flags specify what kinds of broadcast messages we want to listen for.\n    let groups = nl_mgrp(RTNLGRP_LINK)\n        | nl_mgrp(RTNLGRP_IPV4_IFADDR)\n        | nl_mgrp(RTNLGRP_IPV6_IFADDR)\n        | nl_mgrp(RTNLGRP_IPV4_ROUTE)\n        | nl_mgrp(RTNLGRP_IPV6_ROUTE)\n        | nl_mgrp(RTNLGRP_MPLS_ROUTE)\n        | nl_mgrp(RTNLGRP_IPV4_MROUTE)\n        | nl_mgrp(RTNLGRP_IPV6_MROUTE)\n        | nl_mgrp(RTNLGRP_NEIGH)\n        | nl_mgrp(RTNLGRP_IPV4_NETCONF)\n        | nl_mgrp(RTNLGRP_IPV6_NETCONF)\n        | nl_mgrp(RTNLGRP_IPV4_RULE)\n        | nl_mgrp(RTNLGRP_IPV6_RULE)\n        | nl_mgrp(RTNLGRP_NSID)\n        | nl_mgrp(RTNLGRP_MPLS_NETCONF);\n\n    let addr = SocketAddr::new(0, groups);\n    conn.socket_mut()\n        .socket_mut()\n        .bind(&addr)\n        .expect(\"Failed to bind\");\n\n    // Spawn `Connection` to start polling netlink socket.\n    tokio::spawn(conn);\n\n    // Use `Handle` to send request to kernel to start multicasting rtnetlink events.\n    tokio::spawn(async move {\n        // Create message to enable\n    });\n\n    // Start receiving events through `messages` channel.\n    while let Some((message, _)) = messages.next().await {\n        let payload = message.payload;\n        println!(\"{:?}\", payload);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/listen.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This example opens a netlink socket, registers for IPv4 and IPv6 routing changes, listens for\n//! said changes and prints the received messages.\n\nuse futures::stream::StreamExt;\n\nuse rtnetlink::{\n    constants::{RTMGRP_IPV4_ROUTE, RTMGRP_IPV6_ROUTE},\n    new_connection,\n    sys::{AsyncSocket, SocketAddr},\n};\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    // Open the netlink socket\n    let (mut connection, _, mut messages) = new_connection().map_err(|e| format!(\"{}\", e))?;\n\n    // These flags specify what kinds of broadcast messages we want to listen for.\n    let mgroup_flags = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;\n\n    // A netlink socket address is created with said flags.\n    let addr = SocketAddr::new(0, mgroup_flags);\n    // Said address is bound so new conenctions and thus new message broadcasts can be received.\n    connection\n        .socket_mut()\n        .socket_mut()\n        .bind(&addr)\n        .expect(\"failed to bind\");\n    tokio::spawn(connection);\n\n    while let Some((message, _)) = messages.next().await {\n        let payload = message.payload;\n        println!(\"Route change message - {:?}\", payload);\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "rtnetlink/examples/property_altname.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{\n    new_connection,\n    packet::{\n        rtnl::link::nlas::{Nla, Prop},\n        LinkMessage,\n    },\n    Error,\n    Handle,\n};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), ()> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() < 3 {\n        usage();\n        return Ok(());\n    }\n\n    let link_name = &args[1];\n    let action = &args[2];\n    let alt_ifnames = &args[3..].iter().map(String::as_str).collect();\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    match action.as_str() {\n        \"add\" => {\n            if let Err(e) = add_property_alt_ifnames(link_name, alt_ifnames, handle.clone()).await {\n                eprintln!(\"{}\", e);\n            }\n        }\n\n        \"del\" => {\n            if let Err(e) = del_property_alt_ifnames(link_name, alt_ifnames, handle.clone()).await {\n                eprintln!(\"{}\", e);\n            }\n        }\n\n        \"show\" => {\n            if let Err(e) = show_property_alt_ifnames(link_name, handle.clone()).await {\n                eprintln!(\"{}\", e);\n            }\n        }\n\n        _ => panic!(\"Unknown action {:?}\", action),\n    }\n\n    Ok(())\n}\n\nasync fn show_property_alt_ifnames(link_name: &str, handle: Handle) -> Result<(), Error> {\n    for nla in get_link(link_name, handle).await?.nlas.into_iter() {\n        if let Nla::PropList(ref prop_list) = nla {\n            for prop in prop_list {\n                if let Prop::AltIfName(altname) = prop {\n                    println!(\"altname: {}\", altname);\n                }\n            }\n        }\n    }\n\n    Ok(())\n}\n\nasync fn add_property_alt_ifnames(\n    link_name: &str,\n    alt_ifnames: &Vec<&str>,\n    handle: Handle,\n) -> Result<(), Error> {\n    let link_index = get_link_index(link_name, handle.clone()).await?;\n\n    handle\n        .link()\n        .property_add(link_index)\n        .alt_ifname(alt_ifnames)\n        .execute()\n        .await?;\n\n    Ok(())\n}\n\nasync fn del_property_alt_ifnames(\n    link_name: &str,\n    alt_ifnames: &Vec<&str>,\n    handle: Handle,\n) -> Result<(), Error> {\n    let link_index = get_link_index(link_name, handle.clone()).await?;\n\n    handle\n        .link()\n        .property_del(link_index)\n        .alt_ifname(alt_ifnames)\n        .execute()\n        .await?;\n\n    Ok(())\n}\n\nasync fn get_link(link_name: &str, handle: Handle) -> Result<LinkMessage, Error> {\n    let mut links = handle\n        .link()\n        .get()\n        .match_name(link_name.to_string())\n        .execute();\n\n    match links.try_next().await? {\n        Some(msg) => Ok(msg),\n        _ => {\n            eprintln!(\"Interface {} not found\", link_name);\n            Err(Error::RequestFailed)\n        }\n    }\n}\n\nasync fn get_link_index(link_name: &str, handle: Handle) -> Result<u32, Error> {\n    Ok(get_link(link_name, handle.clone()).await?.header.index)\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example property_altname -- <link_name> [add | del | show] ALTNAME [ALTNAME ...]\n\nNote that you need to run this program as root for add and del. Instead of running cargo as root,\nbuild the example normally:\n\n    cd rtnetlink ; cargo build --example property_altname\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./property_altname <link_name> <ip_address>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/examples/set_link_down.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse rtnetlink::{new_connection, Error, Handle};\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), String> {\n    let args: Vec<String> = env::args().collect();\n    if args.len() != 2 {\n        usage();\n        return Ok(());\n    }\n    let link_name = &args[1];\n\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n\n    set_link_down(handle, link_name.to_string())\n        .await\n        .map_err(|e| format!(\"{}\", e))\n}\n\nasync fn set_link_down(handle: Handle, name: String) -> Result<(), Error> {\n    let mut links = handle.link().get().match_name(name.clone()).execute();\n    if let Some(link) = links.try_next().await? {\n        handle\n            .link()\n            .set(link.header.index)\n            .down()\n            .execute()\n            .await?\n    } else {\n        println!(\"no link link {} found\", name);\n    }\n    Ok(())\n}\n\nfn usage() {\n    eprintln!(\n        \"usage:\n    cargo run --example set_link_down -- <link name>\n\nNote that you need to run this program as root. Instead of running cargo as root,\nbuild the example normally:\n\n    cd netlink-ip ; cargo build --example set_link_down\n\nThen find the binary in the target directory:\n\n    cd ../target/debug/example ; sudo ./set_link_down <link_name>\"\n    );\n}\n"
  },
  {
    "path": "rtnetlink/src/addr/add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\nuse std::net::{IpAddr, Ipv4Addr};\n\nuse netlink_packet_route::{\n    nlas::address::Nla,\n    AddressMessage,\n    NetlinkMessage,\n    RtnlMessage,\n    AF_INET,\n    AF_INET6,\n    NLM_F_ACK,\n    NLM_F_CREATE,\n    NLM_F_EXCL,\n    NLM_F_REPLACE,\n    NLM_F_REQUEST,\n};\n\nuse crate::{try_nl, Error, Handle};\n\n/// A request to create a new address. This is equivalent to the `ip address add` commands.\npub struct AddressAddRequest {\n    handle: Handle,\n    message: AddressMessage,\n    replace: bool,\n}\n\nimpl AddressAddRequest {\n    pub(crate) fn new(handle: Handle, index: u32, address: IpAddr, prefix_len: u8) -> Self {\n        let mut message = AddressMessage::default();\n\n        message.header.prefix_len = prefix_len;\n        message.header.index = index;\n\n        let address_vec = match address {\n            IpAddr::V4(ipv4) => {\n                message.header.family = AF_INET as u8;\n                ipv4.octets().to_vec()\n            }\n            IpAddr::V6(ipv6) => {\n                message.header.family = AF_INET6 as u8;\n                ipv6.octets().to_vec()\n            }\n        };\n\n        if address.is_multicast() {\n            message.nlas.push(Nla::Multicast(address_vec));\n        } else if address.is_unspecified() {\n            message.nlas.push(Nla::Unspec(address_vec));\n        } else if address.is_ipv6() {\n            message.nlas.push(Nla::Address(address_vec));\n        } else {\n            message.nlas.push(Nla::Address(address_vec.clone()));\n\n            // for IPv4 the IFA_LOCAL address can be set to the same value as IFA_ADDRESS\n            message.nlas.push(Nla::Local(address_vec.clone()));\n\n            // set the IFA_BROADCAST address as well (IPv6 does not support broadcast)\n            if prefix_len == 32 {\n                message.nlas.push(Nla::Broadcast(address_vec));\n            } else {\n                let ip_addr: u32 = u32::from(Ipv4Addr::new(\n                    address_vec[0],\n                    address_vec[1],\n                    address_vec[2],\n                    address_vec[3],\n                ));\n                let brd = Ipv4Addr::from((0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr);\n                message.nlas.push(Nla::Broadcast(brd.octets().to_vec()));\n            };\n        }\n        AddressAddRequest {\n            handle,\n            message,\n            replace: false,\n        }\n    }\n\n    /// Replace existing matching address.\n    pub fn replace(self) -> Self {\n        Self {\n            replace: true,\n            ..self\n        }\n    }\n\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let AddressAddRequest {\n            mut handle,\n            message,\n            replace,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::NewAddress(message));\n        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request message.\n    pub fn message_mut(&mut self) -> &mut AddressMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/addr/del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{AddressMessage, NetlinkMessage, RtnlMessage, NLM_F_ACK, NLM_F_REQUEST},\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct AddressDelRequest {\n    handle: Handle,\n    message: AddressMessage,\n}\n\nimpl AddressDelRequest {\n    pub(crate) fn new(handle: Handle, message: AddressMessage) -> Self {\n        AddressDelRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let AddressDelRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::DelAddress(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n        let mut response = handle.request(req)?;\n        while let Some(msg) = response.next().await {\n            try_nl!(msg);\n        }\n        Ok(())\n    }\n\n    pub fn message_mut(&mut self) -> &mut AddressMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/addr/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream, TryStreamExt},\n    FutureExt,\n};\nuse std::net::IpAddr;\n\nuse netlink_packet_route::{\n    nlas::address::Nla,\n    AddressMessage,\n    NetlinkMessage,\n    RtnlMessage,\n    NLM_F_DUMP,\n    NLM_F_REQUEST,\n};\n\nuse crate::{try_rtnl, Error, Handle};\n\npub struct AddressGetRequest {\n    handle: Handle,\n    message: AddressMessage,\n    filter_builder: AddressFilterBuilder,\n}\n\nimpl AddressGetRequest {\n    pub(crate) fn new(handle: Handle) -> Self {\n        AddressGetRequest {\n            handle,\n            message: AddressMessage::default(),\n            filter_builder: AddressFilterBuilder::new(),\n        }\n    }\n\n    pub fn message_mut(&mut self) -> &mut AddressMessage {\n        &mut self.message\n    }\n\n    pub fn execute(self) -> impl TryStream<Ok = AddressMessage, Error = Error> {\n        let AddressGetRequest {\n            mut handle,\n            message,\n            filter_builder,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetAddress(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        let filter = filter_builder.build();\n        match handle.request(req) {\n            Ok(response) => Either::Left(\n                response\n                    .map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewAddress)))\n                    .try_filter(move |msg| future::ready(filter(msg))),\n            ),\n            Err(e) => Either::Right(future::err::<AddressMessage, Error>(e).into_stream()),\n        }\n    }\n\n    /// Return only the addresses of the given interface.\n    pub fn set_link_index_filter(mut self, index: u32) -> Self {\n        self.filter_builder.index = Some(index);\n        self\n    }\n\n    /// Return only the addresses of the given prefix length.\n    pub fn set_prefix_length_filter(mut self, prefix: u8) -> Self {\n        self.filter_builder.prefix_len = Some(prefix);\n        self\n    }\n\n    /// Return only the addresses of the given prefix length.\n    pub fn set_address_filter(mut self, address: IpAddr) -> Self {\n        self.filter_builder.address = Some(address);\n        self\n    }\n}\n\n// The reason for having filters, is that we cannot retrieve addresses\n// that match the given message, like we do for links.\n//\n// See:\n// https://lists.infradead.org/pipermail/libnl/2013-June/001014.html\n// https://patchwork.ozlabs.org/patch/133440/\n#[derive(Default)]\nstruct AddressFilterBuilder {\n    index: Option<u32>,\n    address: Option<IpAddr>,\n    prefix_len: Option<u8>,\n}\n\nimpl AddressFilterBuilder {\n    fn new() -> Self {\n        Default::default()\n    }\n\n    fn build(self) -> impl Fn(&AddressMessage) -> bool {\n        use Nla::*;\n\n        move |msg: &AddressMessage| {\n            if let Some(index) = self.index {\n                if msg.header.index != index {\n                    return false;\n                }\n            }\n\n            if let Some(prefix_len) = self.prefix_len {\n                if msg.header.prefix_len != prefix_len {\n                    return false;\n                }\n            }\n\n            if let Some(address) = self.address {\n                for nla in msg.nlas.iter() {\n                    if let Unspec(x) | Address(x) | Local(x) | Multicast(x) | Anycast(x) = nla {\n                        let is_match = match address {\n                            IpAddr::V4(address) => x[..] == address.octets()[..],\n                            IpAddr::V6(address) => x[..] == address.octets()[..],\n                        };\n                        if is_match {\n                            return true;\n                        }\n                    }\n                }\n                return false;\n            }\n            true\n        }\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/addr/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::net::IpAddr;\n\nuse super::{AddressAddRequest, AddressDelRequest, AddressGetRequest};\nuse crate::Handle;\n\nuse netlink_packet_route::AddressMessage;\n\npub struct AddressHandle(Handle);\n\nimpl AddressHandle {\n    pub fn new(handle: Handle) -> Self {\n        AddressHandle(handle)\n    }\n\n    /// Retrieve the list of ip addresses (equivalent to `ip addr show`)\n    pub fn get(&self) -> AddressGetRequest {\n        AddressGetRequest::new(self.0.clone())\n    }\n\n    /// Add an ip address on an interface (equivalent to `ip addr add`)\n    pub fn add(&self, index: u32, address: IpAddr, prefix_len: u8) -> AddressAddRequest {\n        AddressAddRequest::new(self.0.clone(), index, address, prefix_len)\n    }\n\n    /// Delete the given address\n    pub fn del(&self, address: AddressMessage) -> AddressDelRequest {\n        AddressDelRequest::new(self.0.clone(), address)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/addr/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod add;\npub use self::add::*;\n\nmod del;\npub use self::del::*;\n\nmod get;\npub use self::get::*;\n"
  },
  {
    "path": "rtnetlink/src/connection.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::io;\n\nuse futures::channel::mpsc::UnboundedReceiver;\n\nuse crate::{\n    packet::{NetlinkMessage, RtnlMessage},\n    proto::Connection,\n    sys::{protocols::NETLINK_ROUTE, AsyncSocket, SocketAddr},\n    Handle,\n};\n\n#[cfg(feature = \"tokio_socket\")]\n#[allow(clippy::type_complexity)]\npub fn new_connection() -> io::Result<(\n    Connection<RtnlMessage>,\n    Handle,\n    UnboundedReceiver<(NetlinkMessage<RtnlMessage>, SocketAddr)>,\n)> {\n    new_connection_with_socket()\n}\n\n#[allow(clippy::type_complexity)]\npub fn new_connection_with_socket<S>() -> io::Result<(\n    Connection<RtnlMessage, S>,\n    Handle,\n    UnboundedReceiver<(NetlinkMessage<RtnlMessage>, SocketAddr)>,\n)>\nwhere\n    S: AsyncSocket,\n{\n    let (conn, handle, messages) = netlink_proto::new_connection_with_socket(NETLINK_ROUTE)?;\n    Ok((conn, Handle::new(handle), messages))\n}\n"
  },
  {
    "path": "rtnetlink/src/constants.rs",
    "content": "// SPDX-License-Identifier: MIT\n\npub const RTMGRP_LINK: u32 = 1;\npub const RTMGRP_NOTIFY: u32 = 2;\npub const RTMGRP_NEIGH: u32 = 4;\npub const RTMGRP_TC: u32 = 8;\npub const RTMGRP_IPV4_IFADDR: u32 = 16;\npub const RTMGRP_IPV4_MROUTE: u32 = 32;\npub const RTMGRP_IPV4_ROUTE: u32 = 64;\npub const RTMGRP_IPV4_RULE: u32 = 128;\npub const RTMGRP_IPV6_IFADDR: u32 = 256;\npub const RTMGRP_IPV6_MROUTE: u32 = 512;\npub const RTMGRP_IPV6_ROUTE: u32 = 1024;\npub const RTMGRP_IPV6_IFINFO: u32 = 2048;\npub const RTMGRP_DECNET_IFADDR: u32 = 4096;\npub const RTMGRP_DECNET_ROUTE: u32 = 16_384;\npub const RTMGRP_IPV6_PREFIX: u32 = 131_072;\n"
  },
  {
    "path": "rtnetlink/src/errors.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse thiserror::Error;\n\nuse crate::packet::{ErrorMessage, NetlinkMessage, RtnlMessage};\n\n#[derive(Clone, Eq, PartialEq, Debug, Error)]\npub enum Error {\n    #[error(\"Received an unexpected message {0:?}\")]\n    UnexpectedMessage(NetlinkMessage<RtnlMessage>),\n\n    #[error(\"Received a netlink error message {0}\")]\n    NetlinkError(ErrorMessage),\n\n    #[error(\"A netlink request failed\")]\n    RequestFailed,\n\n    #[error(\"Namespace error {0}\")]\n    NamespaceError(String),\n\n    #[error(\n        \"Received a link message (RTM_GETLINK, RTM_NEWLINK, RTM_SETLINK or RTMGETLINK) with an invalid hardware address attribute: {0:?}.\"\n    )]\n    InvalidHardwareAddress(Vec<u8>),\n\n    #[error(\"Failed to parse an IP address: {0:?}\")]\n    InvalidIp(Vec<u8>),\n\n    #[error(\"Failed to parse a network address (IP and mask): {0:?}/{1:?}\")]\n    InvalidAddress(Vec<u8>, Vec<u8>),\n}\n"
  },
  {
    "path": "rtnetlink/src/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::Stream;\n\nuse crate::{\n    packet::{NetlinkMessage, RtnlMessage},\n    AddressHandle,\n    Error,\n    LinkHandle,\n    NeighbourHandle,\n    QDiscHandle,\n    RouteHandle,\n    RuleHandle,\n    TrafficChainHandle,\n    TrafficClassHandle,\n    TrafficFilterHandle,\n};\nuse netlink_proto::{sys::SocketAddr, ConnectionHandle};\n\n#[derive(Clone, Debug)]\npub struct Handle(ConnectionHandle<RtnlMessage>);\n\nimpl Handle {\n    pub(crate) fn new(conn: ConnectionHandle<RtnlMessage>) -> Self {\n        Handle(conn)\n    }\n\n    pub fn request(\n        &mut self,\n        message: NetlinkMessage<RtnlMessage>,\n    ) -> Result<impl Stream<Item = NetlinkMessage<RtnlMessage>>, Error> {\n        self.0\n            .request(message, SocketAddr::new(0, 0))\n            .map_err(|_| Error::RequestFailed)\n    }\n\n    pub fn notify(&mut self, msg: NetlinkMessage<RtnlMessage>) -> Result<(), Error> {\n        self.0\n            .notify(msg, SocketAddr::new(0, 0))\n            .map_err(|_| Error::RequestFailed)?;\n        Ok(())\n    }\n\n    /// Create a new handle, specifically for link requests (equivalent to `ip link` commands)\n    pub fn link(&self) -> LinkHandle {\n        LinkHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for address requests (equivalent to `ip addr` commands)\n    pub fn address(&self) -> AddressHandle {\n        AddressHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for routing table requests (equivalent to `ip route` commands)\n    pub fn route(&self) -> RouteHandle {\n        RouteHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for routing rule requests (equivalent to `ip rule` commands)\n    pub fn rule(&self) -> RuleHandle {\n        RuleHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for routing neighbours requests (equivalent to `ip neighbour` commands)\n    pub fn neighbours(&self) -> NeighbourHandle {\n        NeighbourHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for traffic control qdisc requests\n    /// (equivalent to `tc qdisc show` commands)\n    pub fn qdisc(&self) -> QDiscHandle {\n        QDiscHandle::new(self.clone())\n    }\n\n    /// Create a new handle, specifically for traffic control class requests\n    /// (equivalent to `tc class show dev <interface_name>` commands)\n    pub fn traffic_class(&self, ifindex: i32) -> TrafficClassHandle {\n        TrafficClassHandle::new(self.clone(), ifindex)\n    }\n\n    /// Create a new handle, specifically for traffic control filter requests\n    /// (equivalent to `tc filter show dev <interface_name>` commands)\n    pub fn traffic_filter(&self, ifindex: i32) -> TrafficFilterHandle {\n        TrafficFilterHandle::new(self.clone(), ifindex)\n    }\n\n    /// Create a new handle, specifically for traffic control chain requests\n    /// (equivalent to `tc chain show dev <interface_name>` commands)\n    pub fn traffic_chain(&self, ifindex: i32) -> TrafficChainHandle {\n        TrafficChainHandle::new(self.clone(), ifindex)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/lib.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n//! This crate provides methods to manipulate networking resources (links, addresses, arp tables,\n//! route tables) via the netlink protocol.\n\n#![allow(clippy::module_inception)]\n\nmod handle;\npub use crate::handle::*;\n\nmod ns;\npub use crate::ns::*;\n\nmod errors;\npub use crate::errors::*;\n\nmod link;\npub use crate::link::*;\n\nmod addr;\npub use crate::addr::*;\n\nmod route;\npub use crate::route::*;\n\nmod rule;\npub use crate::rule::*;\n\nmod connection;\npub use crate::connection::*;\n\nmod traffic_control;\npub use crate::traffic_control::*;\n\nmod neighbour;\npub use crate::neighbour::*;\n\npub mod constants;\n\npub use netlink_packet_route as packet;\npub mod proto {\n    pub use netlink_proto::{\n        packet::{NetlinkMessage, NetlinkPayload},\n        Connection,\n        ConnectionHandle,\n        Error,\n    };\n}\npub use netlink_proto::sys;\n\nmod macros;\n"
  },
  {
    "path": "rtnetlink/src/link/add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\nuse netlink_packet_route::link::nlas::InfoMacVtap;\nuse std::net::{Ipv4Addr, Ipv6Addr};\n\nuse crate::{\n    packet::{\n        nlas::link::{\n            Info,\n            InfoBond,\n            InfoData,\n            InfoKind,\n            InfoMacVlan,\n            InfoVlan,\n            InfoVxlan,\n            Nla,\n            VethInfo,\n        },\n        LinkMessage,\n        NetlinkMessage,\n        RtnlMessage,\n        IFF_UP,\n        NLM_F_ACK,\n        NLM_F_CREATE,\n        NLM_F_EXCL,\n        NLM_F_REPLACE,\n        NLM_F_REQUEST,\n    },\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct BondAddRequest {\n    request: LinkAddRequest,\n    info_data: Vec<InfoBond>,\n}\n\nimpl BondAddRequest {\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let s = self\n            .request\n            .link_info(InfoKind::Bond, Some(InfoData::Bond(self.info_data)));\n        s.execute().await\n    }\n\n    /// Sets the interface up\n    /// This is equivalent to `ip link set up dev NAME`.\n    pub fn up(mut self) -> Self {\n        self.request = self.request.up();\n        self\n    }\n\n    /// Adds the `mode` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond mode MODE`.\n    pub fn mode(mut self, mode: u8) -> Self {\n        self.info_data.push(InfoBond::Mode(mode));\n        self\n    }\n\n    /// Adds the `active_slave` attribute to the bond, where `active_slave`\n    /// is the ifindex of an interface attached to the bond.\n    /// This is equivalent to `ip link add name NAME type bond active_slave ACTIVE_SLAVE_NAME`.\n    pub fn active_slave(mut self, active_slave: u32) -> Self {\n        self.info_data.push(InfoBond::ActiveSlave(active_slave));\n        self\n    }\n\n    /// Adds the `miimon` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond miimon MIIMON`.\n    pub fn miimon(mut self, miimon: u32) -> Self {\n        self.info_data.push(InfoBond::MiiMon(miimon));\n        self\n    }\n\n    /// Adds the `updelay` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond updelay UPDELAY`.\n    pub fn updelay(mut self, updelay: u32) -> Self {\n        self.info_data.push(InfoBond::UpDelay(updelay));\n        self\n    }\n\n    /// Adds the `downdelay` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond downdelay DOWNDELAY`.\n    pub fn downdelay(mut self, downdelay: u32) -> Self {\n        self.info_data.push(InfoBond::DownDelay(downdelay));\n        self\n    }\n\n    /// Adds the `use_carrier` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond use_carrier USE_CARRIER`.\n    pub fn use_carrier(mut self, use_carrier: u8) -> Self {\n        self.info_data.push(InfoBond::UseCarrier(use_carrier));\n        self\n    }\n\n    /// Adds the `arp_interval` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond arp_interval ARP_INTERVAL`.\n    pub fn arp_interval(mut self, arp_interval: u32) -> Self {\n        self.info_data.push(InfoBond::ArpInterval(arp_interval));\n        self\n    }\n\n    /// Adds the `arp_validate` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond arp_validate ARP_VALIDATE`.\n    pub fn arp_validate(mut self, arp_validate: u32) -> Self {\n        self.info_data.push(InfoBond::ArpValidate(arp_validate));\n        self\n    }\n\n    /// Adds the `arp_all_targets` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond arp_all_targets ARP_ALL_TARGETS`\n    pub fn arp_all_targets(mut self, arp_all_targets: u32) -> Self {\n        self.info_data\n            .push(InfoBond::ArpAllTargets(arp_all_targets));\n        self\n    }\n\n    /// Adds the `primary` attribute to the bond, where `primary` is the ifindex\n    /// of an interface.\n    /// This is equivalent to `ip link add name NAME type bond primary PRIMARY_NAME`\n    pub fn primary(mut self, primary: u32) -> Self {\n        self.info_data.push(InfoBond::Primary(primary));\n        self\n    }\n\n    /// Adds the `primary_reselect` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond primary_reselect PRIMARY_RESELECT`.\n    pub fn primary_reselect(mut self, primary_reselect: u8) -> Self {\n        self.info_data\n            .push(InfoBond::PrimaryReselect(primary_reselect));\n        self\n    }\n\n    /// Adds the `fail_over_mac` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond fail_over_mac FAIL_OVER_MAC`.\n    pub fn fail_over_mac(mut self, fail_over_mac: u8) -> Self {\n        self.info_data.push(InfoBond::FailOverMac(fail_over_mac));\n        self\n    }\n\n    /// Adds the `xmit_hash_policy` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond xmit_hash_policy XMIT_HASH_POLICY`.\n    pub fn xmit_hash_policy(mut self, xmit_hash_policy: u8) -> Self {\n        self.info_data\n            .push(InfoBond::XmitHashPolicy(xmit_hash_policy));\n        self\n    }\n\n    /// Adds the `resend_igmp` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond resend_igmp RESEND_IGMP`.\n    pub fn resend_igmp(mut self, resend_igmp: u32) -> Self {\n        self.info_data.push(InfoBond::ResendIgmp(resend_igmp));\n        self\n    }\n\n    /// Adds the `num_peer_notif` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond num_peer_notif NUM_PEER_NOTIF`.\n    pub fn num_peer_notif(mut self, num_peer_notif: u8) -> Self {\n        self.info_data.push(InfoBond::NumPeerNotif(num_peer_notif));\n        self\n    }\n\n    /// Adds the `all_slaves_active` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond all_slaves_active ALL_SLAVES_ACTIVE`.\n    pub fn all_slaves_active(mut self, all_slaves_active: u8) -> Self {\n        self.info_data\n            .push(InfoBond::AllSlavesActive(all_slaves_active));\n        self\n    }\n\n    /// Adds the `min_links` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond min_links MIN_LINKS`.\n    pub fn min_links(mut self, min_links: u32) -> Self {\n        self.info_data.push(InfoBond::MinLinks(min_links));\n        self\n    }\n\n    /// Adds the `lp_interval` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond lp_interval LP_INTERVAL`.\n    pub fn lp_interval(mut self, lp_interval: u32) -> Self {\n        self.info_data.push(InfoBond::LpInterval(lp_interval));\n        self\n    }\n\n    /// Adds the `packets_per_slave` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond packets_per_slave PACKETS_PER_SLAVE`.\n    pub fn packets_per_slave(mut self, packets_per_slave: u32) -> Self {\n        self.info_data\n            .push(InfoBond::PacketsPerSlave(packets_per_slave));\n        self\n    }\n\n    /// Adds the `ad_lacp_rate` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_lacp_rate AD_LACP_RATE`.\n    pub fn ad_lacp_rate(mut self, ad_lacp_rate: u8) -> Self {\n        self.info_data.push(InfoBond::AdLacpRate(ad_lacp_rate));\n        self\n    }\n\n    /// Adds the `ad_select` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_select AD_SELECT`.\n    pub fn ad_select(mut self, ad_select: u8) -> Self {\n        self.info_data.push(InfoBond::AdSelect(ad_select));\n        self\n    }\n\n    /// Adds the `ad_actor_sys_prio` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_actor_sys_prio AD_ACTOR_SYS_PRIO`.\n    pub fn ad_actor_sys_prio(mut self, ad_actor_sys_prio: u16) -> Self {\n        self.info_data\n            .push(InfoBond::AdActorSysPrio(ad_actor_sys_prio));\n        self\n    }\n\n    /// Adds the `ad_user_port_key` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_user_port_key AD_USER_PORT_KEY`.\n    pub fn ad_user_port_key(mut self, ad_user_port_key: u16) -> Self {\n        self.info_data\n            .push(InfoBond::AdUserPortKey(ad_user_port_key));\n        self\n    }\n\n    /// Adds the `ad_actor_system` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_actor_system AD_ACTOR_SYSTEM`.\n    pub fn ad_actor_system(mut self, ad_actor_system: [u8; 6]) -> Self {\n        self.info_data\n            .push(InfoBond::AdActorSystem(ad_actor_system));\n        self\n    }\n\n    /// Adds the `tlb_dynamic_lb` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond tlb_dynamic_lb TLB_DYNAMIC_LB`.\n    pub fn tlb_dynamic_lb(mut self, tlb_dynamic_lb: u8) -> Self {\n        self.info_data.push(InfoBond::TlbDynamicLb(tlb_dynamic_lb));\n        self\n    }\n\n    /// Adds the `peer_notif_delay` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond peer_notif_delay PEER_NOTIF_DELAY`.\n    pub fn peer_notif_delay(mut self, peer_notif_delay: u32) -> Self {\n        self.info_data\n            .push(InfoBond::PeerNotifDelay(peer_notif_delay));\n        self\n    }\n\n    /// Adds the `ad_lacp_active` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ad_lacp_active AD_LACP_ACTIVE`.\n    pub fn ad_lacp_active(mut self, ad_lacp_active: u8) -> Self {\n        self.info_data.push(InfoBond::AdLacpActive(ad_lacp_active));\n        self\n    }\n\n    /// Adds the `missed_max` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond missed_max MISSED_MAX`.\n    pub fn missed_max(mut self, missed_max: u8) -> Self {\n        self.info_data.push(InfoBond::MissedMax(missed_max));\n        self\n    }\n\n    /// Adds the `arp_ip_target` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond arp_ip_target LIST`.\n    pub fn arp_ip_target(mut self, arp_ip_target: Vec<Ipv4Addr>) -> Self {\n        self.info_data.push(InfoBond::ArpIpTarget(arp_ip_target));\n        self\n    }\n\n    /// Adds the `ns_ip6_target` attribute to the bond\n    /// This is equivalent to `ip link add name NAME type bond ns_ip6_target LIST`.\n    pub fn ns_ip6_target(mut self, ns_ip6_target: Vec<Ipv6Addr>) -> Self {\n        self.info_data.push(InfoBond::NsIp6Target(ns_ip6_target));\n        self\n    }\n}\n\n/// A request to create a new vxlan link.\n///  This is equivalent to `ip link add NAME vxlan id ID ...` commands.\n/// It provides methods to customize the creation of the vxlan interface\n/// It provides almost all parameters that are listed by `man ip link`.\npub struct VxlanAddRequest {\n    request: LinkAddRequest,\n    info_data: Vec<InfoVxlan>,\n}\n\nimpl VxlanAddRequest {\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let s = self\n            .request\n            .link_info(InfoKind::Vxlan, Some(InfoData::Vxlan(self.info_data)));\n        s.execute().await\n    }\n\n    /// Sets the interface up\n    /// This is equivalent to `ip link set up dev NAME`.\n    pub fn up(mut self) -> Self {\n        self.request = self.request.up();\n        self\n    }\n\n    /// Adds the `dev` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI dev LINK`,\n    ///  dev LINK - specifies the physical device to use\n    ///  for tunnel endpoint communication.\n    /// But instead of specifing a link name (`LINK`), we specify a link index.\n    pub fn link(mut self, index: u32) -> Self {\n        self.info_data.push(InfoVxlan::Link(index));\n        self\n    }\n\n    /// Adds the `dstport` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI dstport PORT`.\n    /// dstport PORT - specifies the UDP destination port to\n    /// communicate to the remote VXLAN tunnel endpoint.\n    pub fn port(mut self, port: u16) -> Self {\n        self.info_data.push(InfoVxlan::Port(port));\n        self\n    }\n\n    /// Adds the `group` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI group IPADDR`,\n    /// group IPADDR - specifies the multicast IP address to join.\n    /// This function takes an IPv4 address\n    /// WARNING: only one between `remote` and `group` can be present.\n    pub fn group(mut self, addr: std::net::Ipv4Addr) -> Self {\n        self.info_data\n            .push(InfoVxlan::Group(addr.octets().to_vec()));\n        self\n    }\n\n    /// Adds the `group` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI group IPADDR`,\n    /// group IPADDR - specifies the multicast IP address to join.\n    /// This function takes an IPv6 address\n    /// WARNING: only one between `remote` and `group` can be present.\n    pub fn group6(mut self, addr: std::net::Ipv6Addr) -> Self {\n        self.info_data\n            .push(InfoVxlan::Group6(addr.octets().to_vec()));\n        self\n    }\n\n    /// Adds the `remote` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI remote IPADDR`,\n    /// remote IPADDR - specifies the unicast destination IP\n    /// address to use in outgoing packets when the\n    /// destination link layer address is not known in the\n    /// VXLAN device forwarding database.\n    /// This function takes an IPv4 address.\n    /// WARNING: only one between `remote` and `group` can be present.\n    pub fn remote(self, addr: std::net::Ipv4Addr) -> Self {\n        self.group(addr)\n    }\n\n    /// Adds the `remote` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI remote IPADDR`,\n    /// remote IPADDR - specifies the unicast destination IP\n    /// address to use in outgoing packets when the\n    /// destination link layer address is not known in the\n    /// VXLAN device forwarding database.\n    /// This function takes an IPv6 address.\n    /// WARNING: only one between `remote` and `group` can be present.\n    pub fn remote6(self, addr: std::net::Ipv6Addr) -> Self {\n        self.group6(addr)\n    }\n\n    /// Adds the `local` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI local IPADDR`,\n    /// local IPADDR - specifies the source IP address to use in outgoing packets.\n    /// This function takes an IPv4 address.\n    pub fn local(mut self, addr: std::net::Ipv4Addr) -> Self {\n        self.info_data\n            .push(InfoVxlan::Local(addr.octets().to_vec()));\n        self\n    }\n\n    /// Adds the `local` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI local IPADDR`,\n    /// local IPADDR - specifies the source IP address to use in outgoing packets.\n    /// This function takes an IPv6 address.\n    pub fn local6(mut self, addr: std::net::Ipv6Addr) -> Self {\n        self.info_data\n            .push(InfoVxlan::Local6(addr.octets().to_vec()));\n        self\n    }\n\n    /// Adds the `tos` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI tos TOS`.\n    /// tos TOS - specifies the TOS value to use in outgoing packets.\n    pub fn tos(mut self, tos: u8) -> Self {\n        self.info_data.push(InfoVxlan::Tos(tos));\n        self\n    }\n\n    /// Adds the `ttl` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI ttl TTL`.\n    /// ttl TTL - specifies the TTL value to use in outgoing packets.\n    pub fn ttl(mut self, ttl: u8) -> Self {\n        self.info_data.push(InfoVxlan::Ttl(ttl));\n        self\n    }\n\n    /// Adds the `flowlabel` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI flowlabel LABEL`.\n    /// flowlabel LABEL - specifies the flow label to use in outgoing packets.\n    pub fn label(mut self, label: u32) -> Self {\n        self.info_data.push(InfoVxlan::Label(label));\n        self\n    }\n\n    /// Adds the `learning` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]learning`.\n    /// [no]learning - specifies if unknown source link layer\n    /// addresses and IP addresses are entered into the VXLAN\n    /// device forwarding database.\n    pub fn learning(mut self, learning: u8) -> Self {\n        self.info_data.push(InfoVxlan::Learning(learning));\n        self\n    }\n\n    /// Adds the `ageing` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI ageing SECONDS`.\n    /// ageing SECONDS - specifies the lifetime in seconds of\n    /// FDB entries learnt by the kernel.\n    pub fn ageing(mut self, seconds: u32) -> Self {\n        self.info_data.push(InfoVxlan::Ageing(seconds));\n        self\n    }\n\n    /// Adds the `maxaddress` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI maxaddress LIMIT`.\n    /// maxaddress LIMIT - specifies the maximum number of\n    /// FDB entries.\n    pub fn limit(mut self, limit: u32) -> Self {\n        self.info_data.push(InfoVxlan::Limit(limit));\n        self\n    }\n\n    /// Adds the `srcport` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI srcport MIN MAX`.\n    /// srcport MIN MAX - specifies the range of port numbers\n    /// to use as UDP source ports to communicate to the\n    /// remote VXLAN tunnel endpoint.\n    pub fn port_range(mut self, min: u16, max: u16) -> Self {\n        self.info_data.push(InfoVxlan::PortRange((min, max)));\n        self\n    }\n\n    /// Adds the `proxy` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]proxy`.\n    /// [no]proxy - specifies ARP proxy is turned on.\n    pub fn proxy(mut self, proxy: u8) -> Self {\n        self.info_data.push(InfoVxlan::Proxy(proxy));\n        self\n    }\n\n    /// Adds the `rsc` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]rsc`.\n    /// [no]rsc - specifies if route short circuit is turned on.\n    pub fn rsc(mut self, rsc: u8) -> Self {\n        self.info_data.push(InfoVxlan::Rsc(rsc));\n        self\n    }\n\n    // Adds the `l2miss` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]l2miss`.\n    /// [no]l2miss - specifies if netlink LLADDR miss notifications are generated.\n    pub fn l2miss(mut self, l2miss: u8) -> Self {\n        self.info_data.push(InfoVxlan::L2Miss(l2miss));\n        self\n    }\n\n    // Adds the `l3miss` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]l3miss`.\n    /// [no]l3miss - specifies if netlink IP ADDR miss notifications are generated.\n    pub fn l3miss(mut self, l3miss: u8) -> Self {\n        self.info_data.push(InfoVxlan::L3Miss(l3miss));\n        self\n    }\n\n    pub fn collect_metadata(mut self, collect_metadata: u8) -> Self {\n        self.info_data\n            .push(InfoVxlan::CollectMetadata(collect_metadata));\n        self\n    }\n\n    // Adds the `udp_csum` attribute to the VXLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI [no]udp_csum`.\n    /// [no]udpcsum - specifies if UDP checksum is calculated for transmitted packets over IPv4.\n    pub fn udp_csum(mut self, udp_csum: u8) -> Self {\n        self.info_data.push(InfoVxlan::UDPCsum(udp_csum));\n        self\n    }\n}\n\n/// A request to create a new link. This is equivalent to the `ip link add` commands.\n///\n/// A few methods for common actions (creating a veth pair, creating a vlan interface, etc.) are\n/// provided, but custom requests can be made using the [`message_mut()`](#method.message_mut)\n/// accessor.\npub struct LinkAddRequest {\n    handle: Handle,\n    message: LinkMessage,\n    replace: bool,\n}\n\nimpl LinkAddRequest {\n    pub(crate) fn new(handle: Handle) -> Self {\n        LinkAddRequest {\n            handle,\n            message: LinkMessage::default(),\n            replace: false,\n        }\n    }\n\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let LinkAddRequest {\n            mut handle,\n            message,\n            replace,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::NewLink(message));\n        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request message.\n    ///\n    /// # Example\n    ///\n    /// Let's say we want to create a vlan interface on a link with id 6. By default, the\n    /// [`vlan()`](#method.vlan) method would create a request with the `IFF_UP` link set, so that the\n    /// interface is up after creation. If we want to create a interface tha tis down by default we\n    /// could do:\n    ///\n    /// ```rust,no_run\n    /// use futures::Future;\n    /// use rtnetlink::{Handle, new_connection, packet::IFF_UP};\n    ///\n    /// async fn run(handle: Handle) -> Result<(), String> {\n    ///     let vlan_id = 100;\n    ///     let link_id = 6;\n    ///     let mut request = handle.link().add().vlan(\"my-vlan-itf\".into(), link_id, vlan_id);\n    ///     // unset the IFF_UP flag before sending the request\n    ///     request.message_mut().header.flags &= !IFF_UP;\n    ///     request.message_mut().header.change_mask &= !IFF_UP;\n    ///     // send the request\n    ///     request.execute().await.map_err(|e| format!(\"{}\", e))\n    /// }\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n\n    /// Create a dummy link.\n    /// This is equivalent to `ip link add NAME type dummy`.\n    pub fn dummy(self, name: String) -> Self {\n        self.name(name).link_info(InfoKind::Dummy, None).up()\n    }\n\n    /// Create a veth pair.\n    /// This is equivalent to `ip link add NAME1 type veth peer name NAME2`.\n    pub fn veth(self, name: String, peer_name: String) -> Self {\n        // NOTE: `name` is the name of the peer in the netlink message (ie the link created via the\n        // VethInfo::Peer attribute, and `peer_name` is the name in the main netlink message.\n        // This is a bit weird, but it's all hidden from the user.\n\n        let mut peer = LinkMessage::default();\n        // FIXME: we get a -107 (ENOTCONN) (???) when trying to set `name` up.\n        // peer.header.flags = LinkFlags::from(IFF_UP);\n        // peer.header.change_mask = LinkFlags::from(IFF_UP);\n        peer.nlas.push(Nla::IfName(name));\n        let link_info_data = InfoData::Veth(VethInfo::Peer(peer));\n        self.name(peer_name)\n            .up() // iproute2 does not set this one up\n            .link_info(InfoKind::Veth, Some(link_info_data))\n    }\n\n    /// Create VLAN on a link.\n    /// This is equivalent to `ip link add link LINK name NAME type vlan id VLAN_ID`,\n    /// but instead of specifying a link name (`LINK`), we specify a link index.\n    pub fn vlan(self, name: String, index: u32, vlan_id: u16) -> Self {\n        self.name(name)\n            .link_info(\n                InfoKind::Vlan,\n                Some(InfoData::Vlan(vec![InfoVlan::Id(vlan_id)])),\n            )\n            .append_nla(Nla::Link(index))\n            .up()\n    }\n\n    /// Create macvlan on a link.\n    /// This is equivalent to `ip link add name NAME link LINK type macvlan mode MACVLAN_MODE`,\n    ///   but instead of specifying a link name (`LINK`), we specify a link index.\n    /// The MACVLAN_MODE is an integer consisting of flags from MACVLAN_MODE (netlink-packet-route/src/rtnl/constants.rs)\n    ///   being: _PRIVATE, _VEPA, _BRIDGE, _PASSTHRU, _SOURCE, which can be *combined*.\n    pub fn macvlan(self, name: String, index: u32, mode: u32) -> Self {\n        self.name(name)\n            .link_info(\n                InfoKind::MacVlan,\n                Some(InfoData::MacVlan(vec![InfoMacVlan::Mode(mode)])),\n            )\n            .append_nla(Nla::Link(index))\n            .up()\n    }\n\n    /// Create macvtap on a link.\n    /// This is equivalent to `ip link add name NAME link LINK type macvtap mode MACVTAP_MODE`,\n    ///   but instead of specifying a link name (`LINK`), we specify a link index.\n    /// The MACVTAP_MODE is an integer consisting of flags from MACVTAP_MODE (netlink-packet-route/src/rtnl/constants.rs)\n    ///   being: _PRIVATE, _VEPA, _BRIDGE, _PASSTHRU, _SOURCE, which can be *combined*.\n    pub fn macvtap(self, name: String, index: u32, mode: u32) -> Self {\n        self.name(name)\n            .link_info(\n                InfoKind::MacVtap,\n                Some(InfoData::MacVtap(vec![InfoMacVtap::Mode(mode)])),\n            )\n            .append_nla(Nla::Link(index))\n            .up()\n    }\n\n    /// Create a VxLAN\n    /// This is equivalent to `ip link add name NAME type vxlan id VNI`,\n    /// it returns a VxlanAddRequest to further customize the vxlan\n    /// interface creation.\n    pub fn vxlan(self, name: String, vni: u32) -> VxlanAddRequest {\n        let s = self.name(name);\n        VxlanAddRequest {\n            request: s,\n            info_data: vec![InfoVxlan::Id(vni)],\n        }\n    }\n\n    /// Create a new bond.\n    /// This is equivalent to `ip link add link NAME type bond`.\n    pub fn bond(self, name: String) -> BondAddRequest {\n        let s = self.name(name);\n        BondAddRequest {\n            request: s,\n            info_data: vec![],\n        }\n    }\n\n    /// Create a new bridge.\n    /// This is equivalent to `ip link add link NAME type bridge`.\n    pub fn bridge(self, name: String) -> Self {\n        self.name(name.clone())\n            .link_info(InfoKind::Bridge, None)\n            .append_nla(Nla::IfName(name))\n    }\n\n    /// Replace existing matching link.\n    pub fn replace(self) -> Self {\n        Self {\n            replace: true,\n            ..self\n        }\n    }\n\n    fn up(mut self) -> Self {\n        self.message.header.flags = IFF_UP;\n        self.message.header.change_mask = IFF_UP;\n        self\n    }\n\n    fn link_info(self, kind: InfoKind, data: Option<InfoData>) -> Self {\n        let mut link_info_nlas = vec![Info::Kind(kind)];\n        if let Some(data) = data {\n            link_info_nlas.push(Info::Data(data));\n        }\n        self.append_nla(Nla::Info(link_info_nlas))\n    }\n\n    fn name(mut self, name: String) -> Self {\n        self.message.nlas.push(Nla::IfName(name));\n        self\n    }\n\n    fn append_nla(mut self, nla: Nla) -> Self {\n        self.message.nlas.push(nla);\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{LinkMessage, NetlinkMessage, RtnlMessage, NLM_F_ACK, NLM_F_REQUEST},\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct LinkDelRequest {\n    handle: Handle,\n    message: LinkMessage,\n}\n\nimpl LinkDelRequest {\n    pub(crate) fn new(handle: Handle, index: u32) -> Self {\n        let mut message = LinkMessage::default();\n        message.header.index = index;\n        LinkDelRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let LinkDelRequest {\n            mut handle,\n            message,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::DelLink(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message)\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream},\n    FutureExt,\n};\n\nuse crate::{\n    packet::{constants::*, nlas::link::Nla, LinkMessage, NetlinkMessage, RtnlMessage},\n    try_rtnl,\n    Error,\n    Handle,\n};\n\npub struct LinkGetRequest {\n    handle: Handle,\n    message: LinkMessage,\n    // There are two ways to retrieve links: we can either dump them\n    // all and filter the result, or if we already know the index or\n    // the name of the link we're looking for, we can just retrieve\n    // that one. If `dump` is `true`, all the links are fetched.\n    // Otherwise, only the link that match the given index or name\n    // is fetched.\n    dump: bool,\n}\n\nimpl LinkGetRequest {\n    pub(crate) fn new(handle: Handle) -> Self {\n        LinkGetRequest {\n            handle,\n            message: LinkMessage::default(),\n            dump: true,\n        }\n    }\n\n    /// Setting filter mask(e.g. RTEXT_FILTER_BRVLAN and etc)\n    pub fn set_filter_mask(mut self, family: u8, filter_mask: u32) -> Self {\n        self.message.header.interface_family = family;\n        self.message.nlas.push(Nla::ExtMask(filter_mask));\n        self\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = LinkMessage, Error = Error> {\n        let LinkGetRequest {\n            mut handle,\n            message,\n            dump,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetLink(message));\n\n        if dump {\n            req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n        } else {\n            req.header.flags = NLM_F_REQUEST;\n        }\n\n        match handle.request(req) {\n            Ok(response) => {\n                Either::Left(response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewLink))))\n            }\n            Err(e) => Either::Right(future::err::<LinkMessage, Error>(e).into_stream()),\n        }\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n\n    /// Lookup a link by index\n    pub fn match_index(mut self, index: u32) -> Self {\n        self.dump = false;\n        self.message.header.index = index;\n        self\n    }\n\n    /// Lookup a link by name\n    ///\n    /// This function requires support from your kernel (>= 2.6.33). If yours is\n    /// older, consider filtering the resulting stream of links.\n    pub fn match_name(mut self, name: String) -> Self {\n        self.dump = false;\n        self.message.nlas.push(Nla::IfName(name));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::{\n    LinkAddRequest,\n    LinkDelPropRequest,\n    LinkDelRequest,\n    LinkGetRequest,\n    LinkNewPropRequest,\n    LinkSetRequest,\n};\nuse crate::Handle;\n\npub struct LinkHandle(Handle);\n\nimpl LinkHandle {\n    pub fn new(handle: Handle) -> Self {\n        LinkHandle(handle)\n    }\n\n    pub fn set(&self, index: u32) -> LinkSetRequest {\n        LinkSetRequest::new(self.0.clone(), index)\n    }\n\n    pub fn add(&self) -> LinkAddRequest {\n        LinkAddRequest::new(self.0.clone())\n    }\n\n    pub fn property_add(&self, index: u32) -> LinkNewPropRequest {\n        LinkNewPropRequest::new(self.0.clone(), index)\n    }\n\n    pub fn property_del(&self, index: u32) -> LinkDelPropRequest {\n        LinkDelPropRequest::new(self.0.clone(), index)\n    }\n\n    pub fn del(&mut self, index: u32) -> LinkDelRequest {\n        LinkDelRequest::new(self.0.clone(), index)\n    }\n\n    /// Retrieve the list of links (equivalent to `ip link show`)\n    pub fn get(&mut self) -> LinkGetRequest {\n        LinkGetRequest::new(self.0.clone())\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod add;\npub use self::add::*;\n\nmod del;\npub use self::del::*;\n\nmod get;\npub use self::get::*;\n\nmod set;\npub use self::set::*;\n\nmod property_add;\npub use self::property_add::*;\n\nmod property_del;\npub use self::property_del::*;\n\n#[cfg(test)]\nmod test;\n"
  },
  {
    "path": "rtnetlink/src/link/property_add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    packet::{\n        nlas::link::{Nla, Prop},\n        LinkMessage,\n        NetlinkMessage,\n        NetlinkPayload,\n        RtnlMessage,\n        NLM_F_ACK,\n        NLM_F_APPEND,\n        NLM_F_CREATE,\n        NLM_F_EXCL,\n        NLM_F_REQUEST,\n    },\n    Error,\n    Handle,\n};\nuse futures::stream::StreamExt;\n\npub struct LinkNewPropRequest {\n    handle: Handle,\n    message: LinkMessage,\n}\n\nimpl LinkNewPropRequest {\n    pub(crate) fn new(handle: Handle, index: u32) -> Self {\n        let mut message = LinkMessage::default();\n        message.header.index = index;\n        LinkNewPropRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let LinkNewPropRequest {\n            mut handle,\n            message,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::NewLinkProp(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            if let NetlinkPayload::Error(err) = message.payload {\n                return Err(Error::NetlinkError(err));\n            }\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n\n    /// Add alternative name to the link. This is equivalent to `ip link property add altname\n    /// ALT_IFNAME dev LINK`.\n    pub fn alt_ifname(mut self, alt_ifnames: &[&str]) -> Self {\n        let mut props = Vec::new();\n        for alt_ifname in alt_ifnames {\n            props.push(Prop::AltIfName(alt_ifname.to_string()));\n        }\n\n        self.message.nlas.push(Nla::PropList(props));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/property_del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    packet::{\n        nlas::link::{Nla, Prop},\n        LinkMessage,\n        NetlinkMessage,\n        NetlinkPayload,\n        RtnlMessage,\n        NLM_F_ACK,\n        NLM_F_EXCL,\n        NLM_F_REQUEST,\n    },\n    Error,\n    Handle,\n};\nuse futures::stream::StreamExt;\n\npub struct LinkDelPropRequest {\n    handle: Handle,\n    message: LinkMessage,\n}\n\nimpl LinkDelPropRequest {\n    pub(crate) fn new(handle: Handle, index: u32) -> Self {\n        let mut message = LinkMessage::default();\n        message.header.index = index;\n        LinkDelPropRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let LinkDelPropRequest {\n            mut handle,\n            message,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::DelLinkProp(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            if let NetlinkPayload::Error(err) = message.payload {\n                return Err(Error::NetlinkError(err));\n            }\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n\n    /// Remove alternative name to the link. This is equivalent to `ip link property del altname\n    /// ALT_IFNAME dev LINK`.\n    pub fn alt_ifname(mut self, alt_ifnames: &[&str]) -> Self {\n        let mut props = Vec::new();\n        for alt_ifname in alt_ifnames {\n            props.push(Prop::AltIfName(alt_ifname.to_string()));\n        }\n\n        self.message.nlas.push(Nla::PropList(props));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/set.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{\n    packet::{\n        nlas::link::Nla,\n        LinkMessage,\n        NetlinkMessage,\n        RtnlMessage,\n        IFF_NOARP,\n        IFF_PROMISC,\n        IFF_UP,\n        NLM_F_ACK,\n        NLM_F_CREATE,\n        NLM_F_EXCL,\n        NLM_F_REQUEST,\n    },\n    try_nl,\n    Error,\n    Handle,\n};\nuse futures::stream::StreamExt;\nuse std::os::unix::io::RawFd;\n\npub struct LinkSetRequest {\n    handle: Handle,\n    message: LinkMessage,\n}\n\nimpl LinkSetRequest {\n    pub(crate) fn new(handle: Handle, index: u32) -> Self {\n        let mut message = LinkMessage::default();\n        message.header.index = index;\n        LinkSetRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let LinkSetRequest {\n            mut handle,\n            message,\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::SetLink(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut LinkMessage {\n        &mut self.message\n    }\n\n    /// Attach the link to a bridge (its _master_). This is equivalent to `ip link set LINK master\n    /// BRIDGE`. To succeed, both the bridge and the link that is being attached must be UP.\n    ///\n    /// To Remove a link from a bridge, set its master to zero.\n    /// This is equvalent to `ip link set LINK nomaster`\n    pub fn master(mut self, master_index: u32) -> Self {\n        self.message.nlas.push(Nla::Master(master_index));\n        self\n    }\n\n    /// Detach the link from its _master_. This is equivalent to `ip link set LINK nomaster`.\n    ///To succeed, the link that is being detached must be UP.\n    pub fn nomaster(mut self) -> Self {\n        self.message.nlas.push(Nla::Master(0u32));\n        self\n    }\n\n    /// Set the link with the given index up (equivalent to `ip link set dev DEV up`)\n    pub fn up(mut self) -> Self {\n        self.message.header.flags |= IFF_UP;\n        self.message.header.change_mask |= IFF_UP;\n        self\n    }\n\n    /// Set the link with the given index down (equivalent to `ip link set dev DEV down`)\n    pub fn down(mut self) -> Self {\n        self.message.header.flags &= !IFF_UP;\n        self.message.header.change_mask |= IFF_UP;\n        self\n    }\n\n    /// Enable or disable promiscious mode of the link with the given index (equivalent to `ip link set dev DEV promisc on/off`)\n    pub fn promiscuous(mut self, enable: bool) -> Self {\n        if enable {\n            self.message.header.flags |= IFF_PROMISC;\n        } else {\n            self.message.header.flags &= !IFF_PROMISC;\n        }\n        self.message.header.change_mask |= IFF_PROMISC;\n        self\n    }\n\n    /// Enable or disable the ARP protocol of the link with the given index (equivalent to `ip link set dev DEV arp on/off`)\n    pub fn arp(mut self, enable: bool) -> Self {\n        if enable {\n            self.message.header.flags &= !IFF_NOARP;\n        } else {\n            self.message.header.flags |= IFF_NOARP;\n        }\n        self.message.header.change_mask |= IFF_NOARP;\n        self\n    }\n\n    /// Set the name of the link with the given index (equivalent to `ip link set DEV name NAME`)\n    pub fn name(mut self, name: String) -> Self {\n        self.message.nlas.push(Nla::IfName(name));\n        self\n    }\n\n    /// Set the mtu of the link with the given index (equivalent to `ip link set DEV mtu MTU`)\n    pub fn mtu(mut self, mtu: u32) -> Self {\n        self.message.nlas.push(Nla::Mtu(mtu));\n        self\n    }\n\n    /// Set the hardware address of the link with the given index (equivalent to `ip link set DEV address ADDRESS`)\n    pub fn address(mut self, address: Vec<u8>) -> Self {\n        self.message.nlas.push(Nla::Address(address));\n        self\n    }\n\n    /// Move this network device into the network namespace of the process with the given `pid`.\n    pub fn setns_by_pid(mut self, pid: u32) -> Self {\n        self.message.nlas.push(Nla::NetNsPid(pid));\n        self\n    }\n\n    /// Move this network device into the network namespace corresponding to the given file\n    /// descriptor.\n    pub fn setns_by_fd(mut self, fd: RawFd) -> Self {\n        self.message.nlas.push(Nla::NetNsFd(fd));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/link/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::TryStreamExt;\nuse tokio::runtime::Runtime;\n\nuse crate::{\n    new_connection,\n    packet::rtnl::link::{\n        nlas::{Info, InfoKind, Nla},\n        LinkMessage,\n    },\n    Error,\n    LinkHandle,\n};\n\nconst IFACE_NAME: &str = \"wg142\"; // rand?\n\n#[test]\nfn create_get_delete_wg() {\n    let rt = Runtime::new().unwrap();\n    let handle = rt.block_on(_create_wg());\n    assert!(handle.is_ok());\n    let mut handle = handle.unwrap();\n    let msg = rt.block_on(_get_wg(&mut handle));\n    assert!(msg.is_ok());\n    let msg = msg.unwrap();\n    assert!(has_nla(\n        &msg,\n        &Nla::Info(vec![Info::Kind(InfoKind::Wireguard)])\n    ));\n    rt.block_on(_del_wg(&mut handle, msg.header.index)).unwrap();\n}\n\nfn has_nla(msg: &LinkMessage, nla: &Nla) -> bool {\n    msg.nlas.iter().any(|x| x == nla)\n}\n\nasync fn _create_wg() -> Result<LinkHandle, Error> {\n    let (conn, handle, _) = new_connection().unwrap();\n    tokio::spawn(conn);\n    let link_handle = handle.link();\n    let mut req = link_handle.add();\n    let mutator = req.message_mut();\n    let info = Nla::Info(vec![Info::Kind(InfoKind::Wireguard)]);\n    mutator.nlas.push(info);\n    mutator.nlas.push(Nla::IfName(IFACE_NAME.to_owned()));\n    req.execute().await?;\n    Ok(link_handle)\n}\n\nasync fn _get_wg(handle: &mut LinkHandle) -> Result<LinkMessage, Error> {\n    let mut links = handle.get().match_name(IFACE_NAME.to_owned()).execute();\n    let msg = links.try_next().await?;\n    msg.ok_or(Error::RequestFailed)\n}\n\nasync fn _del_wg(handle: &mut LinkHandle, index: u32) -> Result<(), Error> {\n    handle.del(index).execute().await\n}\n"
  },
  {
    "path": "rtnetlink/src/macros.rs",
    "content": "// SPDX-License-Identifier: MIT\n\n#[macro_export]\nmacro_rules! try_rtnl {\n    ($msg: expr, $message_type:path) => {{\n        use netlink_packet_route::{NetlinkMessage, NetlinkPayload, RtnlMessage};\n        use $crate::Error;\n\n        let (header, payload) = $msg.into_parts();\n        match payload {\n            NetlinkPayload::InnerMessage($message_type(msg)) => msg,\n            NetlinkPayload::Error(err) => return Err(Error::NetlinkError(err)),\n            _ => {\n                return Err(Error::UnexpectedMessage(NetlinkMessage::new(\n                    header, payload,\n                )))\n            }\n        }\n    }};\n}\n\n#[macro_export]\nmacro_rules! try_nl {\n    ($msg: expr) => {{\n        use netlink_packet_route::NetlinkPayload;\n        use $crate::Error;\n        if let NetlinkPayload::Error(err) = $msg.payload {\n            return Err(Error::NetlinkError(err));\n        }\n    }};\n}\n"
  },
  {
    "path": "rtnetlink/src/neighbour/add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse netlink_packet_route::{\n    constants::*,\n    neighbour::{NeighbourMessage, Nla},\n    NetlinkPayload,\n    RtnlMessage,\n};\n\nuse netlink_proto::packet::NetlinkMessage;\n\nuse crate::{Error, Handle};\nuse std::net::IpAddr;\n\npub struct NeighbourAddRequest {\n    handle: Handle,\n    message: NeighbourMessage,\n    replace: bool,\n}\n\nimpl NeighbourAddRequest {\n    pub(crate) fn new(handle: Handle, index: u32, destination: IpAddr) -> Self {\n        let mut message = NeighbourMessage::default();\n\n        message.header.family = match destination {\n            IpAddr::V4(_) => AF_INET as u8,\n            IpAddr::V6(_) => AF_INET6 as u8,\n        };\n\n        message.header.ifindex = index;\n        message.header.state = IFA_F_PERMANENT as u16;\n        message.header.ntype = NDA_UNSPEC as u8;\n\n        message.nlas.push(Nla::Destination(match destination {\n            IpAddr::V4(v4) => v4.octets().to_vec(),\n            IpAddr::V6(v6) => v6.octets().to_vec(),\n        }));\n\n        NeighbourAddRequest {\n            handle,\n            message,\n            replace: false,\n        }\n    }\n\n    pub(crate) fn new_bridge(handle: Handle, index: u32, lla: &[u8]) -> Self {\n        let mut message = NeighbourMessage::default();\n\n        message.header.family = AF_BRIDGE as u8;\n        message.header.ifindex = index;\n        message.header.state = NUD_PERMANENT;\n        message.header.ntype = NDA_UNSPEC as u8;\n\n        message.nlas.push(Nla::LinkLocalAddress(lla.to_vec()));\n\n        NeighbourAddRequest {\n            handle,\n            message,\n            replace: false,\n        }\n    }\n\n    /// Set a bitmask of states for the neighbor cache entry.\n    /// It should be a combination of `NUD_*` constants.\n    pub fn state(mut self, state: u16) -> Self {\n        self.message.header.state = state;\n        self\n    }\n\n    /// Set flags for the neighbor cache entry.\n    /// It should be a combination of `NTF_*` constants.\n    pub fn flags(mut self, flags: u8) -> Self {\n        self.message.header.flags = flags;\n        self\n    }\n\n    /// Set attributes applicable to the the neighbor cache entry.\n    /// It should be one of `NDA_*` constants.\n    pub fn ntype(mut self, ntype: u8) -> Self {\n        self.message.header.ntype = ntype;\n        self\n    }\n\n    /// Set a neighbor cache link layer address (see `NDA_LLADDR` for details).\n    pub fn link_local_address(mut self, addr: &[u8]) -> Self {\n        let lla = self.message.nlas.iter_mut().find_map(|nla| match nla {\n            Nla::LinkLocalAddress(lla) => Some(lla),\n            _ => None,\n        });\n\n        if let Some(lla) = lla {\n            *lla = addr.to_vec();\n        } else {\n            self.message.nlas.push(Nla::LinkLocalAddress(addr.to_vec()));\n        }\n\n        self\n    }\n\n    /// Set the destination address for the neighbour (see `NDA_DST` for details).\n    pub fn destination(mut self, addr: IpAddr) -> Self {\n        let dst = self.message.nlas.iter_mut().find_map(|nla| match nla {\n            Nla::Destination(dst) => Some(dst),\n            _ => None,\n        });\n\n        let addr = match addr {\n            IpAddr::V4(v4) => v4.octets().to_vec(),\n            IpAddr::V6(v6) => v6.octets().to_vec(),\n        };\n\n        if let Some(dst) = dst {\n            *dst = addr;\n        } else {\n            self.message.nlas.push(Nla::Destination(addr));\n        }\n\n        self\n    }\n\n    /// Replace existing matching neighbor.\n    pub fn replace(self) -> Self {\n        Self {\n            replace: true,\n            ..self\n        }\n    }\n\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let NeighbourAddRequest {\n            mut handle,\n            message,\n            replace,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message));\n        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            if let NetlinkPayload::Error(err) = message.payload {\n                return Err(Error::NetlinkError(err));\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request message.\n    pub fn message_mut(&mut self) -> &mut NeighbourMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/neighbour/del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse netlink_packet_route::{\n    constants::*,\n    neighbour::NeighbourMessage,\n    NetlinkPayload,\n    RtnlMessage,\n};\n\nuse netlink_proto::packet::NetlinkMessage;\n\nuse crate::{Error, Handle};\n\npub struct NeighbourDelRequest {\n    handle: Handle,\n    message: NeighbourMessage,\n}\n\nimpl NeighbourDelRequest {\n    pub(crate) fn new(handle: Handle, message: NeighbourMessage) -> Self {\n        NeighbourDelRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let NeighbourDelRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::DelNeighbour(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n        let mut response = handle.request(req)?;\n        while let Some(msg) = response.next().await {\n            if let NetlinkPayload::Error(e) = msg.payload {\n                return Err(Error::NetlinkError(e));\n            }\n        }\n        Ok(())\n    }\n\n    pub fn message_mut(&mut self) -> &mut NeighbourMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/neighbour/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream},\n    FutureExt,\n};\n\nuse netlink_packet_route::{\n    constants::*,\n    neighbour::NeighbourMessage,\n    NetlinkPayload,\n    RtnlMessage,\n};\n\nuse netlink_proto::packet::NetlinkMessage;\n\nuse crate::{Error, Handle, IpVersion};\n\npub struct NeighbourGetRequest {\n    handle: Handle,\n    message: NeighbourMessage,\n}\n\nimpl NeighbourGetRequest {\n    pub(crate) fn new(handle: Handle) -> Self {\n        let message = NeighbourMessage::default();\n        NeighbourGetRequest { handle, message }\n    }\n\n    /// List neighbor proxies in the system (equivalent to: `ip neighbor show proxy`).\n    pub fn proxies(mut self) -> Self {\n        self.message.header.flags |= NTF_PROXY;\n        self\n    }\n\n    pub fn set_family(mut self, ip_version: IpVersion) -> Self {\n        self.message.header.family = ip_version.family();\n        self\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = NeighbourMessage, Error = Error> {\n        let NeighbourGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetNeighbour(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => Either::Left(response.map(move |msg| {\n                let (header, payload) = msg.into_parts();\n                match payload {\n                    NetlinkPayload::InnerMessage(RtnlMessage::NewNeighbour(msg)) => Ok(msg),\n                    NetlinkPayload::Error(err) => Err(Error::NetlinkError(err)),\n                    _ => Err(Error::UnexpectedMessage(NetlinkMessage::new(\n                        header, payload,\n                    ))),\n                }\n            })),\n            Err(e) => Either::Right(future::err::<NeighbourMessage, Error>(e).into_stream()),\n        }\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut NeighbourMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/neighbour/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{Handle, NeighbourAddRequest, NeighbourDelRequest, NeighbourGetRequest};\nuse netlink_packet_route::NeighbourMessage;\nuse std::net::IpAddr;\n\npub struct NeighbourHandle(Handle);\n\nimpl NeighbourHandle {\n    pub fn new(handle: Handle) -> Self {\n        NeighbourHandle(handle)\n    }\n\n    /// List neighbour entries (equivalent to `ip neighbour show`)\n    pub fn get(&self) -> NeighbourGetRequest {\n        NeighbourGetRequest::new(self.0.clone())\n    }\n\n    /// Add a new neighbour entry (equivalent to `ip neighbour add`)\n    pub fn add(&self, index: u32, destination: IpAddr) -> NeighbourAddRequest {\n        NeighbourAddRequest::new(self.0.clone(), index, destination)\n    }\n\n    /// Add a new fdb entry (equivalent to `bridge fdb add`)\n    pub fn add_bridge(&self, index: u32, lla: &[u8]) -> NeighbourAddRequest {\n        NeighbourAddRequest::new_bridge(self.0.clone(), index, lla)\n    }\n\n    /// Delete a neighbour entry (equivalent to `ip neighbour delete`)\n    pub fn del(&self, message: NeighbourMessage) -> NeighbourDelRequest {\n        NeighbourDelRequest::new(self.0.clone(), message)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/neighbour/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod get;\npub use self::get::*;\n\nmod add;\npub use self::add::*;\n\nmod del;\npub use self::del::*;\n"
  },
  {
    "path": "rtnetlink/src/ns.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::Error;\nuse nix::{\n    fcntl::OFlag,\n    sched::CloneFlags,\n    sys::{\n        stat::Mode,\n        wait::{waitpid, WaitStatus},\n    },\n    unistd::{fork, ForkResult},\n};\nuse std::{option::Option, path::Path, process::exit};\n\n// if \"only\" smol or smol+tokio were enabled, we use smol because\n// it doesn't require an active tokio runtime - just to be sure.\n#[cfg(feature = \"smol_socket\")]\nasync fn try_spawn_blocking<F, R>(fut: F) -> R\nwhere\n    F: FnOnce() -> R + Send + 'static,\n    R: Send + 'static,\n{\n    async_global_executor::spawn_blocking(fut).await\n}\n\n// only tokio enabled, so use tokio\n#[cfg(all(not(feature = \"smol_socket\"), feature = \"tokio_socket\"))]\nasync fn try_spawn_blocking<F, R>(fut: F) -> R\nwhere\n    F: FnOnce() -> R + Send + 'static,\n    R: Send + 'static,\n{\n    match tokio::task::spawn_blocking(fut).await {\n        Ok(v) => v,\n        Err(err) => {\n            std::panic::resume_unwind(err.into_panic());\n        }\n    }\n}\n\n// neither smol nor tokio - just run blocking op directly.\n// hopefully not too blocking...\n#[cfg(all(not(feature = \"smol_socket\"), not(feature = \"tokio_socket\")))]\nasync fn try_spawn_blocking<F, R>(fut: F) -> R\nwhere\n    F: FnOnce() -> R + Send + 'static,\n    R: Send + 'static,\n{\n    fut()\n}\n\npub const NETNS_PATH: &str = \"/run/netns/\";\npub const SELF_NS_PATH: &str = \"/proc/self/ns/net\";\npub const NONE_FS: &str = \"none\";\n\npub struct NetworkNamespace();\n\nimpl NetworkNamespace {\n    /// Add a new network namespace.\n    /// This is equivalent to `ip netns add NS_NAME`.\n    pub async fn add(ns_name: String) -> Result<(), Error> {\n        // Forking process to avoid moving caller into new namespace\n        NetworkNamespace::prep_for_fork()?;\n        log::trace!(\"Forking...\");\n        match unsafe { fork() } {\n            Ok(ForkResult::Parent { child, .. }) => NetworkNamespace::parent_process(child),\n            Ok(ForkResult::Child) => {\n                NetworkNamespace::child_process(ns_name);\n            }\n            Err(e) => {\n                let err_msg = format!(\"Fork failed: {}\", e);\n                Err(Error::NamespaceError(err_msg))\n            }\n        }\n    }\n\n    /// Remove a network namespace\n    /// This is equivalent to `ip netns del NS_NAME`.\n    pub async fn del(ns_name: String) -> Result<(), Error> {\n        try_spawn_blocking(move || {\n            let mut netns_path = String::new();\n            netns_path.push_str(NETNS_PATH);\n            netns_path.push_str(&ns_name);\n            let ns_path = Path::new(&netns_path);\n\n            if nix::mount::umount2(ns_path, nix::mount::MntFlags::MNT_DETACH).is_err() {\n                let err_msg = String::from(\"Namespace unmount failed (are you running as root?)\");\n                return Err(Error::NamespaceError(err_msg));\n            }\n\n            if nix::unistd::unlink(ns_path).is_err() {\n                let err_msg =\n                    String::from(\"Namespace file remove failed (are you running as root?)\");\n                return Err(Error::NamespaceError(err_msg));\n            }\n\n            Ok(())\n        })\n        .await\n    }\n\n    pub fn prep_for_fork() -> Result<(), Error> {\n        // Placeholder function, nothing to do here.\n        Ok(())\n    }\n\n    /// This is the parent process form the fork, it waits for the\n    /// child to exit properly\n    pub fn parent_process(child: nix::unistd::Pid) -> Result<(), Error> {\n        log::trace!(\"parent_process child PID: {}\", child);\n        log::trace!(\"Waiting for child to finish...\");\n        match waitpid(child, None) {\n            Ok(wait_status) => match wait_status {\n                WaitStatus::Exited(_, res) => {\n                    log::trace!(\"Child exited with: {}\", res);\n                    if res == 0 {\n                        return Ok(());\n                    }\n                    log::error!(\"Error child result: {}\", res);\n                    let err_msg = format!(\"Error child result: {}\", res);\n                    Err(Error::NamespaceError(err_msg))\n                }\n                WaitStatus::Signaled(_, signal, has_dump) => {\n                    log::error!(\"Error child killed by signal: {}\", signal);\n                    let err_msg = format!(\n                        \"Error child process was killed by signal: {} with core dump {}\",\n                        signal, has_dump\n                    );\n                    Err(Error::NamespaceError(err_msg))\n                }\n                _ => {\n                    log::error!(\"Unknown child process status\");\n                    let err_msg = String::from(\"Unknown child process status\");\n                    Err(Error::NamespaceError(err_msg))\n                }\n            },\n            Err(e) => {\n                log::error!(\"wait error: {}\", e);\n                let err_msg = format!(\"wait error: {}\", e);\n                Err(Error::NamespaceError(err_msg))\n            }\n        }\n    }\n\n    fn child_process(ns_name: String) -> ! {\n        let res = std::panic::catch_unwind(|| -> Result<(), Error> {\n            let netns_path = NetworkNamespace::child_process_create_ns(ns_name)?;\n            NetworkNamespace::unshare_processing(netns_path)?;\n            Ok(())\n        });\n        match res {\n            Err(_panic) => {\n                // panic should have already been printed by the handler\n                log::error!(\"child process crashed\");\n                std::process::abort()\n            }\n            Ok(Err(fail)) => {\n                log::error!(\"child process failed: {}\", fail);\n                exit(1)\n            }\n            Ok(Ok(())) => exit(0),\n        }\n    }\n\n    /// This is the child process, it will actually create the namespace\n    /// resources. It creates the folder and namespace file.\n    /// Returns the namespace file path\n    pub fn child_process_create_ns(ns_name: String) -> Result<String, Error> {\n        log::trace!(\"child_process will create the namespace\");\n\n        let mut netns_path = String::new();\n\n        let dir_path = Path::new(NETNS_PATH);\n        let mut mkdir_mode = Mode::empty();\n        let mut open_flags = OFlag::empty();\n        let mut mount_flags = nix::mount::MsFlags::empty();\n        let none_fs = Path::new(&NONE_FS);\n        let none_p4: Option<&Path> = None;\n\n        // flags in mkdir\n        mkdir_mode.insert(Mode::S_IRWXU);\n        mkdir_mode.insert(Mode::S_IRGRP);\n        mkdir_mode.insert(Mode::S_IXGRP);\n        mkdir_mode.insert(Mode::S_IROTH);\n        mkdir_mode.insert(Mode::S_IXOTH);\n\n        open_flags.insert(OFlag::O_RDONLY);\n        open_flags.insert(OFlag::O_CREAT);\n        open_flags.insert(OFlag::O_EXCL);\n\n        netns_path.push_str(NETNS_PATH);\n        netns_path.push_str(&ns_name);\n\n        // creating namespaces folder if not exists\n        #[allow(clippy::collapsible_if)]\n        if nix::sys::stat::stat(dir_path).is_err() {\n            if let Err(e) = nix::unistd::mkdir(dir_path, mkdir_mode) {\n                log::error!(\"mkdir error: {}\", e);\n                let err_msg = format!(\"mkdir error: {}\", e);\n                return Err(Error::NamespaceError(err_msg));\n            }\n        }\n\n        // Try to mount /run/netns, with MS_REC | MS_SHARED\n        // If it fails, creates the mount with MS_BIND | MS_REC\n        // This is the same strategy used by `ip netns add NS`\n        mount_flags.insert(nix::mount::MsFlags::MS_REC);\n        mount_flags.insert(nix::mount::MsFlags::MS_SHARED);\n        if nix::mount::mount(\n            Some(Path::new(\"\")),\n            dir_path,\n            Some(none_fs),\n            mount_flags,\n            none_p4,\n        )\n        .is_err()\n        {\n            mount_flags = nix::mount::MsFlags::empty();\n            mount_flags.insert(nix::mount::MsFlags::MS_BIND);\n            mount_flags.insert(nix::mount::MsFlags::MS_REC);\n\n            if let Err(e) = nix::mount::mount(\n                Some(Path::new(dir_path)),\n                dir_path,\n                Some(none_fs),\n                mount_flags,\n                none_p4,\n            ) {\n                log::error!(\"mount error: {}\", e);\n                let err_msg = format!(\"mount error: {}\", e);\n                return Err(Error::NamespaceError(err_msg));\n            }\n        }\n\n        mount_flags = nix::mount::MsFlags::empty();\n        mount_flags.insert(nix::mount::MsFlags::MS_REC);\n        mount_flags.insert(nix::mount::MsFlags::MS_SHARED);\n        if let Err(e) = nix::mount::mount(\n            Some(Path::new(\"\")),\n            dir_path,\n            Some(none_fs),\n            mount_flags,\n            none_p4,\n        ) {\n            log::error!(\"mount error: {}\", e);\n            let err_msg = format!(\"mount error: {}\", e);\n            return Err(Error::NamespaceError(err_msg));\n        }\n\n        let ns_path = Path::new(&netns_path);\n\n        // creating the netns file\n        let fd = match nix::fcntl::open(ns_path, open_flags, Mode::empty()) {\n            Ok(raw_fd) => raw_fd,\n            Err(e) => {\n                log::error!(\"open error: {}\", e);\n                let err_msg = format!(\"open error: {}\", e);\n                return Err(Error::NamespaceError(err_msg));\n            }\n        };\n\n        if let Err(e) = nix::unistd::close(fd) {\n            log::error!(\"close error: {}\", e);\n            let err_msg = format!(\"close error: {}\", e);\n            let _ = nix::unistd::unlink(ns_path);\n            return Err(Error::NamespaceError(err_msg));\n        }\n\n        Ok(netns_path)\n    }\n\n    /// This function unshare the calling process and move into\n    /// the given network namespace\n    #[allow(unused)]\n    pub fn unshare_processing(netns_path: String) -> Result<(), Error> {\n        let mut setns_flags = CloneFlags::empty();\n        let mut open_flags = OFlag::empty();\n        let ns_path = Path::new(&netns_path);\n\n        let none_fs = Path::new(&NONE_FS);\n        let none_p4: Option<&Path> = None;\n\n        // unshare to the new network namespace\n        if let Err(e) = nix::sched::unshare(CloneFlags::CLONE_NEWNET) {\n            log::error!(\"unshare error: {}\", e);\n            let err_msg = format!(\"unshare error: {}\", e);\n            let _ = nix::unistd::unlink(ns_path);\n            return Err(Error::NamespaceError(err_msg));\n        }\n\n        open_flags = OFlag::empty();\n        open_flags.insert(OFlag::O_RDONLY);\n        open_flags.insert(OFlag::O_CLOEXEC);\n\n        let fd = match nix::fcntl::open(Path::new(&SELF_NS_PATH), open_flags, Mode::empty()) {\n            Ok(raw_fd) => raw_fd,\n            Err(e) => {\n                log::error!(\"open error: {}\", e);\n                let err_msg = format!(\"open error: {}\", e);\n                return Err(Error::NamespaceError(err_msg));\n            }\n        };\n\n        let self_path = Path::new(&SELF_NS_PATH);\n\n        // bind to the netns\n        if let Err(e) = nix::mount::mount(\n            Some(self_path),\n            ns_path,\n            Some(none_fs),\n            nix::mount::MsFlags::MS_BIND,\n            none_p4,\n        ) {\n            log::error!(\"mount error: {}\", e);\n            let err_msg = format!(\"mount error: {}\", e);\n            let _ = nix::unistd::unlink(ns_path);\n            return Err(Error::NamespaceError(err_msg));\n        }\n\n        setns_flags.insert(CloneFlags::CLONE_NEWNET);\n        if let Err(e) = nix::sched::setns(fd, setns_flags) {\n            log::error!(\"setns error: {}\", e);\n            let err_msg = format!(\"setns error: {}\", e);\n            let _ = nix::unistd::unlink(ns_path);\n            return Err(Error::NamespaceError(err_msg));\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/route/add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\nuse std::{\n    marker::PhantomData,\n    net::{Ipv4Addr, Ipv6Addr},\n};\n\nuse netlink_packet_route::{\n    constants::*,\n    nlas::route::Nla,\n    NetlinkMessage,\n    RouteMessage,\n    RtnlMessage,\n};\n\nuse crate::{try_nl, Error, Handle};\n\n/// A request to create a new route. This is equivalent to the `ip route add` commands.\npub struct RouteAddRequest<T = ()> {\n    handle: Handle,\n    message: RouteMessage,\n    replace: bool,\n    _phantom: PhantomData<T>,\n}\n\nimpl<T> RouteAddRequest<T> {\n    pub(crate) fn new(handle: Handle) -> Self {\n        let mut message = RouteMessage::default();\n\n        message.header.table = RT_TABLE_MAIN;\n        message.header.protocol = RTPROT_STATIC;\n        message.header.scope = RT_SCOPE_UNIVERSE;\n        message.header.kind = RTN_UNICAST;\n\n        RouteAddRequest {\n            handle,\n            message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Sets the input interface index.\n    pub fn input_interface(mut self, index: u32) -> Self {\n        self.message.nlas.push(Nla::Iif(index));\n        self\n    }\n\n    /// Sets the output interface index.\n    pub fn output_interface(mut self, index: u32) -> Self {\n        self.message.nlas.push(Nla::Oif(index));\n        self\n    }\n\n    /// Sets the route table.\n    ///\n    /// Default is main route table.\n    pub fn table(mut self, table: u8) -> Self {\n        self.message.header.table = table;\n        self\n    }\n\n    /// Sets the route protocol.\n    ///\n    /// Default is static route protocol.\n    pub fn protocol(mut self, protocol: u8) -> Self {\n        self.message.header.protocol = protocol;\n        self\n    }\n\n    /// Sets the route scope.\n    ///\n    /// Default is universe route scope.\n    pub fn scope(mut self, scope: u8) -> Self {\n        self.message.header.scope = scope;\n        self\n    }\n\n    /// Sets the route kind.\n    ///\n    /// Default is unicast route kind.\n    pub fn kind(mut self, kind: u8) -> Self {\n        self.message.header.kind = kind;\n        self\n    }\n\n    /// Build an IP v4 route request\n    pub fn v4(mut self) -> RouteAddRequest<Ipv4Addr> {\n        self.message.header.address_family = AF_INET as u8;\n        RouteAddRequest {\n            handle: self.handle,\n            message: self.message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Build an IP v6 route request\n    pub fn v6(mut self) -> RouteAddRequest<Ipv6Addr> {\n        self.message.header.address_family = AF_INET6 as u8;\n        RouteAddRequest {\n            handle: self.handle,\n            message: self.message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Replace existing matching route.\n    pub fn replace(self) -> Self {\n        Self {\n            replace: true,\n            ..self\n        }\n    }\n\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let RouteAddRequest {\n            mut handle,\n            message,\n            replace,\n            ..\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::NewRoute(message));\n        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request message.\n    pub fn message_mut(&mut self) -> &mut RouteMessage {\n        &mut self.message\n    }\n}\n\nimpl RouteAddRequest<Ipv4Addr> {\n    /// Sets the source address prefix.\n    pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {\n        self.message.header.source_prefix_length = prefix_length;\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Source(src));\n        self\n    }\n\n    /// Sets the preferred source address.\n    pub fn pref_source(mut self, addr: Ipv4Addr) -> Self {\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::PrefSource(src));\n        self\n    }\n\n    /// Sets the destination address prefix.\n    pub fn destination_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {\n        self.message.header.destination_prefix_length = prefix_length;\n        let dst = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Destination(dst));\n        self\n    }\n\n    /// Sets the gateway (via) address.\n    pub fn gateway(mut self, addr: Ipv4Addr) -> Self {\n        let gtw = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Gateway(gtw));\n        self\n    }\n}\n\nimpl RouteAddRequest<Ipv6Addr> {\n    /// Sets the source address prefix.\n    pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {\n        self.message.header.source_prefix_length = prefix_length;\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Source(src));\n        self\n    }\n\n    /// Sets the preferred source address.\n    pub fn pref_source(mut self, addr: Ipv6Addr) -> Self {\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::PrefSource(src));\n        self\n    }\n\n    /// Sets the destination address prefix.\n    pub fn destination_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {\n        self.message.header.destination_prefix_length = prefix_length;\n        let dst = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Destination(dst));\n        self\n    }\n\n    /// Sets the gateway (via) address.\n    pub fn gateway(mut self, addr: Ipv6Addr) -> Self {\n        let gtw = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Gateway(gtw));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/route/del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{NetlinkMessage, NetlinkPayload, RouteMessage, RtnlMessage, NLM_F_ACK, NLM_F_REQUEST},\n    Error,\n    Handle,\n};\n\npub struct RouteDelRequest {\n    handle: Handle,\n    message: RouteMessage,\n}\n\nimpl RouteDelRequest {\n    pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self {\n        RouteDelRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let RouteDelRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::DelRoute(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n        let mut response = handle.request(req)?;\n        while let Some(msg) = response.next().await {\n            if let NetlinkPayload::Error(e) = msg.payload {\n                return Err(Error::NetlinkError(e));\n            }\n        }\n        Ok(())\n    }\n\n    pub fn message_mut(&mut self) -> &mut RouteMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/route/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream},\n    FutureExt,\n};\n\nuse netlink_packet_route::{constants::*, NetlinkMessage, RouteMessage, RtnlMessage};\n\nuse crate::{try_rtnl, Error, Handle};\n\npub struct RouteGetRequest {\n    handle: Handle,\n    message: RouteMessage,\n}\n\n/// Internet Protocol (IP) version.\n#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]\npub enum IpVersion {\n    /// IPv4\n    V4,\n    /// IPv6\n    V6,\n}\n\nimpl IpVersion {\n    pub(crate) fn family(self) -> u8 {\n        match self {\n            IpVersion::V4 => AF_INET as u8,\n            IpVersion::V6 => AF_INET6 as u8,\n        }\n    }\n}\n\nimpl RouteGetRequest {\n    pub(crate) fn new(handle: Handle, ip_version: IpVersion) -> Self {\n        let mut message = RouteMessage::default();\n        message.header.address_family = ip_version.family();\n\n        // As per rtnetlink(7) documentation, setting the following\n        // fields to 0 gets us all the routes from all the tables\n        //\n        // > For RTM_GETROUTE, setting rtm_dst_len and rtm_src_len to 0\n        // > means you get all entries for the specified routing table.\n        // > For the other fields, except rtm_table and rtm_protocol, 0\n        // > is the wildcard.\n        message.header.destination_prefix_length = 0;\n        message.header.source_prefix_length = 0;\n        message.header.scope = RT_SCOPE_UNIVERSE;\n        message.header.kind = RTN_UNSPEC;\n\n        // I don't know if these two fields matter\n        message.header.table = RT_TABLE_UNSPEC;\n        message.header.protocol = RTPROT_UNSPEC;\n\n        RouteGetRequest { handle, message }\n    }\n\n    pub fn message_mut(&mut self) -> &mut RouteMessage {\n        &mut self.message\n    }\n\n    pub fn execute(self) -> impl TryStream<Ok = RouteMessage, Error = Error> {\n        let RouteGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetRoute(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => {\n                Either::Left(response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewRoute))))\n            }\n            Err(e) => Either::Right(future::err::<RouteMessage, Error>(e).into_stream()),\n        }\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/route/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{Handle, IpVersion, RouteAddRequest, RouteDelRequest, RouteGetRequest};\nuse netlink_packet_route::RouteMessage;\n\npub struct RouteHandle(Handle);\n\nimpl RouteHandle {\n    pub fn new(handle: Handle) -> Self {\n        RouteHandle(handle)\n    }\n\n    /// Retrieve the list of routing table entries (equivalent to `ip route show`)\n    pub fn get(&self, ip_version: IpVersion) -> RouteGetRequest {\n        RouteGetRequest::new(self.0.clone(), ip_version)\n    }\n\n    /// Add an routing table entry (equivalent to `ip route add`)\n    pub fn add(&self) -> RouteAddRequest {\n        RouteAddRequest::new(self.0.clone())\n    }\n\n    /// Delete the given routing table entry (equivalent to `ip route del`)\n    pub fn del(&self, route: RouteMessage) -> RouteDelRequest {\n        RouteDelRequest::new(self.0.clone(), route)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/route/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod add;\npub use self::add::*;\n\nmod del;\npub use self::del::*;\n\nmod get;\npub use self::get::*;\n"
  },
  {
    "path": "rtnetlink/src/rule/add.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\nuse std::{\n    marker::PhantomData,\n    net::{Ipv4Addr, Ipv6Addr},\n};\n\nuse netlink_packet_route::{\n    constants::*,\n    nlas::rule::Nla,\n    NetlinkMessage,\n    RtnlMessage,\n    RuleMessage,\n};\n\nuse crate::{try_nl, Error, Handle};\n\n/// A request to create a new rule. This is equivalent to the `ip rule add` command.\npub struct RuleAddRequest<T = ()> {\n    handle: Handle,\n    message: RuleMessage,\n    replace: bool,\n    _phantom: PhantomData<T>,\n}\n\nimpl<T> RuleAddRequest<T> {\n    pub(crate) fn new(handle: Handle) -> Self {\n        let mut message = RuleMessage::default();\n\n        message.header.table = RT_TABLE_MAIN;\n        message.header.action = FR_ACT_UNSPEC;\n\n        RuleAddRequest {\n            handle,\n            message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Sets the input interface name.\n    pub fn input_interface(mut self, ifname: String) -> Self {\n        self.message.nlas.push(Nla::Iifname(ifname));\n        self\n    }\n\n    /// Sets the output interface name.\n    pub fn output_interface(mut self, ifname: String) -> Self {\n        self.message.nlas.push(Nla::OifName(ifname));\n        self\n    }\n\n    /// Sets the rule table.\n    ///\n    /// Default is main rule table.\n    pub fn table(mut self, table: u8) -> Self {\n        self.message.header.table = table;\n        self\n    }\n\n    /// Set the tos.\n    pub fn tos(mut self, tos: u8) -> Self {\n        self.message.header.tos = tos;\n        self\n    }\n\n    /// Set action.\n    pub fn action(mut self, action: u8) -> Self {\n        self.message.header.action = action;\n        self\n    }\n\n    /// Set the priority.\n    pub fn priority(mut self, priority: u32) -> Self {\n        self.message.nlas.push(Nla::Priority(priority));\n        self\n    }\n\n    /// Build an IP v4 rule\n    pub fn v4(mut self) -> RuleAddRequest<Ipv4Addr> {\n        self.message.header.family = AF_INET as u8;\n        RuleAddRequest {\n            handle: self.handle,\n            message: self.message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Build an IP v6 rule\n    pub fn v6(mut self) -> RuleAddRequest<Ipv6Addr> {\n        self.message.header.family = AF_INET6 as u8;\n        RuleAddRequest {\n            handle: self.handle,\n            message: self.message,\n            replace: false,\n            _phantom: Default::default(),\n        }\n    }\n\n    /// Replace existing matching rule.\n    pub fn replace(self) -> Self {\n        Self {\n            replace: true,\n            ..self\n        }\n    }\n\n    /// Execute the request.\n    pub async fn execute(self) -> Result<(), Error> {\n        let RuleAddRequest {\n            mut handle,\n            message,\n            replace,\n            ..\n        } = self;\n        let mut req = NetlinkMessage::from(RtnlMessage::NewRule(message));\n        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n\n        Ok(())\n    }\n\n    pub fn message_mut(&mut self) -> &mut RuleMessage {\n        &mut self.message\n    }\n}\n\nimpl RuleAddRequest<Ipv4Addr> {\n    /// Sets the source address prefix.\n    pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {\n        self.message.header.src_len = prefix_length;\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Source(src));\n        self\n    }\n\n    /// Sets the destination address prefix.\n    pub fn destination_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {\n        self.message.header.dst_len = prefix_length;\n        let dst = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Destination(dst));\n        self\n    }\n}\n\nimpl RuleAddRequest<Ipv6Addr> {\n    /// Sets the source address prefix.\n    pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {\n        self.message.header.src_len = prefix_length;\n        let src = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Source(src));\n        self\n    }\n\n    /// Sets the destination address prefix.\n    pub fn destination_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {\n        self.message.header.dst_len = prefix_length;\n        let dst = addr.octets().to_vec();\n        self.message.nlas.push(Nla::Destination(dst));\n        self\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/rule/del.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{NetlinkMessage, RtnlMessage, RuleMessage, NLM_F_ACK, NLM_F_REQUEST},\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct RuleDelRequest {\n    handle: Handle,\n    message: RuleMessage,\n}\n\nimpl RuleDelRequest {\n    pub(crate) fn new(handle: Handle, message: RuleMessage) -> Self {\n        RuleDelRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let RuleDelRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::DelRule(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n        let mut response = handle.request(req)?;\n        while let Some(msg) = response.next().await {\n            try_nl!(msg);\n        }\n        Ok(())\n    }\n\n    pub fn message_mut(&mut self) -> &mut RuleMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/rule/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::IpVersion;\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream},\n    FutureExt,\n};\n\nuse netlink_packet_route::{constants::*, NetlinkMessage, RtnlMessage, RuleMessage};\n\nuse crate::{try_rtnl, Error, Handle};\n\npub struct RuleGetRequest {\n    handle: Handle,\n    message: RuleMessage,\n}\n\nimpl RuleGetRequest {\n    pub(crate) fn new(handle: Handle, ip_version: IpVersion) -> Self {\n        let mut message = RuleMessage::default();\n        message.header.family = ip_version.family();\n\n        message.header.dst_len = 0;\n        message.header.src_len = 0;\n        message.header.tos = 0;\n        message.header.action = FR_ACT_UNSPEC;\n        message.header.table = RT_TABLE_UNSPEC;\n\n        RuleGetRequest { handle, message }\n    }\n\n    pub fn message_mut(&mut self) -> &mut RuleMessage {\n        &mut self.message\n    }\n\n    pub fn execute(self) -> impl TryStream<Ok = RuleMessage, Error = Error> {\n        let RuleGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetRule(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => {\n                Either::Left(response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewRule))))\n            }\n            Err(e) => Either::Right(future::err::<RuleMessage, Error>(e).into_stream()),\n        }\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/rule/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse crate::{Handle, IpVersion, RuleAddRequest, RuleDelRequest, RuleGetRequest};\nuse netlink_packet_route::RuleMessage;\n\npub struct RuleHandle(Handle);\n\nimpl RuleHandle {\n    pub fn new(handle: Handle) -> Self {\n        RuleHandle(handle)\n    }\n\n    /// Retrieve the list of route rule entries (equivalent to `ip rule show`)\n    pub fn get(&self, ip_version: IpVersion) -> RuleGetRequest {\n        RuleGetRequest::new(self.0.clone(), ip_version)\n    }\n\n    /// Add a route rule entry (equivalent to `ip rule add`)\n    pub fn add(&self) -> RuleAddRequest {\n        RuleAddRequest::new(self.0.clone())\n    }\n\n    /// Delete the given route rule entry (equivalent to `ip rule del`)\n    pub fn del(&self, rule: RuleMessage) -> RuleDelRequest {\n        RuleDelRequest::new(self.0.clone(), rule)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/rule/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod add;\npub use self::add::*;\n\nmod del;\npub use self::del::*;\n\nmod get;\npub use self::get::*;\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/add_filter.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{\n        tc::{self, constants::*},\n        NetlinkMessage,\n        RtnlMessage,\n        TcMessage,\n        NLM_F_ACK,\n        NLM_F_REQUEST,\n        TCM_IFINDEX_MAGIC_BLOCK,\n        TC_H_MAKE,\n    },\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct TrafficFilterNewRequest {\n    handle: Handle,\n    message: TcMessage,\n    flags: u16,\n}\n\nimpl TrafficFilterNewRequest {\n    pub(crate) fn new(handle: Handle, ifindex: i32, flags: u16) -> Self {\n        Self {\n            handle,\n            message: TcMessage::with_index(ifindex),\n            flags: NLM_F_REQUEST | flags,\n        }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let Self {\n            mut handle,\n            message,\n            flags,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::NewTrafficFilter(message));\n        req.header.flags = NLM_F_ACK | flags;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Set interface index.\n    /// Equivalent to `dev STRING`, dev and block are mutually exlusive.\n    pub fn index(mut self, index: i32) -> Self {\n        assert_eq!(self.message.header.index, 0);\n        self.message.header.index = index;\n        self\n    }\n\n    /// Set block index.\n    /// Equivalent to `block BLOCK_INDEX`.\n    pub fn block(mut self, block_index: u32) -> Self {\n        assert_eq!(self.message.header.index, 0);\n        self.message.header.index = TCM_IFINDEX_MAGIC_BLOCK as i32;\n        self.message.header.parent = block_index;\n        self\n    }\n\n    /// Set parent.\n    /// Equivalent to `[ root | ingress | egress | parent CLASSID ]`\n    /// command args. They are mutually exlusive.\n    pub fn parent(mut self, parent: u32) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = parent;\n        self\n    }\n\n    /// Set parent to root.\n    pub fn root(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_ROOT;\n        self\n    }\n\n    /// Set parent to ingress.\n    pub fn ingress(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_MAKE!(TC_H_CLSACT, TC_H_MIN_INGRESS);\n        self\n    }\n\n    /// Set parent to egress.\n    pub fn egress(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_MAKE!(TC_H_CLSACT, TC_H_MIN_EGRESS);\n        self\n    }\n\n    /// Set priority.\n    /// Equivalent to `priority PRIO` or `pref PRIO`.\n    pub fn priority(mut self, priority: u16) -> Self {\n        assert_eq!(self.message.header.info & TC_H_MAJ_MASK, 0);\n        self.message.header.info = TC_H_MAKE!((priority as u32) << 16, self.message.header.info);\n        self\n    }\n\n    /// Set protocol.\n    /// Equivalent to `protocol PROT`.\n    /// Default: ETH_P_ALL 0x0003, see llproto_names at iproute2/lib/ll_proto.c.\n    pub fn protocol(mut self, protocol: u16) -> Self {\n        assert_eq!(self.message.header.info & TC_H_MIN_MASK, 0);\n        self.message.header.info = TC_H_MAKE!(self.message.header.info, protocol as u32);\n        self\n    }\n\n    /// The 32bit filter allows to match arbitrary bitfields in the packet.\n    /// Equivalent to `tc filter ... u32`.\n    pub fn u32(mut self, data: Vec<tc::u32::Nla>) -> Self {\n        assert!(!self\n            .message\n            .nlas\n            .iter()\n            .any(|nla| matches!(nla, tc::Nla::Kind(_))));\n        self.message\n            .nlas\n            .push(tc::Nla::Kind(tc::u32::KIND.to_string()));\n        self.message.nlas.push(tc::Nla::Options(\n            data.into_iter().map(tc::TcOpt::U32).collect(),\n        ));\n        self\n    }\n\n    /// Use u32 to implement traffic redirect.\n    /// Equivalent to\n    /// `tc filter add [dev source] [parent ffff:] [protocol all] u32 match u8 0 0 action mirred egress redirect dev dest`\n    /// You need to set the `parent` and `protocol` before call redirect.\n    pub fn redirect(self, dst_index: u32) -> Self {\n        assert_eq!(self.message.nlas.len(), 0);\n        let u32_nla = vec![\n            tc::u32::Nla::Sel(tc::u32::Sel {\n                flags: TC_U32_TERMINAL,\n                nkeys: 1,\n                keys: vec![tc::u32::Key::default()],\n                ..tc::u32::Sel::default()\n            }),\n            tc::u32::Nla::Act(vec![tc::Action {\n                tab: TCA_ACT_TAB,\n                nlas: vec![\n                    tc::ActNla::Kind(tc::mirred::KIND.to_string()),\n                    tc::ActNla::Options(vec![tc::ActOpt::Mirred(tc::mirred::Nla::Parms(\n                        tc::mirred::TcMirred {\n                            action: TC_ACT_STOLEN,\n                            eaction: TCA_EGRESS_REDIR,\n                            ifindex: dst_index,\n                            ..tc::mirred::TcMirred::default()\n                        },\n                    ))]),\n                ],\n            }]),\n        ];\n        self.u32(u32_nla)\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use std::{fs::File, os::unix::io::AsRawFd, path::Path};\n\n    use futures::stream::TryStreamExt;\n    use nix::sched::{setns, CloneFlags};\n    use tokio::runtime::Runtime;\n\n    use super::*;\n    use crate::{new_connection, packet::LinkMessage, NetworkNamespace, NETNS_PATH, SELF_NS_PATH};\n\n    const TEST_NS: &str = \"netlink_test_filter_ns\";\n    const TEST_VETH_1: &str = \"test_veth_1\";\n    const TEST_VETH_2: &str = \"test_veth_2\";\n\n    struct Netns {\n        path: String,\n        _cur: File,\n        last: File,\n    }\n\n    impl Netns {\n        async fn new(path: &str) -> Self {\n            // record current ns\n            let last = File::open(Path::new(SELF_NS_PATH)).unwrap();\n\n            // create new ns\n            NetworkNamespace::add(path.to_string()).await.unwrap();\n\n            // entry new ns\n            let ns_path = Path::new(NETNS_PATH);\n            let file = File::open(ns_path.join(path)).unwrap();\n            setns(file.as_raw_fd(), CloneFlags::CLONE_NEWNET).unwrap();\n\n            Self {\n                path: path.to_string(),\n                _cur: file,\n                last,\n            }\n        }\n    }\n    impl Drop for Netns {\n        fn drop(&mut self) {\n            println!(\"exit ns: {}\", self.path);\n            setns(self.last.as_raw_fd(), CloneFlags::CLONE_NEWNET).unwrap();\n\n            let ns_path = Path::new(NETNS_PATH).join(&self.path);\n            nix::mount::umount2(&ns_path, nix::mount::MntFlags::MNT_DETACH).unwrap();\n            nix::unistd::unlink(&ns_path).unwrap();\n            // _cur File will be closed auto\n            // Since there is no async drop, NetworkNamespace::del cannot be called\n            // here. Dummy interface will be deleted automatically after netns is\n            // deleted.\n        }\n    }\n\n    async fn setup_env() -> (Handle, LinkMessage, LinkMessage, Netns) {\n        let netns = Netns::new(TEST_NS).await;\n\n        // Notice: The Handle can only be created after the setns, so that the\n        // Handle is the connection within the new ns.\n        let (connection, handle, _) = new_connection().unwrap();\n        tokio::spawn(connection);\n        handle\n            .link()\n            .add()\n            .veth(TEST_VETH_1.to_string(), TEST_VETH_2.to_string())\n            .execute()\n            .await\n            .unwrap();\n\n        let mut links = handle\n            .link()\n            .get()\n            .match_name(TEST_VETH_1.to_string())\n            .execute();\n        let link1 = links.try_next().await.unwrap();\n        links = handle\n            .link()\n            .get()\n            .match_name(TEST_VETH_2.to_string())\n            .execute();\n        let link2 = links.try_next().await.unwrap();\n        (handle, link1.unwrap(), link2.unwrap(), netns)\n    }\n\n    async fn test_async_new_filter() {\n        let (handle, test1, test2, _netns) = setup_env().await;\n        handle\n            .qdisc()\n            .add(test1.header.index as i32)\n            .ingress()\n            .execute()\n            .await\n            .unwrap();\n\n        handle\n            .qdisc()\n            .add(test2.header.index as i32)\n            .ingress()\n            .execute()\n            .await\n            .unwrap();\n\n        handle\n            .traffic_filter(test1.header.index as i32)\n            .add()\n            .parent(0xffff0000)\n            .protocol(0x0003)\n            .redirect(test2.header.index)\n            .execute()\n            .await\n            .unwrap();\n\n        let mut filters_iter = handle\n            .traffic_filter(test1.header.index as i32)\n            .get()\n            .root()\n            .execute();\n\n        let mut found = false;\n        while let Some(nl_msg) = filters_iter.try_next().await.unwrap() {\n            //filters.push(nl_msg.clone());\n            if nl_msg.header.handle == 0x80000800 {\n                let mut iter = nl_msg.nlas.iter();\n                assert_eq!(\n                    iter.next().unwrap(),\n                    &tc::Nla::Kind(String::from(tc::u32::KIND))\n                );\n                assert!(matches!(iter.next().unwrap(), &tc::Nla::Chain(_)));\n                // TCA_OPTIONS\n                let nla = iter.next().unwrap();\n                let filter = if let tc::Nla::Options(f) = nla {\n                    f\n                } else {\n                    panic!(\"expect options nla\");\n                };\n                let mut fi = filter.iter();\n                let fa = fi.next().unwrap();\n                let ua = if let tc::TcOpt::U32(u) = fa {\n                    u\n                } else {\n                    panic!(\"expect u32 nla\");\n                };\n                // TCA_U32_SEL\n                let sel = if let tc::u32::Nla::Sel(s) = ua {\n                    s\n                } else {\n                    panic!(\"expect sel nla\");\n                };\n                assert_eq!(sel.flags, TC_U32_TERMINAL);\n                assert_eq!(sel.nkeys, 1);\n                assert_eq!(sel.keys.len(), 1);\n                assert_eq!(sel.keys[0], tc::u32::Key::default());\n                found = true;\n                break;\n            }\n        }\n        if !found {\n            panic!(\"not found :{} filter.\", test1.header.index);\n        }\n    }\n\n    #[test]\n    fn test_new_filter() {\n        Runtime::new().unwrap().block_on(test_async_new_filter());\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/add_qdisc.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::stream::StreamExt;\n\nuse crate::{\n    packet::{\n        tc::{constants::*, nlas},\n        NetlinkMessage,\n        RtnlMessage,\n        TcMessage,\n        NLM_F_ACK,\n        NLM_F_REQUEST,\n        TC_H_MAKE,\n    },\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct QDiscNewRequest {\n    handle: Handle,\n    message: TcMessage,\n    flags: u16,\n}\n\nimpl QDiscNewRequest {\n    pub(crate) fn new(handle: Handle, message: TcMessage, flags: u16) -> Self {\n        Self {\n            handle,\n            message,\n            flags: NLM_F_REQUEST | flags,\n        }\n    }\n\n    /// Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let Self {\n            mut handle,\n            message,\n            flags,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::NewQueueDiscipline(message));\n        req.header.flags = NLM_F_ACK | flags;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message);\n        }\n        Ok(())\n    }\n\n    /// Set handle,\n    pub fn handle(mut self, maj: u16, min: u16) -> Self {\n        self.message.header.handle = TC_H_MAKE!((maj as u32) << 16, min as u32);\n        self\n    }\n\n    /// Set parent to root.\n    pub fn root(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_ROOT;\n        self\n    }\n\n    /// Set parent\n    pub fn parent(mut self, parent: u32) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = parent;\n        self\n    }\n\n    /// New a ingress qdisc\n    pub fn ingress(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_INGRESS;\n        self.message.header.handle = 0xffff0000;\n        self.message\n            .nlas\n            .push(nlas::Nla::Kind(\"ingress\".to_string()));\n        self\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use std::{fs::File, os::unix::io::AsRawFd, path::Path};\n\n    use futures::stream::TryStreamExt;\n    use nix::sched::{setns, CloneFlags};\n    use tokio::runtime::Runtime;\n\n    use super::*;\n    use crate::{\n        new_connection,\n        packet::{\n            rtnl::tc::nlas::Nla::{HwOffload, Kind},\n            LinkMessage,\n            AF_UNSPEC,\n        },\n        NetworkNamespace,\n        NETNS_PATH,\n        SELF_NS_PATH,\n    };\n\n    const TEST_NS: &str = \"netlink_test_qdisc_ns\";\n    const TEST_DUMMY: &str = \"test_dummy\";\n\n    struct Netns {\n        path: String,\n        _cur: File,\n        last: File,\n    }\n\n    impl Netns {\n        async fn new(path: &str) -> Self {\n            // record current ns\n            let last = File::open(Path::new(SELF_NS_PATH)).unwrap();\n\n            // create new ns\n            NetworkNamespace::add(path.to_string()).await.unwrap();\n\n            // entry new ns\n            let ns_path = Path::new(NETNS_PATH);\n            let file = File::open(ns_path.join(path)).unwrap();\n            setns(file.as_raw_fd(), CloneFlags::CLONE_NEWNET).unwrap();\n\n            Self {\n                path: path.to_string(),\n                _cur: file,\n                last,\n            }\n        }\n    }\n    impl Drop for Netns {\n        fn drop(&mut self) {\n            println!(\"exit ns: {}\", self.path);\n            setns(self.last.as_raw_fd(), CloneFlags::CLONE_NEWNET).unwrap();\n\n            let ns_path = Path::new(NETNS_PATH).join(&self.path);\n            nix::mount::umount2(&ns_path, nix::mount::MntFlags::MNT_DETACH).unwrap();\n            nix::unistd::unlink(&ns_path).unwrap();\n            // _cur File will be closed auto\n            // Since there is no async drop, NetworkNamespace::del cannot be called\n            // here. Dummy interface will be deleted automatically after netns is\n            // deleted.\n        }\n    }\n\n    async fn setup_env() -> (Handle, LinkMessage, Netns) {\n        let netns = Netns::new(TEST_NS).await;\n\n        // Notice: The Handle can only be created after the setns, so that the\n        // Handle is the connection within the new ns.\n        let (connection, handle, _) = new_connection().unwrap();\n        tokio::spawn(connection);\n        handle\n            .link()\n            .add()\n            .dummy(TEST_DUMMY.to_string())\n            .execute()\n            .await\n            .unwrap();\n        let mut links = handle\n            .link()\n            .get()\n            .match_name(TEST_DUMMY.to_string())\n            .execute();\n        let link = links.try_next().await.unwrap();\n        (handle, link.unwrap(), netns)\n    }\n\n    async fn test_async_new_qdisc() {\n        let (handle, test_link, _netns) = setup_env().await;\n        handle\n            .qdisc()\n            .add(test_link.header.index as i32)\n            .ingress()\n            .execute()\n            .await\n            .unwrap();\n        let mut qdiscs_iter = handle\n            .qdisc()\n            .get()\n            .index(test_link.header.index as i32)\n            .ingress()\n            .execute();\n\n        let mut found = false;\n        while let Some(nl_msg) = qdiscs_iter.try_next().await.unwrap() {\n            if nl_msg.header.index == test_link.header.index as i32\n                && nl_msg.header.handle == 0xffff0000\n            {\n                assert_eq!(nl_msg.header.family, AF_UNSPEC as u8);\n                assert_eq!(nl_msg.header.handle, 0xffff0000);\n                assert_eq!(nl_msg.header.parent, TC_H_INGRESS);\n                assert_eq!(nl_msg.header.info, 1); // refcount\n                assert_eq!(nl_msg.nlas[0], Kind(\"ingress\".to_string()));\n                assert_eq!(nl_msg.nlas[2], HwOffload(0));\n                found = true;\n                break;\n            }\n        }\n        if !found {\n            panic!(\"not found dev:{} qdisc.\", test_link.header.index);\n        }\n    }\n\n    #[test]\n    fn test_new_qdisc() {\n        Runtime::new().unwrap().block_on(test_async_new_qdisc());\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/del_qdisc.rs",
    "content": "// SPDX-License-Identifier: MIT\nuse futures::StreamExt;\n\nuse crate::{\n    packet::{NetlinkMessage, RtnlMessage, TcMessage, NLM_F_ACK, NLM_F_REQUEST},\n    try_nl,\n    Error,\n    Handle,\n};\n\npub struct QDiscDelRequest {\n    handle: Handle,\n    message: TcMessage,\n}\n\nimpl QDiscDelRequest {\n    pub(crate) fn new(handle: Handle, message: TcMessage) -> Self {\n        QDiscDelRequest { handle, message }\n    }\n\n    // Execute the request\n    pub async fn execute(self) -> Result<(), Error> {\n        let QDiscDelRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::DelQueueDiscipline(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_ACK;\n\n        let mut response = handle.request(req)?;\n        while let Some(message) = response.next().await {\n            try_nl!(message)\n        }\n        Ok(())\n    }\n\n    /// Return a mutable reference to the request\n    pub fn message_mut(&mut self) -> &mut TcMessage {\n        &mut self.message\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/get.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse futures::{\n    future::{self, Either},\n    stream::{StreamExt, TryStream},\n    FutureExt,\n};\n\nuse crate::{\n    packet::{tc::constants::*, NetlinkMessage, RtnlMessage, TcMessage, NLM_F_DUMP, NLM_F_REQUEST},\n    try_rtnl,\n    Error,\n    Handle,\n};\n\npub struct QDiscGetRequest {\n    handle: Handle,\n    message: TcMessage,\n}\n\nimpl QDiscGetRequest {\n    pub(crate) fn new(handle: Handle) -> Self {\n        QDiscGetRequest {\n            handle,\n            message: TcMessage::default(),\n        }\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = TcMessage, Error = Error> {\n        let QDiscGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetQueueDiscipline(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => Either::Left(\n                response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewQueueDiscipline))),\n            ),\n            Err(e) => Either::Right(future::err::<TcMessage, Error>(e).into_stream()),\n        }\n    }\n\n    pub fn index(mut self, index: i32) -> Self {\n        self.message.header.index = index;\n        self\n    }\n\n    /// Get ingress qdisc\n    pub fn ingress(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_INGRESS;\n        self\n    }\n}\n\npub struct TrafficClassGetRequest {\n    handle: Handle,\n    message: TcMessage,\n}\n\nimpl TrafficClassGetRequest {\n    pub(crate) fn new(handle: Handle, ifindex: i32) -> Self {\n        let mut message = TcMessage::default();\n        message.header.index = ifindex;\n        TrafficClassGetRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = TcMessage, Error = Error> {\n        let TrafficClassGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetTrafficClass(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => Either::Left(\n                response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewTrafficClass))),\n            ),\n            Err(e) => Either::Right(future::err::<TcMessage, Error>(e).into_stream()),\n        }\n    }\n}\n\npub struct TrafficFilterGetRequest {\n    handle: Handle,\n    message: TcMessage,\n}\n\nimpl TrafficFilterGetRequest {\n    pub(crate) fn new(handle: Handle, ifindex: i32) -> Self {\n        let mut message = TcMessage::default();\n        message.header.index = ifindex;\n        TrafficFilterGetRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = TcMessage, Error = Error> {\n        let TrafficFilterGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetTrafficFilter(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => Either::Left(\n                response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewTrafficFilter))),\n            ),\n            Err(e) => Either::Right(future::err::<TcMessage, Error>(e).into_stream()),\n        }\n    }\n\n    /// Set parent to root.\n    pub fn root(mut self) -> Self {\n        assert_eq!(self.message.header.parent, TC_H_UNSPEC);\n        self.message.header.parent = TC_H_ROOT;\n        self\n    }\n}\n\npub struct TrafficChainGetRequest {\n    handle: Handle,\n    message: TcMessage,\n}\n\nimpl TrafficChainGetRequest {\n    pub(crate) fn new(handle: Handle, ifindex: i32) -> Self {\n        let mut message = TcMessage::default();\n        message.header.index = ifindex;\n        TrafficChainGetRequest { handle, message }\n    }\n\n    /// Execute the request\n    pub fn execute(self) -> impl TryStream<Ok = TcMessage, Error = Error> {\n        let TrafficChainGetRequest {\n            mut handle,\n            message,\n        } = self;\n\n        let mut req = NetlinkMessage::from(RtnlMessage::GetTrafficChain(message));\n        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;\n\n        match handle.request(req) {\n            Ok(response) => Either::Left(\n                response.map(move |msg| Ok(try_rtnl!(msg, RtnlMessage::NewTrafficChain))),\n            ),\n            Err(e) => Either::Right(future::err::<TcMessage, Error>(e).into_stream()),\n        }\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/handle.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse super::{\n    QDiscDelRequest,\n    QDiscGetRequest,\n    QDiscNewRequest,\n    TrafficChainGetRequest,\n    TrafficClassGetRequest,\n    TrafficFilterGetRequest,\n    TrafficFilterNewRequest,\n};\n\nuse crate::{\n    packet::{TcMessage, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE},\n    Handle,\n};\n\npub struct QDiscHandle(Handle);\n\nimpl QDiscHandle {\n    pub fn new(handle: Handle) -> Self {\n        QDiscHandle(handle)\n    }\n\n    /// Retrieve the list of qdisc (equivalent to `tc qdisc show`)\n    pub fn get(&mut self) -> QDiscGetRequest {\n        QDiscGetRequest::new(self.0.clone())\n    }\n\n    /// Create a new qdisc, don't replace if the object already exists.\n    /// ( equivalent to `tc qdisc add dev STRING`)\n    pub fn add(&mut self, index: i32) -> QDiscNewRequest {\n        let msg = TcMessage::with_index(index);\n        QDiscNewRequest::new(self.0.clone(), msg, NLM_F_EXCL | NLM_F_CREATE)\n    }\n\n    /// Change the qdisc, the handle cannot be changed and neither can the parent.\n    /// In other words, change cannot move a node.\n    /// ( equivalent to `tc qdisc change dev STRING`)\n    pub fn change(&mut self, index: i32) -> QDiscNewRequest {\n        let msg = TcMessage::with_index(index);\n        QDiscNewRequest::new(self.0.clone(), msg, 0)\n    }\n\n    /// Replace existing matching qdisc, create qdisc if it doesn't already exist.\n    /// ( equivalent to `tc qdisc replace dev STRING`)\n    pub fn replace(&mut self, index: i32) -> QDiscNewRequest {\n        let msg = TcMessage::with_index(index);\n        QDiscNewRequest::new(self.0.clone(), msg, NLM_F_CREATE | NLM_F_REPLACE)\n    }\n\n    /// Performs a replace where the node must exist already.\n    /// ( equivalent to `tc qdisc link dev STRING`)\n    pub fn link(&mut self, index: i32) -> QDiscNewRequest {\n        let msg = TcMessage::with_index(index);\n        QDiscNewRequest::new(self.0.clone(), msg, NLM_F_REPLACE)\n    }\n\n    /// Delete the qdisc ( equivalent to `tc qdisc del dev STRING`)\n    pub fn del(&mut self, index: i32) -> QDiscDelRequest {\n        let msg = TcMessage::with_index(index);\n        QDiscDelRequest::new(self.0.clone(), msg)\n    }\n}\n\npub struct TrafficClassHandle {\n    handle: Handle,\n    ifindex: i32,\n}\n\nimpl TrafficClassHandle {\n    pub fn new(handle: Handle, ifindex: i32) -> Self {\n        TrafficClassHandle { handle, ifindex }\n    }\n\n    /// Retrieve the list of traffic class (equivalent to\n    /// `tc class show dev <interface_name>`)\n    pub fn get(&mut self) -> TrafficClassGetRequest {\n        TrafficClassGetRequest::new(self.handle.clone(), self.ifindex)\n    }\n}\n\npub struct TrafficFilterHandle {\n    handle: Handle,\n    ifindex: i32,\n}\n\nimpl TrafficFilterHandle {\n    pub fn new(handle: Handle, ifindex: i32) -> Self {\n        TrafficFilterHandle { handle, ifindex }\n    }\n\n    /// Retrieve the list of filter (equivalent to\n    /// `tc filter show dev <iface_name>`)\n    pub fn get(&mut self) -> TrafficFilterGetRequest {\n        TrafficFilterGetRequest::new(self.handle.clone(), self.ifindex)\n    }\n\n    /// Add a filter to a node, don't replace if the object already exists.\n    /// ( equivalent to `tc filter add dev STRING`)\n    pub fn add(&mut self) -> TrafficFilterNewRequest {\n        TrafficFilterNewRequest::new(self.handle.clone(), self.ifindex, NLM_F_EXCL | NLM_F_CREATE)\n    }\n\n    /// Change the filter, the handle cannot be changed and neither can the parent.\n    /// In other words, change cannot move a node.\n    /// ( equivalent to `tc filter change dev STRING`)\n    pub fn change(&mut self) -> TrafficFilterNewRequest {\n        TrafficFilterNewRequest::new(self.handle.clone(), self.ifindex, 0)\n    }\n\n    /// Replace existing matching filter, create filter if it doesn't already exist.\n    /// ( equivalent to `tc filter replace dev STRING`)\n    pub fn replace(&mut self) -> TrafficFilterNewRequest {\n        TrafficFilterNewRequest::new(self.handle.clone(), self.ifindex, NLM_F_CREATE)\n    }\n}\n\npub struct TrafficChainHandle {\n    handle: Handle,\n    ifindex: i32,\n}\n\nimpl TrafficChainHandle {\n    pub fn new(handle: Handle, ifindex: i32) -> Self {\n        TrafficChainHandle { handle, ifindex }\n    }\n\n    /// Retrieve the list of chain (equivalent to\n    /// `tc chain show dev <iface_name>`)\n    pub fn get(&mut self) -> TrafficChainGetRequest {\n        TrafficChainGetRequest::new(self.handle.clone(), self.ifindex)\n    }\n}\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/mod.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nmod handle;\npub use self::handle::*;\n\nmod get;\npub use self::get::*;\n\nmod add_qdisc;\npub use self::add_qdisc::*;\n\nmod del_qdisc;\npub use self::del_qdisc::*;\n\nmod add_filter;\npub use self::add_filter::*;\n\n#[cfg(test)]\nmod test;\n"
  },
  {
    "path": "rtnetlink/src/traffic_control/test.rs",
    "content": "// SPDX-License-Identifier: MIT\n\nuse std::process::Command;\n\nuse futures::stream::TryStreamExt;\nuse tokio::runtime::Runtime;\n\nuse crate::{\n    new_connection,\n    packet::{\n        rtnl::tc::nlas::Nla::{Chain, HwOffload, Kind},\n        ErrorMessage,\n        TcMessage,\n        AF_UNSPEC,\n    },\n    Error::NetlinkError,\n};\n\nstatic TEST_DUMMY_NIC: &str = \"netlink-test\";\n\nasync fn _get_qdiscs() -> Vec<TcMessage> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    let mut qdiscs_iter = handle.qdisc().get().execute();\n    let mut qdiscs = Vec::new();\n    while let Some(nl_msg) = qdiscs_iter.try_next().await.unwrap() {\n        qdiscs.push(nl_msg.clone());\n    }\n    qdiscs\n}\n\n#[test]\nfn test_get_qdiscs() {\n    let qdiscs = Runtime::new().unwrap().block_on(_get_qdiscs());\n    let qdisc_of_loopback_nic = &qdiscs[0];\n    assert_eq!(qdisc_of_loopback_nic.header.family, AF_UNSPEC as u8);\n    assert_eq!(qdisc_of_loopback_nic.header.index, 1);\n    assert_eq!(qdisc_of_loopback_nic.header.handle, 0);\n    assert_eq!(qdisc_of_loopback_nic.header.parent, u32::MAX);\n    assert_eq!(qdisc_of_loopback_nic.header.info, 2); // refcount\n    assert_eq!(qdisc_of_loopback_nic.nlas[0], Kind(\"noqueue\".to_string()));\n    assert_eq!(qdisc_of_loopback_nic.nlas[1], HwOffload(0));\n}\n\nasync fn _get_tclasses(ifindex: i32) -> Vec<TcMessage> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    let mut tclasses_iter = handle.traffic_class(ifindex).get().execute();\n    let mut tclasses = Vec::new();\n    while let Some(nl_msg) = tclasses_iter.try_next().await.unwrap() {\n        tclasses.push(nl_msg.clone());\n    }\n    tclasses\n}\n\n// Return 0 for not found\nfn _get_test_dummy_interface_index() -> i32 {\n    let output = Command::new(\"ip\")\n        .args(&[\"-o\", \"link\", \"show\", TEST_DUMMY_NIC])\n        .output()\n        .expect(\"failed to run ip command\");\n    if !output.status.success() {\n        0\n    } else {\n        let line = std::str::from_utf8(&output.stdout).unwrap();\n        line.split(\": \").next().unwrap().parse::<i32>().unwrap()\n    }\n}\n\nfn _add_test_dummy_interface() -> i32 {\n    if _get_test_dummy_interface_index() == 0 {\n        let output = Command::new(\"ip\")\n            .args(&[\"link\", \"add\", TEST_DUMMY_NIC, \"type\", \"dummy\"])\n            .output()\n            .expect(\"failed to run ip command\");\n        if !output.status.success() {\n            eprintln!(\n                \"Failed to create dummy interface {} : {:?}\",\n                TEST_DUMMY_NIC, output\n            );\n        }\n        assert!(output.status.success());\n    }\n\n    _get_test_dummy_interface_index()\n}\n\nfn _remove_test_dummy_interface() {\n    let output = Command::new(\"ip\")\n        .args(&[\"link\", \"del\", TEST_DUMMY_NIC])\n        .output()\n        .expect(\"failed to run ip command\");\n    if !output.status.success() {\n        eprintln!(\n            \"Failed to remove dummy interface {} : {:?}\",\n            TEST_DUMMY_NIC, output\n        );\n    }\n    assert!(output.status.success());\n}\n\nfn _add_test_tclass_to_dummy() {\n    let output = Command::new(\"tc\")\n        .args(&[\n            \"qdisc\",\n            \"add\",\n            \"dev\",\n            TEST_DUMMY_NIC,\n            \"root\",\n            \"handle\",\n            \"1:\",\n            \"htb\",\n            \"default\",\n            \"6\",\n        ])\n        .output()\n        .expect(\"failed to run tc command\");\n    if !output.status.success() {\n        eprintln!(\n            \"Failed to add qdisc to dummy interface {} : {:?}\",\n            TEST_DUMMY_NIC, output\n        );\n    }\n    assert!(output.status.success());\n    let output = Command::new(\"tc\")\n        .args(&[\n            \"class\",\n            \"add\",\n            \"dev\",\n            TEST_DUMMY_NIC,\n            \"parent\",\n            \"1:\",\n            \"classid\",\n            \"1:1\",\n            \"htb\",\n            \"rate\",\n            \"10mbit\",\n            \"ceil\",\n            \"10mbit\",\n        ])\n        .output()\n        .expect(\"failed to run tc command\");\n    if !output.status.success() {\n        eprintln!(\n            \"Failed to add traffic class to dummy interface {}: {:?}\",\n            TEST_DUMMY_NIC, output\n        );\n    }\n    assert!(output.status.success());\n}\n\nfn _add_test_filter_to_dummy() {\n    let output = Command::new(\"tc\")\n        .args(&[\n            \"filter\",\n            \"add\",\n            \"dev\",\n            TEST_DUMMY_NIC,\n            \"parent\",\n            \"1:\",\n            \"basic\",\n            \"match\",\n            \"meta(priority eq 6)\",\n            \"classid\",\n            \"1:1\",\n        ])\n        .output()\n        .expect(\"failed to run tc command\");\n    if !output.status.success() {\n        eprintln!(\"Failed to add trafice filter to lo: {:?}\", output);\n    }\n    assert!(output.status.success());\n}\n\nfn _remove_test_tclass_from_dummy() {\n    Command::new(\"tc\")\n        .args(&[\n            \"class\",\n            \"del\",\n            \"dev\",\n            TEST_DUMMY_NIC,\n            \"parent\",\n            \"1:\",\n            \"classid\",\n            \"1:1\",\n        ])\n        .status()\n        .unwrap_or_else(|_| {\n            panic!(\n                \"failed to remove tclass from dummy interface {}\",\n                TEST_DUMMY_NIC\n            )\n        });\n    Command::new(\"tc\")\n        .args(&[\"qdisc\", \"del\", \"dev\", TEST_DUMMY_NIC, \"root\"])\n        .status()\n        .unwrap_or_else(|_| {\n            panic!(\n                \"failed to remove qdisc from dummy interface {}\",\n                TEST_DUMMY_NIC\n            )\n        });\n}\n\nfn _remove_test_filter_from_dummy() {\n    Command::new(\"tc\")\n        .args(&[\"filter\", \"del\", \"dev\", TEST_DUMMY_NIC])\n        .status()\n        .unwrap_or_else(|_| {\n            panic!(\n                \"failed to remove filter from dummy interface {}\",\n                TEST_DUMMY_NIC\n            )\n        });\n}\n\nasync fn _get_filters(ifindex: i32) -> Vec<TcMessage> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    let mut filters_iter = handle.traffic_filter(ifindex).get().execute();\n    let mut filters = Vec::new();\n    while let Some(nl_msg) = filters_iter.try_next().await.unwrap() {\n        filters.push(nl_msg.clone());\n    }\n    filters\n}\n\nasync fn _get_chains(ifindex: i32) -> Vec<TcMessage> {\n    let (connection, handle, _) = new_connection().unwrap();\n    tokio::spawn(connection);\n    let mut chains_iter = handle.traffic_chain(ifindex).get().execute();\n    let mut chains = Vec::new();\n    // The traffic control chain is only supported by kernel 4.19+,\n    // hence we might get error: 95 Operation not supported\n    loop {\n        match chains_iter.try_next().await {\n            Ok(Some(nl_msg)) => {\n                chains.push(nl_msg.clone());\n            }\n            Ok(None) => {\n                break;\n            }\n            Err(NetlinkError(ErrorMessage { code, header: _ })) => {\n                assert_eq!(code, -95);\n                eprintln!(\n                    \"The chain in traffic control is not supported, \\\n                     please upgrade your kernel\"\n                );\n            }\n            _ => {}\n        }\n    }\n    chains\n}\n\n// The `cargo test` by default run all tests in parallel, in stead\n// of create random named veth/dummy for test, just place class, filter, and\n// chain query test in one test case is much simpler.\n#[test]\n#[cfg_attr(not(feature = \"test_as_root\"), ignore)]\nfn test_get_traffic_classes_filters_and_chains() {\n    let ifindex = _add_test_dummy_interface();\n    _add_test_tclass_to_dummy();\n    _add_test_filter_to_dummy();\n    let tclasses = Runtime::new().unwrap().block_on(_get_tclasses(ifindex));\n    let filters = Runtime::new().unwrap().block_on(_get_filters(ifindex));\n    let chains = Runtime::new().unwrap().block_on(_get_chains(ifindex));\n    _remove_test_filter_from_dummy();\n    _remove_test_tclass_from_dummy();\n    _remove_test_dummy_interface();\n    assert_eq!(tclasses.len(), 1);\n    let tclass = &tclasses[0];\n    assert_eq!(tclass.header.family, AF_UNSPEC as u8);\n    assert_eq!(tclass.header.index, ifindex);\n    assert_eq!(tclass.header.parent, u32::MAX);\n    assert_eq!(tclass.nlas[0], Kind(\"htb\".to_string()));\n    assert_eq!(filters.len(), 2);\n    assert_eq!(filters[0].header.family, AF_UNSPEC as u8);\n    assert_eq!(filters[0].header.index, ifindex);\n    assert_eq!(filters[0].header.parent, u16::MAX as u32 + 1);\n    assert_eq!(filters[0].nlas[0], Kind(\"basic\".to_string()));\n    assert_eq!(filters[1].header.family, AF_UNSPEC as u8);\n    assert_eq!(filters[1].header.index, ifindex);\n    assert_eq!(filters[1].header.parent, u16::MAX as u32 + 1);\n    assert_eq!(filters[1].nlas[0], Kind(\"basic\".to_string()));\n    assert!(chains.len() <= 1);\n    if chains.len() == 1 {\n        assert_eq!(chains[0].header.family, AF_UNSPEC as u8);\n        assert_eq!(chains[0].header.index, ifindex);\n        assert_eq!(chains[0].header.parent, u16::MAX as u32 + 1);\n        assert_eq!(chains[0].nlas[0], Chain([0u8, 0, 0, 0].to_vec()));\n    }\n}\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "# requires unstable rustfmt until the options are stabilized\nformat_code_in_doc_comments = true\nimports_layout = \"HorizontalVertical\"\nimports_granularity = \"Crate\"\n"
  }
]