Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion crates/wdk-build/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
Expand Down
20 changes: 17 additions & 3 deletions crates/wdk-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ pub enum ApiSubset {
Storage,
/// API subset for USB (Universal Serial Bus) drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_usbref/>
Usb,
/// API subset for network drivers: <https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/_netvista/>
Network,
}

#[derive(Debug, Error, PartialEq, Eq)]
Expand Down Expand Up @@ -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)];

Comment on lines +692 to +693
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NDIS_SUPPORT_NDIS6 preprocessor definition is being added unconditionally for all driver builds, regardless of whether the network feature is enabled. This definition should only be added when network functionality is actually being used. Consider making this conditional on the network feature to avoid polluting the preprocessor namespace and potentially affecting non-network driver builds.

Suggested change
let mut defs = vec![("NDIS_SUPPORT_NDIS6", None)];
let mut defs = Vec::new();
if cfg!(feature = "network") {
defs.push(("NDIS_SUPPORT_NDIS6", None));
}

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdk-build does not hide any of this behind feature flags. I don't think this suggestion is correct.

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()
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions crates/wdk-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ parallel-ports = ["gpio"]
spb = []
storage = []
usb = []
network = []

nightly = ["wdk-macros/nightly", "wdk-build/nightly"]
test-stubs = []
Expand Down
34 changes: 34 additions & 0 deletions crates/wdk-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand All @@ -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> {
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions crates/wdk-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
31 changes: 31 additions & 0 deletions crates/wdk-sys/src/network.rs
Original file line number Diff line number Diff line change
@@ -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::*;
12 changes: 12 additions & 0 deletions crates/wdk-sys/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}