Patrick is working on hostap mode for bwfm(4) and found that some
clients would get confused during the WPA key handshake.
(For the uninitiated: "RSN" is WPA2, and "IE" is an "information
element" which is type-length-value encoded data found in all kinds
of 802.11 frames).
During the WPA handshake, Mac OS X clients give up if there's a
discrepancy between the RSN IE from the beacon and the RSN IE
in the handshake:
kernel> process3of4: RSN IE does not match IE in beacon/probe response
kernel> Cached RSN IE Length = 22
kernel> Msg 3 RSN IE Length = 24
The RSN IE sent in beacons is constructed in bwfm firmware (length 22)
The RSN IE in WPA handshake message 3 comes from net80211 (length 24).
It turns out that net80211 adds an unnecessary field to the RSN IE.
Most fields in this IE are optional but all fields must occur in a
fixed order (see 802.11-2012 8.4.2.27.1).
If all data has been consumed while some fields are still missing,
those fields were left out by the sender and use default values.
So if the PMKID list count is zero *and no further fields follow* then
the PMKID count field can be omitted. This is what broadcom's firmware
does when it builds a beacon.
With this diff, our stack behaves the same way when building RSN IEs,
and Mac OS X will happily connect to bwfm(4) hostap.
This *should* not break interop with conforming WPA implementations.
And it works against our own stack.
ok?
Index: ieee80211_output.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_output.c,v
retrieving revision 1.118
diff -u -p -r1.118 ieee80211_output.c
--- ieee80211_output.c 2 Feb 2017 16:47:53 -0000 1.118
+++ ieee80211_output.c 10 Dec 2017 20:12:16 -0000
@@ -977,13 +977,15 @@ ieee80211_add_rsn_body(u_int8_t *frm, st
/* write PMKID List (only 1) */
memcpy(frm, ni->ni_pmkid, IEEE80211_PMKID_LEN);
frm += IEEE80211_PMKID_LEN;
- } else {
- /* no PMKID (PMKID Count=0) */
- LE_WRITE_2(frm, 0); frm += 2;
}
if (!(ic->ic_caps & IEEE80211_C_MFP))
return frm;
+
+ if ((ni->ni_flags & IEEE80211_NODE_PMKID) == 0) {
+ /* no PMKID (PMKID Count=0) */
+ LE_WRITE_2(frm, 0); frm += 2;
+ }
/* write Group Integrity Cipher Suite field */
memcpy(frm, oui, 3); frm += 3;