Skip to content

Commit a1008d2

Browse files
committed
key: add Nl80211KeyDefaultType and NL80211_KEY_DEFAULT_TYPES support
Problem: The `Nl80211KeyAttr` enum was missing `NL80211_KEY_DEFAULT_TYPES` (kind 8), preventing users from marking a group key as the default multicast key via `NL80211_CMD_SET_KEY`. Fix: Add `Nl80211KeyDefaultType` enum mirroring kernel `enum nl80211_key_default_types` (`Unicast`, `Multicast`). Add `DefaultTypes(Vec<Nl80211KeyDefaultType>)` variant to `Nl80211KeyAttr` with full encode/decode support. Export the new type from the crate root. Existing round-trip tests in `tests/key.rs` continue to pass. Signed-off-by: Gris Ge <cnfourt@gmail.com>
1 parent 771da5e commit a1008d2

3 files changed

Lines changed: 127 additions & 18 deletions

File tree

src/key.rs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// SPDX-License-Identifier: MIT
22

33
use netlink_packet_core::{
4-
emit_u32, parse_u32, parse_u8, DecodeError, DefaultNla, ErrorContext, Nla,
5-
NlaBuffer, Parseable,
4+
emit_u32, parse_u32, parse_u8, DecodeError, DefaultNla, Emitable,
5+
ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
66
};
77

88
const NL80211_KEYTYPE_GROUP: u32 = 0;
@@ -55,8 +55,68 @@ const NL80211_KEY_SEQ: u16 = 4;
5555
const NL80211_KEY_DEFAULT: u16 = 5;
5656
const NL80211_KEY_DEFAULT_MGMT: u16 = 6;
5757
const NL80211_KEY_TYPE: u16 = 7;
58+
const NL80211_KEY_DEFAULT_TYPES: u16 = 8;
5859
const NL80211_KEY_MODE: u16 = 9;
5960

