Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Conflicts:
	drivers/net/wireless/iwmc3200wifi/cfg80211.c
	drivers/net/wireless/mwifiex/cfg80211.c
This commit is contained in:
John W. Linville 2012-07-12 15:21:05 -04:00
commit d07d152892
44 changed files with 693 additions and 514 deletions

View File

@ -404,7 +404,6 @@
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k !Finclude/net/mac80211.h ieee80211_get_tkip_p1k
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv !Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv
!Finclude/net/mac80211.h ieee80211_get_tkip_p2k !Finclude/net/mac80211.h ieee80211_get_tkip_p2k
!Finclude/net/mac80211.h ieee80211_key_removed
</chapter> </chapter>
<chapter id="powersave"> <chapter id="powersave">

View File

@ -966,11 +966,11 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar,
return 0; return 0;
} }
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct ath6kl *ar = ath6kl_priv(ndev); struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev);
struct ath6kl_vif *vif = netdev_priv(ndev); struct ath6kl *ar = ath6kl_priv(vif->ndev);
s8 n_channels = 0; s8 n_channels = 0;
u16 *channels = NULL; u16 *channels = NULL;
int ret = 0; int ret = 0;
@ -1487,14 +1487,14 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
return 0; return 0;
} }
static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
char *name, char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
u32 *flags, u32 *flags,
struct vif_params *params) struct vif_params *params)
{ {
struct ath6kl *ar = wiphy_priv(wiphy); struct ath6kl *ar = wiphy_priv(wiphy);
struct net_device *ndev; struct wireless_dev *wdev;
u8 if_idx, nw_type; u8 if_idx, nw_type;
if (ar->num_vif == ar->vif_max) { if (ar->num_vif == ar->vif_max) {
@ -1507,20 +1507,20 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
if (!ndev) if (!wdev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ar->num_vif++; ar->num_vif++;
return ndev; return wdev;
} }
static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
struct net_device *ndev) struct wireless_dev *wdev)
{ {
struct ath6kl *ar = wiphy_priv(wiphy); struct ath6kl *ar = wiphy_priv(wiphy);
struct ath6kl_vif *vif = netdev_priv(ndev); struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
spin_lock_bh(&ar->list_lock); spin_lock_bh(&ar->list_lock);
list_del(&vif->list); list_del(&vif->list);
@ -2975,14 +2975,14 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
} }
static int ath6kl_remain_on_channel(struct wiphy *wiphy, static int ath6kl_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, unsigned int duration,
u64 *cookie) u64 *cookie)
{ {
struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl *ar = ath6kl_priv(vif->ndev);
u32 id; u32 id;
/* TODO: if already pending or ongoing remain-on-channel, /* TODO: if already pending or ongoing remain-on-channel,
@ -2999,11 +2999,11 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy,
} }
static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u64 cookie) u64 cookie)
{ {
struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl *ar = ath6kl_priv(vif->ndev);
if (cookie != vif->last_roc_id) if (cookie != vif->last_roc_id)
return -ENOENT; return -ENOENT;
@ -3134,15 +3134,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
return false; return false;
} }
static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie) bool dont_wait_for_ack, u64 *cookie)
{ {
struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl *ar = ath6kl_priv(vif->ndev);
u32 id; u32 id;
const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt;
bool more_data, queued; bool more_data, queued;
@ -3187,10 +3187,10 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
} }
static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u16 frame_type, bool reg) u16 frame_type, bool reg)
{ {
struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n",
__func__, frame_type, reg); __func__, frame_type, reg);
@ -3477,9 +3477,9 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
ar->num_vif--; ar->num_vif--;
} }
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
enum nl80211_iftype type, u8 fw_vif_idx, enum nl80211_iftype type,
u8 nw_type) u8 fw_vif_idx, u8 nw_type)
{ {
struct net_device *ndev; struct net_device *ndev;
struct ath6kl_vif *vif; struct ath6kl_vif *vif;
@ -3533,7 +3533,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
list_add_tail(&vif->list, &ar->vif_list); list_add_tail(&vif->list, &ar->vif_list);
spin_unlock_bh(&ar->list_lock); spin_unlock_bh(&ar->list_lock);
return ndev; return &vif->wdev;
err: err:
aggr_module_destroy(vif->aggr_cntxt); aggr_module_destroy(vif->aggr_cntxt);

View File

@ -25,9 +25,9 @@ enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_SCHED_SCAN, ATH6KL_CFG_SUSPEND_SCHED_SCAN,
}; };
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type); u8 fw_vif_idx, u8 nw_type);
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode); enum wmi_phy_mode mode);
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);

View File

@ -56,7 +56,7 @@ EXPORT_SYMBOL(ath6kl_core_rx_complete);
int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
{ {
struct ath6kl_bmi_target_info targ_info; struct ath6kl_bmi_target_info targ_info;
struct net_device *ndev; struct wireless_dev *wdev;
int ret = 0, i; int ret = 0, i;
switch (htc_type) { switch (htc_type) {
@ -187,12 +187,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
rtnl_lock(); rtnl_lock();
/* Add an initial station interface */ /* Add an initial station interface */
ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, wdev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0,
INFRA_NETWORK); INFRA_NETWORK);
rtnl_unlock(); rtnl_unlock();
if (!ndev) { if (!wdev) {
ath6kl_err("Failed to instantiate a network device\n"); ath6kl_err("Failed to instantiate a network device\n");
ret = -ENOMEM; ret = -ENOMEM;
wiphy_unregister(ar->wiphy); wiphy_unregister(ar->wiphy);
@ -200,7 +200,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
} }
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
__func__, ndev->name, ndev, ar); __func__, wdev->netdev->name, wdev->netdev, ar);
return ret; return ret;

View File

@ -589,6 +589,11 @@ struct ath6kl_vif {
struct list_head mc_filter; struct list_head mc_filter;
}; };
static inline struct ath6kl_vif *ath6kl_vif_from_wdev(struct wireless_dev *wdev)
{
return container_of(wdev, struct ath6kl_vif, wdev);
}
#define WOW_LIST_ID 0 #define WOW_LIST_ID 0
#define WOW_HOST_REQ_DELAY 500 /* ms */ #define WOW_HOST_REQ_DELAY 500 /* ms */

View File

@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
return -EINVAL; return -EINVAL;
} }
id = vif->last_roc_id; id = vif->last_roc_id;
cfg80211_ready_on_channel(vif->ndev, id, chan, NL80211_CHAN_NO_HT, cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT,
dur, GFP_ATOMIC); dur, GFP_ATOMIC);
return 0; return 0;
@ -513,7 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
else else
id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
vif->last_cancel_roc_id = 0; vif->last_cancel_roc_id = 0;
cfg80211_remain_on_channel_expired(vif->ndev, id, chan, cfg80211_remain_on_channel_expired(&vif->wdev, id, chan,
NL80211_CHAN_NO_HT, GFP_ATOMIC); NL80211_CHAN_NO_HT, GFP_ATOMIC);
return 0; return 0;
@ -533,7 +533,7 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,
ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",
id, ev->ack_status); id, ev->ack_status);
if (wmi->last_mgmt_tx_frame) { if (wmi->last_mgmt_tx_frame) {
cfg80211_mgmt_tx_status(vif->ndev, id, cfg80211_mgmt_tx_status(&vif->wdev, id,
wmi->last_mgmt_tx_frame, wmi->last_mgmt_tx_frame,
wmi->last_mgmt_tx_frame_len, wmi->last_mgmt_tx_frame_len,
!!ev->ack_status, GFP_ATOMIC); !!ev->ack_status, GFP_ATOMIC);
@ -568,7 +568,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
dlen, freq, vif->probe_req_report); dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK) if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
cfg80211_rx_mgmt(vif->ndev, freq, 0, cfg80211_rx_mgmt(&vif->wdev, freq, 0,
ev->data, dlen, GFP_ATOMIC); ev->data, dlen, GFP_ATOMIC);
return 0; return 0;
@ -608,7 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL; return -EINVAL;
} }
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
cfg80211_rx_mgmt(vif->ndev, freq, 0, cfg80211_rx_mgmt(&vif->wdev, freq, 0,
ev->data, dlen, GFP_ATOMIC); ev->data, dlen, GFP_ATOMIC);
return 0; return 0;

View File

@ -691,9 +691,10 @@ scan_out:
} }
static s32 static s32
brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, brcmf_cfg80211_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct net_device *ndev = request->wdev->netdev;
s32 err = 0; s32 err = 0;
WL_TRACE("Enter\n"); WL_TRACE("Enter\n");

View File

@ -5359,7 +5359,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changes & BSS_CHANGED_ASSOC) { if (changes & BSS_CHANGED_ASSOC) {
D_MAC80211("ASSOC %d\n", bss_conf->assoc); D_MAC80211("ASSOC %d\n", bss_conf->assoc);
if (bss_conf->assoc) { if (bss_conf->assoc) {
il->timestamp = bss_conf->last_tsf; il->timestamp = bss_conf->sync_tsf;
if (!il_is_rfkill(il)) if (!il_is_rfkill(il))
il->ops->post_associate(il); il->ops->post_associate(il);

View File

@ -1447,7 +1447,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
if (changes & BSS_CHANGED_ASSOC) { if (changes & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) { if (bss_conf->assoc) {
priv->timestamp = bss_conf->last_tsf; priv->timestamp = bss_conf->sync_tsf;
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
} else { } else {
/* /*

View File

@ -805,7 +805,6 @@ void lbs_scan_done(struct lbs_private *priv)
} }
static int lbs_cfg_scan(struct wiphy *wiphy, static int lbs_cfg_scan(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct lbs_private *priv = wiphy_priv(wiphy); struct lbs_private *priv = wiphy_priv(wiphy);

View File

@ -1440,9 +1440,10 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
* it also informs the results. * it also informs the results.
*/ */
static int static int
mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, mwifiex_cfg80211_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct net_device *dev = request->wdev->netdev;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
int i; int i;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
@ -1576,11 +1577,11 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
/* /*
* create a new virtual interface with the given name * create a new virtual interface with the given name
*/ */
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
char *name, char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
u32 *flags, u32 *flags,
struct vif_params *params) struct vif_params *params)
{ {
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv; struct mwifiex_private *priv;
@ -1701,16 +1702,16 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_init(priv); mwifiex_dev_debugfs_init(priv);
#endif #endif
return dev; return wdev;
} }
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
/* /*
* del_virtual_intf: remove the virtual interface determined by dev * del_virtual_intf: remove the virtual interface determined by dev
*/ */
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv); mwifiex_dev_debugfs_remove(priv);
@ -1722,11 +1723,11 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev)
if (netif_carrier_ok(priv->netdev)) if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev); netif_carrier_off(priv->netdev);
if (dev->reg_state == NETREG_REGISTERED) if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(dev); unregister_netdevice(wdev->netdev);
if (dev->reg_state == NETREG_UNREGISTERED) if (wdev->netdev->reg_state == NETREG_UNREGISTERED)
free_netdev(dev); free_netdev(wdev->netdev);
/* Clear the priv in adapter */ /* Clear the priv in adapter */
priv->netdev = NULL; priv->netdev = NULL;

View File

@ -377,7 +377,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done; goto done;
err_add_intf: err_add_intf:
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
rtnl_unlock(); rtnl_unlock();
err_init_fw: err_init_fw:
pr_debug("info: %s: unregister device\n", __func__); pr_debug("info: %s: unregister device\n", __func__);
@ -844,7 +844,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
rtnl_lock(); rtnl_lock();
if (priv->wdev && priv->netdev) if (priv->wdev && priv->netdev)
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
rtnl_unlock(); rtnl_unlock();
} }

View File

@ -1005,10 +1005,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
int mwifiex_check_network_compatibility(struct mwifiex_private *priv, int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc); struct mwifiex_bssdescriptor *bss_desc);
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
char *name, enum nl80211_iftype type, char *name,
u32 *flags, struct vif_params *params); enum nl80211_iftype type,
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); u32 *flags,
struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config); void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);

View File

@ -138,7 +138,7 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
return err; return err;
} }
static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, static int orinoco_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct orinoco_private *priv = wiphy_priv(wiphy); struct orinoco_private *priv = wiphy_priv(wiphy);

View File

@ -484,7 +484,7 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
struct vif_params *params); struct vif_params *params);
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static int rndis_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request); struct cfg80211_scan_request *request);
static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
@ -1941,9 +1941,10 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
} }
#define SCAN_DELAY_JIFFIES (6 * HZ) #define SCAN_DELAY_JIFFIES (6 * HZ)
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, static int rndis_scan(struct wiphy *wiphy,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct net_device *dev = request->wdev->netdev;
struct usbnet *usbdev = netdev_priv(dev); struct usbnet *usbdev = netdev_priv(dev);
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int ret; int ret;

View File

@ -102,7 +102,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
/* Update the AID, this is needed for dynamic PS support */ /* Update the AID, this is needed for dynamic PS support */
rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0;
rt2x00dev->last_beacon = bss_conf->last_tsf; rt2x00dev->last_beacon = bss_conf->sync_tsf;
/* Update global beacon interval time, this is needed for PS support */ /* Update global beacon interval time, this is needed for PS support */
rt2x00dev->beacon_int = bss_conf->beacon_int; rt2x00dev->beacon_int = bss_conf->beacon_int;

View File

@ -771,6 +771,9 @@ enum nl80211_commands {
* @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
* *
* @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices
* that don't have a netdev (u64)
*
* @NL80211_ATTR_MAC: MAC address (various uses) * @NL80211_ATTR_MAC: MAC address (various uses)
* *
* @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
@ -1493,6 +1496,8 @@ enum nl80211_attrs {
NL80211_ATTR_BG_SCAN_PERIOD, NL80211_ATTR_BG_SCAN_PERIOD,
NL80211_ATTR_WDEV,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,

View File

@ -999,7 +999,7 @@ struct cfg80211_ssid {
* @ie_len: length of ie in octets * @ie_len: length of ie in octets
* @rates: bitmap of rates to advertise for each band * @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for * @wiphy: the wiphy this was for
* @dev: the interface * @wdev: the wireless device to scan for
* @aborted: (internal) scan request was notified as aborted * @aborted: (internal) scan request was notified as aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band * @no_cck: used to send probe requests at non CCK rate in 2GHz band
*/ */
@ -1012,9 +1012,10 @@ struct cfg80211_scan_request {
u32 rates[IEEE80211_NUM_BANDS]; u32 rates[IEEE80211_NUM_BANDS];
struct wireless_dev *wdev;
/* internal */ /* internal */
struct wiphy *wiphy; struct wiphy *wiphy;
struct net_device *dev;
bool aborted; bool aborted;
bool no_cck; bool no_cck;
@ -1435,10 +1436,10 @@ struct cfg80211_gtk_rekey_data {
* *
* @add_virtual_intf: create a new virtual interface with the given name, * @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype. Beware: You must create * must set the struct wireless_dev's iftype. Beware: You must create
* the new netdev in the wiphy's network namespace! Returns the netdev, * the new netdev in the wiphy's network namespace! Returns the struct
* or an ERR_PTR. * wireless_dev, or an ERR_PTR.
* *
* @del_virtual_intf: remove the virtual interface determined by ifindex. * @del_virtual_intf: remove the virtual interface
* *
* @change_virtual_intf: change type/configuration of virtual interface, * @change_virtual_intf: change type/configuration of virtual interface,
* keep the struct wireless_dev's iftype updated. * keep the struct wireless_dev's iftype updated.
@ -1617,12 +1618,13 @@ struct cfg80211_ops {
int (*resume)(struct wiphy *wiphy); int (*resume)(struct wiphy *wiphy);
void (*set_wakeup)(struct wiphy *wiphy, bool enabled); void (*set_wakeup)(struct wiphy *wiphy, bool enabled);
struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
char *name, char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
u32 *flags, u32 *flags,
struct vif_params *params); struct vif_params *params);
int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); int (*del_virtual_intf)(struct wiphy *wiphy,
struct wireless_dev *wdev);
int (*change_virtual_intf)(struct wiphy *wiphy, int (*change_virtual_intf)(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
enum nl80211_iftype type, u32 *flags, enum nl80211_iftype type, u32 *flags,
@ -1699,7 +1701,7 @@ struct cfg80211_ops {
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type); enum nl80211_channel_type channel_type);
int (*scan)(struct wiphy *wiphy, struct net_device *dev, int (*scan)(struct wiphy *wiphy,
struct cfg80211_scan_request *request); struct cfg80211_scan_request *request);
int (*auth)(struct wiphy *wiphy, struct net_device *dev, int (*auth)(struct wiphy *wiphy, struct net_device *dev,
@ -1753,23 +1755,23 @@ struct cfg80211_ops {
int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);
int (*remain_on_channel)(struct wiphy *wiphy, int (*remain_on_channel)(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, unsigned int duration,
u64 *cookie); u64 *cookie);
int (*cancel_remain_on_channel)(struct wiphy *wiphy, int (*cancel_remain_on_channel)(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u64 cookie); u64 cookie);
int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev, int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie); bool dont_wait_for_ack, u64 *cookie);
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u64 cookie); u64 cookie);
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
@ -1780,7 +1782,7 @@ struct cfg80211_ops {
s32 rssi_thold, u32 rssi_hyst); s32 rssi_thold, u32 rssi_hyst);
void (*mgmt_frame_register)(struct wiphy *wiphy, void (*mgmt_frame_register)(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u16 frame_type, bool reg); u16 frame_type, bool reg);
int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
@ -2341,17 +2343,25 @@ struct cfg80211_internal_bss;
struct cfg80211_cached_keys; struct cfg80211_cached_keys;
/** /**
* struct wireless_dev - wireless per-netdev state * struct wireless_dev - wireless device state
* *
* This structure must be allocated by the driver/stack * For netdevs, this structure must be allocated by the driver
* that uses the ieee80211_ptr field in struct net_device * that uses the ieee80211_ptr field in struct net_device (this
* (this is intentional so it can be allocated along with * is intentional so it can be allocated along with the netdev.)
* the netdev.) * It need not be registered then as netdev registration will
* be intercepted by cfg80211 to see the new wireless device.
*
* For non-netdev uses, it must also be allocated by the driver
* in response to the cfg80211 callbacks that require it, as
* there's no netdev registration in that case it may not be
* allocated outside of callback operations that return it.
* *
* @wiphy: pointer to hardware description * @wiphy: pointer to hardware description
* @iftype: interface type * @iftype: interface type
* @list: (private) Used to collect the interfaces * @list: (private) Used to collect the interfaces
* @netdev: (private) Used to reference back to the netdev * @netdev: (private) Used to reference back to the netdev, may be %NULL
* @identifier: (private) Identifier used in nl80211 to identify this
* wireless device if it has no netdev
* @current_bss: (private) Used by the internal configuration code * @current_bss: (private) Used by the internal configuration code
* @channel: (private) Used by the internal configuration code to track * @channel: (private) Used by the internal configuration code to track
* the user-set AP, monitor and WDS channel * the user-set AP, monitor and WDS channel
@ -2383,6 +2393,8 @@ struct wireless_dev {
struct list_head list; struct list_head list;
struct net_device *netdev; struct net_device *netdev;
u32 identifier;
struct list_head mgmt_registrations; struct list_head mgmt_registrations;
spinlock_t mgmt_registrations_lock; spinlock_t mgmt_registrations_lock;
@ -3269,7 +3281,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
/** /**
* cfg80211_ready_on_channel - notification of remain_on_channel start * cfg80211_ready_on_channel - notification of remain_on_channel start
* @dev: network device * @wdev: wireless device
* @cookie: the request cookie * @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request) * @chan: The current channel (from remain_on_channel request)
* @channel_type: Channel type * @channel_type: Channel type
@ -3277,21 +3289,20 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
* channel * channel
* @gfp: allocation flags * @gfp: allocation flags
*/ */
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp); unsigned int duration, gfp_t gfp);
/** /**
* cfg80211_remain_on_channel_expired - remain_on_channel duration expired * cfg80211_remain_on_channel_expired - remain_on_channel duration expired
* @dev: network device * @wdev: wireless device
* @cookie: the request cookie * @cookie: the request cookie
* @chan: The current channel (from remain_on_channel request) * @chan: The current channel (from remain_on_channel request)
* @channel_type: Channel type * @channel_type: Channel type
* @gfp: allocation flags * @gfp: allocation flags
*/ */
void cfg80211_remain_on_channel_expired(struct net_device *dev, void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
gfp_t gfp); gfp_t gfp);
@ -3319,7 +3330,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
/** /**
* cfg80211_rx_mgmt - notification of received, unprocessed management frame * cfg80211_rx_mgmt - notification of received, unprocessed management frame
* @dev: network device * @wdev: wireless device receiving the frame
* @freq: Frequency on which the frame was received in MHz * @freq: Frequency on which the frame was received in MHz
* @sig_dbm: signal strength in mBm, or 0 if unknown * @sig_dbm: signal strength in mBm, or 0 if unknown
* @buf: Management frame (header + body) * @buf: Management frame (header + body)
@ -3334,12 +3345,12 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
* This function is called whenever an Action frame is received for a station * This function is called whenever an Action frame is received for a station
* mode interface, but is not processed in kernel. * mode interface, but is not processed in kernel.
*/ */
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp); const u8 *buf, size_t len, gfp_t gfp);
/** /**
* cfg80211_mgmt_tx_status - notification of TX status for management frame * cfg80211_mgmt_tx_status - notification of TX status for management frame
* @dev: network device * @wdev: wireless device receiving the frame
* @cookie: Cookie returned by cfg80211_ops::mgmt_tx() * @cookie: Cookie returned by cfg80211_ops::mgmt_tx()
* @buf: Management frame (header + body) * @buf: Management frame (header + body)
* @len: length of the frame data * @len: length of the frame data
@ -3350,7 +3361,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm,
* transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the
* transmission attempt. * transmission attempt.
*/ */
void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack, gfp_t gfp); const u8 *buf, size_t len, bool ack, gfp_t gfp);

View File

