diff --git a/crates/wdk-build/src/bindgen.rs b/crates/wdk-build/src/bindgen.rs index f815cd5c6..983d26ab4 100644 --- a/crates/wdk-build/src/bindgen.rs +++ b/crates/wdk-build/src/bindgen.rs @@ -131,6 +131,9 @@ impl BuilderExt for Builder { .blocklist_item(".*USBDEVICE_ABORTIO") .blocklist_item(".*USBDEVICE_STARTIO") .blocklist_item(".*USBDEVICE_TREE_PURGEIO") + // FIXME: bindgen unable to generate nameless fields + .blocklist_item(".*NET_BUFFER_HEADER") + .blocklist_item(".*NDIS_OPEN_BLOCK") // FIXME: arrays with more than 32 entries currently fail to generate a `Default`` impl: https://github.com/rust-lang/rust-bindgen/issues/2803 .no_default(".*tagMONITORINFOEXA") .must_use_type("NTSTATUS") @@ -142,7 +145,8 @@ impl BuilderExt for Builder { .parse_callbacks(Box::new(WdkCallbacks::new(config))) .formatter(bindgen::Formatter::Prettyplease) .rust_target(get_rust_target()?) - .rust_edition(get_rust_edition()?); + .rust_edition(get_rust_edition()?) + .wrap_unsafe_ops(true); // The `_USBPM_CLIENT_CONFIG_EXTRA_INFO` struct only has members when // _KERNEL_MODE flag is defined. We need to mark this type as opaque to avoid diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index dd33189b8..9b89c4375 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -335,6 +335,8 @@ pub enum ApiSubset { Storage, /// API subset for USB (Universal Serial Bus) drivers: Usb, + /// API subset for network drivers: + Network, } #[derive(Debug, Error, PartialEq, Eq)] @@ -687,21 +689,25 @@ impl Config { // ] // .into_iter() // .map(|(key, value)| (key.to_string(), value.map(|v| v.to_string()))) + let mut defs = vec![("NDIS_SUPPORT_NDIS6", None)]; + match self.cpu_architecture { // Definitions sourced from `Program Files\Windows // Kits\10\build\10.0.22621.0\WindowsDriver.x64.props` CpuArchitecture::Amd64 => { - vec![("_WIN64", None), ("_AMD64_", None), ("AMD64", None)] + defs.extend([("_WIN64", None), ("_AMD64_", None), ("AMD64", None)]); + defs } // Definitions sourced from `Program Files\Windows // Kits\10\build\10.0.22621.0\WindowsDriver.arm64.props` CpuArchitecture::Arm64 => { - vec![ + defs.extend([ ("_ARM64_", None), ("ARM64", None), ("_USE_DECLSPECS_FOR_SAL", Some(1)), ("STD_CALL", None), - ] + ]); + defs } } .into_iter() @@ -816,6 +822,7 @@ impl Config { ApiSubset::Wdf => self.wdf_headers(), ApiSubset::Gpio => self.gpio_headers(), ApiSubset::Hid => self.hid_headers(), + ApiSubset::Network => self.network_headers(), ApiSubset::ParallelPorts => self.parallel_ports_headers(), ApiSubset::Spb => self.spb_headers(), ApiSubset::Storage => self.storage_headers(), @@ -994,6 +1001,11 @@ impl Config { Ok(headers) } + #[tracing::instrument(level = "trace")] + fn network_headers(&self) -> Vec<&'static str> { + vec!["ndis.h", "fwpmk.h", "fwpsk.h"] + } + /// Determines whether to include the ufxclient.h header based on the Clang /// version used by bindgen. /// @@ -1167,6 +1179,8 @@ impl Config { println!("cargo::rustc-link-lib=static=wmilib"); println!("cargo::rustc-link-lib=static=WdfLdr"); println!("cargo::rustc-link-lib=static=WdfDriverEntry"); + println!("cargo::rustc-link-lib=static=Fwpkclnt"); + println!("cargo::rustc-link-lib=static=netio"); // Emit ARM64-specific libraries to link to derived from // WindowsDriver.arm64.props diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml index a1428cc09..70dc23253 100644 --- a/crates/wdk-sys/Cargo.toml +++ b/crates/wdk-sys/Cargo.toml @@ -25,6 +25,7 @@ parallel-ports = ["gpio"] spb = [] storage = [] usb = [] +network = [] nightly = ["wdk-macros/nightly", "wdk-build/nightly"] test-stubs = [] diff --git a/crates/wdk-sys/build.rs b/crates/wdk-sys/build.rs index 2a7308487..aa588035d 100644 --- a/crates/wdk-sys/build.rs +++ b/crates/wdk-sys/build.rs @@ -145,6 +145,8 @@ const ENABLED_API_SUBSETS: &[ApiSubset] = &[ ApiSubset::Storage, #[cfg(feature = "usb")] ApiSubset::Usb, + #[cfg(feature = "network")] + ApiSubset::Network, ]; type GenerateFn = fn(&Path, &Config) -> Result<(), ConfigError>; @@ -165,6 +167,8 @@ const BINDGEN_FILE_GENERATORS_TUPLES: &[(&str, GenerateFn)] = &[ ("storage.rs", generate_storage), #[cfg(feature = "usb")] ("usb.rs", generate_usb), + #[cfg(feature = "network")] + ("network.rs", generate_network), ]; fn initialize_tracing() -> Result<(), ParseError> { @@ -495,6 +499,36 @@ fn generate_usb(out_path: &Path, config: &Config) -> Result<(), ConfigError> { .map_err(|source| IoError::with_path(output_file_path, source))?) } +#[cfg(feature = "network")] +fn generate_network(out_path: &Path, config: &Config) -> Result<(), ConfigError> { + info!("Generating bindings to WDK: network.rs"); + + let header_contents = + config.bindgen_header_contents([ApiSubset::Base, ApiSubset::Wdf, ApiSubset::Network])?; + trace!(header_contents = ?header_contents); + + let bindgen_builder = { + let mut builder = bindgen::Builder::wdk_default(config)? + .with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement()) + .header_contents("network.h", &header_contents); + + // Only allowlist files in the network-specific files to avoid + // duplicate definitions + for header_file in config.headers(ApiSubset::Network)? { + builder = builder.allowlist_file(format!("(?i).*{header_file}.*")); + } + builder + }; + trace!(bindgen_builder = ?bindgen_builder); + + let output_file_path = out_path.join("network.rs"); + Ok(bindgen_builder + .generate() + .expect("Bindings should succeed to generate") + .write_to_file(&output_file_path) + .map_err(|source| IoError::with_path(output_file_path, source))?) +} + /// Generates a `wdf_function_count.rs` file in `OUT_DIR` which contains the /// definition of the function `get_wdf_function_count()`. This is required to /// be generated here since the size of the table is derived from either a diff --git a/crates/wdk-sys/src/lib.rs b/crates/wdk-sys/src/lib.rs index 39a88977c..4a575f0ff 100644 --- a/crates/wdk-sys/src/lib.rs +++ b/crates/wdk-sys/src/lib.rs @@ -89,6 +89,16 @@ pub mod storage; ))] pub mod usb; +#[cfg(all( + any( + driver_model__driver_type = "WDM", + driver_model__driver_type = "KMDF", + driver_model__driver_type = "UMDF" + ), + feature = "network" +))] +pub mod network; + #[cfg(feature = "test-stubs")] pub mod test_stubs; diff --git a/crates/wdk-sys/src/network.rs b/crates/wdk-sys/src/network.rs new file mode 100644 index 000000000..0bd7ccb7b --- /dev/null +++ b/crates/wdk-sys/src/network.rs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +//! Direct FFI bindings to network APIs from the Windows Driver Kit (WDK) +//! +//! This module contains all bindings for network headers. Types are not +//! included in this module, but are available in the top-level `wdk_sys` +//! module. +#[allow( + missing_docs, + reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \ + generate documentation for their bindings" +)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(non_upper_case_globals)] +#[allow(unnecessary_transmutes)] +mod bindings { + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] + use crate::types::*; + + include!(concat!(env!("OUT_DIR"), "/network.rs")); +} + +pub use bindings::*; diff --git a/crates/wdk-sys/src/types.rs b/crates/wdk-sys/src/types.rs index 76e8ae9f4..cd3f7e2a8 100644 --- a/crates/wdk-sys/src/types.rs +++ b/crates/wdk-sys/src/types.rs @@ -69,5 +69,17 @@ pub use bindings::*; #[allow(clippy::useless_transmute)] #[allow(clippy::use_self)] mod bindings { + // TODO: These types are blocklisted in bindgen because it cannot handle structs + // with fields that are unnamed. + #[cfg(feature = "network")] + #[repr(C)] + #[derive(Copy, Clone)] + pub union _NET_BUFFER_HEADER { + pub NetBufferData: NET_BUFFER_DATA, + pub Link: SLIST_HEADER, + } + #[cfg(feature = "network")] + pub type NET_BUFFER_HEADER = _NET_BUFFER_HEADER; + include!(concat!(env!("OUT_DIR"), "/types.rs")); }