diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 251 |
1 files changed, 178 insertions, 73 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1675f8cb87f1..57df21e2170a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include <linux/jiffies.h> @@ -1009,43 +1009,20 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) return -1; } -static int ieee80211_get_keyid(struct sk_buff *skb, - const struct ieee80211_cipher_scheme *cs) +static int ieee80211_get_keyid(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; - int hdrlen; - int minlen; - u8 key_idx_off; - u8 key_idx_shift; + __le16 fc = hdr->frame_control; + int hdrlen = ieee80211_hdrlen(fc); u8 keyid; - fc = hdr->frame_control; - hdrlen = ieee80211_hdrlen(fc); - - if (cs) { - minlen = hdrlen + cs->hdr_len; - key_idx_off = hdrlen + cs->key_idx_off; - key_idx_shift = cs->key_idx_shift; - } else { - /* WEP, TKIP, CCMP and GCMP */ - minlen = hdrlen + IEEE80211_WEP_IV_LEN; - key_idx_off = hdrlen + 3; - key_idx_shift = 6; - } - - if (unlikely(skb->len < minlen)) + /* WEP, TKIP, CCMP and GCMP */ + if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN)) return -EINVAL; - skb_copy_bits(skb, key_idx_off, &keyid, 1); + skb_copy_bits(skb, hdrlen + 3, &keyid, 1); - if (cs) - keyid &= cs->key_idx_mask; - keyid >>= key_idx_shift; - - /* cs could use more than the usual two bits for the keyid */ - if (unlikely(keyid >= NUM_DEFAULT_KEYS)) - return -EINVAL; + keyid >>= 6; return keyid; } @@ -1588,8 +1565,12 @@ static void sta_ps_start(struct sta_info *sta) for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { struct ieee80211_txq *txq = sta->sta.txq[tid]; + struct txq_info *txqi = to_txq_info(txq); - ieee80211_unschedule_txq(&local->hw, txq, false); + spin_lock(&local->active_txq_lock[txq->ac]); + if (!list_empty(&txqi->schedule_order)) + list_del_init(&txqi->schedule_order); + spin_unlock(&local->active_txq_lock[txq->ac]); if (txq_has_queue(txq)) set_bit(tid, &sta->txq_buffered_tids); @@ -1895,11 +1876,11 @@ ieee80211_rx_get_bigtk(struct ieee80211_rx_data *rx, int idx) if (rx->sta) key = rcu_dereference(rx->sta->deflink.gtk[idx]); if (!key) - key = rcu_dereference(sdata->keys[idx]); + key = rcu_dereference(sdata->deflink.gtk[idx]); if (!key && rx->sta) key = rcu_dereference(rx->sta->deflink.gtk[idx2]); if (!key) - key = rcu_dereference(sdata->keys[idx2]); + key = rcu_dereference(sdata->deflink.gtk[idx2]); return key; } @@ -1916,7 +1897,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) struct ieee80211_key *ptk_idx = NULL; int mmie_keyidx = -1; __le16 fc; - const struct ieee80211_cipher_scheme *cs = NULL; if (ieee80211_is_ext(hdr->frame_control)) return RX_CONTINUE; @@ -1959,8 +1939,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (ieee80211_has_protected(fc) && !(status->flag & RX_FLAG_IV_STRIPPED)) { - cs = rx->sta->cipher_scheme; - keyid = ieee80211_get_keyid(rx->skb, cs); + keyid = ieee80211_get_keyid(rx->skb); if (unlikely(keyid < 0)) return RX_DROP_UNUSABLE; @@ -2015,7 +1994,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) rx->key = rcu_dereference(rx->sta->deflink.gtk[mmie_keyidx]); } if (!rx->key) - rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]); + rx->key = rcu_dereference(rx->sdata->deflink.gtk[mmie_keyidx]); } else if (!ieee80211_has_protected(fc)) { /* * The frame was not protected, so skip decryption. However, we @@ -2031,7 +2010,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) key = ieee80211_rx_get_bigtk(rx, -1); } else if (ieee80211_is_mgmt(fc) && is_multicast_ether_addr(hdr->addr1)) { - key = rcu_dereference(rx->sdata->default_mgmt_key); + key = rcu_dereference(rx->sdata->deflink.default_mgmt_key); } else { if (rx->sta) { for (i = 0; i < NUM_DEFAULT_KEYS; i++) { @@ -2042,7 +2021,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) } if (!key) { for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - key = rcu_dereference(sdata->keys[i]); + key = rcu_dereference(sdata->deflink.gtk[i]); if (key) break; } @@ -2065,7 +2044,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) (status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; - keyidx = ieee80211_get_keyid(rx->skb, cs); + keyidx = ieee80211_get_keyid(rx->skb); if (unlikely(keyidx < 0)) return RX_DROP_UNUSABLE; @@ -2076,7 +2055,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) /* if not found, try default key */ if (!rx->key) { - rx->key = rcu_dereference(rx->sdata->keys[keyidx]); + if (is_multicast_ether_addr(hdr->addr1)) + rx->key = rcu_dereference(rx->sdata->deflink.gtk[keyidx]); + if (!rx->key) + rx->key = rcu_dereference(rx->sdata->keys[keyidx]); /* * RSNA-protected unicast frames should always be @@ -2131,7 +2113,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) result = ieee80211_crypto_gcmp_decrypt(rx); break; default: - result = ieee80211_crypto_hw_decrypt(rx); + result = RX_DROP_UNUSABLE; } /* the hdr variable is invalid after the decrypt handlers */ @@ -2550,6 +2532,35 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx, bool *port_control) return 0; } +bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata, + const u8 *addr, int *out_link_id) +{ + unsigned int link_id; + + /* non-MLO, or MLD address replaced by hardware */ + if (ether_addr_equal(sdata->vif.addr, addr)) + return true; + + if (!sdata->vif.valid_links) + return false; + + for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { + struct ieee80211_bss_conf *conf; + + conf = rcu_dereference(sdata->vif.link_conf[link_id]); + + if (!conf) + continue; + if (ether_addr_equal(conf->addr, addr)) { + if (out_link_id) + *out_link_id = link_id; + return true; + } + } + + return false; +} + /* * requires that rx->skb is a frame with ethernet header */ @@ -2565,7 +2576,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc) * all other destination addresses for them. */ if (unlikely(ehdr->h_proto == rx->sdata->control_port_protocol)) - return ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) || + return ieee80211_is_our_addr(rx->sdata, ehdr->h_dest, NULL) || ether_addr_equal(ehdr->h_dest, pae_group_addr); if (ieee80211_802_1x_port_control(rx) || @@ -2945,7 +2956,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) tailroom = IEEE80211_ENCRYPT_TAILROOM; fwd_skb = skb_copy_expand(skb, local->tx_headroom + - sdata->encrypt_headroom, + IEEE80211_ENCRYPT_HEADROOM, tailroom, GFP_ATOMIC); if (!fwd_skb) goto out; @@ -3146,8 +3157,8 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, return; } - if (!ether_addr_equal(mgmt->sa, sdata->u.mgd.bssid) || - !ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) { + if (!ether_addr_equal(mgmt->sa, sdata->deflink.u.mgd.bssid) || + !ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) { /* Not from the current AP or not associated yet. */ return; } @@ -3165,7 +3176,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, resp = skb_put_zero(skb, 24); memcpy(resp->da, mgmt->sa, ETH_ALEN); memcpy(resp->sa, sdata->vif.addr, ETH_ALEN); - memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); + memcpy(resp->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); @@ -3192,7 +3203,7 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) return; - if (rx->sdata->vif.csa_active) + if (rx->sdata->vif.bss_conf.csa_active) return; baselen = mgmt->u.beacon.variable - rx->skb->data; @@ -3392,7 +3403,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) sband = rx->local->hw.wiphy->bands[status->band]; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_SMPS_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, @@ -3414,11 +3425,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) max_bw = IEEE80211_STA_RX_BW_20; else - max_bw = ieee80211_sta_cap_rx_bw(rx->sta); + max_bw = ieee80211_sta_cap_rx_bw(&rx->sta->deflink); /* set cur_max_bandwidth and recalc sta bw */ rx->sta->deflink.cur_max_bandwidth = max_bw; - new_bw = ieee80211_sta_cur_vht_bw(rx->sta); + new_bw = ieee80211_sta_cur_vht_bw(&rx->sta->deflink); if (rx->sta->sta.deflink.bandwidth == new_bw) goto handled; @@ -3426,10 +3437,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) rx->sta->sta.deflink.bandwidth = new_bw; sband = rx->local->hw.wiphy->bands[status->band]; sta_opmode.bw = - ieee80211_sta_rx_bw_to_chan_width(rx->sta); + ieee80211_sta_rx_bw_to_chan_width(&rx->sta->deflink); sta_opmode.changed = STA_OPMODE_MAX_BW_CHANGED; - rate_control_rate_update(local, sband, rx->sta, + rate_control_rate_update(local, sband, rx->sta, 0, IEEE80211_RC_BW_CHANGED); cfg80211_sta_opmode_change_notify(sdata->dev, rx->sta->addr, @@ -3449,7 +3460,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) break; if (!rx->sta) break; - if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) + if (!ether_addr_equal(mgmt->bssid, sdata->deflink.u.mgd.bssid)) break; if (mgmt->u.action.u.ext_chan_switch.action_code != WLAN_PUB_ACTION_EXT_CHANSW_ANN) @@ -3550,7 +3561,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) break; if (sdata->vif.type == NL80211_IFTYPE_STATION) - bssid = sdata->u.mgd.bssid; + bssid = sdata->deflink.u.mgd.bssid; else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) bssid = sdata->u.ibss.bssid; else if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) @@ -3633,7 +3644,13 @@ static ieee80211_rx_result debug_noinline ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - int sig = 0; + struct cfg80211_rx_info info = { + .freq = ieee80211_rx_status_to_khz(status), + .buf = rx->skb->data, + .len = rx->skb->len, + .link_id = rx->link_id, + .have_link_id = rx->link_id >= 0, + }; /* skip known-bad action frames and return them in the next handler */ if (status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) @@ -3648,11 +3665,15 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) - sig = status->signal; + info.sig_dbm = status->signal; - if (cfg80211_rx_mgmt_khz(&rx->sdata->wdev, - ieee80211_rx_status_to_khz(status), sig, - rx->skb->data, rx->skb->len, 0)) { + if (ieee80211_is_timing_measurement(rx->skb) || + ieee80211_is_ftm(rx->skb)) { + info.rx_tstamp = ktime_to_ns(skb_hwtstamps(rx->skb)->hwtstamp); + info.ack_tstamp = ktime_to_ns(status->ack_tx_hwtstamp); + } + + if (cfg80211_rx_mgmt_ext(&rx->sdata->wdev, &info)) { if (rx->sta) rx->sta->deflink.rx_stats.packets++; dev_kfree_skb(rx->skb); @@ -3753,7 +3774,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) local->hw.offchannel_tx_hw_queue; } - __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, + __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7, -1, status->band); } dev_kfree_skb(rx->skb); @@ -3969,6 +3990,9 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, */ rx->skb = skb; + if (WARN_ON_ONCE(!rx->link)) + goto rxh_next; + CALL_RXH(ieee80211_rx_h_check_more_data); CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll); CALL_RXH(ieee80211_rx_h_sta_process); @@ -4047,6 +4071,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) /* This is OK -- must be QoS data frame */ .security_idx = tid, .seqno_idx = tid, + .link_id = -1, }; struct tid_ampdu_rx *tid_agg_rx; @@ -4083,6 +4108,7 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, /* This is OK -- must be QoS data frame */ .security_idx = tid, .seqno_idx = tid, + .link_id = -1, }; int i, diff; @@ -4095,6 +4121,7 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid, rx.sta = sta; rx.sdata = sta->sdata; + rx.link = &rx.sdata->deflink; rx.local = sta->local; rcu_read_lock(); @@ -4153,6 +4180,12 @@ EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames); /* main receive path */ +static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) +{ + return ether_addr_equal(raddr, addr) || + is_broadcast_ether_addr(raddr); +} + static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = rx->sdata; @@ -4171,7 +4204,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) return false; if (multicast) return true; - return ether_addr_equal(sdata->vif.addr, hdr->addr1); + return ieee80211_is_our_addr(sdata, hdr->addr1, &rx->link_id); case NL80211_IFTYPE_ADHOC: if (!bssid) return false; @@ -4225,9 +4258,11 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP: if (!bssid) - return ether_addr_equal(sdata->vif.addr, hdr->addr1); + return ieee80211_is_our_addr(sdata, hdr->addr1, + &rx->link_id); - if (!ieee80211_bssid_match(bssid, sdata->vif.addr)) { + if (!is_broadcast_ether_addr(bssid) && + !ieee80211_is_our_addr(sdata, bssid, NULL)) { /* * Accept public action frames even when the * BSSID doesn't match, this is used for P2P @@ -4235,7 +4270,8 @@ 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)) + !ieee80211_is_our_addr(sdata, hdr->addr1, + &rx->link_id)) return false; if (ieee80211_is_public_action(hdr, skb->len)) return true; @@ -4702,6 +4738,9 @@ 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_hdr *hdr = (void *)skb->data; + struct link_sta_info *link_sta = NULL; + struct ieee80211_link_data *link; rx->skb = skb; @@ -4723,9 +4762,30 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!ieee80211_accept_frame(rx)) return false; + if (rx->link_id >= 0) { + link = rcu_dereference(rx->sdata->link[rx->link_id]); + + /* we might race link removal */ + if (!link) + return true; + rx->link = link; + } else { + rx->link = &sdata->deflink; + } + + if (unlikely(!is_multicast_ether_addr(hdr->addr1) && + rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) { + link_sta = rcu_dereference(rx->sta->link[rx->link_id]); + + if (WARN_ON_ONCE(!link_sta)) + return true; + } + if (!consume) { - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) { + struct skb_shared_hwtstamps *shwt; + + rx->skb = skb_copy(skb, GFP_ATOMIC); + if (!rx->skb) { if (net_ratelimit()) wiphy_debug(local->hw.wiphy, "failed to copy skb for %s\n", @@ -4733,7 +4793,28 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, return true; } - rx->skb = skb; + /* skb_copy() does not copy the hw timestamps, so copy it + * explicitly + */ + shwt = skb_hwtstamps(rx->skb); + shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp; + } + + if (unlikely(link_sta)) { + /* translate to MLD addresses */ + if (ether_addr_equal(link->conf->addr, hdr->addr1)) + ether_addr_copy(hdr->addr1, rx->sdata->vif.addr); + if (ether_addr_equal(link_sta->addr, hdr->addr2)) + ether_addr_copy(hdr->addr2, rx->sta->addr); + /* translate A3 only if it's the BSSID */ + if (!ieee80211_has_tods(hdr->frame_control) && + !ieee80211_has_fromds(hdr->frame_control)) { + if (ether_addr_equal(link_sta->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sta->addr); + else if (ether_addr_equal(link->conf->addr, hdr->addr3)) + ether_addr_copy(hdr->addr3, rx->sdata->vif.addr); + } + /* not needed for A4 since it can only carry the SA */ } ieee80211_invoke_rx_handlers(rx); @@ -4753,6 +4834,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, rx.skb = skb; rx.local = local; rx.list = list; + rx.link_id = -1; I802_DEBUG_INC(local->dot11ReceivedFragmentCount); @@ -4765,6 +4847,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, rx.sta = container_of(pubsta, struct sta_info, sta); rx.sdata = rx.sta->sdata; + rx.link = &rx.sdata->deflink; fast_rx = rcu_dereference(rx.sta->fast_rx); if (!fast_rx) @@ -4777,6 +4860,29 @@ drop: dev_kfree_skb(skb); } +static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx, + struct sk_buff *skb, bool consume) +{ + struct link_sta_info *link_sta; + struct ieee80211_hdr *hdr = (void *)skb->data; + + /* + * Look up link station first, in case there's a + * chance that they might have a link address that + * is identical to the MLD address, that way we'll + * have the link information if needed. + */ + link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2); + if (link_sta) { + rx->sta = link_sta->sta; + rx->link_id = link_sta->link_id; + } else { + rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2); + } + + return ieee80211_prepare_and_rx_handle(rx, skb, consume); +} + /* * This is the actual Rx frames handler. as it belongs to Rx path it must * be called with rcu_read_lock protection. @@ -4800,6 +4906,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.skb = skb; rx.local = local; rx.list = list; + rx.link_id = -1; if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) I802_DEBUG_INC(local->dot11ReceivedFragmentCount); @@ -4885,18 +4992,16 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } - rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; - ieee80211_prepare_and_rx_handle(&rx, skb, false); + ieee80211_rx_for_interface(&rx, skb, false); prev = sdata; } if (prev) { - rx.sta = sta_info_get_bss(prev, hdr->addr2); rx.sdata = prev; - if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) + if (ieee80211_rx_for_interface(&rx, skb, true)) return; } |