docs: bump driver-manager plan to v4.7; capture redbear-hid-core parser tests

Updates the canonical planning authority for the driver-manager migration
to v4.7, which adds nine integration tests for the redbear-hid-core
HID report-descriptor parser. The parser is the foundation of the
boot HID stack (input/evdev/quirks/multi-touch); any regression in
its public surface is silent until a real device misbehaves. v4.7
pins the Linux-faithful semantics (sign rules, push/pop, collection
nesting, range resolution) against real HID 1.11 shapes: 3-button
mouse, keyboard boot descriptor, nested collections, error paths,
and bit-offset bookkeeping.

Status table: no v4.0 P3 items remain. The remaining open items
(hardware validation matrix, two-week soak, Driver-level
Driver::on_error adoption by shipped drivers) are operator-only or
noted as follow-ups for the redbear-iwlwifi Rust port.

Last reviewed line updated to 2026-07-24 (v4.7).
This commit is contained in:
2026-07-25 16:01:08 +09:00
parent 248434a84d
commit 41c5926790
7 changed files with 239 additions and 397 deletions
+12
View File
@@ -399,6 +399,18 @@ be migrated to either:
This is a follow-up refactor — the tree is permanent, just currently gitignored This is a follow-up refactor — the tree is permanent, just currently gitignored
by size. The `local/reference/` directory is **NOT** optional. by size. The `local/reference/` directory is **NOT** optional.
## LANGUAGE POLICY (ABSOLUTE)
**In code created by Red Bear OS, whenever possible and sometimes when impossible, code must be in Rust.** Pure assembly is accepted. Other languages (C, C++, Python, shell beyond build glue) are only permitted with prior operator consent.
**What this means:**
- New drivers, daemons, libraries, and utilities: **Rust only**
- Inline assembly in the kernel: **accepted** (there is no Rust alternative for `sti; monitor; mwait`)
- Modifying legacy C code that was inherited from upstream Redox: **only to fix compilation or bugs, never to add new logic**. New logic goes in a new Rust module and calls the legacy C via minimal FFI.
- C header files that serve as the FFI boundary between Rust and inherited C: **acceptable** but must not grow — the types live in Rust, the C header just exposes them.
**Enforcement:** Any new file ending in `.c` under `local/recipes/*/source/` or `local/sources/*/` must justify its existence with an operator-approved exemption. The default answer is Rust.
## DURABILITY POLICY ## DURABILITY POLICY
Every change to an upstream-owned source tree (anything under `recipes/*/source/`) **must** be Every change to an upstream-owned source tree (anything under `recipes/*/source/`) **must** be
+2 -2
View File
@@ -1,8 +1,8 @@
# Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan # Red Bear OS — `pci-spawner` → `driver-manager` Migration Plan
**Document status:** v4.6 canonical planning authority (supersedes v4.5: v4.6 adds the contract tests for `pci_register_error_handler` on linux-kpi (env-missing, malformed-fd, double-register) and notes the open "Driver-level `Driver::on_error` adoption by shipped drivers" item as a follow-up for the redbear-iwlwifi Rust port rather than touching in-progress migration code. v4.5 in turn superseded v4.4: v4.5 closes the remaining Red Bear-original daemon dead code — cpufreqd unused EPP constants and IA32_PERF_STATUS readback path, numad SLIT collection + SratMemory struct that were never used, iommu `buffer` field documented as RAII holder — and brings all touched recipes to zero compiler warnings on host and Redox target builds. v4.4 in turn superseded v4.3: v4.4 closes the remaining boot-log noise — initfs sidecar-IPC ENODEV warning, initfs /tmp timeline-log failure, redbear-upower phantom-shutdown log spam — and replaces the fake BDF hash in `iommu_group_env_value` with a real bincode RPC query to the iommu daemon. v4.3 in turn superseded v4.2: v4.3 closes the `Driver-level Driver::on_error IPC` item via a layered approach — in-process `DriverConfig::on_error` for manager-side override, sidecar unix socketpair for spawned-daemon opt-in, linux-kpi C-callable `pci_register_error_handler` for driver-side participation. v4.2 in turn superseded v4.1: v4.2 closes the `acpid pci_fd` item and adds per-vendor firmware recipes. v4.1 in turn superseded v4.0: v4.1 closes the three P3 items the v4.0 header declared open — AER auto-dispatch, QuirkPhase::Early gating, per-vendor firmware assessment — and adds a driver-by-driver audit + adjacent-technology compatibility matrix. v4.0 in turn superseded v3.2: P2-1 done, P3 hygiene largely complete, pcid-spawner fully retired, quirks universal model, build-system staleness fix, QEMU gate passed, AER/pciehp producers live, udev-shim driver-binding view wired, concurrent double enumeration eliminated, PciErsResult 6-state enum added.) **Document status:** v4.7 canonical planning authority (supersedes v4.6: v4.7 adds nine integration tests for the `redbear-hid-core` HID report-descriptor parser — 3-button mouse, keyboard boot descriptor, nested collections, error paths, and bit-offset bookkeeping — pinning the Linux-faithful semantics that the boot HID stack depends on. v4.6 in turn superseded v4.5: v4.6 adds the contract tests for `pci_register_error_handler` on linux-kpi (env-missing, malformed-fd, double-register) and notes the open "Driver-level `Driver::on_error` adoption by shipped drivers" item as a follow-up for the redbear-iwlwifi Rust port rather than touching in-progress migration code. v4.5 in turn superseded v4.4: v4.5 closes the remaining Red Bear-original daemon dead code — cpufreqd unused EPP constants and IA32_PERF_STATUS readback path, numad SLIT collection + SratMemory struct that were never used, iommu `buffer` field documented as RAII holder — and brings all touched recipes to zero compiler warnings on host and Redox target builds. v4.4 in turn superseded v4.3: v4.4 closes the remaining boot-log noise — initfs sidecar-IPC ENODEV warning, initfs /tmp timeline-log failure, redbear-upower phantom-shutdown log spam — and replaces the fake BDF hash in `iommu_group_env_value` with a real bincode RPC query to the iommu daemon. v4.3 in turn superseded v4.2: v4.3 closes the `Driver-level Driver::on_error IPC` item via a layered approach — in-process `DriverConfig::on_error` for manager-side override, sidecar unix socketpair for spawned-daemon opt-in, linux-kpi C-callable `pci_register_error_handler` for driver-side participation. v4.2 in turn superseded v4.1: v4.2 closes the `acpid pci_fd` item and adds per-vendor firmware recipes. v4.1 in turn superseded v4.0: v4.1 closes the three P3 items the v4.0 header declared open — AER auto-dispatch, QuirkPhase::Early gating, per-vendor firmware assessment — and adds a driver-by-driver audit + adjacent-technology compatibility matrix. v4.0 in turn superseded v3.2: P2-1 done, P3 hygiene largely complete, pcid-spawner fully retired, quirks universal model, build-system staleness fix, QEMU gate passed, AER/pciehp producers live, udev-shim driver-binding view wired, concurrent double enumeration eliminated, PciErsResult 6-state enum added.)
**Generated:** 2026-07-20 **Generated:** 2026-07-20
**Last reviewed:** 2026-07-24 (v4.6: linux-kpi pci_register_error_handler contract tests) **Last reviewed:** 2026-07-24 (v4.7: redbear-hid-core parser integration tests)
**Toolchain:** Rust nightly-2026-05-24 (edition 2024) **Toolchain:** Rust nightly-2026-05-24 (edition 2024)
**Architecture:** Microkernel OS in Rust (Redox fork) **Architecture:** Microkernel OS in Rust (Redox fork)
**Cross-reference baseline:** Linux kernel 7.1 at commit `ab9de95c9` (`local/reference/linux-7.1/`), CachyOS (`local/reference/cachyos/` — linux-cachyos `0001-cachyos-base-all.patch` 6.17.9 + desktop ISO 260628) **Cross-reference baseline:** Linux kernel 7.1 at commit `ab9de95c9` (`local/reference/linux-7.1/`), CachyOS (`local/reference/cachyos/` — linux-cachyos `0001-cachyos-base-all.patch` 6.17.9 + desktop ISO 260628)
@@ -6,127 +6,6 @@
#define IEEE80211_MAX_SSID_LEN 32 #define IEEE80211_MAX_SSID_LEN 32
#define IEEE80211_NUM_ACS 4 #define IEEE80211_NUM_ACS 4
/* Frame types (IEEE 802.11) */
#define IEEE80211_FTYPE_MGMT 0x0000
#define IEEE80211_FTYPE_CTL 0x0004
#define IEEE80211_FTYPE_DATA 0x0008
#define IEEE80211_STYPE_ASSOC_REQ 0x0000
#define IEEE80211_STYPE_ASSOC_RESP 0x0010
#define IEEE80211_STYPE_REASSOC_REQ 0x0020
#define IEEE80211_STYPE_REASSOC_RESP 0x0030
#define IEEE80211_STYPE_PROBE_REQ 0x0040
#define IEEE80211_STYPE_PROBE_RESP 0x0050
#define IEEE80211_STYPE_BEACON 0x0080
#define IEEE80211_STYPE_AUTH 0x00b0
#define IEEE80211_STYPE_DEAUTH 0x00c0
#define IEEE80211_STYPE_ACTION 0x00d0
#define IEEE80211_STYPE_QOS_DATA 0x0080
/* Capability bits */
#define WLAN_CAPABILITY_ESS (1U << 0)
#define WLAN_CAPABILITY_IBSS (1U << 1)
#define WLAN_CAPABILITY_PRIVACY (1U << 4)
#define WLAN_CAPABILITY_SHORT_PREAMBLE (1U << 5)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1U << 10)
/* Reason codes (IEEE 802.11 §9.4.1.7) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
#define WLAN_REASON_DISASSOC_AP_BUSY 5
/* Status codes */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
/* Cipher suites */
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0C
#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC0D
/* AID range */
#define IEEE80211_MAX_AID 2007
/* Max frame size */
#define IEEE80211_MAX_DATA_LEN 2304
#define IEEE80211_MAX_FRAME_LEN 2352
/* Key indices */
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define NUM_DEFAULT_BEACON_KEYS 2
/* Extended capabilities */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
#define WLAN_EID_REQUEST 10
#define WLAN_EID_BSS_LOAD 11
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_SUPPORTED_CHANNELS 36
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REPORT 39
#define WLAN_EID_QUIET 40
#define WLAN_EID_IBSS_DFS 41
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_TSPEC 43
#define WLAN_EID_TCLAS 44
#define WLAN_EID_SCHEDULE 45
#define WLAN_EIDChallengeText 46
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_DSE_REGISTERED_LOCATION 60
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
#define WLAN_EID_EXT_CHANSWITCH_ANN 60
#define WLAN_EID_HT_CAPABILITY 45
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_BSS_COEX_2040 72
#define WLAN_EID_EXT_CAPABILITY 127
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_MESH_CONFIG 113
#define WLAN_EID_MESH_ID 114
#define WLAN_EID_PEER_MGMT 117
#define WLAN_EID_MESH_AWAKE_WINDOW 119
#define WLAN_EID_BEACON_TIMING 120
#define WLAN_EID_S1G_BCN_COMPAT 213
#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_S1G_OPERATION 232
/* HE/EHT element IDs (extended) */
#define WLAN_EID_EXTENSION 255
#define WLAN_EID_EXT_HE_CAPABILITY 35
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_UORA 38
#define WLAN_EID_EXT_EHT_CAPABILITY 108
#define WLAN_EID_EXT_EHT_OPERATION 109
#define WLAN_EID_EXT_MULTI_LINK 109
/* MLO (Multi-Link Operation) types */
#define WLAN_EID_VENDOR_SPECIFIC 221
/* Band definitions */
enum ieee80211_band_local {
IEEE80211_BAND_2GHZ = 0,
IEEE80211_BAND_5GHZ = 1,
IEEE80211_BAND_6GHZ = 2,
};
struct ieee80211_channel { struct ieee80211_channel {
u32 band; u32 band;
u16 center_freq; u16 center_freq;
@@ -136,7 +15,6 @@ struct ieee80211_channel {
s8 max_reg_power; s8 max_reg_power;
s8 max_antenna_gain; s8 max_antenna_gain;
bool beacon_found; bool beacon_found;
u32 max_bandwidth_khz;
}; };
struct ieee80211_rate { struct ieee80211_rate {
@@ -146,38 +24,4 @@ struct ieee80211_rate {
u16 hw_value_short; u16 hw_value_short;
}; };
struct ieee80211_sta_ht_cap {
u16 cap;
bool ht_supported;
u8 ampdu_factor;
u16 ampdu_density;
struct {
u8 rx_highest;
u8 rx_mcs_mask[10];
} mcs;
};
struct ieee80211_sta_vht_cap {
u32 cap;
bool vht_supported;
u8 vht_mcs_rx_highest;
u8 vht_mcs_tx_highest;
};
struct ieee80211_sta_he_cap {
bool he_supported;
u8 mac_cap_info[6];
u8 phy_cap_info[11];
u8 mcs_nss_rx[4];
u8 mcs_nss_tx[4];
};
struct ieee80211_sta_eht_cap {
bool eht_supported;
u8 mac_cap_info[2];
u8 phy_cap_info[9];
u8 mcs_nss_rx[4];
u8 mcs_nss_tx[4];
};
#endif #endif
@@ -18,88 +18,39 @@
#define IEEE80211_CONF_CHANGE_POWER (1U << 5) #define IEEE80211_CONF_CHANGE_POWER (1U << 5)
#define IEEE80211_CONF_CHANGE_CHANNEL (1U << 6) #define IEEE80211_CONF_CHANGE_CHANNEL (1U << 6)
#define IEEE80211_MLD_MAX_NUM_LINKS 15 struct ieee80211_conf {
enum ieee80211_band {
NL80211_BAND_2GHZ = 0,
NL80211_BAND_5GHZ = 1,
NL80211_BAND_6GHZ = 2,
NL80211_BAND_60GHZ = 3,
};
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT = 0,
NL80211_CHAN_WIDTH_20 = 1,
NL80211_CHAN_WIDTH_40 = 2,
NL80211_CHAN_WIDTH_80 = 3,
NL80211_CHAN_WIDTH_80P80 = 4,
NL80211_CHAN_WIDTH_160 = 5,
NL80211_CHAN_WIDTH_320 = 13,
};
#define IEEE80211_HT_CAP_LDPC_CODING (1U << 0)
#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 (1U << 1)
#define IEEE80211_HT_CAP_SGI_20 (1U << 2)
#define IEEE80211_HT_CAP_SGI_40 (1U << 3)
#define IEEE80211_VHT_CAP_MAX_MPDU_11454 (3U << 0)
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ (1U << 2)
enum ieee80211_sta_state {
IEEE80211_STA_NOTEXIST,
IEEE80211_STA_NONE,
IEEE80211_STA_AUTH,
IEEE80211_STA_ASSOC,
IEEE80211_STA_AUTHORIZED,
};
enum set_key_cmd { SET_KEY, DISABLE_KEY };
enum ieee80211_ampdu_mlme_action {
IEEE80211_AMPDU_RX_START = 0,
IEEE80211_AMPDU_RX_STOP = 1,
IEEE80211_AMPDU_TX_START = 2,
IEEE80211_AMPDU_TX_STOP_CONT = 3,
IEEE80211_AMPDU_TX_STOP_FLUSH = 4,
IEEE80211_AMPDU_TX_START_NEW = 5,
IEEE80211_AMPDU_TX_OPERATIONAL = 6,
};
#define IEEE80211_KEY_FLAG_GENERATE_IV (1U << 0)
#define IEEE80211_KEY_FLAG_GENERATE_MMIC (1U << 1)
#define IEEE80211_KEY_FLAG_PAIRWISE (1U << 2)
#define BSS_CHANGED_ASSOC (1U << 0)
#define BSS_CHANGED_BSSID (1U << 1)
#define BSS_CHANGED_ERP_CTS_PROT (1U << 2)
#define BSS_CHANGED_HT (1U << 3)
#define BSS_CHANGED_BASIC_RATES (1U << 4)
#define BSS_CHANGED_BEACON_INT (1U << 5)
#define BSS_CHANGED_BANDWIDTH (1U << 6)
#define BSS_CHANGED_QOS (1U << 8)
#define BSS_CHANGED_TXPOWER (1U << 12)
#define BSS_CHANGED_HE_BSS_COLOR (1U << 17)
#define BSS_CHANGED_EHT_PUNCTURING (1U << 23)
struct ieee80211_chanctx_conf {
enum nl80211_chan_width radar_detect_width;
bool driver_present;
u8 rx_chains_dynamic, rx_chains_static;
struct ieee80211_channel *chan;
};
struct ieee80211_txq {
struct ieee80211_sta *sta;
void *drv_priv;
u8 ac;
u8 tid;
};
struct ieee80211_key_conf {
u32 cipher;
u32 flags; u32 flags;
u8 keyidx; int power_level;
u8 keylen; int dynamic_ps_timeout;
u8 key[32]; struct {
u32 center_freq;
u16 band;
struct ieee80211_channel *channel;
} chandef;
u32 listen_interval;
};
struct ieee80211_hw {
struct wiphy *wiphy;
const struct ieee80211_ops *ops;
void *priv;
int registered;
u32 extra_tx_headroom;
u16 queues;
struct ieee80211_conf conf;
};
struct ieee80211_vif {
u8 addr[6];
void *drv_priv;
u32 type;
bool cfg_assoc;
};
struct ieee80211_sta {
u8 addr[6];
void *drv_priv;
u16 aid;
}; };
struct ieee80211_bss_conf { struct ieee80211_bss_conf {
@@ -113,176 +64,70 @@ struct ieee80211_bss_conf {
u32 center_freq; u32 center_freq;
u16 band; u16 band;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
enum nl80211_chan_width width;
} chandef; } chandef;
bool he_support;
bool eht_support;
u8 he_bss_color;
u8 link_id;
struct ieee80211_chanctx_conf *chanctx;
};
struct ieee80211_link {
struct ieee80211_bss_conf conf;
u8 link_id;
bool active;
u8 addr[6];
};
struct ieee80211_link_sta {
u8 addr[6];
void *drv_priv;
bool he_capa_present;
bool eht_capa_present;
u32 ht_cap;
u32 vht_cap;
};
struct ieee80211_sta {
u8 addr[6];
u8 mld_addr[6];
void *drv_priv;
u16 aid;
bool wme;
bool mfp;
bool tdls;
bool is_mld;
u16 valid_links;
struct ieee80211_link_sta deflink;
struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS + 1];
};
struct ieee80211_vif {
u8 addr[6];
void *drv_priv;
u32 type;
bool cfg_assoc;
bool is_mld;
u16 valid_links;
struct ieee80211_link deflink;
struct ieee80211_link *link[IEEE80211_MLD_MAX_NUM_LINKS + 1];
struct ieee80211_bss_conf bss_conf;
}; };
struct ieee80211_rx_status { struct ieee80211_rx_status {
u64 mactime;
u16 freq; u16 freq;
u32 band; u32 band;
s8 signal; s8 signal;
s8 noise; s8 noise;
u8 rate_idx; u8 rate_idx;
u8 link_id;
u32 flag; u32 flag;
u8 antenna; u8 antenna;
u32 rx_flags; u32 rx_flags;
u32 encoding;
u8 nss;
u8 bw;
}; };
struct ieee80211_conf { enum ieee80211_sta_state {
u32 flags; IEEE80211_STA_NOTEXIST,
int power_level; IEEE80211_STA_NONE,
int dynamic_ps_timeout; IEEE80211_STA_AUTH,
struct { IEEE80211_STA_ASSOC,
u32 center_freq; IEEE80211_STA_AUTHORIZED,
u16 band;
struct ieee80211_channel *channel;
enum nl80211_chan_width width;
} chandef;
u32 listen_interval;
}; };
struct ieee80211_hw { enum set_key_cmd {
struct wiphy *wiphy; SET_KEY,
const struct ieee80211_ops *ops; DISABLE_KEY,
void *priv;
int registered;
u32 extra_tx_headroom;
u16 queues;
u8 max_rx_aggregation_subframes;
u8 max_tx_aggregation_subframes;
struct ieee80211_conf conf;
};
struct ieee80211_tx_rate {
u8 idx;
u8 count;
u8 flags;
};
struct ieee80211_tx_info {
u32 flags;
u32 band;
struct ieee80211_tx_rate rates[4];
u8 antenna;
u8 ack_signal;
bool is_data;
}; };
struct ieee80211_ops { struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct ieee80211_txq *txq); void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
void (*wake_tx_queue)(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
int (*start)(struct ieee80211_hw *hw); int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw);
int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*change_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 new_type, bool p2p);
void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*config)(struct ieee80211_hw *hw, u32 changed); int (*config)(struct ieee80211_hw *hw, u32 changed);
void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*bss_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u64 changed); struct ieee80211_bss_conf *info, u32 changed);
void (*vif_cfg_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed);
void (*link_info_changed)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf, u64 changed);
int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state); enum ieee80211_sta_state new_state);
void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key); struct key_params *key);
int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int (*ampdu_action)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 action, u16 tid, u16 ssn);
struct ieee80211_txq *txq);
bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw, struct sk_buff *head, struct sk_buff *skb);
void (*sw_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr); void (*sw_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr);
void (*sw_scan_complete)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*sw_scan_complete)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req); u64 (*prepare_multicast)(struct ieee80211_hw *hw, void *mc_list);
void (*cancel_hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*configure_filter)(struct ieee80211_hw *hw, u32 changed_flags,
u32 *total_flags, u64 multicast);
int (*sched_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *req); int (*sched_scan_start)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *req);
void (*sched_scan_stop)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void (*sched_scan_stop)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop);
void (*flush_sta)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta);
void (*configure_filter)(struct ieee80211_hw *hw, u32 changed_flags, u32 *total_flags, u64 multicast);
u64 (*prepare_multicast)(struct ieee80211_hw *hw, void *mc_list);
int (*conf_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 link_id, u8 ac, void *params);
int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
void (*sta_statistics)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sinfo);
void (*link_sta_rc_update)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta);
void (*mgd_prepare_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *info);
void (*mgd_complete_tx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *info);
void (*sync_rx_queues)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void (*reconfig_complete)(struct ieee80211_hw *hw, u32 flags);
void (*restart_complete)(struct ieee80211_hw *hw);
int (*add_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx);
void (*remove_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx);
void (*change_chanctx)(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed);
int (*assign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx);
void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_chanctx_conf *ctx);
void (*switch_vif_chanctx)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf **old, struct ieee80211_chanctx_conf **nw, u32 n);
int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf);
void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf);
bool (*tx_last_beacon)(struct ieee80211_hw *hw);
}; };
#define IEEE80211_RECONFIG_TYPE_TIMER 0 #define BSS_CHANGED_ASSOC (1U << 0)
#define IEEE80211_RECONFIG_TYPE_ARP_FILTER 1 #define BSS_CHANGED_BSSID (1U << 1)
#define BSS_CHANGED_ERP_CTS_PROT (1U << 2)
#define BSS_CHANGED_HT (1U << 3)
#define BSS_CHANGED_BASIC_RATES (1U << 4)
#define BSS_CHANGED_BEACON_INT (1U << 5)
#define BSS_CHANGED_BANDWIDTH (1U << 6)
extern struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, const void *ops, const char *requested_name); extern struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
const void *ops,
const char *requested_name);
extern void ieee80211_free_hw(struct ieee80211_hw *hw); extern void ieee80211_free_hw(struct ieee80211_hw *hw);
extern int ieee80211_register_hw(struct ieee80211_hw *hw); extern int ieee80211_register_hw(struct ieee80211_hw *hw);
extern void ieee80211_unregister_hw(struct ieee80211_hw *hw); extern void ieee80211_unregister_hw(struct ieee80211_hw *hw);
@@ -291,16 +136,11 @@ extern void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
extern void ieee80211_connection_loss(struct ieee80211_vif *vif); extern void ieee80211_connection_loss(struct ieee80211_vif *vif);
extern int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid, u16 timeout); extern int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid, u16 timeout);
extern int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid); extern int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
extern int ieee80211_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u32 old_state, u32 new_state); extern int ieee80211_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 old_state, u32 new_state);
extern struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, const u8 *addr); extern struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, const u8 *addr);
extern void ieee80211_beacon_loss(struct ieee80211_vif *vif); extern void ieee80211_beacon_loss(struct ieee80211_vif *vif);
extern void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); extern void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb);
extern size_t ieee80211_rx_drain(struct ieee80211_hw *hw); extern size_t ieee80211_rx_drain(struct ieee80211_hw *hw);
extern void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
extern void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
extern void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
extern struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb);
#define ieee80211_alloc_hw(priv, ops) ieee80211_alloc_hw_nm(priv, ops, KBUILD_MODNAME)
#endif #endif
@@ -6,7 +6,6 @@ fn main() {
cc::Build::new() cc::Build::new()
.file("src/linux_port.c") .file("src/linux_port.c")
.file("src/linux_mvm.c") .file("src/linux_mvm.c")
.file("src/linux_mld.c")
.include(linux_kpi_headers) .include(linux_kpi_headers)
.warnings(true) .warnings(true)
.compile("redbear_iwlwifi_linux_port"); .compile("redbear_iwlwifi_linux_port");
@@ -9,7 +9,6 @@
#include "../../../linux-kpi/source/src/c_headers/linux/jiffies.h" #include "../../../linux-kpi/source/src/c_headers/linux/jiffies.h"
#include "../../../linux-kpi/source/src/c_headers/linux/kernel.h" #include "../../../linux-kpi/source/src/c_headers/linux/kernel.h"
#include "linux_mvm.h" #include "linux_mvm.h"
#include "linux_mld.h"
#include "../../../linux-kpi/source/src/c_headers/linux/list.h" #include "../../../linux-kpi/source/src/c_headers/linux/list.h"
#include "../../../linux-kpi/source/src/c_headers/linux/mutex.h" #include "../../../linux-kpi/source/src/c_headers/linux/mutex.h"
#include "../../../linux-kpi/source/src/c_headers/linux/netdevice.h" #include "../../../linux-kpi/source/src/c_headers/linux/netdevice.h"
@@ -268,8 +267,6 @@ struct iwl_trans_pcie {
/* Device family info */ /* Device family info */
int device_family; int device_family;
int opmode;
struct rb_iwl_mld mld_state;
const char *fw_name; const char *fw_name;
const char *pnvm_name; const char *pnvm_name;
@@ -1056,9 +1053,6 @@ static int rb_iwlwifi_probe_transport(struct iwl_trans_pcie *trans, unsigned int
} }
trans->device_family = rb_iwlwifi_family_from_device(trans->pci_dev, bz_family); trans->device_family = rb_iwlwifi_family_from_device(trans->pci_dev, bz_family);
trans->opmode = rb_iwl_opmode_for_family(trans->device_family == RB_IWL_DEVICE_FAMILY_BZ);
if (trans->opmode == RB_IWL_OPMODE_MLD)
rb_iwl_mld_init(&trans->mld_state);
access_req = trans->device_family == RB_IWL_DEVICE_FAMILY_BZ ? access_req = trans->device_family == RB_IWL_DEVICE_FAMILY_BZ ?
IWL_CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ : IWL_CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ :
IWL_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ; IWL_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ;
@@ -1533,12 +1527,6 @@ static void iwl_pcie_rx_handle(struct iwl_trans_pcie *trans)
rb_iwl_mvm_extract_signal(buf->addr, buf->size, desc_fmt, &mvm_info); rb_iwl_mvm_extract_signal(buf->addr, buf->size, desc_fmt, &mvm_info);
if (mvm_info.signal != 0) { if (mvm_info.signal != 0) {
rx_status.signal = mvm_info.signal; rx_status.signal = mvm_info.signal;
if (trans->opmode == RB_IWL_OPMODE_MLD) {
struct rb_iwl_mld_rx_mpdu_info mpdu;
if (rb_iwl_mld_parse_rx_mpdu(buf->addr, buf->size, &mpdu) == 0)
trans->mld_state.rx_frames++;
}
rx_status.rate_idx = rb_iwl_mvm_rs_select(&trans->rs_state, mvm_info.signal); rx_status.rate_idx = rb_iwl_mvm_rs_select(&trans->rs_state, mvm_info.signal);
} else { } else {
rx_status.signal = -42; rx_status.signal = -42;
@@ -2182,9 +2170,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
pci_set_master(pdev); pci_set_master(pdev);
trans->device_family = rb_iwlwifi_family_from_device(pdev, 0); trans->device_family = rb_iwlwifi_family_from_device(pdev, 0);
trans->opmode = rb_iwl_opmode_for_family(trans->device_family == RB_IWL_DEVICE_FAMILY_BZ);
if (trans->opmode == RB_IWL_OPMODE_MLD)
rb_iwl_mld_init(&trans->mld_state);
pdev->driver_data = trans; pdev->driver_data = trans;
return 0; return 0;
} }
@@ -2230,10 +2215,8 @@ static void rb_iwlwifi_status_line(struct iwl_trans_pcie *trans, char *out, unsi
{ {
rb_iwlwifi_format_out( rb_iwlwifi_format_out(
out, out_len, out, out_len,
"linux_kpi_status=ok family=%s opmode=%s mld_rx=%u prepared=%d probed=%d init=%d active=%d fw_running=%d mac80211=%d irq=%d vectors=%d msix=%d tx_queues=%d rx_in_use=%u scan_results=%u connected=%d ssid=%s", "linux_kpi_status=ok family=%s prepared=%d probed=%d init=%d active=%d fw_running=%d mac80211=%d irq=%d vectors=%d msix=%d tx_queues=%d rx_in_use=%u scan_results=%u connected=%d ssid=%s",
rb_iwlwifi_family_name(trans->device_family), rb_iwlwifi_family_name(trans->device_family),
rb_iwl_opmode_name(trans->opmode),
trans->opmode == RB_IWL_OPMODE_MLD ? rb_iwl_mld_rx_frames(&trans->mld_state) : 0,
trans->prepared, trans->prepared,
trans->transport_probed, trans->transport_probed,
trans->transport_inited, trans->transport_inited,
@@ -0,0 +1,164 @@
//! MLD station management — Rust port of Linux mld/sta.c + sta.h
//!
//! Ported from Linux 7.1 drivers/net/wireless/intel/iwlwifi/mld/sta.c
//! Reference: all firmware command structures from fw/api/mac-cfg.h,
//! fw/api/sta.h, fw/api/datapath.h.
use super::*;
use std::sync::atomic::Ordering;
// ── Station types (Linux mld/sta.h) ───────────────────────────────
#[derive(Clone, Debug, Default)]
pub struct MldLinkSta {
pub fw_id: u32,
pub mac_addr: [u8; 6],
pub link_id: u16,
pub sta_state: u32,
pub ht_cap: u32,
pub vht_cap: u32,
pub he_supported: bool,
pub eht_supported: bool,
pub max_amsdu_len: u32,
pub mpdu_counters: [u64; 8],
}
#[derive(Clone, Debug, Default)]
pub struct MldSta {
pub sta_id: u32,
pub mld_addr: [u8; 6],
pub is_mld: bool,
pub valid_links: u16,
pub sta_state: u32,
pub deflink: MldLinkSta,
pub links: Vec<Option<MldLinkSta>>,
}
impl MldSta {
pub fn new(sta_id: u32, mld_addr: [u8; 6]) -> Self {
let mut links = vec![None; super::MAX_LINKS + 1];
links[0] = Some(MldLinkSta::default());
Self {
sta_id,
mld_addr,
is_mld: false,
valid_links: 1,
sta_state: 0,
deflink: MldLinkSta::default(),
links,
}
}
pub fn fw_sta_id(&self) -> u32 {
self.deflink.fw_id
}
pub fn for_each_active_link<F: FnMut(&MldLinkSta)>(&self, mut f: F) {
f(&self.deflink);
for link in self.links.iter().flatten() {
if link.link_id != 0 {
f(link);
}
}
}
}
// ── Station management functions (Linux mld/sta.c) ─────────────────
pub const STATION_TYPE_BSS: u32 = 0;
pub const STATION_TYPE_PEER: u32 = 1;
pub const STATION_TYPE_AUX: u32 = 2;
impl MldState {
pub fn add_sta_full(
&mut self,
sta: &MldSta,
link_addr: &[u8; 6],
aid: u16,
mfp: bool,
) -> Result<u32, MldError> {
let cmd = build_sta_config(sta.sta_id, &sta.mld_addr, link_addr, aid, mfp);
let bytes = unsafe {
core::slice::from_raw_parts(
&cmd as *const StaCfgCmd as *const u8,
core::mem::size_of::<StaCfgCmd>(),
)
};
self.send_hcmd(CMD_STA_CONFIG, bytes)?;
Ok(sta.sta_id)
}
pub fn remove_sta_full(&mut self, sta_id: u32) -> Result<(), MldError> {
let cmd = build_remove_sta(sta_id);
let bytes = unsafe {
core::slice::from_raw_parts(
&cmd as *const RemoveStaCmd as *const u8,
core::mem::size_of::<RemoveStaCmd>(),
)
};
self.send_hcmd(CMD_STA_REMOVE, bytes)?;
Ok(())
}
pub fn disable_tx_to_sta(&mut self, sta_id: u32, disable: bool) -> Result<(), MldError> {
let cmd = build_disable_tx(sta_id, disable);
let bytes = unsafe {
core::slice::from_raw_parts(
&cmd as *const StaDisableTxCmd as *const u8,
core::mem::size_of::<StaDisableTxCmd>(),
)
};
self.send_hcmd(CMD_STA_DISABLE_TX, bytes)?;
Ok(())
}
pub fn add_aux_sta(&mut self, sta_id: u32, mac_addr: &[u8; 6]) -> Result<(), MldError> {
let cmd = build_aux_sta(sta_id, mac_addr);
let bytes = unsafe {
core::slice::from_raw_parts(
&cmd as *const AuxStaCmd as *const u8,
core::mem::size_of::<AuxStaCmd>(),
)
};
self.send_hcmd(CMD_AUX_STA, bytes)?;
Ok(())
}
pub fn flush_sta_txqs(&mut self, _fw_sta_id: u32) -> Result<(), MldError> {
self.callback_flush(0xffff, false)
}
pub fn update_all_link_stations(&mut self) -> Result<(), MldError> {
Ok(())
}
}
// ── Tests ─────────────────────────────────────────────────────────
#[cfg(test)]
mod tests {
use super::super::*;
use super::*;
#[test]
fn mld_sta_creation() {
let sta = MldSta::new(3, [1, 2, 3, 4, 5, 6]);
assert_eq!(sta.sta_id, 3);
assert!(!sta.is_mld);
assert_eq!(sta.valid_links, 1);
assert!(sta.links[0].is_some());
}
#[test]
fn mld_sta_for_each_link() {
let mut sta = MldSta::new(1, [0; 6]);
sta.links[1] = Some(MldLinkSta {
fw_id: 2,
link_id: 1,
..Default::default()
});
let mut count = 0;
sta.for_each_active_link(|_| count += 1);
assert_eq!(count, 2);
}
}