Commit 93124d4a authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-net-2021-06-09' of...

Merge tag 'mac80211-for-net-2021-06-09' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes berg says:

====================
A fair number of fixes:
 * fix more fallout from RTNL locking changes
 * fixes for some of the bugs found by syzbot
 * drop multicast fragments in mac80211 to align
   with the spec and what drivers are doing now
 * fix NULL-ptr deref in radiotap injection
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a8b897c7 a9799541
...@@ -1693,8 +1693,13 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw) ...@@ -1693,8 +1693,13 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)
static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
{ {
struct mac80211_hwsim_data *data = hw->priv; struct mac80211_hwsim_data *data = hw->priv;
data->started = false; data->started = false;
hrtimer_cancel(&data->beacon_timer); hrtimer_cancel(&data->beacon_timer);
while (!skb_queue_empty(&data->pending))
ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
wiphy_dbg(hw->wiphy, "%s\n", __func__); wiphy_dbg(hw->wiphy, "%s\n", __func__);
} }
......
...@@ -2284,7 +2284,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str ...@@ -2284,7 +2284,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str
mon_wdev->iftype = NL80211_IFTYPE_MONITOR; mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
mon_ndev->ieee80211_ptr = mon_wdev; mon_ndev->ieee80211_ptr = mon_wdev;
ret = register_netdevice(mon_ndev); ret = cfg80211_register_netdevice(mon_ndev);
if (ret) { if (ret) {
goto out; goto out;
} }
...@@ -2360,7 +2360,7 @@ static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy, ...@@ -2360,7 +2360,7 @@ static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
adapter = rtw_netdev_priv(ndev); adapter = rtw_netdev_priv(ndev);
pwdev_priv = adapter_wdev_data(adapter); pwdev_priv = adapter_wdev_data(adapter);
unregister_netdevice(ndev); cfg80211_unregister_netdevice(ndev);
if (ndev == pwdev_priv->pmon_ndev) { if (ndev == pwdev_priv->pmon_ndev) {
pwdev_priv->pmon_ndev = NULL; pwdev_priv->pmon_ndev = NULL;
......
...@@ -5537,7 +5537,7 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, ...@@ -5537,7 +5537,7 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
* *
* This function iterates over the interfaces associated with a given * This function iterates over the interfaces associated with a given
* hardware that are currently active and calls the callback for them. * hardware that are currently active and calls the callback for them.
* This version can only be used while holding the RTNL. * This version can only be used while holding the wiphy mutex.
* *
* @hw: the hardware struct of which the interfaces should be iterated over * @hw: the hardware struct of which the interfaces should be iterated over
* @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
...@@ -6392,7 +6392,12 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, ...@@ -6392,7 +6392,12 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
/** /**
* ieee80211_parse_tx_radiotap - Sanity-check and parse the radiotap header * ieee80211_parse_tx_radiotap - Sanity-check and parse the radiotap header
* of injected frames * of injected frames.
*
* To accurately parse and take into account rate and retransmission fields,
* you must initialize the chandef field in the ieee80211_tx_info structure
* of the skb before calling this function.
*
* @skb: packet injected by userspace * @skb: packet injected by userspace
* @dev: the &struct device of this 802.11 device * @dev: the &struct device of this 802.11 device
*/ */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2018 - 2019 Intel Corporation * Copyright (C) 2018 - 2019, 2021 Intel Corporation
*/ */
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -387,10 +387,17 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, ...@@ -387,10 +387,17 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ieee80211_local *local = file->private_data; struct ieee80211_local *local = file->private_data;
int ret;
rtnl_lock(); rtnl_lock();
wiphy_lock(local->hw.wiphy);
__ieee80211_suspend(&local->hw, NULL); __ieee80211_suspend(&local->hw, NULL);
__ieee80211_resume(&local->hw); ret = __ieee80211_resume(&local->hw);
wiphy_unlock(local->hw.wiphy);
if (ret)
cfg80211_shutdown_all_interfaces(local->hw.wiphy);
rtnl_unlock(); rtnl_unlock();
return count; return count;
......
...@@ -1442,7 +1442,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) ...@@ -1442,7 +1442,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
rcu_read_lock(); rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON_ONCE(!chanctx_conf)) { if (!chanctx_conf) {
rcu_read_unlock(); rcu_read_unlock();
return NULL; return NULL;
} }
......
...@@ -476,14 +476,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do ...@@ -476,14 +476,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
GFP_KERNEL); GFP_KERNEL);
} }
/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) { if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
WARN_ON(!list_empty(&sdata->u.ap.vlans)); WARN_ON(!list_empty(&sdata->u.ap.vlans));
} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
/* remove all packets in parent bc_buf pointing to this dev */ /* remove all packets in parent bc_buf pointing to this dev */
...@@ -641,6 +634,15 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -641,6 +634,15 @@ static int ieee80211_stop(struct net_device *dev)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
/* close all dependent VLAN interfaces before locking wiphy */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
u.vlan.list)
dev_close(vlan->dev);
}
wiphy_lock(sdata->local->hw.wiphy); wiphy_lock(sdata->local->hw.wiphy);
ieee80211_do_stop(sdata, true); ieee80211_do_stop(sdata, true);
wiphy_unlock(sdata->local->hw.wiphy); wiphy_unlock(sdata->local->hw.wiphy);
...@@ -1591,6 +1593,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, ...@@ -1591,6 +1593,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
if (!list_empty(&sdata->u.ap.vlans))
return -EBUSY;
break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_OCB:
......
...@@ -252,6 +252,7 @@ static void ieee80211_restart_work(struct work_struct *work) ...@@ -252,6 +252,7 @@ static void ieee80211_restart_work(struct work_struct *work)
struct ieee80211_local *local = struct ieee80211_local *local =
container_of(work, struct ieee80211_local, restart_work); container_of(work, struct ieee80211_local, restart_work);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int ret;
/* wait for scan work complete */ /* wait for scan work complete */
flush_workqueue(local->workqueue); flush_workqueue(local->workqueue);
...@@ -301,8 +302,12 @@ static void ieee80211_restart_work(struct work_struct *work) ...@@ -301,8 +302,12 @@ static void ieee80211_restart_work(struct work_struct *work)
/* wait for all packet processing to be done */ /* wait for all packet processing to be done */
synchronize_net(); synchronize_net();
ieee80211_reconfig(local); ret = ieee80211_reconfig(local);
wiphy_unlock(local->hw.wiphy); wiphy_unlock(local->hw.wiphy);
if (ret)
cfg80211_shutdown_all_interfaces(local->hw.wiphy);
rtnl_unlock(); rtnl_unlock();
} }
......
...@@ -2240,17 +2240,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) ...@@ -2240,17 +2240,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
sc = le16_to_cpu(hdr->seq_ctrl); sc = le16_to_cpu(hdr->seq_ctrl);
frag = sc & IEEE80211_SCTL_FRAG; frag = sc & IEEE80211_SCTL_FRAG;
if (is_multicast_ether_addr(hdr->addr1)) {
I802_DEBUG_INC(rx->local->dot11MulticastReceivedFrameCount);
goto out_no_led;
}
if (rx->sta) if (rx->sta)
cache = &rx->sta->frags; cache = &rx->sta->frags;
if (likely(!ieee80211_has_morefrags(fc) && frag == 0)) if (likely(!ieee80211_has_morefrags(fc) && frag == 0))
goto out; goto out;
if (is_multicast_ether_addr(hdr->addr1))
return RX_DROP_MONITOR;
I802_DEBUG_INC(rx->local->rx_handlers_fragments); I802_DEBUG_INC(rx->local->rx_handlers_fragments);
if (skb_linearize(rx->skb)) if (skb_linearize(rx->skb))
...@@ -2376,7 +2374,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) ...@@ -2376,7 +2374,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
out: out:
ieee80211_led_rx(rx->local); ieee80211_led_rx(rx->local);
out_no_led:
if (rx->sta) if (rx->sta)
rx->sta->rx_stats.packets++; rx->sta->rx_stats.packets++;
return RX_CONTINUE; return RX_CONTINUE;
......
...@@ -251,13 +251,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) ...@@ -251,13 +251,24 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
size_t min_hdr_len = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { if (!ieee80211_is_probe_resp(mgmt->frame_control) &&
if (skb->len < 15) !ieee80211_is_beacon(mgmt->frame_control) &&
!ieee80211_is_s1g_beacon(mgmt->frame_control))
return; return;
} else if (skb->len < 24 ||
(!ieee80211_is_probe_resp(mgmt->frame_control) && if (ieee80211_is_s1g_beacon(mgmt->frame_control)) {
!ieee80211_is_beacon(mgmt->frame_control))) if (ieee80211_is_s1g_short_beacon(mgmt->frame_control))
min_hdr_len = offsetof(struct ieee80211_ext,
u.s1g_short_beacon.variable);
else
min_hdr_len = offsetof(struct ieee80211_ext,
u.s1g_beacon);
}
if (skb->len < min_hdr_len)
return; return;
sdata1 = rcu_dereference(local->scan_sdata); sdata1 = rcu_dereference(local->scan_sdata);
......
...@@ -2014,6 +2014,26 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, ...@@ -2014,6 +2014,26 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
ieee80211_tx(sdata, sta, skb, false); ieee80211_tx(sdata, sta, skb, false);
} }
static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
{
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *)skb->data;
/* check for not even having the fixed radiotap header part */
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
return false; /* too short to be possibly valid */
/* is it a header version we can trust to find length from? */
if (unlikely(rthdr->it_version))
return false; /* only version 0 is supported */
/* does the skb contain enough to deliver on the alleged length? */
if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
return false; /* skb too short for claimed rt header extent */
return true;
}
bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
...@@ -2022,8 +2042,6 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, ...@@ -2022,8 +2042,6 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
struct ieee80211_radiotap_header *rthdr = struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data; (struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[info->band];
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL); NULL);
u16 txflags; u16 txflags;
...@@ -2036,17 +2054,8 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, ...@@ -2036,17 +2054,8 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
u8 vht_mcs = 0, vht_nss = 0; u8 vht_mcs = 0, vht_nss = 0;
int i; int i;
/* check for not even having the fixed radiotap header part */ if (!ieee80211_validate_radiotap_len(skb))
if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) return false;
return false; /* too short to be possibly valid */
/* is it a header version we can trust to find length from? */
if (unlikely(rthdr->it_version))
return false; /* only version 0 is supported */
/* does the skb contain enough to deliver on the alleged length? */
if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
return false; /* skb too short for claimed rt header extent */
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_DONTFRAG; IEEE80211_TX_CTL_DONTFRAG;
...@@ -2186,6 +2195,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, ...@@ -2186,6 +2195,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
return false; return false;
if (rate_found) { if (rate_found) {
struct ieee80211_supported_band *sband =
local->hw.wiphy->bands[info->band];
info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
...@@ -2199,7 +2211,7 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, ...@@ -2199,7 +2211,7 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
} else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) { } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
ieee80211_rate_set_vht(info->control.rates, vht_mcs, ieee80211_rate_set_vht(info->control.rates, vht_mcs,
vht_nss); vht_nss);
} else { } else if (sband) {
for (i = 0; i < sband->n_bitrates; i++) { for (i = 0; i < sband->n_bitrates; i++) {
if (rate * 5 != sband->bitrates[i].bitrate) if (rate * 5 != sband->bitrates[i].bitrate)
continue; continue;
...@@ -2236,8 +2248,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, ...@@ -2236,8 +2248,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_CTL_INJECTED; IEEE80211_TX_CTL_INJECTED;
/* Sanity-check and process the injection radiotap header */ /* Sanity-check the length of the radiotap header */
if (!ieee80211_parse_tx_radiotap(skb, dev)) if (!ieee80211_validate_radiotap_len(skb))
goto fail; goto fail;
/* we now know there is a radiotap header with a length we can use */ /* we now know there is a radiotap header with a length we can use */
...@@ -2351,6 +2363,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, ...@@ -2351,6 +2363,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
ieee80211_select_queue_80211(sdata, skb, hdr); ieee80211_select_queue_80211(sdata, skb, hdr);
skb_set_queue_mapping(skb, ieee80211_ac_from_tid(skb->priority)); skb_set_queue_mapping(skb, ieee80211_ac_from_tid(skb->priority));
/*
* Process the radiotap header. This will now take into account the
* selected chandef above to accurately set injection rates and
* retransmissions.
*/
if (!ieee80211_parse_tx_radiotap(skb, dev))
goto fail_rcu;
/* remove the injection radiotap header */ /* remove the injection radiotap header */
skb_pull(skb, len_rthdr); skb_pull(skb, len_rthdr);
......
...@@ -2178,8 +2178,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) ...@@ -2178,8 +2178,6 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
list_for_each_entry(ctx, &local->chanctx_list, list) list_for_each_entry(ctx, &local->chanctx_list, list)
ctx->driver_present = false; ctx->driver_present = false;
mutex_unlock(&local->chanctx_mtx); mutex_unlock(&local->chanctx_mtx);
cfg80211_shutdown_all_interfaces(local->hw.wiphy);
} }
static void ieee80211_assign_chanctx(struct ieee80211_local *local, static void ieee80211_assign_chanctx(struct ieee80211_local *local,
......
...@@ -1340,6 +1340,11 @@ void cfg80211_register_wdev(struct cfg80211_registered_device *rdev, ...@@ -1340,6 +1340,11 @@ void cfg80211_register_wdev(struct cfg80211_registered_device *rdev,
rdev->devlist_generation++; rdev->devlist_generation++;
wdev->registered = true; wdev->registered = true;
if (wdev->netdev &&
sysfs_create_link(&wdev->netdev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211"))
pr_err("failed to add phy80211 symlink to netdev!\n");
nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
} }
...@@ -1365,14 +1370,6 @@ int cfg80211_register_netdevice(struct net_device *dev) ...@@ -1365,14 +1370,6 @@ int cfg80211_register_netdevice(struct net_device *dev)
if (ret) if (ret)
goto out; goto out;
if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
"phy80211")) {
pr_err("failed to add phy80211 symlink to netdev!\n");
unregister_netdevice(dev);
ret = -EINVAL;
goto out;
}
cfg80211_register_wdev(rdev, wdev); cfg80211_register_wdev(rdev, wdev);
ret = 0; ret = 0;
out: out:
......
...@@ -133,6 +133,10 @@ static int wiphy_resume(struct device *dev) ...@@ -133,6 +133,10 @@ static int wiphy_resume(struct device *dev)
if (rdev->wiphy.registered && rdev->ops->resume) if (rdev->wiphy.registered && rdev->ops->resume)
ret = rdev_resume(rdev); ret = rdev_resume(rdev);
wiphy_unlock(&rdev->wiphy); wiphy_unlock(&rdev->wiphy);
if (ret)
cfg80211_shutdown_all_interfaces(&rdev->wiphy);
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
......
...@@ -1059,6 +1059,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ...@@ -1059,6 +1059,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
/* mesh should be handled? */ /* mesh should be handled? */
break; break;
case NL80211_IFTYPE_OCB:
cfg80211_leave_ocb(rdev, dev);
break;
default: default:
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment