mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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:
commit
d07d152892
@ -404,7 +404,6 @@
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv
|
||||
!Finclude/net/mac80211.h ieee80211_get_tkip_p2k
|
||||
!Finclude/net/mac80211.h ieee80211_key_removed
|
||||
</chapter>
|
||||
|
||||
<chapter id="powersave">
|
||||
|
@ -966,11 +966,11 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar,
|
||||
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 ath6kl *ar = ath6kl_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
s8 n_channels = 0;
|
||||
u16 *channels = NULL;
|
||||
int ret = 0;
|
||||
@ -1487,14 +1487,14 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ath6kl *ar = wiphy_priv(wiphy);
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
u8 if_idx, nw_type;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
|
||||
if (!ndev)
|
||||
wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
|
||||
if (!wdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ar->num_vif++;
|
||||
|
||||
return ndev;
|
||||
return wdev;
|
||||
}
|
||||
|
||||
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_vif *vif = netdev_priv(ndev);
|
||||
struct ath6kl_vif *vif = netdev_priv(wdev->netdev);
|
||||
|
||||
spin_lock_bh(&ar->list_lock);
|
||||
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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration,
|
||||
u64 *cookie)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
u32 id;
|
||||
|
||||
/* 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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
u64 cookie)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
|
||||
if (cookie != vif->last_roc_id)
|
||||
return -ENOENT;
|
||||
@ -3134,15 +3134,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
|
||||
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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
bool dont_wait_for_ack, u64 *cookie)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
|
||||
struct ath6kl *ar = ath6kl_priv(vif->ndev);
|
||||
u32 id;
|
||||
const struct ieee80211_mgmt *mgmt;
|
||||
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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
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",
|
||||
__func__, frame_type, reg);
|
||||
@ -3477,9 +3477,9 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif)
|
||||
ar->num_vif--;
|
||||
}
|
||||
|
||||
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
enum nl80211_iftype type, u8 fw_vif_idx,
|
||||
u8 nw_type)
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
enum nl80211_iftype type,
|
||||
u8 fw_vif_idx, u8 nw_type)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
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);
|
||||
spin_unlock_bh(&ar->list_lock);
|
||||
|
||||
return ndev;
|
||||
return &vif->wdev;
|
||||
|
||||
err:
|
||||
aggr_module_destroy(vif->aggr_cntxt);
|
||||
|
@ -25,9 +25,9 @@ enum ath6kl_cfg_suspend_mode {
|
||||
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
|
||||
};
|
||||
|
||||
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
enum nl80211_iftype type,
|
||||
u8 fw_vif_idx, u8 nw_type);
|
||||
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name,
|
||||
enum nl80211_iftype type,
|
||||
u8 fw_vif_idx, u8 nw_type);
|
||||
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
|
||||
enum wmi_phy_mode mode);
|
||||
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
|
||||
|
@ -56,7 +56,7 @@ EXPORT_SYMBOL(ath6kl_core_rx_complete);
|
||||
int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
|
||||
{
|
||||
struct ath6kl_bmi_target_info targ_info;
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
int ret = 0, i;
|
||||
|
||||
switch (htc_type) {
|
||||
@ -187,12 +187,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
|
||||
rtnl_lock();
|
||||
|
||||
/* 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);
|
||||
|
||||
rtnl_unlock();
|
||||
|
||||
if (!ndev) {
|
||||
if (!wdev) {
|
||||
ath6kl_err("Failed to instantiate a network device\n");
|
||||
ret = -ENOMEM;
|
||||
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",
|
||||
__func__, ndev->name, ndev, ar);
|
||||
__func__, wdev->netdev->name, wdev->netdev, ar);
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -589,6 +589,11 @@ struct ath6kl_vif {
|
||||
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_HOST_REQ_DELAY 500 /* ms */
|
||||
|
||||
|
@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
|
||||
return 0;
|
||||
@ -513,7 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
|
||||
else
|
||||
id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
|
||||
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);
|
||||
|
||||
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",
|
||||
id, ev->ack_status);
|
||||
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_len,
|
||||
!!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);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
@ -608,7 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -691,9 +691,10 @@ scan_out:
|
||||
}
|
||||
|
||||
static s32
|
||||
brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
||||
brcmf_cfg80211_scan(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct net_device *ndev = request->wdev->netdev;
|
||||
s32 err = 0;
|
||||
|
||||
WL_TRACE("Enter\n");
|
||||
|
@ -5359,7 +5359,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
if (changes & BSS_CHANGED_ASSOC) {
|
||||
D_MAC80211("ASSOC %d\n", bss_conf->assoc);
|
||||
if (bss_conf->assoc) {
|
||||
il->timestamp = bss_conf->last_tsf;
|
||||
il->timestamp = bss_conf->sync_tsf;
|
||||
|
||||
if (!il_is_rfkill(il))
|
||||
il->ops->post_associate(il);
|
||||
|
@ -1447,7 +1447,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
|
||||
|
||||
if (changes & BSS_CHANGED_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;
|
||||
} else {
|
||||
/*
|
||||
|
@ -805,7 +805,6 @@ void lbs_scan_done(struct lbs_private *priv)
|
||||
}
|
||||
|
||||
static int lbs_cfg_scan(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
|
@ -1440,9 +1440,10 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
|
||||
* it also informs the results.
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
|
||||
mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct net_device *dev = request->wdev->netdev;
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
int i;
|
||||
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
|
||||
*/
|
||||
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
|
||||
struct mwifiex_private *priv;
|
||||
@ -1701,16 +1702,16 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mwifiex_dev_debugfs_init(priv);
|
||||
#endif
|
||||
return dev;
|
||||
return wdev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
|
||||
|
||||
/*
|
||||
* 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
|
||||
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))
|
||||
netif_carrier_off(priv->netdev);
|
||||
|
||||
if (dev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdevice(dev);
|
||||
if (wdev->netdev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdevice(wdev->netdev);
|
||||
|
||||
if (dev->reg_state == NETREG_UNREGISTERED)
|
||||
free_netdev(dev);
|
||||
if (wdev->netdev->reg_state == NETREG_UNREGISTERED)
|
||||
free_netdev(wdev->netdev);
|
||||
|
||||
/* Clear the priv in adapter */
|
||||
priv->netdev = NULL;
|
||||
|
@ -377,7 +377,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
|
||||
goto done;
|
||||
|
||||
err_add_intf:
|
||||
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
|
||||
mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
|
||||
rtnl_unlock();
|
||||
err_init_fw:
|
||||
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();
|
||||
if (priv->wdev && priv->netdev)
|
||||
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
|
||||
mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
|
@ -1005,10 +1005,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
|
||||
int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc);
|
||||
|
||||
struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name, enum nl80211_iftype type,
|
||||
u32 *flags, struct vif_params *params);
|
||||
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
|
||||
struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
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);
|
||||
|
||||
|
@ -138,7 +138,7 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
|
||||
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 orinoco_private *priv = wiphy_priv(wiphy);
|
||||
|
@ -484,7 +484,7 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
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);
|
||||
|
||||
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)
|
||||
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
|
||||
static int rndis_scan(struct wiphy *wiphy,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct net_device *dev = request->wdev->netdev;
|
||||
struct usbnet *usbdev = netdev_priv(dev);
|
||||
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
|
||||
int ret;
|
||||
|
@ -102,7 +102,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
|
||||
|
||||
/* Update the AID, this is needed for dynamic PS support */
|
||||
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 */
|
||||
rt2x00dev->beacon_int = bss_conf->beacon_int;
|
||||
|
@ -771,6 +771,9 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_IFNAME: network interface name
|
||||
* @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_KEY_DATA: (temporal) key data; for TKIP this consists of
|
||||
@ -1493,6 +1496,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_BG_SCAN_PERIOD,
|
||||
|
||||
NL80211_ATTR_WDEV,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -999,7 +999,7 @@ struct cfg80211_ssid {
|
||||
* @ie_len: length of ie in octets
|
||||
* @rates: bitmap of rates to advertise for each band
|
||||
* @wiphy: the wiphy this was for
|
||||
* @dev: the interface
|
||||
* @wdev: the wireless device to scan for
|
||||
* @aborted: (internal) scan request was notified as aborted
|
||||
* @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];
|
||||
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
/* internal */
|
||||
struct wiphy *wiphy;
|
||||
struct net_device *dev;
|
||||
bool aborted;
|
||||
bool no_cck;
|
||||
|
||||
@ -1435,10 +1436,10 @@ struct cfg80211_gtk_rekey_data {
|
||||
*
|
||||
* @add_virtual_intf: create a new virtual interface with the given name,
|
||||
* must set the struct wireless_dev's iftype. Beware: You must create
|
||||
* the new netdev in the wiphy's network namespace! Returns the netdev,
|
||||
* or an ERR_PTR.
|
||||
* the new netdev in the wiphy's network namespace! Returns the struct
|
||||
* 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,
|
||||
* keep the struct wireless_dev's iftype updated.
|
||||
@ -1617,12 +1618,13 @@ struct cfg80211_ops {
|
||||
int (*resume)(struct wiphy *wiphy);
|
||||
void (*set_wakeup)(struct wiphy *wiphy, bool enabled);
|
||||
|
||||
struct net_device * (*add_virtual_intf)(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev);
|
||||
struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
|
||||
char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
int (*del_virtual_intf)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev);
|
||||
int (*change_virtual_intf)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
@ -1699,7 +1701,7 @@ struct cfg80211_ops {
|
||||
struct ieee80211_channel *chan,
|
||||
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);
|
||||
|
||||
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 (*remain_on_channel)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration,
|
||||
u64 *cookie);
|
||||
int (*cancel_remain_on_channel)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
bool dont_wait_for_ack, u64 *cookie);
|
||||
int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
u64 cookie);
|
||||
|
||||
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
|
||||
@ -1780,7 +1782,7 @@ struct cfg80211_ops {
|
||||
s32 rssi_thold, u32 rssi_hyst);
|
||||
|
||||
void (*mgmt_frame_register)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg);
|
||||
|
||||
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 wireless_dev - wireless per-netdev state
|
||||
* struct wireless_dev - wireless device state
|
||||
*
|
||||
* This structure must be allocated by the driver/stack
|
||||
* that uses the ieee80211_ptr field in struct net_device
|
||||
* (this is intentional so it can be allocated along with
|
||||
* the netdev.)
|
||||
* For netdevs, this structure must be allocated by the driver
|
||||
* that uses the ieee80211_ptr field in struct net_device (this
|
||||
* is intentional so it can be allocated along with 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
|
||||
* @iftype: interface type
|
||||
* @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
|
||||
* @channel: (private) Used by the internal configuration code to track
|
||||
* the user-set AP, monitor and WDS channel
|
||||
@ -2383,6 +2393,8 @@ struct wireless_dev {
|
||||
struct list_head list;
|
||||
struct net_device *netdev;
|
||||
|
||||
u32 identifier;
|
||||
|
||||
struct list_head mgmt_registrations;
|
||||
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
|
||||
* @dev: network device
|
||||
* @wdev: wireless device
|
||||
* @cookie: the request cookie
|
||||
* @chan: The current channel (from remain_on_channel request)
|
||||
* @channel_type: Channel type
|
||||
@ -3277,21 +3289,20 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
|
||||
* channel
|
||||
* @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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_remain_on_channel_expired - remain_on_channel duration expired
|
||||
* @dev: network device
|
||||
* @wdev: wireless device
|
||||
* @cookie: the request cookie
|
||||
* @chan: The current channel (from remain_on_channel request)
|
||||
* @channel_type: Channel type
|
||||
* @gfp: allocation flags
|
||||
*/
|
||||
void cfg80211_remain_on_channel_expired(struct net_device *dev,
|
||||
u64 cookie,
|
||||
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
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
|
||||
* @dev: network device
|
||||
* @wdev: wireless device receiving the frame
|
||||
* @freq: Frequency on which the frame was received in MHz
|
||||
* @sig_dbm: signal strength in mBm, or 0 if unknown
|
||||
* @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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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()
|
||||
* @buf: Management frame (header + body)
|
||||
* @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
|
||||
* 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);
|
||||
|
||||
|
||||
|
@ -233,8 +233,10 @@ enum ieee80211_rssi_event {
|
||||
* valid in station mode only while @assoc is true and if also
|
||||
* requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
|
||||
* @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)
|
||||
* @sync_device_ts: the device timestamp corresponding to the sync_tsf,
|
||||
* the driver/device can use this to calculate synchronisation
|
||||
* @beacon_int: beacon interval
|
||||
* @assoc_capability: capabilities taken from assoc resp
|
||||
* @basic_rates: bitmap of basic rates, each bit stands for an
|
||||
@ -281,7 +283,8 @@ struct ieee80211_bss_conf {
|
||||
u8 dtim_period;
|
||||
u16 beacon_int;
|
||||
u16 assoc_capability;
|
||||
u64 last_tsf;
|
||||
u64 sync_tsf;
|
||||
u32 sync_device_ts;
|
||||
u32 basic_rates;
|
||||
int mcast_rate[IEEE80211_NUM_BANDS];
|
||||
u16 ht_operation_mode;
|
||||
@ -696,6 +699,8 @@ enum mac80211_rx_flags {
|
||||
*
|
||||
* @mactime: value in microseconds of the 64-bit Time Synchronization Function
|
||||
* (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
|
||||
* @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
|
||||
@ -709,13 +714,14 @@ enum mac80211_rx_flags {
|
||||
*/
|
||||
struct ieee80211_rx_status {
|
||||
u64 mactime;
|
||||
enum ieee80211_band band;
|
||||
int freq;
|
||||
int signal;
|
||||
int antenna;
|
||||
int rate_idx;
|
||||
int flag;
|
||||
unsigned int rx_flags;
|
||||
u32 device_timestamp;
|
||||
u16 flag;
|
||||
u16 freq;
|
||||
u8 rate_idx;
|
||||
u8 rx_flags;
|
||||
u8 band;
|
||||
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,
|
||||
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
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
|
@ -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->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);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_send_bar);
|
||||
|
@ -20,31 +20,31 @@
|
||||
#include "rate.h"
|
||||
#include "mesh.h"
|
||||
|
||||
static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
struct net_device *dev;
|
||||
struct wireless_dev *wdev;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int err;
|
||||
|
||||
err = ieee80211_if_add(local, name, &dev, type, params);
|
||||
err = ieee80211_if_add(local, name, &wdev, type, params);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1741,6 +1741,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1761,10 +1763,11 @@ static int ieee80211_resume(struct wiphy *wiphy)
|
||||
#endif
|
||||
|
||||
static int ieee80211_scan(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
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)) {
|
||||
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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration,
|
||||
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;
|
||||
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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
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;
|
||||
|
||||
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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
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 sk_buff *skb;
|
||||
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,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
u64 cookie)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
||||
return ieee80211_cancel_roc(local, cookie, true);
|
||||
}
|
||||
|
||||
static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
u16 frame_type, bool reg)
|
||||
{
|
||||
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) {
|
||||
case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH:
|
||||
|
@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
|
||||
local->rx_handlers_drop_defrag);
|
||||
DEBUGFS_STATS_ADD(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,
|
||||
local->tx_expand_skb_head);
|
||||
DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
|
||||
|
@ -85,6 +85,8 @@ struct ieee80211_bss {
|
||||
size_t ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
|
||||
u32 device_ts;
|
||||
|
||||
u8 dtim_period;
|
||||
|
||||
bool wmm_used;
|
||||
@ -207,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
|
||||
* enum ieee80211_packet_rx_flags - packet RX flags
|
||||
* @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed
|
||||
* (incl. multicast frames)
|
||||
* @IEEE80211_RX_IN_SCAN: received while scanning
|
||||
* @IEEE80211_RX_FRAGMENTED: fragmented frame
|
||||
* @IEEE80211_RX_AMSDU: a-MSDU packet
|
||||
* @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.
|
||||
*/
|
||||
enum ieee80211_packet_rx_flags {
|
||||
IEEE80211_RX_IN_SCAN = BIT(0),
|
||||
IEEE80211_RX_RA_MATCH = BIT(1),
|
||||
IEEE80211_RX_FRAGMENTED = BIT(2),
|
||||
IEEE80211_RX_AMSDU = BIT(3),
|
||||
@ -965,14 +965,14 @@ struct ieee80211_local {
|
||||
int scan_channel_idx;
|
||||
int scan_ies_len;
|
||||
|
||||
bool sched_scanning;
|
||||
struct ieee80211_sched_scan_ies sched_scan_ies;
|
||||
struct work_struct sched_scan_stopped_work;
|
||||
struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
|
||||
|
||||
unsigned long leave_oper_channel_time;
|
||||
enum mac80211_scan_state next_scan_state;
|
||||
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;
|
||||
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_defrag;
|
||||
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_cloned;
|
||||
unsigned int rx_expand_skb_head;
|
||||
@ -1091,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *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 */
|
||||
struct ieee80211_ra_tid {
|
||||
u8 ra[ETH_ALEN];
|
||||
@ -1241,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_scan_request *req);
|
||||
void ieee80211_scan_cancel(struct ieee80211_local *local);
|
||||
void ieee80211_run_deferred_scan(struct ieee80211_local *local);
|
||||
ieee80211_rx_result
|
||||
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
|
||||
void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb);
|
||||
|
||||
void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
|
||||
struct ieee80211_bss *
|
||||
@ -1278,7 +1282,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
|
||||
int ieee80211_iface_init(void);
|
||||
void ieee80211_iface_exit(void);
|
||||
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);
|
||||
int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
|
||||
enum nl80211_iftype type);
|
||||
|
@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||
}
|
||||
}
|
||||
|
||||
if (local->scan_sdata &&
|
||||
!(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||
scanning = true;
|
||||
local->scan_sdata->vif.bss_conf.idle = false;
|
||||
sdata->vif.bss_conf.idle = false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
|
||||
if (local->monitor_sdata)
|
||||
return 0;
|
||||
goto out_unlock;
|
||||
|
||||
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
|
||||
if (!sdata)
|
||||
return -ENOMEM;
|
||||
if (!sdata) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* set up data */
|
||||
sdata->local = local;
|
||||
@ -357,18 +362,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
if (WARN_ON(ret)) {
|
||||
/* ok .. stupid driver, it asked for this! */
|
||||
kfree(sdata);
|
||||
return ret;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = ieee80211_check_queues(sdata);
|
||||
if (ret) {
|
||||
kfree(sdata);
|
||||
return ret;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(local->monitor_sdata, sdata);
|
||||
|
||||
return 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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))
|
||||
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)
|
||||
return;
|
||||
goto out_unlock;
|
||||
|
||||
rcu_assign_pointer(local->monitor_sdata, NULL);
|
||||
synchronize_net();
|
||||
@ -389,6 +397,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
||||
drv_remove_interface(local, 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);
|
||||
|
||||
if (local->scan_sdata == sdata)
|
||||
if (rcu_access_pointer(local->scan_sdata) == sdata)
|
||||
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,
|
||||
struct net_device **new_dev, enum nl80211_iftype type,
|
||||
struct wireless_dev **new_wdev, enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
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);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
if (new_dev)
|
||||
*new_dev = ndev;
|
||||
if (new_wdev)
|
||||
*new_wdev = &sdata->wdev;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
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,
|
||||
int idx, bool uni, bool multi)
|
||||
{
|
||||
|
@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work)
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
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__);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
|
@ -1108,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
|
||||
if (!local->ops->conf_tx)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (!wmm_param)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
|
||||
uapsd_queues = ifmgd->uapsd_queues;
|
||||
|
||||
count = wmm_param[6] & 0x0f;
|
||||
if (count == ifmgd->wmm_last_param_set)
|
||||
return;
|
||||
return false;
|
||||
ifmgd->wmm_last_param_set = count;
|
||||
|
||||
pos = wmm_param + 8;
|
||||
@ -1202,6 +1202,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
|
||||
|
||||
/* enable WMM or activate new settings */
|
||||
sdata->vif.bss_conf.qos = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_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,
|
||||
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 (directed_tim) {
|
||||
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_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) {
|
||||
erp_valid = true;
|
||||
erp_value = elems.erp_info[0];
|
||||
@ -2974,7 +2969,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
/* scan finished notification */
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES);
|
||||
BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES |
|
||||
BSS_CHANGED_BEACON_INT);
|
||||
|
||||
if (assoc)
|
||||
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
|
||||
|
@ -191,7 +191,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
|
||||
roc->frame = NULL;
|
||||
}
|
||||
} 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->req_duration, GFP_KERNEL);
|
||||
}
|
||||
@ -299,7 +299,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
|
||||
|
||||
/* was never transmitted */
|
||||
if (roc->frame) {
|
||||
cfg80211_mgmt_tx_status(roc->sdata->dev,
|
||||
cfg80211_mgmt_tx_status(&roc->sdata->wdev,
|
||||
(unsigned long)roc->frame,
|
||||
roc->frame->data, roc->frame->len,
|
||||
false, GFP_KERNEL);
|
||||
@ -307,7 +307,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
|
||||
}
|
||||
|
||||
if (!roc->mgmt_tx_cookie)
|
||||
cfg80211_remain_on_channel_expired(roc->sdata->dev,
|
||||
cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
|
||||
(unsigned long)roc,
|
||||
roc->chan, roc->chan_type,
|
||||
GFP_KERNEL);
|
||||
|
@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
/* use fixed index if set */
|
||||
if (mp->fixed_rate_idx != -1)
|
||||
sample_idx = mp->fixed_rate_idx;
|
||||
if (mp->fixed_rate_idx != -1) {
|
||||
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
|
||||
|
||||
if (sample_idx >= 0) {
|
||||
|
@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
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,
|
||||
GFP_ATOMIC)) {
|
||||
if (rx->sta)
|
||||
@ -2695,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
|
||||
goto rxh_next; \
|
||||
} while (0);
|
||||
|
||||
CALL_RXH(ieee80211_rx_h_passive_scan)
|
||||
CALL_RXH(ieee80211_rx_h_check)
|
||||
|
||||
ieee80211_rx_reorder_ampdu(rx);
|
||||
@ -2765,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
return 0;
|
||||
if (ieee80211_is_beacon(hdr->frame_control)) {
|
||||
return 1;
|
||||
}
|
||||
else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
||||
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN))
|
||||
return 0;
|
||||
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
|
||||
} else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
|
||||
return 0;
|
||||
} else if (!multicast &&
|
||||
!ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
|
||||
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
|
||||
* itself never looks at these frames.
|
||||
*/
|
||||
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
|
||||
ieee80211_is_public_action(hdr, skb->len))
|
||||
if (ieee80211_is_public_action(hdr, skb->len))
|
||||
return 1;
|
||||
if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
|
||||
!ieee80211_is_beacon(hdr->frame_control))
|
||||
if (!ieee80211_is_beacon(hdr->frame_control))
|
||||
return 0;
|
||||
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,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
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))
|
||||
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))
|
||||
err = skb_linearize(skb);
|
||||
else
|
||||
@ -2914,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
|
||||
ieee80211_parse_qos(&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)) {
|
||||
prev_sta = NULL;
|
||||
|
||||
|
@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
|
||||
cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel,
|
||||
mgmt, len, signal, GFP_ATOMIC);
|
||||
|
||||
if (!cbss)
|
||||
return NULL;
|
||||
|
||||
cbss->free_priv = ieee80211_rx_bss_free;
|
||||
bss = (void *)cbss->priv;
|
||||
|
||||
bss->device_ts = rx_status->device_timestamp;
|
||||
|
||||
if (elems->parse_error) {
|
||||
if (beacon)
|
||||
bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
|
||||
@ -165,52 +166,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
||||
return bss;
|
||||
}
|
||||
|
||||
ieee80211_rx_result
|
||||
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||
void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *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;
|
||||
u8 *elements;
|
||||
struct ieee80211_channel *channel;
|
||||
size_t baselen;
|
||||
int freq;
|
||||
__le16 fc;
|
||||
bool presp, beacon = false;
|
||||
bool beacon;
|
||||
struct ieee802_11_elems elems;
|
||||
|
||||
if (skb->len < 2)
|
||||
return RX_DROP_UNUSABLE;
|
||||
if (skb->len < 24 ||
|
||||
(!ieee80211_is_probe_resp(mgmt->frame_control) &&
|
||||
!ieee80211_is_beacon(mgmt->frame_control)))
|
||||
return;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||
fc = mgmt->frame_control;
|
||||
sdata1 = rcu_dereference(local->scan_sdata);
|
||||
sdata2 = rcu_dereference(local->sched_scan_sdata);
|
||||
|
||||
if (ieee80211_is_ctl(fc))
|
||||
return RX_CONTINUE;
|
||||
if (likely(!sdata1 && !sdata2))
|
||||
return;
|
||||
|
||||
if (skb->len < 24)
|
||||
return RX_CONTINUE;
|
||||
|
||||
presp = ieee80211_is_probe_resp(fc);
|
||||
if (presp) {
|
||||
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
|
||||
/* ignore ProbeResp to foreign address */
|
||||
if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
|
||||
return RX_DROP_MONITOR;
|
||||
if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
|
||||
(!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
|
||||
return;
|
||||
|
||||
presp = true;
|
||||
elements = mgmt->u.probe_resp.variable;
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
||||
beacon = false;
|
||||
} else {
|
||||
beacon = ieee80211_is_beacon(fc);
|
||||
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
elements = mgmt->u.beacon.variable;
|
||||
beacon = true;
|
||||
}
|
||||
|
||||
if (!presp && !beacon)
|
||||
return RX_CONTINUE;
|
||||
|
||||
if (baselen > skb->len)
|
||||
return RX_DROP_MONITOR;
|
||||
return;
|
||||
|
||||
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
|
||||
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)
|
||||
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,
|
||||
channel, beacon);
|
||||
if (bss)
|
||||
ieee80211_rx_bss_put(sdata->local, bss);
|
||||
|
||||
if (channel == sdata->local->oper_channel)
|
||||
return RX_CONTINUE;
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return RX_QUEUED;
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
/* return false if no more work */
|
||||
@ -293,7 +283,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
|
||||
return;
|
||||
|
||||
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)
|
||||
return;
|
||||
}
|
||||
@ -394,7 +390,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
|
||||
if (!local->scan_req || local->scanning)
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));;
|
||||
|
||||
for (i = 0; i < local->scan_req->n_ssids; i++)
|
||||
ieee80211_send_probe_req(
|
||||
sdata, NULL,
|
||||
@ -439,7 +441,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
if (!ieee80211_can_scan(local, sdata)) {
|
||||
/* wait for the work to finish/time out */
|
||||
local->scan_req = req;
|
||||
local->scan_sdata = sdata;
|
||||
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -473,7 +475,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
local->scan_req = req;
|
||||
local->scan_sdata = sdata;
|
||||
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||
|
||||
if (local->ops->hw_scan) {
|
||||
__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);
|
||||
|
||||
local->scan_req = NULL;
|
||||
local->scan_sdata = NULL;
|
||||
rcu_assign_pointer(local->scan_sdata, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -720,7 +722,8 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
|
||||
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. */
|
||||
if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
|
||||
@ -741,7 +744,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
int rc;
|
||||
|
||||
local->scan_req = NULL;
|
||||
local->scan_sdata = NULL;
|
||||
rcu_assign_pointer(local->scan_sdata, NULL);
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
if (rc) {
|
||||
@ -893,7 +896,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||
|
||||
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -915,9 +920,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
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;
|
||||
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++) {
|
||||
if (!local->hw.wiphy->bands[i])
|
||||
continue;
|
||||
|
||||
local->sched_scan_ies.ie[i] = kzalloc(2 +
|
||||
IEEE80211_MAX_SSID_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,
|
||||
&local->sched_scan_ies);
|
||||
if (ret == 0) {
|
||||
local->sched_scanning = true;
|
||||
rcu_assign_pointer(local->sched_scan_sdata, sdata);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -956,7 +964,7 @@ out_free:
|
||||
while (i > 0)
|
||||
kfree(local->sched_scan_ies.ie[--i]);
|
||||
out:
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -965,22 +973,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int ret = 0, i;
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (!local->ops->sched_scan_stop) {
|
||||
ret = -ENOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (local->sched_scanning) {
|
||||
if (rcu_access_pointer(local->sched_scan_sdata)) {
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
|
||||
kfree(local->sched_scan_ies.ie[i]);
|
||||
|
||||
drv_sched_scan_stop(local, sdata);
|
||||
local->sched_scanning = false;
|
||||
rcu_assign_pointer(local->sched_scan_sdata, NULL);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1004,7 +1012,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
||||
if (!local->sched_scanning) {
|
||||
if (!rcu_access_pointer(local->sched_scan_sdata)) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
}
|
||||
@ -1012,7 +1020,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work)
|
||||
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
|
||||
kfree(local->sched_scan_ies.ie[i]);
|
||||
|
||||
local->sched_scanning = false;
|
||||
rcu_assign_pointer(local->sched_scan_sdata, NULL);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
|
@ -519,14 +519,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
u64 cookie = (unsigned long)skb;
|
||||
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) ||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control))
|
||||
cfg80211_probe_status(skb->dev, hdr->addr1,
|
||||
cookie, acked, GFP_ATOMIC);
|
||||
else
|
||||
cfg80211_mgmt_tx_status(
|
||||
skb->dev, cookie, skb->data, skb->len,
|
||||
acked, GFP_ATOMIC);
|
||||
skb->dev->ieee80211_ptr, cookie, skb->data,
|
||||
skb->len, acked, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
if (unlikely(info->ack_frame_id)) {
|
||||
|
@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__field(u8, dtimper)
|
||||
__field(u16, bcnint)
|
||||
__field(u16, assoc_cap)
|
||||
__field(u64, timestamp)
|
||||
__field(u64, sync_tsf)
|
||||
__field(u32, sync_device_ts)
|
||||
__field(u32, basic_rates)
|
||||
__field(u32, changed)
|
||||
__field(bool, enable_beacon)
|
||||
@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed,
|
||||
__entry->dtimper = info->dtim_period;
|
||||
__entry->bcnint = info->beacon_int;
|
||||
__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->enable_beacon = info->enable_beacon;
|
||||
__entry->ht_operation_mode = info->ht_operation_mode;
|
||||
|
@ -523,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
|
||||
static ieee80211_tx_result debug_noinline
|
||||
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_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) &&
|
||||
(key = rcu_dereference(tx->sdata->default_unicast_key)))
|
||||
tx->key = key;
|
||||
else if (tx->sdata->drop_unencrypted &&
|
||||
(tx->skb->protocol != tx->sdata->control_port_protocol) &&
|
||||
!(info->flags & IEEE80211_TX_CTL_INJECTED) &&
|
||||
(!ieee80211_is_robust_mgmt_frame(hdr) ||
|
||||
(ieee80211_is_action(hdr->frame_control) &&
|
||||
tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) {
|
||||
else if (info->flags & IEEE80211_TX_CTL_INJECTED)
|
||||
tx->key = NULL;
|
||||
else if (!tx->sdata->drop_unencrypted)
|
||||
tx->key = NULL;
|
||||
else if (tx->skb->protocol == tx->sdata->control_port_protocol)
|
||||
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);
|
||||
return TX_DROP;
|
||||
} else
|
||||
tx->key = NULL;
|
||||
}
|
||||
|
||||
if (tx->key) {
|
||||
bool skip_hw = false;
|
||||
|
@ -529,6 +529,11 @@ void ieee80211_iterate_active_interfaces(
|
||||
&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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
|
||||
@ -557,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic(
|
||||
&sdata->vif);
|
||||
}
|
||||
|
||||
sdata = rcu_dereference(local->monitor_sdata);
|
||||
if (sdata)
|
||||
iterator(data, sdata->vif.addr, &sdata->vif);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
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;
|
||||
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
if (WARN_ON_ONCE(!sband))
|
||||
return 0;
|
||||
|
||||
pos = buffer;
|
||||
|
||||
|
@ -103,15 +103,13 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
cfg80211_get_chan_state(struct wireless_dev *wdev,
|
||||
struct ieee80211_channel **chan,
|
||||
enum cfg80211_chan_mode *chanmode)
|
||||
{
|
||||
*chan = NULL;
|
||||
*chanmode = CHAN_MODE_UNDEFINED;
|
||||
|
||||
ASSERT_RDEV_LOCK(rdev);
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!netif_running(wdev->netdev))
|
||||
|
@ -176,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
|
||||
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
|
||||
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;
|
||||
err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
|
||||
if (err)
|
||||
@ -188,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
|
||||
/* failed -- clean up to old netns */
|
||||
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) {
|
||||
if (!wdev->netdev)
|
||||
continue;
|
||||
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
|
||||
err = dev_change_net_namespace(wdev->netdev, net,
|
||||
"wlan%d");
|
||||
@ -226,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
|
||||
rtnl_lock();
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
|
||||
list_for_each_entry(wdev, &rdev->netdev_list, list)
|
||||
dev_close(wdev->netdev);
|
||||
list_for_each_entry(wdev, &rdev->wdev_list, list)
|
||||
if (wdev->netdev)
|
||||
dev_close(wdev->netdev);
|
||||
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
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->devlist_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);
|
||||
INIT_LIST_HEAD(&rdev->bss_list);
|
||||
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
|
||||
@ -622,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy)
|
||||
__count == 0; }));
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
BUG_ON(!list_empty(&rdev->netdev_list));
|
||||
BUG_ON(!list_empty(&rdev->wdev_list));
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
/*
|
||||
@ -703,7 +708,7 @@ static void wdev_cleanup_work(struct work_struct *work)
|
||||
|
||||
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;
|
||||
___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);
|
||||
if (has_monitors_only_new != has_monitors_only_old) {
|
||||
rdev->ops->set_monitor_enabled(&rdev->wiphy,
|
||||
has_monitors_only_new);
|
||||
if (rdev->ops->set_monitor_enabled)
|
||||
rdev->ops->set_monitor_enabled(&rdev->wiphy,
|
||||
has_monitors_only_new);
|
||||
|
||||
if (!has_monitors_only_new) {
|
||||
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);
|
||||
|
||||
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++;
|
||||
/* can only change netns with wiphy */
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
|
@ -47,11 +47,11 @@ struct cfg80211_registered_device {
|
||||
/* wiphy index, internal only */
|
||||
int wiphy_idx;
|
||||
|
||||
/* associate netdev list */
|
||||
/* associated wireless interfaces */
|
||||
struct mutex devlist_mtx;
|
||||
/* protected by devlist_mtx or RCU */
|
||||
struct list_head netdev_list;
|
||||
int devlist_generation;
|
||||
struct list_head wdev_list;
|
||||
int devlist_generation, wdev_id;
|
||||
int opencount; /* also protected by devlist_mtx */
|
||||
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_purge_registrations(struct wireless_dev *wdev);
|
||||
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan, bool offchan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
@ -463,8 +463,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
cfg80211_get_chan_state(struct wireless_dev *wdev,
|
||||
struct ieee80211_channel **chan,
|
||||
enum cfg80211_chan_mode *chanmode);
|
||||
|
||||
|
@ -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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
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);
|
||||
|
||||
nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
|
||||
nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
|
||||
duration, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_ready_on_channel);
|
||||
|
||||
void cfg80211_remain_on_channel_expired(struct net_device *dev,
|
||||
u64 cookie,
|
||||
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
|
||||
struct wiphy *wiphy = wdev->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);
|
||||
}
|
||||
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);
|
||||
|
||||
if (rdev->ops->mgmt_frame_register)
|
||||
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
|
||||
frame_type, true);
|
||||
rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true);
|
||||
|
||||
out:
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -731,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
|
||||
}
|
||||
|
||||
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan, bool offchan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
bool channel_type_valid, unsigned int wait,
|
||||
const u8 *buf, size_t len, bool no_cck,
|
||||
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;
|
||||
u16 stype;
|
||||
|
||||
@ -825,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
|
||||
return -EINVAL;
|
||||
|
||||
/* 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,
|
||||
wait, buf, len, no_cck, dont_wait_for_ack,
|
||||
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)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
struct cfg80211_mgmt_registration *reg;
|
||||
@ -871,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
|
||||
/* found match! */
|
||||
|
||||
/* 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,
|
||||
buf, len, gfp))
|
||||
continue;
|
||||
@ -886,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = {
|
||||
.post_doit = nl80211_post_doit,
|
||||
};
|
||||
|
||||
/* internal helper: get rdev and dev */
|
||||
static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct net_device **dev)
|
||||
/* returns ERR_PTR values */
|
||||
static struct wireless_dev *
|
||||
__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
|
||||
{
|
||||
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])
|
||||
return -EINVAL;
|
||||
assert_cfg80211_lock();
|
||||
|
||||
ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
|
||||
*dev = dev_get_by_index(netns, ifindex);
|
||||
if (!*dev)
|
||||
return -ENODEV;
|
||||
if (!have_ifidx && !have_wdev_id)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
*rdev = cfg80211_get_dev_from_ifindex(netns, ifindex);
|
||||
if (IS_ERR(*rdev)) {
|
||||
dev_put(*dev);
|
||||
return PTR_ERR(*rdev);
|
||||
if (have_ifidx)
|
||||
ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
|
||||
if (have_wdev_id) {
|
||||
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 *
|
||||
@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
|
||||
assert_cfg80211_lock();
|
||||
|
||||
if (!attrs[NL80211_ATTR_WIPHY] &&
|
||||
!attrs[NL80211_ATTR_IFINDEX])
|
||||
!attrs[NL80211_ATTR_IFINDEX] &&
|
||||
!attrs[NL80211_ATTR_WDEV])
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (attrs[NL80211_ATTR_WIPHY])
|
||||
rdev = cfg80211_rdev_by_wiphy_idx(
|
||||
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]) {
|
||||
int ifindex = nla_get_u32(attrs[NL80211_ATTR_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_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@ -1668,22 +1728,32 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
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,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct net_device *dev = wdev->netdev;
|
||||
void *hdr;
|
||||
|
||||
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFTYPE,
|
||||
dev->ieee80211_ptr->iftype) ||
|
||||
if (dev &&
|
||||
(nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
|
||||
nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr)))
|
||||
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,
|
||||
rdev->devlist_generation ^
|
||||
(cfg80211_rdev_list_generation << 2)))
|
||||
@ -1724,14 +1794,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
|
||||
if_idx = 0;
|
||||
|
||||
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_idx++;
|
||||
continue;
|
||||
}
|
||||
if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
rdev, wdev->netdev) < 0) {
|
||||
rdev, wdev) < 0) {
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
goto out;
|
||||
}
|
||||
@ -1754,14 +1824,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
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);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
|
||||
dev, netdev) < 0) {
|
||||
dev, wdev) < 0) {
|
||||
nlmsg_free(msg);
|
||||
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 vif_params params;
|
||||
struct net_device *dev;
|
||||
struct wireless_dev *wdev;
|
||||
struct sk_buff *msg;
|
||||
int err;
|
||||
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
||||
u32 flags;
|
||||
@ -1928,19 +1999,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
dev = rdev->ops->add_virtual_intf(&rdev->wiphy,
|
||||
wdev = rdev->ops->add_virtual_intf(&rdev->wiphy,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
type, err ? NULL : &flags, ¶ms);
|
||||
if (IS_ERR(dev))
|
||||
return PTR_ERR(dev);
|
||||
if (IS_ERR(wdev)) {
|
||||
nlmsg_free(msg);
|
||||
return PTR_ERR(wdev);
|
||||
}
|
||||
|
||||
if (type == NL80211_IFTYPE_MESH_POINT &&
|
||||
info->attrs[NL80211_ATTR_MESH_ID]) {
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
|
||||
wdev_lock(wdev);
|
||||
BUILD_BUG_ON(IEEE80211_MAX_SSID_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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
@ -2350,7 +2441,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
|
||||
|
||||
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 &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
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)
|
||||
{
|
||||
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 nlattr *attr;
|
||||
struct wiphy *wiphy;
|
||||
@ -4199,15 +4290,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
request->no_cck =
|
||||
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
|
||||
|
||||
request->dev = dev;
|
||||
request->wdev = wdev;
|
||||
request->wiphy = &rdev->wiphy;
|
||||
|
||||
rdev->scan_req = request;
|
||||
err = rdev->ops->scan(&rdev->wiphy, dev, request);
|
||||
err = rdev->ops->scan(&rdev->wiphy, request);
|
||||
|
||||
if (!err) {
|
||||
nl80211_send_scan_start(rdev, dev);
|
||||
dev_hold(dev);
|
||||
nl80211_send_scan_start(rdev, wdev);
|
||||
if (wdev->netdev)
|
||||
dev_hold(wdev->netdev);
|
||||
} else {
|
||||
out_free:
|
||||
rdev->scan_req = NULL;
|
||||
@ -5685,7 +5777,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
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 sk_buff *msg;
|
||||
void *hdr;
|
||||
@ -5733,7 +5825,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
||||
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);
|
||||
|
||||
if (err)
|
||||
@ -5757,7 +5849,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
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;
|
||||
|
||||
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]);
|
||||
|
||||
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,
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
|
||||
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])
|
||||
frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* not much point in registering if we can't reply */
|
||||
if (!rdev->ops->mgmt_tx)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
|
||||
frame_type,
|
||||
return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type,
|
||||
nla_data(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)
|
||||
{
|
||||
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;
|
||||
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
|
||||
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)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_DURATION]) {
|
||||
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,
|
||||
nla_data(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)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -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_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
|
||||
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,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wireless_dev *wdev;
|
||||
struct net_device *dev;
|
||||
int err;
|
||||
bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
|
||||
|
||||
if (rtnl)
|
||||
@ -6675,24 +6782,51 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
info->user_ptr[0] = rdev;
|
||||
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
|
||||
err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs,
|
||||
&rdev, &dev);
|
||||
if (err) {
|
||||
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
|
||||
ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
|
||||
info->attrs);
|
||||
if (IS_ERR(wdev)) {
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
if (rtnl)
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
return PTR_ERR(wdev);
|
||||
}
|
||||
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
|
||||
!netif_running(dev)) {
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
dev_put(dev);
|
||||
if (rtnl)
|
||||
rtnl_unlock();
|
||||
return -ENETDOWN;
|
||||
|
||||
dev = wdev->netdev;
|
||||
rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
||||
if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
|
||||
if (!dev) {
|
||||
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[1] = dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -6703,8 +6837,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
|
||||
{
|
||||
if (info->user_ptr[0])
|
||||
cfg80211_unlock_rdev(info->user_ptr[0]);
|
||||
if (info->user_ptr[1])
|
||||
dev_put(info->user_ptr[1]);
|
||||
if (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)
|
||||
rtnl_unlock();
|
||||
}
|
||||
@ -6731,7 +6873,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.dumpit = nl80211_dump_interface,
|
||||
.policy = nl80211_policy,
|
||||
/* can be retrieved by unprivileged users */
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV,
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_INTERFACE,
|
||||
@ -6754,7 +6896,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_del_interface,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -6925,7 +7067,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_trigger_scan,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -7066,7 +7208,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_remain_on_channel,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -7074,7 +7216,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_cancel_remain_on_channel,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -7090,7 +7232,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_register_mgmt,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -7098,7 +7240,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_tx_mgmt,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
@ -7106,7 +7248,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.doit = nl80211_tx_mgmt_cancel_wait,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
||||
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,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
struct wireless_dev *wdev,
|
||||
u32 pid, u32 seq, int flags,
|
||||
u32 cmd)
|
||||
{
|
||||
@ -7328,7 +7470,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
|
||||
return -1;
|
||||
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
struct net_device *netdev)
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
@ -7373,7 +7517,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
|
||||
if (!msg)
|
||||
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) {
|
||||
nlmsg_free(msg);
|
||||
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,
|
||||
struct net_device *netdev)
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
@ -7392,7 +7536,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
|
||||
if (!msg)
|
||||
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) {
|
||||
nlmsg_free(msg);
|
||||
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,
|
||||
struct net_device *netdev)
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
@ -7411,7 +7555,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
|
||||
if (!msg)
|
||||
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) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
@ -7934,7 +8078,7 @@ nla_put_failure:
|
||||
|
||||
static void nl80211_send_remain_on_chan_event(
|
||||
int cmd, struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u64 cookie,
|
||||
struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
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) ||
|
||||
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_CHANNEL_TYPE, channel_type) ||
|
||||
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,
|
||||
struct net_device *netdev, u64 cookie,
|
||||
struct wireless_dev *wdev, u64 cookie,
|
||||
struct ieee80211_channel *chan,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, gfp_t gfp)
|
||||
{
|
||||
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
|
||||
rdev, netdev, cookie, chan,
|
||||
rdev, wdev, cookie, chan,
|
||||
channel_type, duration, gfp);
|
||||
}
|
||||
|
||||
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,
|
||||
enum nl80211_channel_type channel_type, gfp_t gfp)
|
||||
{
|
||||
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
|
||||
rdev, netdev, cookie, chan,
|
||||
rdev, wdev, cookie, chan,
|
||||
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,
|
||||
struct net_device *netdev, u32 nlpid,
|
||||
struct wireless_dev *wdev, u32 nlpid,
|
||||
int freq, int sig_dbm,
|
||||
const u8 *buf, size_t len, gfp_t gfp)
|
||||
{
|
||||
struct net_device *netdev = wdev->netdev;
|
||||
struct sk_buff *msg;
|
||||
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) ||
|
||||
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) ||
|
||||
(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,
|
||||
struct net_device *netdev, u64 cookie,
|
||||
struct wireless_dev *wdev, u64 cookie,
|
||||
const u8 *buf, size_t len, bool ack,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct net_device *netdev = wdev->netdev;
|
||||
struct sk_buff *msg;
|
||||
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) ||
|
||||
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_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
|
||||
(ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
|
||||
@ -8483,7 +8634,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
||||
rcu_read_lock();
|
||||
|
||||
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);
|
||||
if (rdev->ap_beacons_nlpid == notify->pid)
|
||||
rdev->ap_beacons_nlpid = 0;
|
||||
|
@ -7,11 +7,11 @@ int nl80211_init(void);
|
||||
void nl80211_exit(void);
|
||||
void nl80211_notify_dev_rename(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,
|
||||
struct net_device *netdev);
|
||||
struct wireless_dev *wdev);
|
||||
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,
|
||||
struct net_device *netdev, u32 cmd);
|
||||
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);
|
||||
|
||||
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,
|
||||
enum nl80211_channel_type channel_type,
|
||||
unsigned int duration, gfp_t gfp);
|
||||
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,
|
||||
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);
|
||||
|
||||
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,
|
||||
const u8 *buf, size_t len, gfp_t gfp);
|
||||
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,
|
||||
gfp_t gfp);
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
|
||||
{
|
||||
struct cfg80211_scan_request *request;
|
||||
struct net_device *dev;
|
||||
struct wireless_dev *wdev;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
union iwreq_data wrqu;
|
||||
#endif
|
||||
@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
|
||||
if (!request)
|
||||
return;
|
||||
|
||||
dev = request->dev;
|
||||
wdev = request->wdev;
|
||||
|
||||
/*
|
||||
* This must be before sending the other events!
|
||||
* Otherwise, wpa_supplicant gets completely confused with
|
||||
* wext events.
|
||||
*/
|
||||
cfg80211_sme_scan_done(dev);
|
||||
if (wdev->netdev)
|
||||
cfg80211_sme_scan_done(wdev->netdev);
|
||||
|
||||
if (request->aborted)
|
||||
nl80211_send_scan_aborted(rdev, dev);
|
||||
nl80211_send_scan_aborted(rdev, wdev);
|
||||
else
|
||||
nl80211_send_scan_done(rdev, dev);
|
||||
nl80211_send_scan_done(rdev, wdev);
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
if (!request->aborted) {
|
||||
if (wdev->netdev && !request->aborted) {
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
|
||||
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
|
||||
wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
dev_put(dev);
|
||||
if (wdev->netdev)
|
||||
dev_put(wdev->netdev);
|
||||
|
||||
rdev->scan_req = NULL;
|
||||
|
||||
@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
|
||||
}
|
||||
|
||||
creq->wiphy = wiphy;
|
||||
creq->dev = dev;
|
||||
creq->wdev = dev->ieee80211_ptr;
|
||||
/* SSIDs come after channels */
|
||||
creq->ssids = (void *)&creq->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;
|
||||
|
||||
rdev->scan_req = creq;
|
||||
err = rdev->ops->scan(wiphy, dev, creq);
|
||||
err = rdev->ops->scan(wiphy, creq);
|
||||
if (err) {
|
||||
rdev->scan_req = NULL;
|
||||
/* creq will be freed below */
|
||||
} else {
|
||||
nl80211_send_scan_start(rdev, dev);
|
||||
nl80211_send_scan_start(rdev, dev->ieee80211_ptr);
|
||||
/* creq now owned by driver */
|
||||
creq = NULL;
|
||||
dev_hold(dev);
|
||||
|
@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void)
|
||||
*/
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
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);
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||||
is_all_idle = false;
|
||||
@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
|
||||
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;
|
||||
|
||||
rdev->scan_req = request;
|
||||
|
||||
err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
|
||||
err = rdev->ops->scan(wdev->wiphy, request);
|
||||
if (!err) {
|
||||
wdev->conn->state = CFG80211_CONN_SCANNING;
|
||||
nl80211_send_scan_start(rdev, wdev->netdev);
|
||||
nl80211_send_scan_start(rdev, wdev);
|
||||
dev_hold(wdev->netdev);
|
||||
} else {
|
||||
rdev->scan_req = NULL;
|
||||
@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work)
|
||||
cfg80211_lock_rdev(rdev);
|
||||
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);
|
||||
if (!netif_running(wdev->netdev)) {
|
||||
wdev_unlock(wdev);
|
||||
|
@ -793,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
|
||||
|
||||
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);
|
||||
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
@ -994,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
|
||||
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)
|
||||
continue;
|
||||
if (wdev->beacon_interval != beacon_int) {
|
||||
@ -1050,7 +1050,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
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)
|
||||
continue;
|
||||
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))
|
||||
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) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
|
Loading…
Reference in New Issue
Block a user