mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
Too many robustness fixes to list. Mostly for
- slight out-of-bounds reads of SKBs, - leaks on error conditions, and - malformed netlink input rejection. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEpeA8sTs3M8SN2hR410qiO8sPaAAFAmpPimsACgkQ10qiO8sP aAAS3g/+JviDe4Xbaw49OXN3ABCDmSLRf+wMjlD3ot1Ct4enpCVk2krYvpQZl2ho aLMDoGtTK6mZ04YULtn1LpRuJfLIiTLV+taZV2xHFZRZMBm6lpzSrfwjYT9EcR5h 4u34FWypBfkZIEs4YGYszpCVjdMJh7Vkm3HXUIWWHS5xNmq82RTVmT3ft6CRqQZG UZcxqj3VZwRbPLjYmszCgVwj6xvcgEbxfFfGp4eWxZYOONacYMjNw3gSx+yXun15 qKBUisH4V39FOCoFDeXKxZlsz2bALi+qB3jQKqOhh51kqzHzonsgjjId92h34Hih SwjNqbdK496itSL7a9QL6kOWNgXvhfIDnDquwPhrtV5kCXhpIoElcHGT6hoxlXl9 DqOEvNgrumvB7iTNwH4i9MXhUTK1HxmZ74AsGQcCcPFuLdVmYA8/Vd2iQvawoI1b 1zLzsUBa2rV3Ulr/pIKnTWDxQki2uiTAYt8mCS5YIxNpUir5m6e7sM1AOKwJPQbq H+J313XM3dA8zf60LeBGKFVyTaAsG2SqK9NE4oZZirsJlNUM6i5q6JPRkFjHXVB5 m0YZ6nTtz6SgBz3wnUSWnqZXJ2LRWiaBBwytZlaGmgdTjOgBTM4DJ0JO/2icRAxI 4511CiUEXxivZ82E7QKEn3mOeSxLa0nvPRMP3w90fDjtwOa24ZI= =qyPx -----END PGP SIGNATURE----- Merge tag 'wireless-2026-07-09' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless Johannes Berg says: ==================== Too many robustness fixes to list. Mostly for - slight out-of-bounds reads of SKBs, - leaks on error conditions, and - malformed netlink input rejection. * tag 'wireless-2026-07-09' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: (46 commits) wifi: cfg80211: bound element ID read when checking non-inheritance wifi: brcmfmac: cyw: fix heap overflow on a short auth frame wifi: brcmfmac: initialize SDIO data work before cleanup wifi: cfg80211: validate assoc response length before status and IE access wifi: cfg80211: validate rx/tx MLME callback frame lengths before access wifi: mac80211: ibss: wait for in-flight TX on disconnect wifi: mac80211: recalculate rx_nss on IBSS peer capability update wifi: cfg80211: use wiphy work for socket owner autodisconnect wifi: mac80211: fix memory leak in ieee80211_register_hw() wifi: mac80211: free AP_VLAN bc_buf SKBs outside IRQ lock wifi: mac80211: validate deauth frame length before reason access wifi: mac80211: avoid non-S1G AID fallback for S1G assoc wifi: cfg80211: reject empty PMSR peer lists wifi: cfg80211: reject unsupported PMSR FTM location requests wifi: cfg80211: validate PMSR FTM preamble range wifi: cfg80211: validate PMSR measurement type data wifi: nl80211: constrain MBSSID TX link ID range wifi: nl80211: validate nested MBSSID IE blobs wifi: ieee80211: validate MLE common info length wifi: cfg80211: derive S1G beacon TSF from S1G fields ... ==================== Link: https://patch.msgid.link/20260709115038.243870-3-johannes@sipsolutions.net Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
a0d82fb850
|
|
@ -293,6 +293,12 @@ brcmf_notify_auth_frame_rx(struct brcmf_if *ifp,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mgmt_frame_len < offsetof(struct ieee80211_mgmt, u)) {
|
||||
bphy_err(drvr, "Event %s (%d) frame too small. Ignore\n",
|
||||
brcmf_fweh_event_name(e->event_code), e->event_code);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdev = &ifp->vif->wdev;
|
||||
WARN_ON(!wdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -4465,6 +4465,7 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
bus->sdiodev = sdiodev;
|
||||
sdiodev->bus = bus;
|
||||
skb_queue_head_init(&bus->glom);
|
||||
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
|
||||
bus->txbound = BRCMF_TXBOUND;
|
||||
bus->rxbound = BRCMF_RXBOUND;
|
||||
bus->txminmax = BRCMF_TXMINMAX;
|
||||
|
|
@ -4479,7 +4480,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
|
|||
goto fail;
|
||||
}
|
||||
brcmf_sdiod_freezer_count(sdiodev);
|
||||
INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
|
||||
bus->brcmf_wq = wq;
|
||||
|
||||
/* attempt to attach to the dongle */
|
||||
|
|
|
|||
|
|
@ -6157,6 +6157,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
|||
if (err) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"Error calling pci_enable_device.\n");
|
||||
free_libipw(dev, 0);
|
||||
pci_iounmap(pci_dev, ioaddr);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -6169,16 +6171,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
|
|||
if (err) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"Error calling pci_set_dma_mask.\n");
|
||||
pci_disable_device(pci_dev);
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = pci_request_regions(pci_dev, DRV_NAME);
|
||||
if (err) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"Error calling pci_request_regions.\n");
|
||||
pci_disable_device(pci_dev);
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We disable the RETRY_TIMEOUT register (0x41) to keep
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
|
|||
ieee->host_mc_decrypt : ieee->host_decrypt;
|
||||
|
||||
if (can_be_decrypted) {
|
||||
if (skb->len >= hdrlen + 3) {
|
||||
if (skb->len >= hdrlen + 4) {
|
||||
/* Top two-bits of byte 3 are the key index */
|
||||
keyidx = skb->data[hdrlen + 3] >> 6;
|
||||
}
|
||||
|
|
@ -660,7 +660,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
|
|||
int trimlen = 0;
|
||||
|
||||
/* Top two-bits of byte 3 are the key index */
|
||||
if (skb->len >= hdrlen + 3)
|
||||
if (skb->len >= hdrlen + 4)
|
||||
keyidx = skb->data[hdrlen + 3] >> 6;
|
||||
|
||||
/* To strip off any security data which appears before the
|
||||
|
|
|
|||
|
|
@ -499,11 +499,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv,
|
|||
if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size)
|
||||
return;
|
||||
|
||||
if (eeprom->v2.data + priv->eeprom_slice_size >
|
||||
skb_tail_pointer(skb))
|
||||
return;
|
||||
|
||||
memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size);
|
||||
} else {
|
||||
if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size)
|
||||
return;
|
||||
|
||||
if (eeprom->v1.data + priv->eeprom_slice_size >
|
||||
skb_tail_pointer(skb))
|
||||
return;
|
||||
|
||||
memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ static void helper_firmware_cb(const struct firmware *firmware, void *context)
|
|||
} else {
|
||||
/* No main firmware needed for this helper --> success! */
|
||||
lbs_fw_loaded(priv, 0, firmware, NULL);
|
||||
release_firmware(firmware);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
|
||||
|
||||
if (skb->len < sizeof(*rtap_hdr) + 4 + ETH_ALEN) {
|
||||
lbs_deb_tx("tx err: short monitor frame %u\n", skb->len);
|
||||
dev->stats.tx_dropped++;
|
||||
dev->stats.tx_errors++;
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* set txpd fields from the radiotap header */
|
||||
txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ static void lbtf_free_adapter(struct lbtf_private *priv)
|
|||
{
|
||||
lbtf_deb_enter(LBTF_DEB_MAIN);
|
||||
lbtf_free_cmd_buffer(priv);
|
||||
timer_delete(&priv->command_timer);
|
||||
timer_delete_sync(&priv->command_timer);
|
||||
lbtf_deb_leave(LBTF_DEB_MAIN);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4334,7 +4334,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!priv->auth_flag) {
|
||||
if (!(priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
|
||||
ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET,
|
||||
req->bss->channel,
|
||||
AUTH_TX_DEFAULT_WAIT_TIME);
|
||||
|
|
|
|||
|
|
@ -736,7 +736,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
|
|||
/* Send a Media Connected event, according to the Spec */
|
||||
priv->media_connected = true;
|
||||
|
||||
priv->adapter->ps_state = PS_STATE_AWAKE;
|
||||
priv->adapter->pps_uapsd_mode = false;
|
||||
priv->adapter->tx_lock_flag = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -1429,7 +1429,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
|
|||
*/
|
||||
static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct eeprom_93cx6 eeprom;
|
||||
struct eeprom_93cx6 eeprom = {};
|
||||
u32 reg;
|
||||
u16 word;
|
||||
u8 *mac;
|
||||
|
|
|
|||
|
|
@ -1555,7 +1555,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
|
|||
*/
|
||||
static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct eeprom_93cx6 eeprom;
|
||||
struct eeprom_93cx6 eeprom = {};
|
||||
u32 reg;
|
||||
u16 word;
|
||||
u8 *mac;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
|
|||
|
||||
static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct eeprom_93cx6 eeprom;
|
||||
struct eeprom_93cx6 eeprom = {};
|
||||
u32 reg;
|
||||
|
||||
reg = rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR);
|
||||
|
|
|
|||
|
|
@ -1388,7 +1388,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
GFP_KERNEL);
|
||||
if (!rt2x00dev->drv_data) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1422,7 +1422,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
|
||||
if (!rt2x00dev->workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
goto exit_free_drv_data;
|
||||
}
|
||||
|
||||
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
|
||||
|
|
@ -1494,6 +1494,14 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
exit:
|
||||
rt2x00lib_remove_dev(rt2x00dev);
|
||||
|
||||
return retval;
|
||||
|
||||
exit_free_drv_data:
|
||||
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
||||
|
||||
kfree(rt2x00dev->drv_data);
|
||||
rt2x00dev->drv_data = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
|
||||
|
|
|
|||
|
|
@ -2298,7 +2298,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
|||
*/
|
||||
static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
struct eeprom_93cx6 eeprom;
|
||||
struct eeprom_93cx6 eeprom = {};
|
||||
u32 reg;
|
||||
u16 word;
|
||||
u8 *mac;
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
|
|||
struct ieee80211_vif *vif;
|
||||
struct sk_buff *mac_bcn;
|
||||
u8 vap_id = 0, i;
|
||||
unsigned int tailroom;
|
||||
u16 tim_offset = 0;
|
||||
|
||||
for (i = 0; i < RSI_MAX_VIFS; i++) {
|
||||
|
|
@ -480,6 +481,13 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb)
|
|||
if (mac_bcn->data[tim_offset + 2] == 0)
|
||||
bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON);
|
||||
|
||||
tailroom = skb_tailroom(skb);
|
||||
if (tailroom < FRAME_DESC_SZ ||
|
||||
mac_bcn->len > tailroom - FRAME_DESC_SZ) {
|
||||
dev_kfree_skb(mac_bcn);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len);
|
||||
skb_put(skb, mac_bcn->len + FRAME_DESC_SZ);
|
||||
|
||||
|
|
|
|||
|
|
@ -848,8 +848,10 @@ int rsi_hal_load_key(struct rsi_common *common,
|
|||
} else {
|
||||
memcpy(&set_key->key[0][0], data, key_len);
|
||||
}
|
||||
memcpy(set_key->tx_mic_key, &data[16], 8);
|
||||
memcpy(set_key->rx_mic_key, &data[24], 8);
|
||||
if (cipher == WLAN_CIPHER_SUITE_TKIP) {
|
||||
memcpy(set_key->tx_mic_key, &data[16], 8);
|
||||
memcpy(set_key->rx_mic_key, &data[24], 8);
|
||||
}
|
||||
} else {
|
||||
memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ);
|
||||
}
|
||||
|
|
@ -1911,6 +1913,12 @@ int rsi_send_bgscan_probe_req(struct rsi_common *common,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (probereq_skb->len > MAX_BGSCAN_PROBE_REQ_LEN) {
|
||||
dev_kfree_skb(probereq_skb);
|
||||
dev_kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&skb->data[frame_len], probereq_skb->data, probereq_skb->len);
|
||||
|
||||
bgscan->probe_req_length = cpu_to_le16(probereq_skb->len);
|
||||
|
|
|
|||
|
|
@ -1324,6 +1324,17 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
static struct ieee80211_rate *
|
||||
mac80211_hwsim_get_tx_rate(struct ieee80211_hw *hw,
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
if (info->control.rates[0].flags &
|
||||
(IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
|
||||
return NULL;
|
||||
|
||||
return ieee80211_get_tx_rate(hw, info);
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
||||
struct sk_buff *tx_skb,
|
||||
struct ieee80211_channel *chan)
|
||||
|
|
@ -1333,7 +1344,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
|
|||
struct hwsim_radiotap_hdr *hdr;
|
||||
u16 flags, bitrate;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_skb);
|
||||
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
|
||||
struct ieee80211_rate *txrate = mac80211_hwsim_get_tx_rate(hw, info);
|
||||
|
||||
if (!txrate)
|
||||
bitrate = 0;
|
||||
|
|
@ -1603,7 +1614,7 @@ static void mac80211_hwsim_write_tsf(struct mac80211_hwsim_data *data,
|
|||
|
||||
spin_lock_bh(&data->tsf_offset_lock);
|
||||
|
||||
txrate = ieee80211_get_tx_rate(data->hw, info);
|
||||
txrate = mac80211_hwsim_get_tx_rate(data->hw, info);
|
||||
if (txrate)
|
||||
bitrate = txrate->bitrate;
|
||||
|
||||
|
|
@ -7289,6 +7300,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
|
|||
|
||||
skb->data = skb->head;
|
||||
skb_reset_tail_pointer(skb);
|
||||
len = min(len, skb_end_offset(skb));
|
||||
skb_put(skb, len);
|
||||
hwsim_virtio_handle_cmd(skb);
|
||||
|
||||
|
|
|
|||
|
|
@ -857,7 +857,7 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
const struct ieee80211_multi_link_elem *mle = (const void *)data;
|
||||
u8 fixed = sizeof(*mle);
|
||||
u8 common = 0;
|
||||
bool check_common_len = false;
|
||||
u8 common_len;
|
||||
u16 control;
|
||||
|
||||
if (!data || len < fixed)
|
||||
|
|
@ -868,7 +868,6 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
switch (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE)) {
|
||||
case IEEE80211_ML_CONTROL_TYPE_BASIC:
|
||||
common += sizeof(struct ieee80211_mle_basic_common_info);
|
||||
check_common_len = true;
|
||||
if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID)
|
||||
common += 1;
|
||||
if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)
|
||||
|
|
@ -888,9 +887,9 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
common += sizeof(struct ieee80211_mle_preq_common_info);
|
||||
if (control & IEEE80211_MLC_PREQ_PRES_MLD_ID)
|
||||
common += 1;
|
||||
check_common_len = true;
|
||||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_RECONF:
|
||||
common += 1;
|
||||
if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR)
|
||||
common += ETH_ALEN;
|
||||
if (control & IEEE80211_MLC_RECONF_PRES_EML_CAPA)
|
||||
|
|
@ -902,7 +901,6 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_TDLS:
|
||||
common += sizeof(struct ieee80211_mle_tdls_common_info);
|
||||
check_common_len = true;
|
||||
break;
|
||||
case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS:
|
||||
common = ETH_ALEN + 1;
|
||||
|
|
@ -915,11 +913,9 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len)
|
|||
if (len < fixed + common)
|
||||
return false;
|
||||
|
||||
if (!check_common_len)
|
||||
return true;
|
||||
common_len = mle->variable[0];
|
||||
|
||||
/* if present, common length is the first octet there */
|
||||
return mle->variable[0] >= common;
|
||||
return common_len >= common && common_len <= len - fixed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7228,7 +7228,7 @@ struct wireless_dev {
|
|||
enum ieee80211_bss_type conn_bss_type;
|
||||
u32 conn_owner_nlportid;
|
||||
|
||||
struct work_struct disconnect_wk;
|
||||
struct wiphy_work disconnect_wk;
|
||||
u8 disconnect_bssid[ETH_ALEN];
|
||||
|
||||
struct list_head event_list;
|
||||
|
|
@ -7265,7 +7265,7 @@ struct wireless_dev {
|
|||
|
||||
struct list_head pmsr_list;
|
||||
spinlock_t pmsr_lock;
|
||||
struct work_struct pmsr_free_wk;
|
||||
struct wiphy_work pmsr_free_wk;
|
||||
|
||||
unsigned long unprot_beacon_reported;
|
||||
|
||||
|
|
|
|||
|
|
@ -1146,9 +1146,6 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
|
|||
fd->max_interval = params->max_interval;
|
||||
|
||||
old = sdata_dereference(link->u.ap.fils_discovery, sdata);
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
if (params->tmpl && params->tmpl_len) {
|
||||
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
|
||||
if (!new)
|
||||
|
|
@ -1160,6 +1157,9 @@ static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
|
|||
RCU_INIT_POINTER(link->u.ap.fils_discovery, NULL);
|
||||
}
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
*changed |= BSS_CHANGED_FILS_DISCOVERY;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1179,8 +1179,6 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
link_conf->unsol_bcast_probe_resp_interval = params->interval;
|
||||
|
||||
old = sdata_dereference(link->u.ap.unsol_bcast_probe_resp, sdata);
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
if (params->tmpl && params->tmpl_len) {
|
||||
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
|
||||
|
|
@ -1193,6 +1191,9 @@ ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
|
|||
RCU_INIT_POINTER(link->u.ap.unsol_bcast_probe_resp, NULL);
|
||||
}
|
||||
|
||||
if (old)
|
||||
kfree_rcu(old, rcu_head);
|
||||
|
||||
*changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -668,7 +668,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
||||
|
||||
sta_info_flush(sdata, -1);
|
||||
netif_carrier_off(sdata->dev);
|
||||
if (!sta_info_flush(sdata, -1))
|
||||
synchronize_net();
|
||||
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
while (!list_empty(&ifibss->incomplete_stations)) {
|
||||
|
|
@ -682,8 +684,6 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
|||
}
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
sdata->vif.cfg.ibss_joined = false;
|
||||
sdata->vif.cfg.ibss_creator = false;
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
|
|
@ -710,7 +710,6 @@ static void ieee80211_csa_connection_drop_work(struct wiphy *wiphy,
|
|||
u.ibss.csa_connection_drop_work);
|
||||
|
||||
ieee80211_ibss_disconnect(sdata);
|
||||
synchronize_rcu();
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
|
||||
/* trigger a scan to find another IBSS network to join */
|
||||
|
|
@ -1029,8 +1028,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
|
|||
u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
|
||||
u8 rx_nss = sta->sta.deflink.rx_nss;
|
||||
|
||||
/* Force rx_nss recalculation */
|
||||
sta->sta.deflink.rx_nss = 0;
|
||||
ieee80211_sta_init_nss_bw_capa(&sta->deflink,
|
||||
&sdata->deflink.conf->chanreq.oper);
|
||||
rate_control_rate_init(&sta->deflink);
|
||||
if (sta->sta.deflink.rx_nss != rx_nss)
|
||||
changed |= IEEE80211_RC_NSS_CHANGED;
|
||||
|
|
@ -1797,8 +1796,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
|||
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
|
||||
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
|
||||
|
||||
synchronize_rcu();
|
||||
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
|
||||
timer_delete_sync(&sdata->u.ibss.timer);
|
||||
|
|
|
|||
|
|
@ -588,6 +588,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|||
WARN_ON(!list_empty(&sdata->u.ap.vlans));
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
|
||||
/* remove all packets in parent bc_buf pointing to this dev */
|
||||
__skb_queue_head_init(&freeq);
|
||||
ps = &sdata->bss->ps;
|
||||
|
||||
spin_lock_irqsave(&ps->bc_buf.lock, flags);
|
||||
|
|
@ -595,10 +596,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
|||
if (skb->dev == sdata->dev) {
|
||||
__skb_unlink(skb, &ps->bc_buf);
|
||||
local->total_ps_buffered--;
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
__skb_queue_tail(&freeq, skb);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
|
||||
|
||||
skb_queue_walk_safe(&freeq, skb, tmp) {
|
||||
__skb_unlink(skb, &freeq);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (going_down)
|
||||
|
|
|
|||
|
|
@ -1602,7 +1602,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
sband = kmemdup(sband, sizeof(*sband), GFP_KERNEL);
|
||||
if (!sband) {
|
||||
result = -ENOMEM;
|
||||
goto fail_rate;
|
||||
goto fail_band;
|
||||
}
|
||||
|
||||
wiphy_dbg(hw->wiphy, "copying sband (band %d) due to VHT EXT NSS BW flag\n",
|
||||
|
|
@ -1678,6 +1678,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
#endif
|
||||
wiphy_unregister(local->hw.wiphy);
|
||||
fail_wiphy_register:
|
||||
fail_band:
|
||||
rtnl_lock();
|
||||
rate_control_deinitialize(local);
|
||||
ieee80211_remove_interfaces(local);
|
||||
|
|
|
|||
|
|
@ -5641,13 +5641,15 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
u16 reason_code;
|
||||
|
||||
lockdep_assert_wiphy(sdata->local->hw.wiphy);
|
||||
|
||||
if (len < 24 + 2)
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
|
||||
return;
|
||||
|
||||
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
|
||||
|
||||
if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) {
|
||||
ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code);
|
||||
return;
|
||||
|
|
@ -7138,7 +7140,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
|
||||
u16 capab_info, status_code, aid;
|
||||
u16 capab_info, status_code, aid = 0;
|
||||
struct ieee80211_elems_parse_params parse_params = {
|
||||
.bss = NULL,
|
||||
.link_id = -1,
|
||||
|
|
@ -7217,8 +7219,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
if (elems->aid_resp)
|
||||
aid = le16_to_cpu(elems->aid_resp->aid);
|
||||
else
|
||||
else if (!assoc_data->s1g)
|
||||
aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
|
||||
else if (status_code == WLAN_STATUS_SUCCESS)
|
||||
goto abandon_assoc;
|
||||
|
||||
/*
|
||||
* The 5 MSB of the AID field are reserved for a non-S1G STA. For
|
||||
|
|
|
|||
|
|
@ -253,9 +253,12 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
|
|||
{
|
||||
struct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};
|
||||
struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
|
||||
struct ieee80211_nan_sched_cfg backup_sched;
|
||||
struct ieee80211_nan_sched_cfg *backup_sched __free(kfree) = kmalloc_obj(*backup_sched);
|
||||
int ret;
|
||||
|
||||
if (!backup_sched)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sched->n_channels > IEEE80211_NAN_MAX_CHANNELS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -275,13 +278,13 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
|
||||
|
||||
memcpy(backup_sched.schedule, sched_cfg->schedule,
|
||||
sizeof(backup_sched.schedule));
|
||||
memcpy(backup_sched.channels, sched_cfg->channels,
|
||||
sizeof(backup_sched.channels));
|
||||
memcpy(backup_sched.avail_blob, sched_cfg->avail_blob,
|
||||
sizeof(backup_sched.avail_blob));
|
||||
backup_sched.avail_blob_len = sched_cfg->avail_blob_len;
|
||||
memcpy(backup_sched->schedule, sched_cfg->schedule,
|
||||
sizeof(backup_sched->schedule));
|
||||
memcpy(backup_sched->channels, sched_cfg->channels,
|
||||
sizeof(backup_sched->channels));
|
||||
memcpy(backup_sched->avail_blob, sched_cfg->avail_blob,
|
||||
sizeof(backup_sched->avail_blob));
|
||||
backup_sched->avail_blob_len = sched_cfg->avail_blob_len;
|
||||
|
||||
memcpy(sched_cfg->avail_blob, sched->nan_avail_blob,
|
||||
sched->nan_avail_blob_len);
|
||||
|
|
@ -380,17 +383,17 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
|
|||
if (!chan_def->chan)
|
||||
continue;
|
||||
|
||||
if (!cfg80211_chandef_identical(&backup_sched.channels[i].chanreq.oper,
|
||||
if (!cfg80211_chandef_identical(&backup_sched->channels[i].chanreq.oper,
|
||||
chan_def))
|
||||
ieee80211_nan_remove_channel(sdata,
|
||||
&sched_cfg->channels[i]);
|
||||
}
|
||||
|
||||
/* Re-add all backed up channels */
|
||||
for (int i = 0; i < ARRAY_SIZE(backup_sched.channels); i++) {
|
||||
for (int i = 0; i < ARRAY_SIZE(backup_sched->channels); i++) {
|
||||
struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
|
||||
|
||||
*chan = backup_sched.channels[i];
|
||||
*chan = backup_sched->channels[i];
|
||||
|
||||
/*
|
||||
* For deferred update, no channels were removed and the channel
|
||||
|
|
@ -421,11 +424,11 @@ int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
memcpy(sched_cfg->schedule, backup_sched.schedule,
|
||||
sizeof(backup_sched.schedule));
|
||||
memcpy(sched_cfg->avail_blob, backup_sched.avail_blob,
|
||||
sizeof(backup_sched.avail_blob));
|
||||
sched_cfg->avail_blob_len = backup_sched.avail_blob_len;
|
||||
memcpy(sched_cfg->schedule, backup_sched->schedule,
|
||||
sizeof(backup_sched->schedule));
|
||||
memcpy(sched_cfg->avail_blob, backup_sched->avail_blob,
|
||||
sizeof(backup_sched->avail_blob));
|
||||
sched_cfg->avail_blob_len = backup_sched->avail_blob_len;
|
||||
sched_cfg->deferred = false;
|
||||
bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
|
||||
|
||||
|
|
|
|||
|
|
@ -1526,6 +1526,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
|
|||
if (status->flag & RX_FLAG_DUP_VALIDATED)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (ieee80211_is_ext(hdr->frame_control))
|
||||
return RX_CONTINUE;
|
||||
|
||||
/*
|
||||
* Drop duplicate 802.11 retransmissions
|
||||
* (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
|
||||
|
|
@ -4510,12 +4513,16 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
|||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
|
||||
bool multicast = is_multicast_ether_addr(hdr->addr1) ||
|
||||
ieee80211_is_s1g_beacon(hdr->frame_control);
|
||||
bool multicast;
|
||||
static const u8 nan_network_id[ETH_ALEN] __aligned(2) = {
|
||||
0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00
|
||||
};
|
||||
|
||||
if (ieee80211_is_s1g_beacon(hdr->frame_control))
|
||||
return sdata->vif.type == NL80211_IFTYPE_STATION && bssid;
|
||||
|
||||
multicast = is_multicast_ether_addr(hdr->addr1);
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!bssid && !sdata->u.mgd.use_4addr)
|
||||
|
|
@ -5212,6 +5219,11 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
|
|||
hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||
}
|
||||
|
||||
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
|
||||
ieee80211_invoke_rx_handlers(rx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Store a copy of the pre-translated link addresses for SW crypto */
|
||||
if (unlikely(is_unicast_ether_addr(hdr->addr1) &&
|
||||
!ieee80211_is_data(hdr->frame_control)))
|
||||
|
|
@ -5301,6 +5313,13 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
|
|||
struct sta_info *sta;
|
||||
int link_id = -1;
|
||||
|
||||
if (ieee80211_is_s1g_beacon(hdr->frame_control)) {
|
||||
if (!ieee80211_rx_data_set_sta(rx, NULL, -1))
|
||||
return false;
|
||||
|
||||
return ieee80211_prepare_and_rx_handle(rx, skb, consume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up link station first, in case there's a
|
||||
* chance that they might have a link address that
|
||||
|
|
@ -5376,6 +5395,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
|||
err = -ENOBUFS;
|
||||
else
|
||||
err = skb_linearize(skb);
|
||||
} else if (ieee80211_is_s1g_beacon(fc)) {
|
||||
size_t s1g_hdr_len = offsetof(struct ieee80211_ext,
|
||||
u.s1g_beacon.variable) +
|
||||
ieee80211_s1g_optional_len(fc);
|
||||
|
||||
if (skb->len < s1g_hdr_len)
|
||||
err = -ENOBUFS;
|
||||
else
|
||||
err = skb_linearize(skb);
|
||||
} else if (ieee80211_is_ext(fc)) {
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -355,6 +355,15 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
|
|||
free_percpu(link_sta->pcpu_rx_stats);
|
||||
}
|
||||
|
||||
static void sta_link_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct sta_link_alloc *alloc =
|
||||
container_of(head, struct sta_link_alloc, rcu_head);
|
||||
|
||||
sta_info_free_link(&alloc->info);
|
||||
kfree(alloc);
|
||||
}
|
||||
|
||||
static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id)
|
||||
{
|
||||
struct link_sta_info *link_sta = wiphy_dereference(sta->local->hw.wiphy,
|
||||
|
|
@ -439,10 +448,8 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
|
|||
|
||||
RCU_INIT_POINTER(sta->link[link_id], NULL);
|
||||
RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
|
||||
if (alloc) {
|
||||
sta_info_free_link(&alloc->info);
|
||||
kfree_rcu(alloc, rcu_head);
|
||||
}
|
||||
if (alloc)
|
||||
call_rcu(&alloc->rcu_head, sta_link_free_rcu);
|
||||
|
||||
ieee80211_sta_recalc_aggregates(&sta->sta);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2607,6 +2607,18 @@ static u16 ieee80211_store_ack_skb(struct ieee80211_local *local,
|
|||
return info_id;
|
||||
}
|
||||
|
||||
static void ieee80211_remove_ack_skb(struct ieee80211_local *local, u16 info_id)
|
||||
{
|
||||
struct sk_buff *ack_skb;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&local->ack_status_lock, flags);
|
||||
ack_skb = idr_remove(&local->ack_status_frames, info_id);
|
||||
spin_unlock_irqrestore(&local->ack_status_lock, flags);
|
||||
|
||||
kfree_skb(ack_skb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ieee80211_build_hdr - build 802.11 header in the given frame
|
||||
* @sdata: virtual interface to build the header for
|
||||
|
|
@ -2982,7 +2994,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
skb = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3050,6 +3063,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
return skb;
|
||||
free:
|
||||
if (info_id)
|
||||
ieee80211_remove_ack_skb(local, info_id);
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
|
|||
if (ieee80211_is_s1g_beacon(fc)) {
|
||||
struct ieee80211_ext *ext = (void *) hdr;
|
||||
|
||||
if (len < offsetofend(struct ieee80211_ext, u.s1g_beacon.sa))
|
||||
return NULL;
|
||||
|
||||
return ext->u.s1g_beacon.sa;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1335,6 +1335,7 @@ void wiphy_unregister(struct wiphy *wiphy)
|
|||
/* this has nothing to do now but make sure it's gone */
|
||||
cancel_work_sync(&rdev->wiphy_work);
|
||||
|
||||
cancel_work_sync(&rdev->sched_scan_res_wk);
|
||||
cancel_work_sync(&rdev->rfkill_block);
|
||||
cancel_work_sync(&rdev->conn_work);
|
||||
flush_work(&rdev->event_work);
|
||||
|
|
@ -1424,6 +1425,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
|
|||
list_del_rcu(&wdev->list);
|
||||
synchronize_net();
|
||||
rdev->devlist_generation++;
|
||||
wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
|
||||
|
||||
cfg80211_mlme_purge_registrations(wdev);
|
||||
|
||||
|
|
@ -1613,7 +1615,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
|
|||
INIT_LIST_HEAD(&wdev->mgmt_registrations);
|
||||
INIT_LIST_HEAD(&wdev->pmsr_list);
|
||||
spin_lock_init(&wdev->pmsr_lock);
|
||||
INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
|
||||
wiphy_work_init(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
wdev->wext.default_key = -1;
|
||||
|
|
@ -1637,7 +1639,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
|
|||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
|
||||
wdev->netdev->priv_flags |= IFF_DONT_BRIDGE;
|
||||
|
||||
INIT_WORK(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
|
||||
wiphy_work_init(&wdev->disconnect_wk, cfg80211_autodisconnect_wk);
|
||||
}
|
||||
|
||||
void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
|
||||
|
|
@ -1743,11 +1745,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
break;
|
||||
case NETDEV_GOING_DOWN:
|
||||
cfg80211_leave(rdev, wdev, -1);
|
||||
scoped_guard(wiphy, &rdev->wiphy)
|
||||
scoped_guard(wiphy, &rdev->wiphy) {
|
||||
cfg80211_remove_links(wdev);
|
||||
/* since we just did cfg80211_leave() nothing to do there */
|
||||
cancel_work_sync(&wdev->disconnect_wk);
|
||||
cancel_work_sync(&wdev->pmsr_free_wk);
|
||||
/* since we just did cfg80211_leave() nothing to do there */
|
||||
wiphy_work_cancel(wdev->wiphy, &wdev->disconnect_wk);
|
||||
}
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
wiphy_lock(&rdev->wiphy);
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *peer_addr,
|
|||
const u8 *td_bitmap, u8 td_bitmap_len);
|
||||
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev);
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work);
|
||||
void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
|
||||
/* SME implementation */
|
||||
void cfg80211_conn_work(struct work_struct *work);
|
||||
|
|
@ -586,7 +586,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len,
|
|||
|
||||
void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
|
||||
void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
|
||||
void cfg80211_pmsr_free_wk(struct work_struct *work);
|
||||
void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work);
|
||||
|
||||
void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id);
|
||||
void cfg80211_remove_links(struct wireless_dev *wdev);
|
||||
|
|
|
|||
|
|
@ -32,15 +32,11 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
|
|||
.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED,
|
||||
.req_ie = data->req_ies,
|
||||
.req_ie_len = data->req_ies_len,
|
||||
.resp_ie = mgmt->u.assoc_resp.variable,
|
||||
.resp_ie_len = data->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.assoc_resp.variable),
|
||||
.status = le16_to_cpu(mgmt->u.assoc_resp.status_code),
|
||||
.ap_mld_addr = data->ap_mld_addr,
|
||||
.assoc_encrypted = data->assoc_encrypted,
|
||||
};
|
||||
unsigned int link_id;
|
||||
bool is_s1g = false;
|
||||
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
|
||||
cr.links[link_id].status = data->links[link_id].status;
|
||||
|
|
@ -61,16 +57,32 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
|
|||
|
||||
if (cr.links[link_id].bss->channel->band == NL80211_BAND_S1GHZ) {
|
||||
WARN_ON(link_id);
|
||||
cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
|
||||
cr.resp_ie_len = data->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.s1g_assoc_resp.variable);
|
||||
is_s1g = true;
|
||||
}
|
||||
|
||||
if (cr.ap_mld_addr)
|
||||
cr.valid_links |= BIT(link_id);
|
||||
}
|
||||
|
||||
if (is_s1g) {
|
||||
if (data->len < offsetof(struct ieee80211_mgmt,
|
||||
u.s1g_assoc_resp.variable))
|
||||
goto free_bss;
|
||||
cr.resp_ie = (u8 *)&mgmt->u.s1g_assoc_resp.variable;
|
||||
cr.resp_ie_len = data->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.s1g_assoc_resp.variable);
|
||||
} else {
|
||||
if (data->len < offsetof(struct ieee80211_mgmt,
|
||||
u.assoc_resp.variable))
|
||||
goto free_bss;
|
||||
cr.resp_ie = mgmt->u.assoc_resp.variable;
|
||||
cr.resp_ie_len = data->len -
|
||||
offsetof(struct ieee80211_mgmt,
|
||||
u.assoc_resp.variable);
|
||||
}
|
||||
cr.status = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
|
||||
trace_cfg80211_send_rx_assoc(dev, data);
|
||||
|
||||
/*
|
||||
|
|
@ -79,22 +91,24 @@ void cfg80211_rx_assoc_resp(struct net_device *dev,
|
|||
* and got a reject -- we only try again with an assoc
|
||||
* frame instead of reassoc.
|
||||
*/
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
|
||||
struct cfg80211_bss *bss = data->links[link_id].bss;
|
||||
|
||||
if (!bss)
|
||||
continue;
|
||||
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status))
|
||||
goto free_bss;
|
||||
|
||||
nl80211_send_rx_assoc(rdev, dev, data);
|
||||
/* update current_bss etc., consumes the bss reference */
|
||||
__cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
|
||||
return;
|
||||
|
||||
free_bss:
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(data->links); link_id++) {
|
||||
struct cfg80211_bss *bss = data->links[link_id].bss;
|
||||
|
||||
if (!bss)
|
||||
continue;
|
||||
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
|
||||
|
||||
|
|
@ -151,19 +165,35 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
|
|||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
__le16 fc;
|
||||
|
||||
lockdep_assert_wiphy(wdev->wiphy);
|
||||
|
||||
trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
|
||||
|
||||
if (WARN_ON(len < 2))
|
||||
if (len < sizeof(fc))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_auth(mgmt->frame_control))
|
||||
fc = mgmt->frame_control;
|
||||
|
||||
if (ieee80211_is_auth(fc)) {
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.auth.status_code))
|
||||
return;
|
||||
} else if (ieee80211_is_deauth(fc)) {
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
|
||||
return;
|
||||
} else if (ieee80211_is_disassoc(fc)) {
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.disassoc.reason_code))
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
|
||||
|
||||
if (ieee80211_is_auth(fc))
|
||||
cfg80211_process_auth(wdev, buf, len);
|
||||
else if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
else if (ieee80211_is_deauth(fc))
|
||||
cfg80211_process_deauth(wdev, buf, len, false);
|
||||
else if (ieee80211_is_disassoc(mgmt->frame_control))
|
||||
else
|
||||
cfg80211_process_disassoc(wdev, buf, len, false);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
|
||||
|
|
@ -216,15 +246,28 @@ void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len,
|
|||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_mgmt *mgmt = (void *)buf;
|
||||
__le16 fc;
|
||||
|
||||
lockdep_assert_wiphy(wdev->wiphy);
|
||||
|
||||
trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
|
||||
|
||||
if (WARN_ON(len < 2))
|
||||
if (len < sizeof(fc))
|
||||
return;
|
||||
|
||||
if (ieee80211_is_deauth(mgmt->frame_control))
|
||||
fc = mgmt->frame_control;
|
||||
|
||||
if (ieee80211_is_deauth(fc)) {
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.deauth.reason_code))
|
||||
return;
|
||||
} else if (ieee80211_is_disassoc(fc)) {
|
||||
if (len < offsetofend(struct ieee80211_mgmt, u.disassoc.reason_code))
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect);
|
||||
|
||||
if (ieee80211_is_deauth(fc))
|
||||
cfg80211_process_deauth(wdev, buf, len, reconnect);
|
||||
else
|
||||
cfg80211_process_disassoc(wdev, buf, len, reconnect);
|
||||
|
|
|
|||
|
|
@ -461,7 +461,9 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
|
|||
static const struct nla_policy
|
||||
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] =
|
||||
NLA_POLICY_RANGE(NLA_U32, NL80211_PREAMBLE_LEGACY,
|
||||
NL80211_PREAMBLE_HE),
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
|
||||
NLA_POLICY_MAX(NLA_U8, 15),
|
||||
[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
|
||||
|
|
@ -630,7 +632,7 @@ nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
|
|||
[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
|
||||
[NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
|
||||
[NL80211_MBSSID_CONFIG_ATTR_TX_LINK_ID] =
|
||||
NLA_POLICY_MAX(NLA_U8, IEEE80211_MLD_MAX_NUM_LINKS),
|
||||
NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS - 1),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
|
|
@ -6510,7 +6512,8 @@ static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
|
|||
}
|
||||
|
||||
static struct cfg80211_mbssid_elems *
|
||||
nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
|
||||
nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *nl_elems;
|
||||
struct cfg80211_mbssid_elems *elems;
|
||||
|
|
@ -6521,6 +6524,12 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
|
|||
return ERR_PTR(-EINVAL);
|
||||
|
||||
nla_for_each_nested(nl_elems, attrs, rem_elems) {
|
||||
int ret;
|
||||
|
||||
ret = validate_ie_attr(nl_elems, extack);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (num_elems >= 255)
|
||||
return ERR_PTR(-EINVAL);
|
||||
num_elems++;
|
||||
|
|
@ -6787,7 +6796,8 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
|
|||
if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
|
||||
struct cfg80211_mbssid_elems *mbssid =
|
||||
nl80211_parse_mbssid_elems(&rdev->wiphy,
|
||||
attrs[NL80211_ATTR_MBSSID_ELEMS]);
|
||||
attrs[NL80211_ATTR_MBSSID_ELEMS],
|
||||
extack);
|
||||
|
||||
if (IS_ERR(mbssid))
|
||||
return PTR_ERR(mbssid);
|
||||
|
|
@ -6803,8 +6813,10 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
|
|||
if (IS_ERR(rnr))
|
||||
return PTR_ERR(rnr);
|
||||
|
||||
if (rnr && rnr->cnt < bcn->mbssid_ies->cnt)
|
||||
if (rnr && rnr->cnt < bcn->mbssid_ies->cnt) {
|
||||
kfree(rnr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bcn->rnr_ies = rnr;
|
||||
}
|
||||
|
|
@ -22942,7 +22954,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|||
wdev->nl_owner_dead = true;
|
||||
schedule_work(&rdev->destroy_work);
|
||||
} else if (wdev->conn_owner_nlportid == notify->portid) {
|
||||
schedule_work(&wdev->disconnect_wk);
|
||||
wiphy_work_queue(wdev->wiphy,
|
||||
&wdev->disconnect_wk);
|
||||
}
|
||||
|
||||
cfg80211_release_pmsr(wdev, notify->portid);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
|
|||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
|
||||
"FTM: LCI request not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
out->ftm.request_civicloc =
|
||||
|
|
@ -133,6 +134,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
|
|||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
|
||||
"FTM: civic location request not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
out->ftm.trigger_based =
|
||||
|
|
@ -310,6 +312,7 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
|
|||
{
|
||||
struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
|
||||
struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
|
||||
bool have_measurement_type = false;
|
||||
struct nlattr *treq;
|
||||
int err, rem;
|
||||
|
||||
|
|
@ -376,6 +379,14 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
|
||||
if (have_measurement_type) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, treq,
|
||||
"multiple measurement types in request data");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
have_measurement_type = true;
|
||||
|
||||
switch (nla_type(treq)) {
|
||||
case NL80211_PMSR_TYPE_FTM:
|
||||
err = pmsr_parse_ftm(rdev, treq, out, info);
|
||||
|
|
@ -385,10 +396,16 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
|
|||
"unsupported measurement type");
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!have_measurement_type) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack,
|
||||
req[NL80211_PMSR_REQ_ATTR_DATA],
|
||||
"missing measurement type in request data");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -427,6 +444,11 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
NL_SET_ERR_MSG_ATTR(info->extack, peers, "No peers specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
req = kzalloc_flex(*req, peers, count);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
|
@ -807,13 +829,11 @@ static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev)
|
|||
}
|
||||
}
|
||||
|
||||
void cfg80211_pmsr_free_wk(struct work_struct *work)
|
||||
void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
{
|
||||
struct wireless_dev *wdev = container_of(work, struct wireless_dev,
|
||||
pmsr_free_wk);
|
||||
|
||||
guard(wiphy)(wdev->wiphy);
|
||||
|
||||
cfg80211_pmsr_process_abort(wdev);
|
||||
}
|
||||
|
||||
|
|
@ -829,7 +849,7 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
|
|||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
|
||||
cancel_work_sync(&wdev->pmsr_free_wk);
|
||||
wiphy_work_cancel(wdev->wiphy, &wdev->pmsr_free_wk);
|
||||
if (found)
|
||||
cfg80211_pmsr_process_abort(wdev);
|
||||
|
||||
|
|
@ -844,7 +864,7 @@ void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
|
|||
list_for_each_entry(req, &wdev->pmsr_list, list) {
|
||||
if (req->nl_portid == portid) {
|
||||
req->nl_portid = 0;
|
||||
schedule_work(&wdev->pmsr_free_wk);
|
||||
wiphy_work_queue(wdev->wiphy, &wdev->pmsr_free_wk);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&wdev->pmsr_lock);
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ bool cfg80211_is_element_inherited(const struct element *elem,
|
|||
return true;
|
||||
|
||||
if (elem->id == WLAN_EID_EXTENSION) {
|
||||
if (!ext_id_len)
|
||||
if (!ext_id_len || !elem->datalen)
|
||||
return true;
|
||||
loop_len = ext_id_len;
|
||||
list = &non_inherit_elem->data[3 + id_len];
|
||||
|
|
@ -326,8 +326,11 @@ cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
|
|||
/* For ML probe response, match the MLE in the frame body with
|
||||
* MLD id being 'bssid_index'
|
||||
*/
|
||||
if (parent->id == WLAN_EID_EXTENSION && parent->datalen > 1 &&
|
||||
if (parent->id == WLAN_EID_EXTENSION &&
|
||||
parent->data[0] == WLAN_EID_EXT_EHT_MULTI_LINK &&
|
||||
ieee80211_mle_type_ok(parent->data + 1,
|
||||
IEEE80211_ML_CONTROL_TYPE_BASIC,
|
||||
parent->datalen - 1) &&
|
||||
bssid_index == ieee80211_mle_get_mld_id(parent->data + 1)) {
|
||||
if (!cfg80211_copy_elem_with_frags(parent,
|
||||
ie, ielen,
|
||||
|
|
@ -3311,14 +3314,15 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
|
|||
bssid = ext->u.s1g_beacon.sa;
|
||||
capability = le16_to_cpu(compat->compat_info);
|
||||
beacon_interval = le16_to_cpu(compat->beacon_int);
|
||||
tsf = le32_to_cpu(ext->u.s1g_beacon.timestamp);
|
||||
tsf |= (u64)le32_to_cpu(compat->tsf_completion) << 32;
|
||||
} else {
|
||||
bssid = mgmt->bssid;
|
||||
beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
|
||||
capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
|
||||
tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
}
|
||||
|
||||
tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
|
||||
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control))
|
||||
ftype = CFG80211_BSS_FTYPE_PRESP;
|
||||
else if (ext)
|
||||
|
|
@ -3612,8 +3616,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
|||
/* translate "Scan for SSID" request */
|
||||
if (wreq) {
|
||||
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
|
||||
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
|
||||
return -EINVAL;
|
||||
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(creq->req.ssids[0].ssid, wreq->essid,
|
||||
wreq->essid_len);
|
||||
creq->req.ssids[0].ssid_len = wreq->essid_len;
|
||||
|
|
|
|||
|
|
@ -1578,13 +1578,11 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
|||
* Used to clean up after the connection / connection attempt owner socket
|
||||
* disconnects
|
||||
*/
|
||||
void cfg80211_autodisconnect_wk(struct work_struct *work)
|
||||
void cfg80211_autodisconnect_wk(struct wiphy *wiphy, struct wiphy_work *work)
|
||||
{
|
||||
struct wireless_dev *wdev =
|
||||
container_of(work, struct wireless_dev, disconnect_wk);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
||||
guard(wiphy)(wdev->wiphy);
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
|
||||
if (wdev->conn_owner_nlportid) {
|
||||
switch (wdev->iftype) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user