61+
const NL80211_KEY_DEFAULT_TYPE_UNICAST: u8 = 1;
62+
const NL80211_KEY_DEFAULT_TYPE_MULTICAST: u8 = 2;
63+
64+
/// Key default type, used as a sub-attribute within
65+
/// `NL80211_KEY_DEFAULT_TYPES`.
66+
///
67+
/// Mirrors the kernel `enum nl80211_key_default_types`.
68+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
69+
pub enum Nl80211KeyDefaultType {
70+
/// Key should be used as default unicast key.
71+
Unicast,
72+
/// Key should be used as default multicast key.
73+
Multicast,
74+
/// Any other / kernel-version-specific value.
75+
Other(u8),
76+
}
77+
78+
impl From<u8> for Nl80211KeyDefaultType {
79+
fn from(d: u8) -> Self {
80+
match d {
81+
NL80211_KEY_DEFAULT_TYPE_UNICAST => Self::Unicast,
82+
NL80211_KEY_DEFAULT_TYPE_MULTICAST => Self::Multicast,
83+
_ => Self::Other(d),
84+
}
85+
}
86+
}
87+
88+
impl From<Nl80211KeyDefaultType> for u8 {
89+
fn from(v: Nl80211KeyDefaultType) -> u8 {
90+
match v {
91+
Nl80211KeyDefaultType::Unicast => NL80211_KEY_DEFAULT_TYPE_UNICAST,
92+
Nl80211KeyDefaultType::Multicast => {
93+
NL80211_KEY_DEFAULT_TYPE_MULTICAST
94+
}
95+
Nl80211KeyDefaultType::Other(d) => d,
96+
}
97+
}
98+
}
99+
100+
impl Nla for Nl80211KeyDefaultType {
101+
fn value_len(&self) -> usize {
102+
0
103+
}
104+
105+
fn kind(&self) -> u16 {
106+
u8::from(*self) as u16
107+
}
108+
109+
fn emit_value(&self, _buffer: &mut [u8]) {}
110+
}
111+
112+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
113+
for Nl80211KeyDefaultType
114+
{
115+
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
116+
Ok(Nl80211KeyDefaultType::from(buf.kind() as u8))
117+
}
118+
}
119+
60120
/// Key sub-attribute within the nested `NL80211_ATTR_KEY` attribute, used to
61121
/// install a key with `NL80211_CMD_NEW_KEY` / `NL80211_CMD_SET_KEY`.
62122
///
@@ -81,6 +141,9 @@ pub enum Nl80211KeyAttr {
81141
Type(Nl80211KeyType),
82142
/// Key mode (see kernel `enum nl80211_key_mode`).
83143
Mode(u8),
144+
/// Nested attribute specifying what traffic types this key is the
145+
/// default for (see `Nl80211KeyDefaultType`).
146+
DefaultTypes(Vec<Nl80211KeyDefaultType>),
84147
/// Any other / kernel-version-specific sub-attribute.
85148
Other(DefaultNla),
86149
}
@@ -92,6 +155,7 @@ impl Nla for Nl80211KeyAttr {
92155
Self::Idx(_) | Self::Mode(_) => 1,
93156
Self::Cipher(_) | Self::Type(_) => 4,
94157
Self::Default | Self::DefaultMgmt => 0,
158+
Self::DefaultTypes(types) => types.as_slice().buffer_len(),
95159
Self::Other(attr) => attr.value_len(),
96160
}
97161
}
@@ -105,6 +169,7 @@ impl Nla for Nl80211KeyAttr {
105169
Self::Default => NL80211_KEY_DEFAULT,
106170
Self::DefaultMgmt => NL80211_KEY_DEFAULT_MGMT,
107171
Self::Type(_) => NL80211_KEY_TYPE,
172+
Self::DefaultTypes(_) => NL80211_KEY_DEFAULT_TYPES,
108173
Self::Mode(_) => NL80211_KEY_MODE,
109174
Self::Other(attr) => attr.kind(),
110175
}
@@ -119,6 +184,7 @@ impl Nla for Nl80211KeyAttr {
119184
Self::Cipher(d) => emit_u32(buffer, *d).unwrap(),
120185
Self::Type(d) => emit_u32(buffer, u32::from(*d)).unwrap(),
121186
Self::Default | Self::DefaultMgmt => (),
187+
Self::DefaultTypes(types) => types.as_slice().emit(buffer),
122188
Self::Other(attr) => attr.emit_value(buffer),
123189
}
124190
}
@@ -150,6 +216,20 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
150216
}
151217
NL80211_KEY_DEFAULT => Self::Default,
152218
NL80211_KEY_DEFAULT_MGMT => Self::DefaultMgmt,
219+
NL80211_KEY_DEFAULT_TYPES => {
220+
let err_msg = format!(
221+
"Invalid NL80211_KEY_DEFAULT_TYPES value {payload:?}"
222+
);
223+
let mut types = Vec::new();
224+
for nla in NlasIterator::new(payload) {
225+
let nla = &nla.context(err_msg.clone())?;
226+
types.push(
227+
Nl80211KeyDefaultType::parse(nla)
228+
.context(err_msg.clone())?,
229+
);
230+
}
231+
Self::DefaultTypes(types)
232+
}
153233
_ => Self::Other(DefaultNla::parse(buf)?),
154234
})
155235
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ pub use self::iface::{
7171
Nl80211InterfaceSetRequest, Nl80211InterfaceType,
7272
Nl80211InterfaceVendorRequest, Nl80211NewInterface, Nl80211Vendor,
7373
};
74-
pub use self::key::{Nl80211KeyAttr, Nl80211KeyType};
74+
pub use self::key::{Nl80211KeyAttr, Nl80211KeyDefaultType, Nl80211KeyType};
7575
pub use self::message::Nl80211Message;
7676
pub use self::mlo::Nl80211MloLink;
7777
pub use self::scan::{

src/tests/key.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use netlink_packet_core::{Emitable, NlaBuffer, Parseable};
1212

13-
use crate::{Nl80211Attr, Nl80211KeyAttr};
13+
use crate::{Nl80211Attr, Nl80211KeyAttr, Nl80211KeyDefaultType};
1414

1515
fn assert_roundtrip(expected: Nl80211Attr, raw: Vec<u8>) {
1616
assert_eq!(
@@ -63,23 +63,24 @@ fn test_captured_control_port_ethertype() {
6363
}
6464

6565
// Nested NL80211_ATTR_KEY from CMD_NEW_KEY installing the pairwise (CCMP-128)
66-
// key: KEY_DATA, KEY_CIPHER (00-0f-ac:4), KEY_SEQ, KEY_IDX (0). This is the
67-
// nested form wpa_supplicant actually emits.
66+
// key: KEY_DATA, KEY_CIPHER (00-0f-ac:4), KEY_SEQ, KEY_IDX (0). Captured
67+
// via nlmon while wpa_supplicant connected to a WPA3-SAE AP (hostapd +
68+
// mac80211_hwsim).
6869
#[test]
6970
fn test_captured_new_key_pairwise() {
7071
let raw = vec![
7172
0x34, 0x00, 0x50, 0x00, // len=52, type=80 (NL80211_ATTR_KEY)
7273
0x14, 0x00, 0x01, 0x00, // KEY_DATA, len 20
73-
0x40, 0x49, 0x14, 0x03, 0x37, 0x01, 0x80, 0x87, 0x64, 0x63, 0x2b, 0x11,
74-
0x7d, 0x31, 0xc8, 0xac, 0x08, 0x00, 0x03, 0x00, // KEY_CIPHER
74+
0x8d, 0x44, 0x6e, 0x9e, 0xe5, 0x83, 0xa3, 0x0c, 0xfb, 0x25, 0xee, 0xa7,
75+
0xf4, 0x1b, 0x26, 0x3d, 0x08, 0x00, 0x03, 0x00, // KEY_CIPHER
7576
0x04, 0xac, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, // KEY_SEQ, len 10
76-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6 bytes + 2 pad
77+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6B + 2B pad
7778
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // KEY_IDX = 0
7879
];
7980
let expected = Nl80211Attr::Key(vec![
8081
Nl80211KeyAttr::Data(vec![
81-
0x40, 0x49, 0x14, 0x03, 0x37, 0x01, 0x80, 0x87, 0x64, 0x63, 0x2b,
82-
0x11, 0x7d, 0x31, 0xc8, 0xac,
82+
0x8d, 0x44, 0x6e, 0x9e, 0xe5, 0x83, 0xa3, 0x0c, 0xfb, 0x25, 0xee,
83+
0xa7, 0xf4, 0x1b, 0x26, 0x3d,
8384
]),
8485
Nl80211KeyAttr::Cipher(0x000F_AC04),
8586
Nl80211KeyAttr::Seq(vec![0u8; 6]),
@@ -88,27 +89,55 @@ fn test_captured_new_key_pairwise() {
8889
assert_roundtrip(expected, raw);
8990
}
9091

91-
// Nested NL80211_ATTR_KEY from CMD_NEW_KEY installing the group (CCMP-128) key
92-
// at index 1.
92+
// Nested NL80211_ATTR_KEY from CMD_NEW_KEY installing the group (CCMP-128)
93+
// key at index 1. Captured via nlmon while wpa_supplicant connected to a
94+
// WPA3-SAE AP (hostapd + mac80211_hwsim).
9395
#[test]
9496
fn test_captured_new_key_group() {
9597
let raw = vec![
9698
0x34, 0x00, 0x50, 0x00, // len=52, type=80 (NL80211_ATTR_KEY)
9799
0x14, 0x00, 0x01, 0x00, // KEY_DATA, len 20
98-
0xbe, 0x75, 0x01, 0x0d, 0x8e, 0xc8, 0x8a, 0xb9, 0x5e, 0x05, 0xcf, 0x3b,
99-
0x0e, 0x4a, 0x87, 0xb3, 0x08, 0x00, 0x03, 0x00, // KEY_CIPHER
100+
0x74, 0xf3, 0xcc, 0xf7, 0x16, 0x8a, 0xfe, 0x9a, 0xaa, 0x26, 0x08, 0xd4,
101+
0xe8, 0xc1, 0xca, 0x95, 0x08, 0x00, 0x03, 0x00, // KEY_CIPHER
100102
0x04, 0xac, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, // KEY_SEQ, len 10
101-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6 bytes + 2 pad
103+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6B + 2B pad
102104
0x05, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, // KEY_IDX = 1
103105
];
104106
let expected = Nl80211Attr::Key(vec![
105107
Nl80211KeyAttr::Data(vec![
106-
0xbe, 0x75, 0x01, 0x0d, 0x8e, 0xc8, 0x8a, 0xb9, 0x5e, 0x05, 0xcf,
107-
0x3b, 0x0e, 0x4a, 0x87, 0xb3,
108+
0x74, 0xf3, 0xcc, 0xf7, 0x16, 0x8a, 0xfe, 0x9a, 0xaa, 0x26, 0x08,
109+
0xd4, 0xe8, 0xc1, 0xca, 0x95,
108110
]),
109111
Nl80211KeyAttr::Cipher(0x000F_AC04),
110112
Nl80211KeyAttr::Seq(vec![0u8; 6]),
111113
Nl80211KeyAttr::Idx(1),
112114
]);
113115
assert_roundtrip(expected, raw);
114116
}
117+
118+
// Nested NL80211_ATTR_KEY from CMD_SET_KEY marking the group key at index 1
119+
// as the default multicast key: KEY_IDX (1), KEY_DEFAULT, KEY_DEFAULT_TYPES
120+
// nested with NL80211_KEY_DEFAULT_TYPE_MULTICAST.
121+
//
122+
// Captured via nlmon while shulid sent SET_KEY after NEW_KEY (matching
123+
// wpa_supplicant's documented pattern at src/drivers/driver_nl80211.c:3624
124+
// which is used for IBSS / other modes requiring DEFAULT flag). Wire bytes
125+
// verified with `tshark -r traffic.pcap -x`.
126+
#[test]
127+
fn test_captured_set_key_group_default_types() {
128+
let raw = vec![
129+
0x18, 0x00, 0x50, 0x00, // len=24, type=80 (NL80211_ATTR_KEY)
130+
0x05, 0x00, 0x02, 0x00, // KEY_IDX: len=5, type=2
131+
0x01, 0x00, 0x00, 0x00, // value=1 + pad
132+
0x04, 0x00, 0x05, 0x00, // KEY_DEFAULT: len=4, type=5 (flag)
133+
0x08, 0x00, 0x08,
134+
0x00, // KEY_DEFAULT_TYPES: len=8, type=8 (nested)
135+
0x04, 0x00, 0x02, 0x00, // MULTICAST flag: len=4, type=2
136+
];
137+
let expected = Nl80211Attr::Key(vec![
138+
Nl80211KeyAttr::Idx(1),
139+
Nl80211KeyAttr::Default,
140+
Nl80211KeyAttr::DefaultTypes(vec![Nl80211KeyDefaultType::Multicast]),
141+
]);
142+
assert_roundtrip(expected, raw);
143+
}

0 commit comments

Comments
 (0)