@@ -3025,6 +3025,25 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
return _ieee80211_is_robust_mgmt_frame((void *)skb->data);
}
+static inline bool ieee80211_is_not_group_privacy(struct ieee80211_hdr *hdr)
+{
+ if (ieee80211_is_action(hdr->frame_control)) {
+ u8 *category;
+
+ /*
+ * Action frames, excluding Public Action frames, are Robust
+ * Management Frames. However, if we are looking at a Protected
+ * frame, skip the check since the data may be encrypted and
+ * the frame has already been found to be a Robust Management
+ * Frame (by the other end).
+ */
+ category = ((u8 *)hdr) + 24;
+ return *category != WLAN_CATEGORY_MESH_ACTION &&
+ *category != WLAN_CATEGORY_MULTIHOP_ACTION;
+ }
+
+ return true;
+}
/**
* ieee80211_is_public_action - check if frame is a public action frame
* @hdr: the frame
@@ -468,12 +468,19 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
struct sk_buff *skb)
{
- if (!ieee80211_is_mgmt(fc))
- return 0;
- if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (!ieee80211_is_mgmt(fc))
return 0;
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ if (!ieee80211_is_not_group_privacy(hdr))
+ return 1;
+ } else {
+ if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
+ return 0;
+ }
if (!ieee80211_is_robust_mgmt_frame(skb))
return 0;