@ -233,8 +233,10 @@ enum ieee80211_rssi_event {
* valid in station mode only while @assoc is true and if also * valid in station mode only while @assoc is true and if also
* requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
* @ps_dtim_period) * @ps_dtim_period)
* @last_tsf: last beacon's/probe response's TSF timestamp (could be old * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
* as it may have been received during scanning long ago) * as it may have been received during scanning long ago)
* @sync_device_ts: the device timestamp corresponding to the sync_tsf,
* the driver/device can use this to calculate synchronisation
* @beacon_int: beacon interval * @beacon_int: beacon interval
* @assoc_capability: capabilities taken from assoc resp * @assoc_capability: capabilities taken from assoc resp
* @basic_rates: bitmap of basic rates, each bit stands for an * @basic_rates: bitmap of basic rates, each bit stands for an
@ -281,7 +283,8 @@ struct ieee80211_bss_conf {
u8 dtim_period; u8 dtim_period;
u16 beacon_int; u16 beacon_int;
u16 assoc_capability; u16 assoc_capability;
u64 last_tsf; u64 sync_tsf;
u32 sync_device_ts;
u32 basic_rates; u32 basic_rates;
int mcast_rate[IEEE80211_NUM_BANDS]; int mcast_rate[IEEE80211_NUM_BANDS];
u16 ht_operation_mode; u16 ht_operation_mode;
@ -696,6 +699,8 @@ enum mac80211_rx_flags {
* *
* @mactime: value in microseconds of the 64-bit Time Synchronization Function * @mactime: value in microseconds of the 64-bit Time Synchronization Function
* (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
* @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use
* it but can store it and pass it back to the driver for synchronisation
* @band: the active band when this frame was received * @band: the active band when this frame was received
* @freq: frequency the radio was tuned to when receiving this frame, in MHz * @freq: frequency the radio was tuned to when receiving this frame, in MHz
* @signal: signal strength when receiving this frame, either in dBm, in dB or * @signal: signal strength when receiving this frame, either in dBm, in dB or
@ -709,13 +714,14 @@ enum mac80211_rx_flags {
*/ */
struct ieee80211_rx_status { struct ieee80211_rx_status {
u64 mactime; u64 mactime;
enum ieee80211_band band; u32 device_timestamp;
int freq; u16 flag;
int signal; u16 freq;
int antenna; u8 rate_idx;
int rate_idx; u8 rx_flags;
int flag; u8 band;
unsigned int rx_flags; u8 antenna;
s8 signal;
}; };
/** /**
@ -3591,22 +3597,6 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
void ieee80211_request_smps(struct ieee80211_vif *vif, void ieee80211_request_smps(struct ieee80211_vif *vif,
enum ieee80211_smps_mode smps_mode); enum ieee80211_smps_mode smps_mode);
/**
* ieee80211_key_removed - disable hw acceleration for key
* @key_conf: The key hw acceleration should be disabled for
*
* This allows drivers to indicate that the given key has been
* removed from hardware acceleration, due to a new key that
* was added. Don't use this if the key can continue to be used
* for TX, if the key restriction is on RX only it is permitted
* to keep the key for TX only and not call this function.
*
* Due to locking constraints, it may only be called during
* @set_key. This function must be allowed to sleep, and the
* key it tries to disable may still be used until it returns.
*/
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf);
/** /**
* ieee80211_ready_on_channel - notification of remain-on-channel start * ieee80211_ready_on_channel - notification of remain-on-channel start
* @hw: pointer as obtained from ieee80211_alloc_hw() * @hw: pointer as obtained from ieee80211_alloc_hw()

View File

@ -135,7 +135,8 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
bar->control = cpu_to_le16(bar_control); bar->control = cpu_to_le16(bar_control);
bar->start_seq_num = cpu_to_le16(ssn); bar->start_seq_num = cpu_to_le16(ssn);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
IEEE80211_TX_CTL_REQ_TX_STATUS;
ieee80211_tx_skb_tid(sdata, skb, tid); ieee80211_tx_skb_tid(sdata, skb, tid);
} }
EXPORT_SYMBOL(ieee80211_send_bar); EXPORT_SYMBOL(ieee80211_send_bar);

View File

@ -20,31 +20,31 @@
#include "rate.h" #include "rate.h"
#include "mesh.h" #include "mesh.h"
static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name,
enum nl80211_iftype type, enum nl80211_iftype type,
u32 *flags, u32 *flags,
struct vif_params *params) struct vif_params *params)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev; struct wireless_dev *wdev;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int err; int err;
err = ieee80211_if_add(local, name, &dev, type, params); err = ieee80211_if_add(local, name, &wdev, type, params);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
if (type == NL80211_IFTYPE_MONITOR && flags) { if (type == NL80211_IFTYPE_MONITOR && flags) {
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
sdata->u.mntr_flags = *flags; sdata->u.mntr_flags = *flags;
} }
return dev; return wdev;
} }
static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
{ {
ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev));
return 0; return 0;
} }
@ -1741,6 +1741,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
} }
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
return 0; return 0;
} }
@ -1761,10 +1763,11 @@ static int ieee80211_resume(struct wiphy *wiphy)
#endif #endif
static int ieee80211_scan(struct wiphy *wiphy, static int ieee80211_scan(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_scan_request *req) struct cfg80211_scan_request *req)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata;
sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev);
switch (ieee80211_vif_type_p2p(&sdata->vif)) { switch (ieee80211_vif_type_p2p(&sdata->vif)) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
@ -2297,13 +2300,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
} }
static int ieee80211_remain_on_channel(struct wiphy *wiphy, static int ieee80211_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, unsigned int duration,
u64 *cookie) u64 *cookie)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int ret; int ret;
@ -2390,23 +2393,23 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
} }
static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u64 cookie) u64 cookie)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
return ieee80211_cancel_roc(local, cookie, false); return ieee80211_cancel_roc(local, cookie, false);
} }
static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie) bool dont_wait_for_ack, u64 *cookie)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
struct sta_info *sta; struct sta_info *sta;
@ -2511,21 +2514,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
} }
static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u64 cookie) u64 cookie)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_local *local = sdata->local;
return ieee80211_cancel_roc(local, cookie, true); return ieee80211_cancel_roc(local, cookie, true);
} }
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
struct net_device *dev, struct wireless_dev *wdev,
u16 frame_type, bool reg) u16 frame_type, bool reg)
{ {
struct ieee80211_local *local = wiphy_priv(wiphy); struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
switch (frame_type) { switch (frame_type) {
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH:

View File

@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
local->rx_handlers_drop_defrag); local->rx_handlers_drop_defrag);
DEBUGFS_STATS_ADD(rx_handlers_drop_short, DEBUGFS_STATS_ADD(rx_handlers_drop_short,
local->rx_handlers_drop_short); local->rx_handlers_drop_short);
DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
local->rx_handlers_drop_passive_scan);
DEBUGFS_STATS_ADD(tx_expand_skb_head, DEBUGFS_STATS_ADD(tx_expand_skb_head,
local->tx_expand_skb_head); local->tx_expand_skb_head);
DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,

View File

@ -85,6 +85,8 @@ struct ieee80211_bss {
size_t ssid_len; size_t ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid[IEEE80211_MAX_SSID_LEN];
u32 device_ts;
u8 dtim_period; u8 dtim_period;
bool wmm_used; bool wmm_used;
@ -207,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
* enum ieee80211_packet_rx_flags - packet RX flags * enum ieee80211_packet_rx_flags - packet RX flags
* @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
* (incl. multicast frames) * (incl. multicast frames)
* @IEEE80211_RX_IN_SCAN: received while scanning
* @IEEE80211_RX_FRAGMENTED: fragmented frame * @IEEE80211_RX_FRAGMENTED: fragmented frame
* @IEEE80211_RX_AMSDU: a-MSDU packet * @IEEE80211_RX_AMSDU: a-MSDU packet
* @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed
@ -217,7 +218,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
* @rx_flags field of &struct ieee80211_rx_status. * @rx_flags field of &struct ieee80211_rx_status.
*/ */
enum ieee80211_packet_rx_flags { enum ieee80211_packet_rx_flags {
IEEE80211_RX_IN_SCAN = BIT(0),
IEEE80211_RX_RA_MATCH = BIT(1), IEEE80211_RX_RA_MATCH = BIT(1),
IEEE80211_RX_FRAGMENTED = BIT(2), IEEE80211_RX_FRAGMENTED = BIT(2),
IEEE80211_RX_AMSDU = BIT(3), IEEE80211_RX_AMSDU = BIT(3),
@ -965,14 +965,14 @@ struct ieee80211_local {
int scan_channel_idx; int scan_channel_idx;
int scan_ies_len; int scan_ies_len;
bool sched_scanning;
struct ieee80211_sched_scan_ies sched_scan_ies; struct ieee80211_sched_scan_ies sched_scan_ies;
struct work_struct sched_scan_stopped_work; struct work_struct sched_scan_stopped_work;
struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
unsigned long leave_oper_channel_time; unsigned long leave_oper_channel_time;
enum mac80211_scan_state next_scan_state; enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work; struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata; struct ieee80211_sub_if_data __rcu *scan_sdata;
enum nl80211_channel_type _oper_channel_type; enum nl80211_channel_type _oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel; struct ieee80211_channel *oper_channel, *csa_channel;
@ -1014,7 +1014,6 @@ struct ieee80211_local {
unsigned int rx_handlers_drop_nullfunc; unsigned int rx_handlers_drop_nullfunc;
unsigned int rx_handlers_drop_defrag; unsigned int rx_handlers_drop_defrag;
unsigned int rx_handlers_drop_short; unsigned int rx_handlers_drop_short;
unsigned int rx_handlers_drop_passive_scan;
unsigned int tx_expand_skb_head; unsigned int tx_expand_skb_head;
unsigned int tx_expand_skb_head_cloned; unsigned int tx_expand_skb_head_cloned;
unsigned int rx_expand_skb_head; unsigned int rx_expand_skb_head;
@ -1091,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
return netdev_priv(dev); return netdev_priv(dev);
} }
static inline struct ieee80211_sub_if_data *
IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev)
{
return container_of(wdev, struct ieee80211_sub_if_data, wdev);
}
/* this struct represents 802.11n's RA/TID combination */ /* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid { struct ieee80211_ra_tid {
u8 ra[ETH_ALEN]; u8 ra[ETH_ALEN];
@ -1241,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req); struct cfg80211_scan_request *req);
void ieee80211_scan_cancel(struct ieee80211_local *local); void ieee80211_scan_cancel(struct ieee80211_local *local);
void ieee80211_run_deferred_scan(struct ieee80211_local *local); void ieee80211_run_deferred_scan(struct ieee80211_local *local);
ieee80211_rx_result void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb);
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
struct ieee80211_bss * struct ieee80211_bss *
@ -1278,7 +1282,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
int ieee80211_iface_init(void); int ieee80211_iface_init(void);
void ieee80211_iface_exit(void); void ieee80211_iface_exit(void);
int ieee80211_if_add(struct ieee80211_local *local, const char *name, int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, enum nl80211_iftype type, struct wireless_dev **new_wdev, enum nl80211_iftype type,
struct vif_params *params); struct vif_params *params);
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type); enum nl80211_iftype type);

View File

@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
} }
} }
if (local->scan_sdata && sdata = rcu_dereference_protected(local->scan_sdata,
!(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { lockdep_is_held(&local->mtx));
if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
scanning = true; scanning = true;
local->scan_sdata->vif.bss_conf.idle = false; sdata->vif.bss_conf.idle = false;
} }
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
@ -333,17 +334,21 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
int ieee80211_add_virtual_monitor(struct ieee80211_local *local) int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int ret; int ret = 0;
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return 0; return 0;
mutex_lock(&local->iflist_mtx);
if (local->monitor_sdata) if (local->monitor_sdata)
return 0; goto out_unlock;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
if (!sdata) if (!sdata) {
return -ENOMEM; ret = -ENOMEM;
goto out_unlock;
}
/* set up data */ /* set up data */
sdata->local = local; sdata->local = local;
@ -357,18 +362,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (WARN_ON(ret)) { if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */ /* ok .. stupid driver, it asked for this! */
kfree(sdata); kfree(sdata);
return ret; goto out_unlock;
} }
ret = ieee80211_check_queues(sdata); ret = ieee80211_check_queues(sdata);
if (ret) { if (ret) {
kfree(sdata); kfree(sdata);
return ret; goto out_unlock;
} }
rcu_assign_pointer(local->monitor_sdata, sdata); rcu_assign_pointer(local->monitor_sdata, sdata);
out_unlock:
return 0; mutex_unlock(&local->iflist_mtx);
return ret;
} }
void ieee80211_del_virtual_monitor(struct ieee80211_local *local) void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@ -378,10 +384,12 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return; return;
sdata = rtnl_dereference(local->monitor_sdata); mutex_lock(&local->iflist_mtx);
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (!sdata) if (!sdata)
return; goto out_unlock;
rcu_assign_pointer(local->monitor_sdata, NULL); rcu_assign_pointer(local->monitor_sdata, NULL);
synchronize_net(); synchronize_net();
@ -389,6 +397,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
kfree(sdata); kfree(sdata);
out_unlock:
mutex_unlock(&local->iflist_mtx);
} }
/* /*
@ -628,7 +638,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
clear_bit(SDATA_STATE_RUNNING, &sdata->state); clear_bit(SDATA_STATE_RUNNING, &sdata->state);
if (local->scan_sdata == sdata) if (rcu_access_pointer(local->scan_sdata) == sdata)
ieee80211_scan_cancel(local); ieee80211_scan_cancel(local);
/* /*
@ -1373,7 +1383,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
} }
int ieee80211_if_add(struct ieee80211_local *local, const char *name, int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, enum nl80211_iftype type, struct wireless_dev **new_wdev, enum nl80211_iftype type,
struct vif_params *params) struct vif_params *params)
{ {
struct net_device *ndev; struct net_device *ndev;
@ -1463,8 +1473,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
list_add_tail_rcu(&sdata->list, &local->interfaces); list_add_tail_rcu(&sdata->list, &local->interfaces);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
if (new_dev) if (new_wdev)
*new_dev = ndev; *new_wdev = &sdata->wdev;
return 0; return 0;

View File

@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
} }
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
{
struct ieee80211_key *key;
key = container_of(key_conf, struct ieee80211_key, conf);
might_sleep();
assert_key_lock(key->local);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
/*
* Flush TX path to avoid attempts to use this key
* after this function returns. Until then, drivers
* must be prepared to handle the key.
*/
synchronize_rcu();
}
EXPORT_SYMBOL_GPL(ieee80211_key_removed);
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
int idx, bool uni, bool multi) int idx, bool uni, bool multi)
{ {

View File

@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work)
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
local->sched_scanning, rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx)),
"%s called with hardware scan in progress\n", __func__); "%s called with hardware scan in progress\n", __func__);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);

View File

@ -1108,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
} }
/* MLME */ /* MLME */
static void ieee80211_sta_wmm_params(struct ieee80211_local *local, static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
u8 *wmm_param, size_t wmm_param_len) u8 *wmm_param, size_t wmm_param_len)
{ {
@ -1119,23 +1119,23 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
u8 *pos, uapsd_queues = 0; u8 *pos, uapsd_queues = 0;
if (!local->ops->conf_tx) if (!local->ops->conf_tx)
return; return false;
if (local->hw.queues < IEEE80211_NUM_ACS) if (local->hw.queues < IEEE80211_NUM_ACS)
return; return false;
if (!wmm_param) if (!wmm_param)
return; return false;
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return; return false;
if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
uapsd_queues = ifmgd->uapsd_queues; uapsd_queues = ifmgd->uapsd_queues;
count = wmm_param[6] & 0x0f; count = wmm_param[6] & 0x0f;
if (count == ifmgd->wmm_last_param_set) if (count == ifmgd->wmm_last_param_set)
return; return false;
ifmgd->wmm_last_param_set = count; ifmgd->wmm_last_param_set = count;
pos = wmm_param + 8; pos = wmm_param + 8;
@ -1202,6 +1202,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
/* enable WMM or activate new settings */ /* enable WMM or activate new settings */
sdata->vif.bss_conf.qos = true; sdata->vif.bss_conf.qos = true;
return true;
} }
static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
@ -1268,11 +1269,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
bss_info_changed |= BSS_CHANGED_ASSOC; bss_info_changed |= BSS_CHANGED_ASSOC;
/* set timing information */
bss_conf->beacon_int = cbss->beacon_interval;
bss_conf->last_tsf = cbss->tsf;
bss_info_changed |= BSS_CHANGED_BEACON_INT;
bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss_info_changed |= ieee80211_handle_bss_capability(sdata,
bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value); bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
@ -2435,14 +2431,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
ifmgd->aid); ifmgd->aid);
if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
true);
ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len);
}
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
if (directed_tim) { if (directed_tim) {
if (local->hw.conf.dynamic_ps_timeout > 0) { if (local->hw.conf.dynamic_ps_timeout > 0) {
@ -2473,6 +2461,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc = ncrc;
ifmgd->beacon_crc_valid = true; ifmgd->beacon_crc_valid = true;
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
true);
if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
elems.wmm_param_len))
changed |= BSS_CHANGED_QOS;
if (elems.erp_info && elems.erp_info_len >= 1) { if (elems.erp_info && elems.erp_info_len >= 1) {
erp_valid = true; erp_valid = true;
erp_value = elems.erp_info[0]; erp_value = elems.erp_info[0];
@ -2974,7 +2969,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
/* scan finished notification */ /* scan finished notification */
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata = local->scan_sdata; struct ieee80211_sub_if_data *sdata;
/* Restart STA timers */ /* Restart STA timers */
rcu_read_lock(); rcu_read_lock();
@ -3132,9 +3127,15 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN);
/* tell driver about BSSID and basic rates */ /* set timing information */
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
sdata->vif.bss_conf.sync_tsf = cbss->tsf;
sdata->vif.bss_conf.sync_device_ts = bss->device_ts;
/* tell driver about BSSID, basic rates and timing */
ieee80211_bss_info_change_notify(sdata, ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
BSS_CHANGED_BEACON_INT);
if (assoc) if (assoc)
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);

View File

@ -191,7 +191,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
roc->frame = NULL; roc->frame = NULL;
} }
} else { } else {
cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc, cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc,
roc->chan, roc->chan_type, roc->chan, roc->chan_type,
roc->req_duration, GFP_KERNEL); roc->req_duration, GFP_KERNEL);
} }
@ -299,7 +299,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
/* was never transmitted */ /* was never transmitted */
if (roc->frame) { if (roc->frame) {
cfg80211_mgmt_tx_status(roc->sdata->dev, cfg80211_mgmt_tx_status(&roc->sdata->wdev,
(unsigned long)roc->frame, (unsigned long)roc->frame,
roc->frame->data, roc->frame->len, roc->frame->data, roc->frame->len,
false, GFP_KERNEL); false, GFP_KERNEL);
@ -307,7 +307,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
} }
if (!roc->mgmt_tx_cookie) if (!roc->mgmt_tx_cookie)
cfg80211_remain_on_channel_expired(roc->sdata->dev, cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
(unsigned long)roc, (unsigned long)roc,
roc->chan, roc->chan_type, roc->chan, roc->chan_type,
GFP_KERNEL); GFP_KERNEL);

View File

@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
/* use fixed index if set */ /* use fixed index if set */
if (mp->fixed_rate_idx != -1) if (mp->fixed_rate_idx != -1) {
sample_idx = mp->fixed_rate_idx; mi->max_tp_rate = mp->fixed_rate_idx;
mi->max_tp_rate2 = mp->fixed_rate_idx;
mi->max_prob_rate = mp->fixed_rate_idx;
sample_idx = -1;
}
#endif #endif
if (sample_idx >= 0) { if (sample_idx >= 0) {

View File

@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
/* rx handlers */ /* rx handlers */
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
struct sk_buff *skb = rx->skb;
if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
!local->sched_scanning))
return RX_CONTINUE;
if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
test_bit(SCAN_SW_SCANNING, &local->scanning) ||
test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
local->sched_scanning)
return ieee80211_scan_rx(rx->sdata, skb);
/* scanning finished during invoking of handlers */
I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
return RX_DROP_UNUSABLE;
}
static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@ -2404,7 +2381,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
sig = status->signal; sig = status->signal;
if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
rx->skb->data, rx->skb->len, rx->skb->data, rx->skb->len,
GFP_ATOMIC)) { GFP_ATOMIC)) {
if (rx->sta) if (rx->sta)
@ -2695,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
goto rxh_next; \ goto rxh_next; \
} while (0); } while (0);
CALL_RXH(ieee80211_rx_h_passive_scan)
CALL_RXH(ieee80211_rx_h_check) CALL_RXH(ieee80211_rx_h_check)
ieee80211_rx_reorder_ampdu(rx); ieee80211_rx_reorder_ampdu(rx);
@ -2765,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
return 0; return 0;
if (ieee80211_is_beacon(hdr->frame_control)) { if (ieee80211_is_beacon(hdr->frame_control)) {
return 1; return 1;
} } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { return 0;
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
return 0;
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast && } else if (!multicast &&
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) { !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
if (!(sdata->dev->flags & IFF_PROMISC)) if (!(sdata->dev->flags & IFF_PROMISC))
@ -2807,11 +2780,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
* and location updates. Note that mac80211 * and location updates. Note that mac80211
* itself never looks at these frames. * itself never looks at these frames.
*/ */
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && if (ieee80211_is_public_action(hdr, skb->len))
ieee80211_is_public_action(hdr, skb->len))
return 1; return 1;
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && if (!ieee80211_is_beacon(hdr->frame_control))
!ieee80211_is_beacon(hdr->frame_control))
return 0; return 0;
status->rx_flags &= ~IEEE80211_RX_RA_MATCH; status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} }
@ -2877,7 +2848,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
@ -2895,11 +2865,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
local->dot11ReceivedFragmentCount++; local->dot11ReceivedFragmentCount++;
if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
test_bit(SCAN_SW_SCANNING, &local->scanning)))
status->rx_flags |= IEEE80211_RX_IN_SCAN;
if (ieee80211_is_mgmt(fc)) if (ieee80211_is_mgmt(fc))
err = skb_linearize(skb); err = skb_linearize(skb);
else else
@ -2914,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
ieee80211_parse_qos(&rx); ieee80211_parse_qos(&rx);
ieee80211_verify_alignment(&rx); ieee80211_verify_alignment(&rx);
if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) ||
ieee80211_is_beacon(hdr->frame_control)))
ieee80211_scan_rx(local, skb);
if (ieee80211_is_data(fc)) { if (ieee80211_is_data(fc)) {
prev_sta = NULL; prev_sta = NULL;

View File

@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
mgmt, len, signal, GFP_ATOMIC); mgmt, len, signal, GFP_ATOMIC);
if (!cbss) if (!cbss)
return NULL; return NULL;
cbss->free_priv = ieee80211_rx_bss_free; cbss->free_priv = ieee80211_rx_bss_free;
bss = (void *)cbss->priv; bss = (void *)cbss->priv;
bss->device_ts = rx_status->device_timestamp;
if (elems->parse_error) { if (elems->parse_error) {
if (beacon) if (beacon)
bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
@ -165,52 +166,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
return bss; return bss;
} }
ieee80211_rx_result void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
{ {
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_mgmt *mgmt; struct ieee80211_sub_if_data *sdata1, *sdata2;
struct ieee80211_mgmt *mgmt = (void *)skb->data;
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
u8 *elements; u8 *elements;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
size_t baselen; size_t baselen;
int freq; int freq;
__le16 fc; bool beacon;
bool presp, beacon = false;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
if (skb->len < 2) if (skb->len < 24 ||
return RX_DROP_UNUSABLE; (!ieee80211_is_probe_resp(mgmt->frame_control) &&
!ieee80211_is_beacon(mgmt->frame_control)))
return;
mgmt = (struct ieee80211_mgmt *) skb->data; sdata1 = rcu_dereference(local->scan_sdata);
fc = mgmt->frame_control; sdata2 = rcu_dereference(local->sched_scan_sdata);
if (ieee80211_is_ctl(fc)) if (likely(!sdata1 && !sdata2))
return RX_CONTINUE; return;
if (skb->len < 24) if (ieee80211_is_probe_resp(mgmt->frame_control)) {
return RX_CONTINUE;
presp = ieee80211_is_probe_resp(fc);
if (presp) {
/* ignore ProbeResp to foreign address */ /* ignore ProbeResp to foreign address */
if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
return RX_DROP_MONITOR; (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
return;
presp = true;
elements = mgmt->u.probe_resp.variable; elements = mgmt->u.probe_resp.variable;
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
beacon = false;
} else { } else {
beacon = ieee80211_is_beacon(fc);
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
elements = mgmt->u.beacon.variable; elements = mgmt->u.beacon.variable;
beacon = true;
} }
if (!presp && !beacon)
return RX_CONTINUE;
if (baselen > skb->len) if (baselen > skb->len)
return RX_DROP_MONITOR; return;
ieee802_11_parse_elems(elements, skb->len - baselen, &elems); ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
@ -220,22 +216,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
else else
freq = rx_status->freq; freq = rx_status->freq;
channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); channel = ieee80211_get_channel(local->hw.wiphy, freq);
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return RX_DROP_MONITOR; return;
bss = ieee80211_bss_info_update(sdata->local, rx_status, bss = ieee80211_bss_info_update(local, rx_status,
mgmt, skb->len, &elems, mgmt, skb->len, &elems,
channel, beacon); channel, beacon);
if (bss) if (bss)
ieee80211_rx_bss_put(sdata->local, bss); ieee80211_rx_bss_put(local, bss);
if (channel == sdata->local->oper_channel)
return RX_CONTINUE;
dev_kfree_skb(skb);
return RX_QUEUED;
} }
/* return false if no more work */ /* return false if no more work */
@ -293,7 +283,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
return; return;
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); int rc;
rc = drv_hw_scan(local,
rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx)),
local->hw_scan_req);
if (rc == 0) if (rc == 0)
return; return;
} }
@ -394,7 +390,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
if (!local->scan_req || local->scanning) if (!local->scan_req || local->scanning)
return; return;
if (!ieee80211_can_scan(local, local->scan_sdata)) if (!ieee80211_can_scan(local,
rcu_dereference_protected(
local->scan_sdata,
lockdep_is_held(&local->mtx))))
return; return;
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
@ -405,9 +404,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
unsigned long *next_delay) unsigned long *next_delay)
{ {
int i; int i;
struct ieee80211_sub_if_data *sdata = local->scan_sdata; struct ieee80211_sub_if_data *sdata;
enum ieee80211_band band = local->hw.conf.channel->band; enum ieee80211_band band = local->hw.conf.channel->band;
sdata = rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx));;
for (i = 0; i < local->scan_req->n_ssids; i++) for (i = 0; i < local->scan_req->n_ssids; i++)
ieee80211_send_probe_req( ieee80211_send_probe_req(
sdata, NULL, sdata, NULL,
@ -439,7 +441,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (!ieee80211_can_scan(local, sdata)) { if (!ieee80211_can_scan(local, sdata)) {
/* wait for the work to finish/time out */ /* wait for the work to finish/time out */
local->scan_req = req; local->scan_req = req;
local->scan_sdata = sdata; rcu_assign_pointer(local->scan_sdata, sdata);
return 0; return 0;
} }
@ -473,7 +475,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
} }
local->scan_req = req; local->scan_req = req;
local->scan_sdata = sdata; rcu_assign_pointer(local->scan_sdata, sdata);
if (local->ops->hw_scan) { if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning); __set_bit(SCAN_HW_SCANNING, &local->scanning);
@ -533,7 +535,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_idle(local); ieee80211_recalc_idle(local);
local->scan_req = NULL; local->scan_req = NULL;
local->scan_sdata = NULL; rcu_assign_pointer(local->scan_sdata, NULL);
} }
return rc; return rc;
@ -720,7 +722,8 @@ void ieee80211_scan_work(struct work_struct *work)
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
sdata = local->scan_sdata; sdata = rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx));
/* When scanning on-channel, the first-callback means completed. */ /* When scanning on-channel, the first-callback means completed. */
if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
@ -741,7 +744,7 @@ void ieee80211_scan_work(struct work_struct *work)
int rc; int rc;
local->scan_req = NULL; local->scan_req = NULL;
local->scan_sdata = NULL; rcu_assign_pointer(local->scan_sdata, NULL);
rc = __ieee80211_start_scan(sdata, req); rc = __ieee80211_start_scan(sdata, req);
if (rc) { if (rc) {
@ -893,7 +896,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
if (local->ops->cancel_hw_scan) if (local->ops->cancel_hw_scan)
drv_cancel_hw_scan(local, local->scan_sdata); drv_cancel_hw_scan(local,
rcu_dereference_protected(local->scan_sdata,
lockdep_is_held(&local->mtx)));
goto out; goto out;
} }
@ -915,9 +920,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int ret, i; int ret, i;
mutex_lock(&sdata->local->mtx); mutex_lock(&local->mtx);
if (local->sched_scanning) { if (rcu_access_pointer(local->sched_scan_sdata)) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
@ -928,6 +933,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
} }
for (i = 0; i < IEEE80211_NUM_BANDS; i++) { for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
if (!local->hw.wiphy->bands[i])
continue;
local->sched_scan_ies.ie[i] = kzalloc(2 + local->sched_scan_ies.ie[i] = kzalloc(2 +
IEEE80211_MAX_SSID_LEN + IEEE80211_MAX_SSID_LEN +
local->scan_ies_len + local->scan_ies_len +
@ -948,7 +956,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
ret = drv_sched_scan_start(local, sdata, req, ret = drv_sched_scan_start(local, sdata, req,
&local->sched_scan_ies); &local->sched_scan_ies);
if (ret == 0) { if (ret == 0) {
local->sched_scanning = true; rcu_assign_pointer(local->sched_scan_sdata, sdata);
goto out; goto out;
} }
@ -956,7 +964,7 @@ out_free:
while (i > 0) while (i > 0)
kfree(local->sched_scan_ies.ie[--i]); kfree(local->sched_scan_ies.ie[--i]);
out: out:
mutex_unlock(&sdata->local->mtx); mutex_unlock(&local->mtx);
return ret; return ret;
} }
@ -965,22 +973,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int ret = 0, i; int ret = 0, i;
mutex_lock(&sdata->local->mtx); mutex_lock(&local->mtx);
if (!local->ops->sched_scan_stop) { if (!local->ops->sched_scan_stop) {
ret = -ENOTSUPP; ret = -ENOTSUPP;
goto out; goto out;
} }
if (local->sched_scanning) { if (rcu_access_pointer(local->sched_scan_sdata)) {
for (i = 0; i < IEEE80211_NUM_BANDS; i++) for (i = 0; i < IEEE80211_NUM_BANDS; i++)
kfree(local->sched_scan_ies.ie[i]); kfree(local->sched_scan_ies.ie[i]);
drv_sched_scan_stop(local, sdata); drv_sched_scan_stop(local, sdata);
local->sched_scanning = false; rcu_assign_pointer(local->sched_scan_sdata, NULL);
} }
out: out:
mutex_unlock(&sdata->local->mtx); mutex_unlock(&local->mtx);
return ret; return ret;
} }
@ -1004,7 +1012,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
if (!local->sched_scanning) { if (!rcu_access_pointer(local->sched_scan_sdata)) {
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
return; return;
} }
@ -1012,7 +1020,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
for (i = 0; i < IEEE80211_NUM_BANDS; i++) for (i = 0; i < IEEE80211_NUM_BANDS; i++)
kfree(local->sched_scan_ies.ie[i]); kfree(local->sched_scan_ies.ie[i]);
local->sched_scanning = false; rcu_assign_pointer(local->sched_scan_sdata, NULL);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);

View File

@ -519,14 +519,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
u64 cookie = (unsigned long)skb; u64 cookie = (unsigned long)skb;
acked = info->flags & IEEE80211_TX_STAT_ACK; acked = info->flags & IEEE80211_TX_STAT_ACK;
/*
* TODO: When we have non-netdev frame TX,
* we cannot use skb->dev->ieee80211_ptr
*/
if (ieee80211_is_nullfunc(hdr->frame_control) || if (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) ieee80211_is_qos_nullfunc(hdr->frame_control))
cfg80211_probe_status(skb->dev, hdr->addr1, cfg80211_probe_status(skb->dev, hdr->addr1,
cookie, acked, GFP_ATOMIC); cookie, acked, GFP_ATOMIC);
else else
cfg80211_mgmt_tx_status( cfg80211_mgmt_tx_status(
skb->dev, cookie, skb->data, skb->len, skb->dev->ieee80211_ptr, cookie, skb->data,
acked, GFP_ATOMIC); skb->len, acked, GFP_ATOMIC);
} }
if (unlikely(info->ack_frame_id)) { if (unlikely(info->ack_frame_id)) {

View File

@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed,
__field(u8, dtimper) __field(u8, dtimper)
__field(u16, bcnint) __field(u16, bcnint)
__field(u16, assoc_cap) __field(u16, assoc_cap)
__field(u64, timestamp) __field(u64, sync_tsf)
__field(u32, sync_device_ts)
__field(u32, basic_rates) __field(u32, basic_rates)
__field(u32, changed) __field(u32, changed)
__field(bool, enable_beacon) __field(bool, enable_beacon)
@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed,
__entry->dtimper = info->dtim_period; __entry->dtimper = info->dtim_period;
__entry->bcnint = info->beacon_int; __entry->bcnint = info->beacon_int;
__entry->assoc_cap = info->assoc_capability; __entry->assoc_cap = info->assoc_capability;
__entry->timestamp = info->last_tsf; __entry->sync_tsf = info->sync_tsf;
__entry->sync_device_ts = info->sync_device_ts;
__entry->basic_rates = info->basic_rates; __entry->basic_rates = info->basic_rates;
__entry->enable_beacon = info->enable_beacon; __entry->enable_beacon = info->enable_beacon;
__entry->ht_operation_mode = info->ht_operation_mode; __entry->ht_operation_mode = info->ht_operation_mode;

View File

@ -523,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
static ieee80211_tx_result debug_noinline static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{ {
struct ieee80211_key *key = NULL; struct ieee80211_key *key;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@ -542,16 +542,23 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
else if (!is_multicast_ether_addr(hdr->addr1) && else if (!is_multicast_ether_addr(hdr->addr1) &&
(key = rcu_dereference(tx->sdata->default_unicast_key))) (key = rcu_dereference(tx->sdata->default_unicast_key)))
tx->key = key; tx->key = key;
else if (tx->sdata->drop_unencrypted && else if (info->flags & IEEE80211_TX_CTL_INJECTED)
(tx->skb->protocol != tx->sdata->control_port_protocol) && tx->key = NULL;
!(info->flags & IEEE80211_TX_CTL_INJECTED) && else if (!tx->sdata->drop_unencrypted)
(!ieee80211_is_robust_mgmt_frame(hdr) || tx->key = NULL;
(ieee80211_is_action(hdr->frame_control) && else if (tx->skb->protocol == tx->sdata->control_port_protocol)
tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { tx->key = NULL;
else if (ieee80211_is_robust_mgmt_frame(hdr) &&
!(ieee80211_is_action(hdr->frame_control) &&
tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
tx->key = NULL;
else if (ieee80211_is_mgmt(hdr->frame_control) &&
!ieee80211_is_robust_mgmt_frame(hdr))
tx->key = NULL;
else {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
return TX_DROP; return TX_DROP;
} else }
tx->key = NULL;
if (tx->key) { if (tx->key) {
bool skip_hw = false; bool skip_hw = false;

View File

@ -529,6 +529,11 @@ void ieee80211_iterate_active_interfaces(
&sdata->vif); &sdata->vif);
} }
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
if (sdata)
iterator(data, sdata->vif.addr, &sdata->vif);
mutex_unlock(&local->iflist_mtx); mutex_unlock(&local->iflist_mtx);
} }
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
@ -557,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic(
&sdata->vif); &sdata->vif);
} }
sdata = rcu_dereference(local->monitor_sdata);
if (sdata)
iterator(data, sdata->vif.addr, &sdata->vif);
rcu_read_unlock(); rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
@ -999,6 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
int ext_rates_len; int ext_rates_len;
sband = local->hw.wiphy->bands[band]; sband = local->hw.wiphy->bands[band];
if (WARN_ON_ONCE(!sband))
return 0;
pos = buffer; pos = buffer;

View File

@ -103,15 +103,13 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
} }
void void
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, cfg80211_get_chan_state(struct wireless_dev *wdev,
struct wireless_dev *wdev,
struct ieee80211_channel **chan, struct ieee80211_channel **chan,
enum cfg80211_chan_mode *chanmode) enum cfg80211_chan_mode *chanmode)
{ {
*chan = NULL; *chan = NULL;
*chanmode = CHAN_MODE_UNDEFINED; *chanmode = CHAN_MODE_UNDEFINED;
ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (!netif_running(wdev->netdev)) if (!netif_running(wdev->netdev))

View File

@ -176,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
return -EOPNOTSUPP; return -EOPNOTSUPP;
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
if (err) if (err)
@ -188,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
/* failed -- clean up to old netns */ /* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy); net = wiphy_net(&rdev->wiphy);
list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list,
list) { list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net, err = dev_change_net_namespace(wdev->netdev, net,
"wlan%d"); "wlan%d");
@ -226,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
rtnl_lock(); rtnl_lock();
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) list_for_each_entry(wdev, &rdev->wdev_list, list)
dev_close(wdev->netdev); if (wdev->netdev)
dev_close(wdev->netdev);
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock(); rtnl_unlock();
@ -304,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
mutex_init(&rdev->mtx); mutex_init(&rdev->mtx);
mutex_init(&rdev->devlist_mtx); mutex_init(&rdev->devlist_mtx);
mutex_init(&rdev->sched_scan_mtx); mutex_init(&rdev->sched_scan_mtx);
INIT_LIST_HEAD(&rdev->netdev_list); INIT_LIST_HEAD(&rdev->wdev_list);
spin_lock_init(&rdev->bss_lock); spin_lock_init(&rdev->bss_lock);
INIT_LIST_HEAD(&rdev->bss_list); INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
@ -622,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy)
__count == 0; })); __count == 0; }));
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
BUG_ON(!list_empty(&rdev->netdev_list)); BUG_ON(!list_empty(&rdev->wdev_list));
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
/* /*
@ -703,7 +708,7 @@ static void wdev_cleanup_work(struct work_struct *work)
cfg80211_lock_rdev(rdev); cfg80211_lock_rdev(rdev);
if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
rdev->scan_req->aborted = true; rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, true); ___cfg80211_scan_done(rdev, true);
} }
@ -774,8 +779,9 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
has_monitors_only_new = cfg80211_has_monitors_only(rdev); has_monitors_only_new = cfg80211_has_monitors_only(rdev);
if (has_monitors_only_new != has_monitors_only_old) { if (has_monitors_only_new != has_monitors_only_old) {
rdev->ops->set_monitor_enabled(&rdev->wiphy, if (rdev->ops->set_monitor_enabled)
has_monitors_only_new); rdev->ops->set_monitor_enabled(&rdev->wiphy,
has_monitors_only_new);
if (!has_monitors_only_new) { if (!has_monitors_only_new) {
rdev->monitor_channel = NULL; rdev->monitor_channel = NULL;
@ -820,7 +826,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
spin_lock_init(&wdev->mgmt_registrations_lock); spin_lock_init(&wdev->mgmt_registrations_lock);
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_add_rcu(&wdev->list, &rdev->netdev_list); wdev->identifier = ++rdev->wdev_id;
list_add_rcu(&wdev->list, &rdev->wdev_list);
rdev->devlist_generation++; rdev->devlist_generation++;
/* can only change netns with wiphy */ /* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL; dev->features |= NETIF_F_NETNS_LOCAL;

View File

@ -47,11 +47,11 @@ struct cfg80211_registered_device {
/* wiphy index, internal only */ /* wiphy index, internal only */
int wiphy_idx; int wiphy_idx;
/* associate netdev list */ /* associated wireless interfaces */
struct mutex devlist_mtx; struct mutex devlist_mtx;
/* protected by devlist_mtx or RCU */ /* protected by devlist_mtx or RCU */
struct list_head netdev_list; struct list_head wdev_list;
int devlist_generation; int devlist_generation, wdev_id;
int opencount; /* also protected by devlist_mtx */ int opencount; /* also protected by devlist_mtx */
wait_queue_head_t dev_wait; wait_queue_head_t dev_wait;
@ -372,7 +372,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
@ -463,8 +463,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
} }
void void
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, cfg80211_get_chan_state(struct wireless_dev *wdev,
struct wireless_dev *wdev,
struct ieee80211_channel **chan, struct ieee80211_channel **chan,
enum cfg80211_chan_mode *chanmode); enum cfg80211_chan_mode *chanmode);

View File

@ -567,29 +567,28 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
} }
} }
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp) unsigned int duration, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
duration, gfp); duration, gfp);
} }
EXPORT_SYMBOL(cfg80211_ready_on_channel); EXPORT_SYMBOL(cfg80211_ready_on_channel);
void cfg80211_remain_on_channel_expired(struct net_device *dev, void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
gfp_t gfp) gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
channel_type, gfp); channel_type, gfp);
} }
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
@ -678,8 +677,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
list_add(&nreg->list, &wdev->mgmt_registrations); list_add(&nreg->list, &wdev->mgmt_registrations);
if (rdev->ops->mgmt_frame_register) if (rdev->ops->mgmt_frame_register)
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true);
frame_type, true);
out: out:
spin_unlock_bh(&wdev->mgmt_registrations_lock); spin_unlock_bh(&wdev->mgmt_registrations_lock);
@ -702,7 +700,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
if (rdev->ops->mgmt_frame_register) { if (rdev->ops->mgmt_frame_register) {
u16 frame_type = le16_to_cpu(reg->frame_type); u16 frame_type = le16_to_cpu(reg->frame_type);
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, rdev->ops->mgmt_frame_register(wiphy, wdev,
frame_type, false); frame_type, false);
} }
@ -731,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
} }
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait, bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck, const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie) bool dont_wait_for_ack, u64 *cookie)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct net_device *dev = wdev->netdev;
const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt;
u16 stype; u16 stype;
@ -825,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return -EINVAL; return -EINVAL;
/* Transmit the Action frame as requested by user space */ /* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
channel_type, channel_type_valid, channel_type, channel_type_valid,
wait, buf, len, no_cck, dont_wait_for_ack, wait, buf, len, no_cck, dont_wait_for_ack,
cookie); cookie);
} }
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
const u8 *buf, size_t len, gfp_t gfp) const u8 *buf, size_t len, gfp_t gfp)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_mgmt_registration *reg; struct cfg80211_mgmt_registration *reg;
@ -871,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
/* found match! */ /* found match! */
/* Indicate the received Action frame to user space */ /* Indicate the received Action frame to user space */
if (nl80211_send_mgmt(rdev, dev, reg->nlpid, if (nl80211_send_mgmt(rdev, wdev, reg->nlpid,
freq, sig_mbm, freq, sig_mbm,
buf, len, gfp)) buf, len, gfp))
continue; continue;
@ -886,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
} }
EXPORT_SYMBOL(cfg80211_rx_mgmt); EXPORT_SYMBOL(cfg80211_rx_mgmt);
void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack, gfp_t gfp) const u8 *buf, size_t len, bool ack, gfp_t gfp)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
/* Indicate TX status of the Action frame to user space */ /* Indicate TX status of the Action frame to user space */
nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
} }
EXPORT_SYMBOL(cfg80211_mgmt_tx_status); EXPORT_SYMBOL(cfg80211_mgmt_tx_status);

View File

@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = {
.post_doit = nl80211_post_doit, .post_doit = nl80211_post_doit,
}; };
/* internal helper: get rdev and dev */ /* returns ERR_PTR values */
static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, static struct wireless_dev *
struct cfg80211_registered_device **rdev, __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
struct net_device **dev)
{ {
int ifindex; struct cfg80211_registered_device *rdev;
struct wireless_dev *result = NULL;
bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
u64 wdev_id;
int wiphy_idx = -1;
int ifidx = -1;
if (!attrs[NL80211_ATTR_IFINDEX]) assert_cfg80211_lock();
return -EINVAL;
ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); if (!have_ifidx && !have_wdev_id)
*dev = dev_get_by_index(netns, ifindex); return ERR_PTR(-EINVAL);
if (!*dev)
return -ENODEV;
*rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); if (have_ifidx)
if (IS_ERR(*rdev)) { ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
dev_put(*dev); if (have_wdev_id) {
return PTR_ERR(*rdev); wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
wiphy_idx = wdev_id >> 32;
} }
return 0; list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
struct wireless_dev *wdev;
if (wiphy_net(&rdev->wiphy) != netns)
continue;
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
continue;
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (have_ifidx && wdev->netdev &&
wdev->netdev->ifindex == ifidx) {
result = wdev;
break;
}
if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
result = wdev;
break;
}
}
mutex_unlock(&rdev->devlist_mtx);
if (result)
break;
}
if (result)
return result;
return ERR_PTR(-ENODEV);
} }
static struct cfg80211_registered_device * static struct cfg80211_registered_device *
@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
assert_cfg80211_lock(); assert_cfg80211_lock();
if (!attrs[NL80211_ATTR_WIPHY] && if (!attrs[NL80211_ATTR_WIPHY] &&
!attrs[NL80211_ATTR_IFINDEX]) !attrs[NL80211_ATTR_IFINDEX] &&
!attrs[NL80211_ATTR_WDEV])
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (attrs[NL80211_ATTR_WIPHY]) if (attrs[NL80211_ATTR_WIPHY])
rdev = cfg80211_rdev_by_wiphy_idx( rdev = cfg80211_rdev_by_wiphy_idx(
nla_get_u32(attrs[NL80211_ATTR_WIPHY])); nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
if (attrs[NL80211_ATTR_WDEV]) {
u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
struct wireless_dev *wdev;
bool found = false;
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
if (tmp) {
/* make sure wdev exists */
mutex_lock(&tmp->devlist_mtx);
list_for_each_entry(wdev, &tmp->wdev_list, list) {
if (wdev->identifier != (u32)wdev_id)
continue;
found = true;
break;
}
mutex_unlock(&tmp->devlist_mtx);
if (!found)
tmp = NULL;
if (rdev && tmp != rdev)
return ERR_PTR(-EINVAL);
rdev = tmp;
}
}
if (attrs[NL80211_ATTR_IFINDEX]) { if (attrs[NL80211_ATTR_IFINDEX]) {
int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
netdev = dev_get_by_index(netns, ifindex); netdev = dev_get_by_index(netns, ifindex);
@ -294,6 +353,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
@ -1668,22 +1728,32 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
return result; return result;
} }
static inline u64 wdev_id(struct wireless_dev *wdev)
{
return (u64)wdev->identifier |
((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32);
}
static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *rdev, struct cfg80211_registered_device *rdev,
struct net_device *dev) struct wireless_dev *wdev)
{ {
struct net_device *dev = wdev->netdev;
void *hdr; void *hdr;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
if (!hdr) if (!hdr)
return -1; return -1;
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || if (dev &&
nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE, nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr)))
dev->ieee80211_ptr->iftype) || goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_GENERATION, nla_put_u32(msg, NL80211_ATTR_GENERATION,
rdev->devlist_generation ^ rdev->devlist_generation ^
(cfg80211_rdev_list_generation << 2))) (cfg80211_rdev_list_generation << 2)))
@ -1724,14 +1794,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
if_idx = 0; if_idx = 0;
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (if_idx < if_start) { if (if_idx < if_start) {
if_idx++; if_idx++;
continue; continue;
} }
if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh->nlmsg_seq, NLM_F_MULTI,
rdev, wdev->netdev) < 0) { rdev, wdev) < 0) {
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
goto out; goto out;
} }
@ -1754,14 +1824,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{ {
struct sk_buff *msg; struct sk_buff *msg;
struct cfg80211_registered_device *dev = info->user_ptr[0]; struct cfg80211_registered_device *dev = info->user_ptr[0];
struct net_device *netdev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return -ENOMEM; return -ENOMEM;
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
dev, netdev) < 0) { dev, wdev) < 0) {
nlmsg_free(msg); nlmsg_free(msg);
return -ENOBUFS; return -ENOBUFS;
} }
@ -1901,7 +1971,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct vif_params params; struct vif_params params;
struct net_device *dev; struct wireless_dev *wdev;
struct sk_buff *msg;
int err; int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
u32 flags; u32 flags;
@ -1928,19 +1999,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags); &flags);
dev = rdev->ops->add_virtual_intf(&rdev->wiphy, wdev = rdev->ops->add_virtual_intf(&rdev->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]), nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params); type, err ? NULL : &flags, &params);
if (IS_ERR(dev)) if (IS_ERR(wdev)) {
return PTR_ERR(dev); nlmsg_free(msg);
return PTR_ERR(wdev);
}
if (type == NL80211_IFTYPE_MESH_POINT && if (type == NL80211_IFTYPE_MESH_POINT &&
info->attrs[NL80211_ATTR_MESH_ID]) { info->attrs[NL80211_ATTR_MESH_ID]) {
struct wireless_dev *wdev = dev->ieee80211_ptr;
wdev_lock(wdev); wdev_lock(wdev);
BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
IEEE80211_MAX_MESH_ID_LEN); IEEE80211_MAX_MESH_ID_LEN);
@ -1951,18 +2026,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
wdev_unlock(wdev); wdev_unlock(wdev);
} }
return 0; if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
rdev, wdev) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
}
return genlmsg_reply(msg, info);
} }
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
if (!rdev->ops->del_virtual_intf) if (!rdev->ops->del_virtual_intf)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); /*
* If we remove a wireless device without a netdev then clear
* user_ptr[1] so that nl80211_post_doit won't dereference it
* to check if it needs to do dev_put(). Otherwise it crashes
* since the wdev has been freed, unlike with a netdev where
* we need the dev_put() for the netdev to really be freed.
*/
if (!wdev->netdev)
info->user_ptr[1] = NULL;
return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
} }
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@ -2350,7 +2441,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP && if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO) wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue; continue;
@ -4039,7 +4130,7 @@ static int validate_scan_freqs(struct nlattr *freqs)
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
struct cfg80211_scan_request *request; struct cfg80211_scan_request *request;
struct nlattr *attr; struct nlattr *attr;
struct wiphy *wiphy; struct wiphy *wiphy;
@ -4199,15 +4290,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->no_cck = request->no_cck =
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
request->dev = dev; request->wdev = wdev;
request->wiphy = &rdev->wiphy; request->wiphy = &rdev->wiphy;
rdev->scan_req = request; rdev->scan_req = request;
err = rdev->ops->scan(&rdev->wiphy, dev, request); err = rdev->ops->scan(&rdev->wiphy, request);
if (!err) { if (!err) {
nl80211_send_scan_start(rdev, dev); nl80211_send_scan_start(rdev, wdev);
dev_hold(dev); if (wdev->netdev)
dev_hold(wdev->netdev);
} else { } else {
out_free: out_free:
rdev->scan_req = NULL; rdev->scan_req = NULL;
@ -5685,7 +5777,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
@ -5733,7 +5825,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
goto free_msg; goto free_msg;
} }
err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
channel_type, duration, &cookie); channel_type, duration, &cookie);
if (err) if (err)
@ -5757,7 +5849,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
u64 cookie; u64 cookie;
if (!info->attrs[NL80211_ATTR_COOKIE]) if (!info->attrs[NL80211_ATTR_COOKIE])
@ -5768,7 +5860,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
} }
static u32 rateset_to_mask(struct ieee80211_supported_band *sband, static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@ -5917,7 +6009,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
@ -5926,21 +6018,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_FRAME_TYPE]) if (info->attrs[NL80211_ATTR_FRAME_TYPE])
frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && switch (wdev->iftype) {
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && case NL80211_IFTYPE_STATION:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && case NL80211_IFTYPE_ADHOC:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && case NL80211_IFTYPE_P2P_CLIENT:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && case NL80211_IFTYPE_AP:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && case NL80211_IFTYPE_AP_VLAN:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
/* not much point in registering if we can't reply */ /* not much point in registering if we can't reply */
if (!rdev->ops->mgmt_tx) if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP; return -EOPNOTSUPP;
return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type,
frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
} }
@ -5948,7 +6043,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
bool channel_type_valid = false; bool channel_type_valid = false;
@ -5969,14 +6064,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->mgmt_tx) if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && switch (wdev->iftype) {
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && case NL80211_IFTYPE_STATION:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && case NL80211_IFTYPE_ADHOC:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && case NL80211_IFTYPE_P2P_CLIENT:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && case NL80211_IFTYPE_AP:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && case NL80211_IFTYPE_AP_VLAN:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
if (info->attrs[NL80211_ATTR_DURATION]) { if (info->attrs[NL80211_ATTR_DURATION]) {
if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
@ -6025,7 +6124,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
} }
} }
err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type,
channel_type_valid, wait, channel_type_valid, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]),
@ -6053,7 +6152,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = info->user_ptr[1];
u64 cookie; u64 cookie;
if (!info->attrs[NL80211_ATTR_COOKIE]) if (!info->attrs[NL80211_ATTR_COOKIE])
@ -6062,17 +6161,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
if (!rdev->ops->mgmt_tx_cancel_wait) if (!rdev->ops->mgmt_tx_cancel_wait)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && switch (wdev->iftype) {
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && case NL80211_IFTYPE_STATION:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && case NL80211_IFTYPE_ADHOC:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && case NL80211_IFTYPE_P2P_CLIENT:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && case NL80211_IFTYPE_AP:
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
} }
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
@ -6655,13 +6758,17 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
#define NL80211_FLAG_CHECK_NETDEV_UP 0x08 #define NL80211_FLAG_CHECK_NETDEV_UP 0x08
#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
NL80211_FLAG_CHECK_NETDEV_UP) NL80211_FLAG_CHECK_NETDEV_UP)
#define NL80211_FLAG_NEED_WDEV 0x10
/* If a netdev is associated, it must be UP */
#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
struct net_device *dev; struct net_device *dev;
int err;
bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
if (rtnl) if (rtnl)
@ -6675,24 +6782,51 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
return PTR_ERR(rdev); return PTR_ERR(rdev);
} }
info->user_ptr[0] = rdev; info->user_ptr[0] = rdev;
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
&rdev, &dev); mutex_lock(&cfg80211_mutex);
if (err) { wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
info->attrs);
if (IS_ERR(wdev)) {
mutex_unlock(&cfg80211_mutex);
if (rtnl) if (rtnl)
rtnl_unlock(); rtnl_unlock();
return err; return PTR_ERR(wdev);
} }
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
!netif_running(dev)) { dev = wdev->netdev;
cfg80211_unlock_rdev(rdev); rdev = wiphy_to_dev(wdev->wiphy);
dev_put(dev);
if (rtnl) if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
rtnl_unlock(); if (!dev) {
return -ENETDOWN; mutex_unlock(&cfg80211_mutex);
if (rtnl)
rtnl_unlock();
return -EINVAL;
}
info->user_ptr[1] = dev;
} else {
info->user_ptr[1] = wdev;
} }
if (dev) {
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
!netif_running(dev)) {
mutex_unlock(&cfg80211_mutex);
if (rtnl)
rtnl_unlock();
return -ENETDOWN;
}
dev_hold(dev);
}
cfg80211_lock_rdev(rdev);
mutex_unlock(&cfg80211_mutex);
info->user_ptr[0] = rdev; info->user_ptr[0] = rdev;
info->user_ptr[1] = dev;
} }
return 0; return 0;
@ -6703,8 +6837,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
{ {
if (info->user_ptr[0]) if (info->user_ptr[0])
cfg80211_unlock_rdev(info->user_ptr[0]); cfg80211_unlock_rdev(info->user_ptr[0]);
if (info->user_ptr[1]) if (info->user_ptr[1]) {
dev_put(info->user_ptr[1]); if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
struct wireless_dev *wdev = info->user_ptr[1];
if (wdev->netdev)
dev_put(wdev->netdev);
} else {
dev_put(info->user_ptr[1]);
}
}
if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
rtnl_unlock(); rtnl_unlock();
} }
@ -6731,7 +6873,7 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_interface, .dumpit = nl80211_dump_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_NETDEV, .internal_flags = NL80211_FLAG_NEED_WDEV,
}, },
{ {
.cmd = NL80211_CMD_SET_INTERFACE, .cmd = NL80211_CMD_SET_INTERFACE,
@ -6754,7 +6896,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_del_interface, .doit = nl80211_del_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV | .internal_flags = NL80211_FLAG_NEED_WDEV |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -6925,7 +7067,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_trigger_scan, .doit = nl80211_trigger_scan,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7066,7 +7208,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_remain_on_channel, .doit = nl80211_remain_on_channel,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7074,7 +7216,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_cancel_remain_on_channel, .doit = nl80211_cancel_remain_on_channel,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7090,7 +7232,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_register_mgmt, .doit = nl80211_register_mgmt,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV | .internal_flags = NL80211_FLAG_NEED_WDEV |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7098,7 +7240,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_tx_mgmt, .doit = nl80211_tx_mgmt,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7106,7 +7248,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_tx_mgmt_cancel_wait, .doit = nl80211_tx_mgmt_cancel_wait,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{ {
@ -7317,7 +7459,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
static int nl80211_send_scan_msg(struct sk_buff *msg, static int nl80211_send_scan_msg(struct sk_buff *msg,
struct cfg80211_registered_device *rdev, struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct wireless_dev *wdev,
u32 pid, u32 seq, int flags, u32 pid, u32 seq, int flags,
u32 cmd) u32 cmd)
{ {
@ -7328,7 +7470,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
return -1; return -1;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
wdev->netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
goto nla_put_failure; goto nla_put_failure;
/* ignore errors and send incomplete event anyway */ /* ignore errors and send incomplete event anyway */
@ -7365,7 +7509,7 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg,
} }
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *netdev) struct wireless_dev *wdev)
{ {
struct sk_buff *msg; struct sk_buff *msg;
@ -7373,7 +7517,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
if (!msg) if (!msg)
return; return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_TRIGGER_SCAN) < 0) { NL80211_CMD_TRIGGER_SCAN) < 0) {
nlmsg_free(msg); nlmsg_free(msg);
return; return;
@ -7384,7 +7528,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
} }
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev) struct wireless_dev *wdev)
{ {
struct sk_buff *msg; struct sk_buff *msg;
@ -7392,7 +7536,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
if (!msg) if (!msg)
return; return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_NEW_SCAN_RESULTS) < 0) { NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg); nlmsg_free(msg);
return; return;
@ -7403,7 +7547,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
} }
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev) struct wireless_dev *wdev)
{ {
struct sk_buff *msg; struct sk_buff *msg;
@ -7411,7 +7555,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
if (!msg) if (!msg)
return; return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_SCAN_ABORTED) < 0) { NL80211_CMD_SCAN_ABORTED) < 0) {
nlmsg_free(msg); nlmsg_free(msg);
return; return;
@ -7934,7 +8078,7 @@ nla_put_failure:
static void nl80211_send_remain_on_chan_event( static void nl80211_send_remain_on_chan_event(
int cmd, struct cfg80211_registered_device *rdev, int cmd, struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie, struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp) unsigned int duration, gfp_t gfp)
@ -7953,7 +8097,9 @@ static void nl80211_send_remain_on_chan_event(
} }
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
wdev->netdev->ifindex)) ||
nla_put_u32(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
@ -7975,23 +8121,24 @@ static void nl80211_send_remain_on_chan_event(
} }
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie, struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp) unsigned int duration, gfp_t gfp)
{ {
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan, rdev, wdev, cookie, chan,
channel_type, duration, gfp); channel_type, duration, gfp);
} }
void nl80211_send_remain_on_channel_cancel( void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev, struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
u64 cookie, struct ieee80211_channel *chan, u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp) enum nl80211_channel_type channel_type, gfp_t gfp)
{ {
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan, rdev, wdev, cookie, chan,
channel_type, 0, gfp); channel_type, 0, gfp);
} }
@ -8105,10 +8252,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev,
} }
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid, struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm, int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp) const u8 *buf, size_t len, gfp_t gfp)
{ {
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
@ -8123,7 +8271,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
} }
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
(sig_dbm && (sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
@ -8141,10 +8290,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
} }
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie, struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack, const u8 *buf, size_t len, bool ack,
gfp_t gfp) gfp_t gfp)
{ {
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
@ -8159,7 +8309,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
} }
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) || nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
(ack && nla_put_flag(msg, NL80211_ATTR_ACK))) (ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
@ -8483,7 +8634,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
cfg80211_mlme_unregister_socket(wdev, notify->pid); cfg80211_mlme_unregister_socket(wdev, notify->pid);
if (rdev->ap_beacons_nlpid == notify->pid) if (rdev->ap_beacons_nlpid == notify->pid)
rdev->ap_beacons_nlpid = 0; rdev->ap_beacons_nlpid = 0;

View File

@ -7,11 +7,11 @@ int nl80211_init(void);
void nl80211_exit(void); void nl80211_exit(void);
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *netdev); struct wireless_dev *wdev);
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev); struct wireless_dev *wdev);
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev); struct wireless_dev *wdev);
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd); struct net_device *netdev, u32 cmd);
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
@ -74,13 +74,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
gfp_t gfp); gfp_t gfp);
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev, struct wireless_dev *wdev, u64 cookie,
u64 cookie,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp); unsigned int duration, gfp_t gfp);
void nl80211_send_remain_on_channel_cancel( void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev, struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
u64 cookie, struct ieee80211_channel *chan, u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp); enum nl80211_channel_type channel_type, gfp_t gfp);
@ -92,11 +92,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
gfp_t gfp); gfp_t gfp);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid, struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm, int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp); const u8 *buf, size_t len, gfp_t gfp);
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie, struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack, const u8 *buf, size_t len, bool ack,
gfp_t gfp); gfp_t gfp);

View File

@ -23,7 +23,7 @@
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{ {
struct cfg80211_scan_request *request; struct cfg80211_scan_request *request;
struct net_device *dev; struct wireless_dev *wdev;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu; union iwreq_data wrqu;
#endif #endif
@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
if (!request) if (!request)
return; return;
dev = request->dev; wdev = request->wdev;
/* /*
* This must be before sending the other events! * This must be before sending the other events!
* Otherwise, wpa_supplicant gets completely confused with * Otherwise, wpa_supplicant gets completely confused with
* wext events. * wext events.
*/ */
cfg80211_sme_scan_done(dev); if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (request->aborted) if (request->aborted)
nl80211_send_scan_aborted(rdev, dev); nl80211_send_scan_aborted(rdev, wdev);
else else
nl80211_send_scan_done(rdev, dev); nl80211_send_scan_done(rdev, wdev);
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
if (!request->aborted) { if (wdev->netdev && !request->aborted) {
memset(&wrqu, 0, sizeof(wrqu)); memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
} }
#endif #endif
dev_put(dev); if (wdev->netdev)
dev_put(wdev->netdev);
rdev->scan_req = NULL; rdev->scan_req = NULL;
@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
} }
creq->wiphy = wiphy; creq->wiphy = wiphy;
creq->dev = dev; creq->wdev = dev->ieee80211_ptr;
/* SSIDs come after channels */ /* SSIDs come after channels */
creq->ssids = (void *)&creq->channels[n_channels]; creq->ssids = (void *)&creq->channels[n_channels];
creq->n_channels = n_channels; creq->n_channels = n_channels;
@ -1024,12 +1026,12 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
rdev->scan_req = creq; rdev->scan_req = creq;
err = rdev->ops->scan(wiphy, dev, creq); err = rdev->ops->scan(wiphy, creq);
if (err) { if (err) {
rdev->scan_req = NULL; rdev->scan_req = NULL;
/* creq will be freed below */ /* creq will be freed below */
} else { } else {
nl80211_send_scan_start(rdev, dev); nl80211_send_scan_start(rdev, dev->ieee80211_ptr);
/* creq now owned by driver */ /* creq now owned by driver */
creq = NULL; creq = NULL;
dev_hold(dev); dev_hold(dev);

View File

@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void)
*/ */
list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
cfg80211_lock_rdev(rdev); cfg80211_lock_rdev(rdev);
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) if (wdev->sme_state != CFG80211_SME_IDLE)
is_all_idle = false; is_all_idle = false;
@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
wdev->conn->params.ssid_len); wdev->conn->params.ssid_len);
request->ssids[0].ssid_len = wdev->conn->params.ssid_len; request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
request->dev = wdev->netdev; request->wdev = wdev;
request->wiphy = &rdev->wiphy; request->wiphy = &rdev->wiphy;
rdev->scan_req = request; rdev->scan_req = request;
err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); err = rdev->ops->scan(wdev->wiphy, request);
if (!err) { if (!err) {
wdev->conn->state = CFG80211_CONN_SCANNING; wdev->conn->state = CFG80211_CONN_SCANNING;
nl80211_send_scan_start(rdev, wdev->netdev); nl80211_send_scan_start(rdev, wdev);
dev_hold(wdev->netdev); dev_hold(wdev->netdev);
} else { } else {
rdev->scan_req = NULL; rdev->scan_req = NULL;
@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work)
cfg80211_lock_rdev(rdev); cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev); wdev_lock(wdev);
if (!netif_running(wdev->netdev)) { if (!netif_running(wdev->netdev)) {
wdev_unlock(wdev); wdev_unlock(wdev);

View File

@ -793,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) list_for_each_entry(wdev, &rdev->wdev_list, list)
cfg80211_process_wdev_events(wdev); cfg80211_process_wdev_events(wdev);
mutex_unlock(&rdev->devlist_mtx); mutex_unlock(&rdev->devlist_mtx);
@ -994,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) { list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->beacon_interval) if (!wdev->beacon_interval)
continue; continue;
if (wdev->beacon_interval != beacon_int) { if (wdev->beacon_interval != beacon_int) {
@ -1050,7 +1050,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
break; break;
} }
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
if (wdev_iter == wdev) if (wdev_iter == wdev)
continue; continue;
if (!netif_running(wdev_iter->netdev)) if (!netif_running(wdev_iter->netdev))
@ -1059,7 +1059,16 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
continue; continue;
cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); /*
* We may be holding the "wdev" mutex, but now need to lock
* wdev_iter. This is OK because once we get here wdev_iter
* is not wdev (tested above), but we need to use the nested
* locking for lockdep.
*/
mutex_lock_nested(&wdev_iter->mtx, 1);
__acquire(wdev_iter->mtx);
cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
wdev_unlock(wdev_iter);
switch (chmode) { switch (chmode) {
case CHAN_MODE_UNDEFINED: case CHAN_MODE_UNDEFINED: