diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 117 |
1 files changed, 62 insertions, 55 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 09beb65d6108..4d4ff4d4917a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -231,8 +231,19 @@ static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata, skb_queue_tail(&sdata->skb_queue, skb); wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); - if (sta) - sta->deflink.rx_stats.packets++; + if (sta) { + struct link_sta_info *link_sta_info; + + if (link_id >= 0) { + link_sta_info = rcu_dereference(sta->link[link_id]); + if (!link_sta_info) + return; + } else { + link_sta_info = &sta->deflink; + } + + link_sta_info->rx_stats.packets++; + } } static void ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata, @@ -1521,9 +1532,8 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) } if (rx->sdata->vif.type == NL80211_IFTYPE_AP && - cfg80211_rx_spurious_frame(rx->sdata->dev, - hdr->addr2, - GFP_ATOMIC)) + cfg80211_rx_spurious_frame(rx->sdata->dev, hdr->addr2, + rx->link_id, GFP_ATOMIC)) return RX_DROP_U_SPURIOUS; return RX_DROP; @@ -1861,7 +1871,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT)) cfg80211_rx_unexpected_4addr_frame( rx->sdata->dev, sta->sta.addr, - GFP_ATOMIC); + rx->link_id, GFP_ATOMIC); return RX_DROP_U_UNEXPECTED_4ADDR_FRAME; } /* @@ -3022,7 +3032,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; struct sk_buff_head frame_list; - ieee80211_rx_result res; struct ethhdr ethhdr; const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source; @@ -3084,24 +3093,18 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset) while (!skb_queue_empty(&frame_list)) { rx->skb = __skb_dequeue(&frame_list); - res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb); - switch (res) { + switch (ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb)) { case RX_QUEUED: - continue; - case RX_CONTINUE: break; + case RX_CONTINUE: + if (ieee80211_frame_allowed(rx, fc)) { + ieee80211_deliver_skb(rx); + break; + } + fallthrough; default: - goto free; + dev_kfree_skb(rx->skb); } - - if (!ieee80211_frame_allowed(rx, fc)) - goto free; - - ieee80211_deliver_skb(rx); - continue; - -free: - dev_kfree_skb(rx->skb); } return RX_QUEUED; @@ -3187,7 +3190,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) if (rx->sta && !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT)) cfg80211_rx_unexpected_4addr_frame( - rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC); + rx->sdata->dev, rx->sta->sta.addr, rx->link_id, + GFP_ATOMIC); return RX_DROP; } @@ -3576,41 +3580,18 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) goto handled; } case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { - struct ieee80211_supported_band *sband; u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; - enum ieee80211_sta_rx_bandwidth max_bw, new_bw; - struct sta_opmode_info sta_opmode = {}; + + if (chanwidth != IEEE80211_HT_CHANWIDTH_20MHZ && + chanwidth != IEEE80211_HT_CHANWIDTH_ANY) + goto invalid; /* If it doesn't support 40 MHz it can't change ... */ if (!(rx->link_sta->pub->ht_cap.cap & - IEEE80211_HT_CAP_SUP_WIDTH_20_40)) - goto handled; - - if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) - max_bw = IEEE80211_STA_RX_BW_20; - else - max_bw = ieee80211_sta_cap_rx_bw(rx->link_sta); - - /* set cur_max_bandwidth and recalc sta bw */ - rx->link_sta->cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->link_sta); - - if (rx->link_sta->pub->bandwidth == new_bw) + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) goto handled; - rx->link_sta->pub->bandwidth = new_bw; - sband = rx->local->hw.wiphy->bands[status->band]; - sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->link_sta); - sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; - - rate_control_rate_update(local, sband, rx->link_sta, - IEEE80211_RC_BW_CHANGED); - cfg80211_sta_opmode_change_notify(sdata->dev, - rx->sta->addr, - &sta_opmode, - GFP_ATOMIC); - goto handled; + goto queue; } default: goto invalid; @@ -4234,10 +4215,16 @@ static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx, rx->link_sta = NULL; } - if (link_id < 0) - rx->link = &rx->sdata->deflink; - else if (!ieee80211_rx_data_set_link(rx, link_id)) + if (link_id < 0) { + if (ieee80211_vif_is_mld(&rx->sdata->vif) && + sta && !sta->sta.valid_links) + rx->link = + rcu_dereference(rx->sdata->link[sta->deflink.link_id]); + else + rx->link = &rx->sdata->deflink; + } else if (!ieee80211_rx_data_set_link(rx, link_id)) { return false; + } return true; } @@ -4432,6 +4419,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) if (!multicast && !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) return false; + /* reject invalid/our STA address */ + if (!is_valid_ether_addr(hdr->addr2) || + ether_addr_equal(sdata->dev->dev_addr, hdr->addr2)) + return false; if (!rx->sta) { int rate_idx; if (status->encoding != RX_ENC_LEGACY) @@ -5115,8 +5106,24 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); sta = sta_info_get_bss(rx->sdata, hdr->addr2); - if (status->link_valid) + if (status->link_valid) { link_id = status->link_id; + } else if (ieee80211_vif_is_mld(&rx->sdata->vif) && + status->freq) { + struct ieee80211_link_data *link; + struct ieee80211_chanctx_conf *conf; + + for_each_link_data_rcu(rx->sdata, link) { + conf = rcu_dereference(link->conf->chanctx_conf); + if (!conf || !conf->def.chan) + continue; + + if (status->freq == conf->def.chan->center_freq) { + link_id = link->link_id; + break; + } + } + } } if (!ieee80211_rx_data_set_sta(rx, sta, link_id)) |