.6.7.33 Fine Timing Measurement frame format */ struct { - uint8_t dialog_token; - uint8_t follow_up; - uint8_t tod[6]; - uint8_t toa[6]; + uint8_t public_action; + uint8_t dialog_token; + uint8_t follow_up; + uint8_t tod[6]; + uint8_t toa[6]; uint16_t tod_error; uint16_t toa_error; uint8_t variable[0]; } __packed ftm; - /* 802.11-2016, 9.6.5.2 ADDBA Request frame format */ + /* 802.11-2024, 9.6.4.2 ADDBA Request frame format */ struct { uint8_t action_code; uint8_t dialog_token; @@ -588,9 +601,12 @@ struct ieee80211_mgmt { /* Optional follows... */ uint8_t variable[0]; } __packed addba_req; - /* XXX */ + /* 802.11-2024, 9.6.13.3 Event Report frame format */ struct { + uint8_t wnm_action; uint8_t dialog_token; + /* Optional follows... */ + uint8_t variable[0]; } __packed wnm_timing_msr; } u; } __packed action; @@ -1087,24 +1103,42 @@ ieee80211_is_bufferable_mmpdu(struct sk_buff *skb) struct ieee80211_mgmt *mgmt; __le16 fc; + KASSERT(skb->len >= sizeof(fc), ("%s: skb %p short len %d\n", + __func__, skb, skb->len)); + mgmt = (struct ieee80211_mgmt *)skb->data; fc = mgmt->frame_control; - /* 11.2.2 Bufferable MMPDUs, 80211-2020. */ - /* XXX we do not care about IBSS yet. */ + /* 11.2.2 Bufferable MMPDUs, 802.11-2024. */ + IMPROVE("XXX IBBS"); if (!ieee80211_is_mgmt(fc)) return (false); - if (ieee80211_is_action(fc)) /* XXX FTM? */ - return (true); /* XXX false? */ if (ieee80211_is_disassoc(fc)) return (true); if (ieee80211_is_deauth(fc)) return (true); + if (!ieee80211_is_action(fc)) + return (false); - TODO(); + /* + * Now we know it is an action frame, so we can check for a proper + * length before accessing any further data to check if it is an + * FTM/FTMR, which is non-bufferable. + * 9.6.7.32 FTM Request frame format + * 9.6.7.33 FTM frame format + */ + if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.public_action)) + return (false); - return (false); + if (mgmt->u.action.category != IEEE80211_ACTION_CAT_PUBLIC) + return (false); + + if (mgmt->u.action.u.ftm.public_action == 33 || /* FTM xxx defines? */ + mgmt->u.action.u.ftmr.public_action == 32) /* FTMR xxx defines? */ + return (false); + + return (true); } static __inline bool @@ -1207,53 +1241,125 @@ ieee80211_get_DA(struct ieee80211_hdr *hdr) return (hdr->addr1); } +static __inline bool +ieee80211_has_morefrags(__le16 fc) +{ + + fc &= htole16(IEEE80211_FC1_MORE_FRAG << 8); + return (fc != 0); +} + static __inline bool ieee80211_is_frag(struct ieee80211_hdr *hdr) { - TODO(); - return (false); + return (ieee80211_has_morefrags(hdr->frame_control) || + (hdr->seq_ctrl & htole16(IEEE80211_SEQ_FRAG_MASK)) != 0); } static __inline bool -ieee80211_is_first_frag(__le16 fc) +ieee80211_is_first_frag(__le16 seq_ctrl) { - TODO(); - return (false); + return ((seq_ctrl & htole16(IEEE80211_SEQ_FRAG_MASK)) == 0); } static __inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb) { - TODO(); - return (false); + struct ieee80211_mgmt *mgmt; + + if (skb->len < sizeof(mgmt->frame_control)) + return (false); + mgmt = (struct ieee80211_mgmt *)skb->data; + + /* 802.11-2024, 12.2.7 Requirements for management frame protection */ + + if (ieee80211_is_disassoc(mgmt->frame_control)) + return (true); + if (ieee80211_is_deauth(mgmt->frame_control)) + return (true); + + if (!ieee80211_is_action(mgmt->frame_control)) + return (false); + + /* + * If the action frame is a protected frame the peer has already + * decided that it is a robust mgmt frame. + * This is not exactly in the books but maintaining the below + * table will go out of sync eventually and this can save us. + */ + if (ieee80211_has_protected(mgmt->frame_control)) + return (true); + + /* + * 802.11-2024, 9.4.1.11 Action Fields, + * Table 9-81-Category values; check for the ones marked Robust: no. + */ + /* Check length again before accessing more data. */ + if (skb->len < offsetofend(typeof(*mgmt), u.action.category)) + return (false); + + switch (mgmt->u.action.category) { + case 4: /* Public */ + case 7: /* HT */ + case 11: /* Unprotected WNM */ + /* 12 */ /* TDLS */ + case 15: /* Self-protected */ + case 20: /* Unprotected DMG */ + case 21: /* VHT */ + case 22: /* Unprotected S1G */ + case 30: /* HE */ + case 127: /* Vendor-specific */ + return (false); + default: + return (true); + } } static __inline bool ieee80211_is_ftm(struct sk_buff *skb) { - TODO(); + struct ieee80211_mgmt *mgmt; + + /* First check length before accessing data. */ + if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.public_action)) + return (false); + + mgmt = (struct ieee80211_mgmt *)skb->data; + if (!ieee80211_is_action(mgmt->frame_control)) + return (false); + if (mgmt->u.action.category != IEEE80211_ACTION_CAT_PUBLIC) + return (false); + if (mgmt->u.action.u.ftm.public_action == 33) /* FTM xxx defines? */ + return (true); + return (false); } static __inline bool ieee80211_is_timing_measurement(struct sk_buff *skb) { - TODO(); - return (false); -} + struct ieee80211_mgmt *mgmt; + + /* First check length before accessing data. */ + if (skb->len < offsetofend(typeof(*mgmt), u.action.u.wnm_timing_msr.wnm_action)) + return (false); + + mgmt = (struct ieee80211_mgmt *)skb->data; + if (!ieee80211_is_action(mgmt->frame_control)) + return (false); + + if (mgmt->u.action.category != IEEE80211_ACTION_CAT_UNPROTECTED_WNM) + return (false); + if (mgmt->u.action.u.wnm_timing_msr.wnm_action == 1) /* Event Report xxx defines? */ + return (true); -static __inline bool -ieee80211_has_pm(__le16 fc) -{ - TODO(); return (false); } static __inline bool -ieee80211_has_morefrags(__le16 fc) +ieee80211_has_pm(__le16 fc) { - - fc &= htole16(IEEE80211_FC1_MORE_FRAG << 8); + fc &= htole16(IEEE80211_FC1_PWR_MGT << 8); return (fc != 0); } diff --git a/sys/compat/linuxkpi/common/include/net/cfg80211.h b/sys/compat/linuxkpi/common/include/net/cfg80211.h index 305026b34451..d7ed2bc97c98 100644 --- a/sys/compat/linuxkpi/common/include/net/cfg80211.h +++ b/sys/compat/linuxkpi/common/include/net/cfg80211.h @@ -55,10 +55,14 @@ extern int linuxkpi_debug_80211; #ifndef D80211_IMPROVE #define D80211_IMPROVE 0x2 #endif +#ifndef TODO #define TODO(fmt, ...) if (linuxkpi_debug_80211 & D80211_TODO) \ printf("%s:%d: XXX LKPI80211 TODO " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) +#endif +#ifndef IMPROVE #define IMPROVE(fmt, ...) if (linuxkpi_debug_80211 & D80211_IMPROVE) \ printf("%s:%d: XXX LKPI80211 IMPROVE " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) +#endif enum rfkill_hard_block_reasons { RFKILL_HARD_BLOCK_NOT_OWNER = BIT(0),