Last active
July 28, 2020 18:09
-
-
Save codedwrench/fa9304a399c7253eba821de0fceea3e5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c | |
index 0528d4cb4..563770a6e 100644 | |
--- a/drivers/net/wireless/mac80211_hwsim.c | |
+++ b/drivers/net/wireless/mac80211_hwsim.c | |
@@ -1779,6 +1779,9 @@ static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, | |
wiphy_dbg(hw->wiphy, "%s\n", __func__); | |
data->rx_filter = 0; | |
+ | |
+ if (*total_flags & FIF_PROMISC_IN_BSS) | |
+ data->rx_filter |= FIF_PROMISC_IN_BSS; | |
if (*total_flags & FIF_ALLMULTI) | |
data->rx_filter |= FIF_ALLMULTI; | |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h | |
index 97fec4d31..3a602e7c1 100644 | |
--- a/include/net/mac80211.h | |
+++ b/include/net/mac80211.h | |
@@ -3067,6 +3067,10 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); | |
* stack. It is always safe to pass more frames than requested, | |
* but this has negative impact on power consumption. | |
* | |
+ * @FIF_PROMISC_IN_BSS: promiscuous mode within your BSS, | |
+ * think of the BSS as your network segment and then this corresponds | |
+ * to the regular ethernet device promiscuous mode. | |
+ * | |
* @FIF_ALLMULTI: pass all multicast frames, this is used if requested | |
* by the user or if the hardware is not capable of filtering by | |
* multicast address. | |
@@ -3083,8 +3087,8 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); | |
* mac80211 needs to do and the amount of CPU wakeups, so you should | |
* honour this flag if possible. | |
* | |
- * @FIF_CONTROL: pass control frames (except for PS Poll) addressed to this | |
- * station | |
+ * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS | |
+ * is not set then only those addressed to this station. | |
* | |
* @FIF_OTHER_BSS: pass frames destined to other BSSes | |
* | |
@@ -3093,6 +3097,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb); | |
* @FIF_PROBE_REQ: pass probe request frames | |
*/ | |
enum ieee80211_filter_flags { | |
+ FIF_PROMISC_IN_BSS = 1<<0, | |
FIF_ALLMULTI = 1<<1, | |
FIF_FCSFAIL = 1<<2, | |
FIF_PLCPFAIL = 1<<3, | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h | |
index f8ed4f621..d751e21bf 100644 | |
--- a/net/mac80211/ieee80211_i.h | |
+++ b/net/mac80211/ieee80211_i.h | |
@@ -187,6 +187,9 @@ typedef unsigned __bitwise ieee80211_rx_result; | |
/** | |
* enum ieee80211_packet_rx_flags - packet RX flags | |
+ * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed | |
+ * (incl. multicast frames) | |
+ * @IEEE80211_RX_FRAGMENTED: fragmented frame | |
* @IEEE80211_RX_AMSDU: a-MSDU packet | |
* @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed | |
* @IEEE80211_RX_DEFERRED_RELEASE: frame was subjected to receive reordering | |
@@ -195,6 +198,8 @@ typedef unsigned __bitwise ieee80211_rx_result; | |
* @rx_flags field of &struct ieee80211_rx_status. | |
*/ | |
enum ieee80211_packet_rx_flags { | |
+ IEEE80211_RX_RA_MATCH = BIT(1), | |
+ IEEE80211_RX_FRAGMENTED = BIT(2), | |
IEEE80211_RX_AMSDU = BIT(3), | |
IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), | |
IEEE80211_RX_DEFERRED_RELEASE = BIT(5), | |
@@ -732,6 +737,7 @@ struct ieee80211_if_mesh { | |
* enum ieee80211_sub_if_data_flags - virtual interface flags | |
* | |
* @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets | |
+ * @IEEE80211_SDATA_PROMISC: interface is promisc | |
* @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode | |
* @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between | |
* associated stations and deliver multicast frames both | |
@@ -741,6 +747,7 @@ struct ieee80211_if_mesh { | |
*/ | |
enum ieee80211_sub_if_data_flags { | |
IEEE80211_SDATA_ALLMULTI = BIT(0), | |
+ IEEE80211_SDATA_PROMISC = BIT(1), | |
IEEE80211_SDATA_OPERATING_GMODE = BIT(2), | |
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), | |
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), | |
@@ -1258,8 +1265,8 @@ struct ieee80211_local { | |
atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES]; | |
- /* number of interfaces with allmulti RX */ | |
- atomic_t iff_allmultis; | |
+ /* number of interfaces with corresponding IFF_ flags */ | |
+ atomic_t iff_allmultis, iff_promiscs; | |
struct rate_control_ref *rate_ctrl; | |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c | |
index d06982570..a49d5fb71 100644 | |
--- a/net/mac80211/iface.c | |
+++ b/net/mac80211/iface.c | |
@@ -720,6 +720,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |
*/ | |
if (sdata->flags & IEEE80211_SDATA_ALLMULTI) | |
atomic_inc(&local->iff_allmultis); | |
+ | |
+ if (sdata->flags & IEEE80211_SDATA_PROMISC) | |
+ atomic_inc(&local->iff_promiscs); | |
if (coming_up) | |
local->open_count++; | |
@@ -855,10 +858,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |
((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || | |
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1))); | |
- /* don't count this interface for allmulti while it is down */ | |
+ /* don't count this interface for promisc/allmulti while it is down */ | |
if (sdata->flags & IEEE80211_SDATA_ALLMULTI) | |
atomic_dec(&local->iff_allmultis); | |
+ if (sdata->flags & IEEE80211_SDATA_PROMISC) | |
+ atomic_dec(&local->iff_promiscs); | |
+ | |
if (sdata->vif.type == NL80211_IFTYPE_AP) { | |
local->fif_pspoll--; | |
local->fif_probe_req--; | |
@@ -1082,10 +1088,12 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |
{ | |
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | |
struct ieee80211_local *local = sdata->local; | |
- int allmulti, sdata_allmulti; | |
+ int allmulti, promisc, sdata_allmulti, sdata_promisc; | |
allmulti = !!(dev->flags & IFF_ALLMULTI); | |
+ promisc = !!(dev->flags & IFF_PROMISC); | |
sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI); | |
+ sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC); | |
if (allmulti != sdata_allmulti) { | |
if (dev->flags & IFF_ALLMULTI) | |
@@ -1094,7 +1102,14 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |
atomic_dec(&local->iff_allmultis); | |
sdata->flags ^= IEEE80211_SDATA_ALLMULTI; | |
} | |
- | |
+ | |
+ if (promisc != sdata_promisc) { | |
+ if (dev->flags & IFF_PROMISC) | |
+ atomic_inc(&local->iff_promiscs); | |
+ else | |
+ atomic_dec(&local->iff_promiscs); | |
+ sdata->flags ^= IEEE80211_SDATA_PROMISC; | |
+ } | |
spin_lock_bh(&local->filter_lock); | |
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); | |
spin_unlock_bh(&local->filter_lock); | |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c | |
index 6423173bb..0798926aa 100644 | |
--- a/net/mac80211/main.c | |
+++ b/net/mac80211/main.c | |
@@ -39,6 +39,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |
unsigned int changed_flags; | |
unsigned int new_flags = 0; | |
+ if (atomic_read(&local->iff_promiscs)) | |
+ new_flags |= FIF_PROMISC_IN_BSS; | |
+ | |
if (atomic_read(&local->iff_allmultis)) | |
new_flags |= FIF_ALLMULTI; | |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c | |
index 91a13aee4..29f395000 100644 | |
--- a/net/mac80211/rx.c | |
+++ b/net/mac80211/rx.c | |
@@ -1363,6 +1363,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |
struct sk_buff *skb = rx->skb; | |
struct ieee80211_local *local = rx->local; | |
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | |
struct sta_info *sta = rx->sta; | |
struct tid_ampdu_rx *tid_agg_rx; | |
u16 sc; | |
@@ -1371,6 +1372,12 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |
if (!ieee80211_is_data_qos(hdr->frame_control) || | |
is_multicast_ether_addr(hdr->addr1)) | |
goto dont_reorder; | |
+ | |
+ /* not actually part of this BA session */ | |
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
+ goto dont_reorder; | |
+ | |
+ | |
/* | |
* filter the QoS data rx stream according to | |
@@ -1460,8 +1467,10 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) | |
if (unlikely(ieee80211_has_retry(hdr->frame_control) && | |
rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) { | |
+ if (status->rx_flags & IEEE80211_RX_RA_MATCH) { | |
I802_DEBUG_INC(rx->local->dot11FrameDuplicateCount); | |
rx->sta->rx_stats.num_duplicates++; | |
+ } | |
return RX_DROP_UNUSABLE; | |
} else if (!(status->flag & RX_FLAG_AMSDU_MORE)) { | |
rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl; | |
@@ -1693,7 +1702,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) | |
struct ieee80211_hdr *hdr = (void *)rx->skb->data; | |
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | |
- if (!rx->sta) | |
+ if (!rx->sta || !(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
return RX_CONTINUE; | |
if (sdata->vif.type != NL80211_IFTYPE_AP && | |
@@ -1779,6 +1788,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |
if (ieee80211_is_data(hdr->frame_control)) | |
sta->rx_stats.last_rate = sta_stats_encode_rate(status); | |
} | |
+ | |
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
+ return RX_CONTINUE; | |
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) | |
ieee80211_sta_rx_notify(rx->sdata, hdr); | |
@@ -1945,6 +1957,13 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |
* every station but there's no such requirement; VLANs could be | |
* possible. | |
*/ | |
+ | |
+ /* | |
+ * No point in finding a key and decrypting if the frame is neither | |
+ * addressed to us nor a multicast frame. | |
+ */ | |
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
+ return RX_CONTINUE; | |
/* start without a key */ | |
rx->key = NULL; | |
@@ -2527,6 +2546,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |
struct sk_buff *skb, *xmit_skb; | |
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; | |
struct sta_info *dsta; | |
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | |
skb = rx->skb; | |
xmit_skb = NULL; | |
@@ -2547,6 +2567,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |
if ((sdata->vif.type == NL80211_IFTYPE_AP || | |
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && | |
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && | |
+ (status->rx_flags & IEEE80211_RX_RA_MATCH) && | |
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { | |
if (is_multicast_ether_addr(ehdr->h_dest) && | |
ieee80211_vif_get_num_mcast_if(sdata) != 0) { | |
@@ -2726,6 +2747,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |
struct sk_buff *skb = rx->skb, *fwd_skb; | |
struct ieee80211_local *local = rx->local; | |
struct ieee80211_sub_if_data *sdata = rx->sdata; | |
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | |
u16 ac, q, hdrlen; | |
int tailroom = 0; | |
@@ -2757,7 +2779,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |
mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr)) | |
return RX_DROP_MONITOR; | |
- if (!ieee80211_is_data(hdr->frame_control)) | |
+ if (!ieee80211_is_data(hdr->frame_control) || | |
+ !(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
return RX_CONTINUE; | |
if (!mesh_hdr->ttl) | |
@@ -2855,9 +2878,11 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames); | |
ieee80211_add_pending_skb(local, fwd_skb); | |
out: | |
- if (is_multicast_ether_addr(hdr->addr1)) | |
+ if (is_multicast_ether_addr(hdr->addr1) || | |
+ sdata->dev->flags & IFF_PROMISC) | |
return RX_CONTINUE; | |
- return RX_DROP_MONITOR; | |
+ else | |
+ return RX_DROP_MONITOR; | |
} | |
#endif | |
@@ -3087,6 +3112,9 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | |
status->freq, sig); | |
rx->flags |= IEEE80211_RX_BEACON_REPORTED; | |
} | |
+ | |
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
+ return RX_DROP_MONITOR; | |
if (ieee80211_drop_unencrypted_mgmt(rx)) | |
return RX_DROP_UNUSABLE; | |
@@ -3114,6 +3142,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |
mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED && | |
mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) | |
return RX_DROP_UNUSABLE; | |
+ | |
+ if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | |
+ return RX_DROP_UNUSABLE; | |
switch (mgmt->u.action.category) { | |
case WLAN_CATEGORY_HT: | |
@@ -3895,6 +3926,15 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
case NL80211_IFTYPE_STATION: | |
if (!bssid && !sdata->u.mgd.use_4addr) | |
return false; | |
+ | |
+ if (!multicast && | |
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | |
+ if (!(sdata->dev->flags & IFF_PROMISC) || | |
+ sdata->u.mgd.use_4addr) | |
+ return false; | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
+ } | |
+ | |
if (ieee80211_is_robust_mgmt_frame(skb) && !rx->sta) | |
return false; | |
if (multicast) | |
@@ -3911,8 +3951,11 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) | |
return false; | |
if (!multicast && | |
- !ether_addr_equal(sdata->vif.addr, hdr->addr1)) | |
- return false; | |
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | |
+ if (!(sdata->dev->flags & IFF_PROMISC)) | |
+ return false; | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
+ } | |
if (!rx->sta) { | |
int rate_idx; | |
if (status->encoding != RX_ENC_LEGACY) | |
@@ -3931,8 +3974,15 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
if (!is_broadcast_ether_addr(bssid)) | |
return false; | |
if (!multicast && | |
- !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) | |
- return false; | |
+ !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) | |
+ { | |
+ /* if we are in promisc mode we also accept | |
+ * packets not destined for us | |
+ */ | |
+ if (!(sdata->dev->flags & IFF_PROMISC)) | |
+ return false; | |
+ rx->flags &= ~IEEE80211_RX_RA_MATCH; | |
+ } | |
if (!rx->sta) { | |
int rate_idx; | |
if (status->encoding != RX_ENC_LEGACY) | |
@@ -3946,6 +3996,13 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
case NL80211_IFTYPE_MESH_POINT: | |
if (ether_addr_equal(sdata->vif.addr, hdr->addr2)) | |
return false; | |
+ if (!multicast && | |
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | |
+ if (!(sdata->dev->flags & IFF_PROMISC)) | |
+ return false; | |
+ | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
+ } | |
if (multicast) | |
return true; | |
return ether_addr_equal(sdata->vif.addr, hdr->addr1); | |
@@ -3962,10 +4019,17 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
* itself never looks at these frames. | |
*/ | |
if (!multicast && | |
- !ether_addr_equal(sdata->vif.addr, hdr->addr1)) | |
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | |
+ if (!(sdata->dev->flags & IFF_PROMISC) || | |
+ sdata->u.mgd.use_4addr) | |
return false; | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
+ } | |
if (ieee80211_is_public_action(hdr, skb->len)) | |
return true; | |
+ if (!ieee80211_is_beacon(hdr->frame_control)) | |
+ return false; | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
return ieee80211_is_beacon(hdr->frame_control); | |
} | |
@@ -4006,10 +4070,15 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) | |
return false; | |
return ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2); | |
case NL80211_IFTYPE_P2P_DEVICE: | |
- return ieee80211_is_public_action(hdr, skb->len) || | |
- ieee80211_is_probe_req(hdr->frame_control) || | |
- ieee80211_is_probe_resp(hdr->frame_control) || | |
- ieee80211_is_beacon(hdr->frame_control); | |
+ if (!ieee80211_is_public_action(hdr, skb->len) && | |
+ !ieee80211_is_probe_req(hdr->frame_control) && | |
+ !ieee80211_is_probe_resp(hdr->frame_control) && | |
+ !ieee80211_is_beacon(hdr->frame_control)) | |
+ return false; | |
+ if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) && | |
+ !multicast) | |
+ status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | |
+ return true;; | |
case NL80211_IFTYPE_NAN: | |
/* Currently no frames on NAN interface are allowed */ | |
return false; | |
@@ -4408,8 +4477,10 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, | |
{ | |
struct ieee80211_local *local = rx->local; | |
struct ieee80211_sub_if_data *sdata = rx->sdata; | |
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | |
rx->skb = skb; | |
+ status->rx_flags |= IEEE80211_RX_RA_MATCH; | |
/* See if we can do fast-rx; if we have to copy we already lost, | |
* so punt in that case. We should never have to deliver a data |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment