Commit 3e122be0 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: make master netdev handling sane

Currently, almost every interface type has a 'bss' pointer
pointing to BSS information. This BSS information, however,
is for a _local_ BSS, not for the BSS we joined, so having
it on a STA mode interface makes little sense, but now they
have it pointing to the master device, which is an AP mode
virtual interface. However, except for some bitrate control
data, this pointer is only used in AP/VLAN modes (for power
saving stations.)

Overall, it is not necessary to even have the master netdev
be a valid virtual interface, and it doesn't have to be on
the list of interfaces either.

This patch changes the master netdev to be special, it now
 - no longer is on the list of virtual interfaces, which
   lets me remove a lot of tests for that
 - no longer has sub_if_data attached, since that isn't used

Additionally, this patch changes some vlan/ap mode handling
that is related to these 'bss' pointers described above (but
in the VLAN case they actually make sense because there they
point to the AP they belong to); it also adds some debugging
code to IEEE80211_DEV_TO_SUB_IF to validate it is not called
on the master netdev any more.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 500c1197
...@@ -57,7 +57,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, ...@@ -57,7 +57,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
if (itype == IEEE80211_IF_TYPE_INVALID) if (itype == IEEE80211_IF_TYPE_INVALID)
return -EINVAL; return -EINVAL;
err = ieee80211_if_add(local->mdev, name, &dev, itype, params); err = ieee80211_if_add(local, name, &dev, itype, params);
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
return err; return err;
......
...@@ -156,6 +156,8 @@ static const struct file_operations name##_ops = { \ ...@@ -156,6 +156,8 @@ static const struct file_operations name##_ops = { \
/* common attributes */ /* common attributes */
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
/* STA/IBSS attributes */ /* STA/IBSS attributes */
IEEE80211_IF_FILE(state, u.sta.state, DEC); IEEE80211_IF_FILE(state, u.sta.state, DEC);
...@@ -191,8 +193,6 @@ __IEEE80211_IF_FILE(flags); ...@@ -191,8 +193,6 @@ __IEEE80211_IF_FILE(flags);
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC); IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast( static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
...@@ -248,6 +248,9 @@ IEEE80211_IF_WFILE(min_discovery_timeout, ...@@ -248,6 +248,9 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
static void add_sta_files(struct ieee80211_sub_if_data *sdata) static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(drop_unencrypted, sta); DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(state, sta); DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(prev_bssid, sta); DEBUGFS_ADD(prev_bssid, sta);
...@@ -268,23 +271,29 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) ...@@ -268,23 +271,29 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata) static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(drop_unencrypted, ap); DEBUGFS_ADD(drop_unencrypted, ap);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(dtim_count, ap);
DEBUGFS_ADD(num_beacons, ap); DEBUGFS_ADD(num_beacons, ap);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(num_buffered_multicast, ap); DEBUGFS_ADD(num_buffered_multicast, ap);
} }
static void add_wds_files(struct ieee80211_sub_if_data *sdata) static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(drop_unencrypted, wds); DEBUGFS_ADD(drop_unencrypted, wds);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(peer, wds); DEBUGFS_ADD(peer, wds);
} }
static void add_vlan_files(struct ieee80211_sub_if_data *sdata) static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(drop_unencrypted, vlan); DEBUGFS_ADD(drop_unencrypted, vlan);
DEBUGFS_ADD(force_unicast_rateidx, ap);
DEBUGFS_ADD(max_ratectrl_rateidx, ap);
} }
static void add_monitor_files(struct ieee80211_sub_if_data *sdata) static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
...@@ -372,6 +381,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata) ...@@ -372,6 +381,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
static void del_sta_files(struct ieee80211_sub_if_data *sdata) static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(drop_unencrypted, sta); DEBUGFS_DEL(drop_unencrypted, sta);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(state, sta); DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(bssid, sta);
DEBUGFS_DEL(prev_bssid, sta); DEBUGFS_DEL(prev_bssid, sta);
...@@ -392,23 +404,29 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) ...@@ -392,23 +404,29 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
static void del_ap_files(struct ieee80211_sub_if_data *sdata) static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(drop_unencrypted, ap); DEBUGFS_DEL(drop_unencrypted, ap);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(dtim_count, ap);
DEBUGFS_DEL(num_beacons, ap); DEBUGFS_DEL(num_beacons, ap);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(num_buffered_multicast, ap); DEBUGFS_DEL(num_buffered_multicast, ap);
} }
static void del_wds_files(struct ieee80211_sub_if_data *sdata) static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(drop_unencrypted, wds); DEBUGFS_DEL(drop_unencrypted, wds);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(peer, wds); DEBUGFS_DEL(peer, wds);
} }
static void del_vlan_files(struct ieee80211_sub_if_data *sdata) static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(drop_unencrypted, vlan); DEBUGFS_DEL(drop_unencrypted, vlan);
DEBUGFS_DEL(force_unicast_rateidx, ap);
DEBUGFS_DEL(max_ratectrl_rateidx, ap);
} }
static void del_monitor_files(struct ieee80211_sub_if_data *sdata) static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
...@@ -525,7 +543,7 @@ static int netdev_notify(struct notifier_block *nb, ...@@ -525,7 +543,7 @@ static int netdev_notify(struct notifier_block *nb,
{ {
struct net_device *dev = ndev; struct net_device *dev = ndev;
struct dentry *dir; struct dentry *dir;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata;
char buf[10+IFNAMSIZ]; char buf[10+IFNAMSIZ];
if (state != NETDEV_CHANGENAME) if (state != NETDEV_CHANGENAME)
...@@ -537,6 +555,8 @@ static int netdev_notify(struct notifier_block *nb, ...@@ -537,6 +555,8 @@ static int netdev_notify(struct notifier_block *nb,
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return 0; return 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sprintf(buf, "netdev:%s", dev->name); sprintf(buf, "netdev:%s", dev->name);
dir = sdata->debugfsdir; dir = sdata->debugfsdir;
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
......
...@@ -237,8 +237,6 @@ struct ieee80211_if_ap { ...@@ -237,8 +237,6 @@ struct ieee80211_if_ap {
struct sk_buff_head ps_bc_buf; struct sk_buff_head ps_bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */ atomic_t num_sta_ps; /* number of stations in PS mode */
int dtim_count; int dtim_count;
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
int num_beacons; /* number of TXed beacon frames for this BSS */ int num_beacons; /* number of TXed beacon frames for this BSS */
}; };
...@@ -248,7 +246,6 @@ struct ieee80211_if_wds { ...@@ -248,7 +246,6 @@ struct ieee80211_if_wds {
}; };
struct ieee80211_if_vlan { struct ieee80211_if_vlan {
struct ieee80211_sub_if_data *ap;
struct list_head list; struct list_head list;
}; };
...@@ -432,16 +429,18 @@ struct ieee80211_sub_if_data { ...@@ -432,16 +429,18 @@ struct ieee80211_sub_if_data {
struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
struct ieee80211_key *default_key; struct ieee80211_key *default_key;
/* BSS configuration for this interface. */
struct ieee80211_bss_conf bss_conf;
/* /*
* BSS configuration for this interface. * AP this belongs to: self in AP mode and
* * corresponding AP in VLAN mode, NULL for
* FIXME: I feel bad putting this here when we already have a * all others (might be needed later in IBSS)
* bss pointer, but the bss pointer is just wrong when
* you have multiple virtual STA mode interfaces...
* This needs to be fixed.
*/ */
struct ieee80211_bss_conf bss_conf; struct ieee80211_if_ap *bss;
struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
int max_ratectrl_rateidx; /* max TX rateidx for rate control */
union { union {
struct ieee80211_if_ap ap; struct ieee80211_if_ap ap;
...@@ -533,8 +532,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) ...@@ -533,8 +532,6 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
return container_of(p, struct ieee80211_sub_if_data, vif); return container_of(p, struct ieee80211_sub_if_data, vif);
} }
#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
enum { enum {
IEEE80211_RX_MSG = 1, IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2, IEEE80211_TX_STATUS_MSG = 2,
...@@ -760,6 +757,16 @@ static inline int ieee80211_is_multiqueue(struct ieee80211_local *local) ...@@ -760,6 +757,16 @@ static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
#endif #endif
} }
static inline struct ieee80211_sub_if_data *
IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
BUG_ON(!local || local->mdev == dev);
return netdev_priv(dev);
}
/* this struct represents 802.11n's RA/TID combination */ /* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid { struct ieee80211_ra_tid {
u8 ra[ETH_ALEN]; u8 ra[ETH_ALEN];
...@@ -883,8 +890,8 @@ int ieee80211_sta_scan_results(struct net_device *dev, ...@@ -883,8 +890,8 @@ int ieee80211_sta_scan_results(struct net_device *dev,
ieee80211_rx_result ieee80211_sta_rx_scan( ieee80211_rx_result ieee80211_sta_rx_scan(
struct net_device *dev, struct sk_buff *skb, struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status); struct ieee80211_rx_status *rx_status);
void ieee80211_rx_bss_list_init(struct net_device *dev); void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
void ieee80211_rx_bss_list_deinit(struct net_device *dev); void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev, struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
struct sk_buff *skb, u8 *bssid, struct sk_buff *skb, u8 *bssid,
...@@ -925,8 +932,8 @@ static inline void ieee80211_start_mesh(struct net_device *dev) ...@@ -925,8 +932,8 @@ static inline void ieee80211_start_mesh(struct net_device *dev)
{} {}
#endif #endif
/* ieee80211_iface.c */ /* interface handling */
int ieee80211_if_add(struct net_device *dev, const char *name, int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, int type, struct net_device **new_dev, int type,
struct vif_params *params); struct vif_params *params);
void ieee80211_if_set_type(struct net_device *dev, int type); void ieee80211_if_set_type(struct net_device *dev, int type);
......
...@@ -27,6 +27,9 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) ...@@ -27,6 +27,9 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
skb_queue_head_init(&sdata->fragments[i].skb_list); skb_queue_head_init(&sdata->fragments[i].skb_list);
INIT_LIST_HEAD(&sdata->key_list); INIT_LIST_HEAD(&sdata->key_list);
sdata->force_unicast_rateidx = -1;
sdata->max_ratectrl_rateidx = -1;
} }
static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
...@@ -38,12 +41,11 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) ...@@ -38,12 +41,11 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
} }
/* Must be called with rtnl lock held. */ /* Must be called with rtnl lock held. */
int ieee80211_if_add(struct net_device *dev, const char *name, int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, int type, struct net_device **new_dev, int type,
struct vif_params *params) struct vif_params *params)
{ {
struct net_device *ndev; struct net_device *ndev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_sub_if_data *sdata = NULL;
int ret; int ret;
...@@ -67,13 +69,10 @@ int ieee80211_if_add(struct net_device *dev, const char *name, ...@@ -67,13 +69,10 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
goto fail; goto fail;
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
ndev->base_addr = dev->base_addr;
ndev->irq = dev->irq;
ndev->mem_start = dev->mem_start;
ndev->mem_end = dev->mem_end;
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
sdata = IEEE80211_DEV_TO_SUB_IF(ndev); /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev);
ndev->ieee80211_ptr = &sdata->wdev; ndev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = local->hw.wiphy; sdata->wdev.wiphy = local->hw.wiphy;
sdata->vif.type = IEEE80211_IF_TYPE_AP; sdata->vif.type = IEEE80211_IF_TYPE_AP;
...@@ -116,14 +115,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ...@@ -116,14 +115,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
int oldtype = sdata->vif.type; int oldtype = sdata->vif.type;
/*
* We need to call this function on the master interface
* which already has a hard_start_xmit routine assigned
* which must not be changed.
*/
if (dev != sdata->local->mdev)
dev->hard_start_xmit = ieee80211_subif_start_xmit;
/* /*
* Called even when register_netdevice fails, it would * Called even when register_netdevice fails, it would
* oops if assigned before initialising the rest. * oops if assigned before initialising the rest.
...@@ -138,22 +129,16 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ...@@ -138,22 +129,16 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
switch (type) { switch (type) {
case IEEE80211_IF_TYPE_WDS: case IEEE80211_IF_TYPE_WDS:
/* nothing special */
break;
case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_VLAN:
sdata->u.vlan.ap = NULL; /* nothing special */
break; break;
case IEEE80211_IF_TYPE_AP: case IEEE80211_IF_TYPE_AP:
sdata->u.ap.force_unicast_rateidx = -1;
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf); skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
sdata->bss = &sdata->u.ap;
INIT_LIST_HEAD(&sdata->u.ap.vlans); INIT_LIST_HEAD(&sdata->u.ap.vlans);
break; break;
case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: { case IEEE80211_IF_TYPE_IBSS: {
struct ieee80211_sub_if_data *msdata;
struct ieee80211_if_sta *ifsta; struct ieee80211_if_sta *ifsta;
ifsta = &sdata->u.sta; ifsta = &sdata->u.sta;
...@@ -171,9 +156,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ...@@ -171,9 +156,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
ifsta->flags |= IEEE80211_STA_WMM_ENABLED; ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
if (ieee80211_vif_is_mesh(&sdata->vif)) if (ieee80211_vif_is_mesh(&sdata->vif))
ieee80211_mesh_init_sdata(sdata); ieee80211_mesh_init_sdata(sdata);
break; break;
...@@ -215,27 +197,8 @@ void ieee80211_if_reinit(struct net_device *dev) ...@@ -215,27 +197,8 @@ void ieee80211_if_reinit(struct net_device *dev)
WARN_ON(1); WARN_ON(1);
break; break;
case IEEE80211_IF_TYPE_AP: { case IEEE80211_IF_TYPE_AP: {
/* Remove all virtual interfaces that use this BSS
* as their sdata->bss */
struct ieee80211_sub_if_data *tsdata, *n;
struct beacon_data *beacon; struct beacon_data *beacon;
list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
printk(KERN_DEBUG "%s: removing virtual "
"interface %s because its BSS interface"
" is being removed\n",
sdata->dev->name, tsdata->dev->name);
list_del_rcu(&tsdata->list);
/*
* We have lots of time and can afford
* to sync for each interface
*/
synchronize_rcu();
__ieee80211_if_del(local, tsdata);
}
}
beacon = sdata->u.ap.beacon; beacon = sdata->u.ap.beacon;
rcu_assign_pointer(sdata->u.ap.beacon, NULL); rcu_assign_pointer(sdata->u.ap.beacon, NULL);
synchronize_rcu(); synchronize_rcu();
...@@ -249,6 +212,7 @@ void ieee80211_if_reinit(struct net_device *dev) ...@@ -249,6 +212,7 @@ void ieee80211_if_reinit(struct net_device *dev)
break; break;
} }
case IEEE80211_IF_TYPE_WDS: case IEEE80211_IF_TYPE_WDS:
case IEEE80211_IF_TYPE_VLAN:
/* nothing to do */ /* nothing to do */
break; break;
case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_MESH_POINT:
...@@ -269,9 +233,6 @@ void ieee80211_if_reinit(struct net_device *dev) ...@@ -269,9 +233,6 @@ void ieee80211_if_reinit(struct net_device *dev)
case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_ETHER; dev->type = ARPHRD_ETHER;
break; break;
case IEEE80211_IF_TYPE_VLAN:
sdata->u.vlan.ap = NULL;
break;
} }
flushed = sta_info_flush(local, sdata); flushed = sta_info_flush(local, sdata);
...@@ -289,8 +250,10 @@ void __ieee80211_if_del(struct ieee80211_local *local, ...@@ -289,8 +250,10 @@ void __ieee80211_if_del(struct ieee80211_local *local,
ieee80211_debugfs_remove_netdev(sdata); ieee80211_debugfs_remove_netdev(sdata);
unregister_netdevice(dev); unregister_netdevice(dev);
/* Except master interface, the net_device will be freed by /*
* net_device->destructor (i. e. ieee80211_if_free). */ * The net_device will be freed by its destructor,
* i.e. ieee80211_if_free.
*/
} }
/* Must be called with rtnl lock held. */ /* Must be called with rtnl lock held. */
...@@ -303,8 +266,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) ...@@ -303,8 +266,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
list_for_each_entry_safe(sdata, n, &local->interfaces, list) { list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
if ((sdata->vif.type == id || id == -1) && if ((sdata->vif.type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 && strcmp(name, sdata->dev->name) == 0) {
sdata->dev != local->mdev) {
list_del_rcu(&sdata->list); list_del_rcu(&sdata->list);
synchronize_rcu(); synchronize_rcu();
__ieee80211_if_del(local, sdata); __ieee80211_if_del(local, sdata);
......
...@@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev) ...@@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev)
/* we hold the RTNL here so can safely walk the list */ /* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->dev != dev && netif_running(sdata->dev)) { if (netif_running(sdata->dev)) {
res = 0; res = 0;
break; break;
} }
...@@ -126,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev) ...@@ -126,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev)
/* we hold the RTNL here so can safely walk the list */ /* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list) list_for_each_entry(sdata, &local->interfaces, list)
if (sdata->dev != dev && netif_running(sdata->dev)) if (netif_running(sdata->dev))
dev_close(sdata->dev); dev_close(sdata->dev);
return 0; return 0;
...@@ -194,7 +194,7 @@ static int ieee80211_open(struct net_device *dev) ...@@ -194,7 +194,7 @@ static int ieee80211_open(struct net_device *dev)
list_for_each_entry(nsdata, &local->interfaces, list) { list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev; struct net_device *ndev = nsdata->dev;
if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { if (ndev != dev && netif_running(ndev)) {
/* /*
* Allow only a single IBSS interface to be up at any * Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution * time. This is restricted because beacon distribution
...@@ -209,30 +209,6 @@ static int ieee80211_open(struct net_device *dev) ...@@ -209,30 +209,6 @@ static int ieee80211_open(struct net_device *dev)
nsdata->vif.type == IEEE80211_IF_TYPE_IBSS) nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
return -EBUSY; return -EBUSY;
/*
* Disallow multiple IBSS/STA mode interfaces.
*
* This is a technical restriction, it is possible although
* most likely not IEEE 802.11 compliant to have multiple
* STAs with just a single hardware (the TSF timer will not
* be adjusted properly.)
*
* However, because mac80211 uses the master device's BSS
* information for each STA/IBSS interface, doing this will
* currently corrupt that BSS information completely, unless,
* a not very useful case, both STAs are associated to the
* same BSS.
*
* To remove this restriction, the BSS information needs to
* be embedded in the STA/IBSS mode sdata instead of using
* the master device's BSS structure.
*/
if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
(nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
return -EBUSY;
/* /*
* The remaining checks are only performed for interfaces * The remaining checks are only performed for interfaces
* with the same MAC address. * with the same MAC address.
...@@ -252,7 +228,7 @@ static int ieee80211_open(struct net_device *dev) ...@@ -252,7 +228,7 @@ static int ieee80211_open(struct net_device *dev)
*/ */
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
nsdata->vif.type == IEEE80211_IF_TYPE_AP) nsdata->vif.type == IEEE80211_IF_TYPE_AP)
sdata->u.vlan.ap = nsdata; sdata->bss = &nsdata->u.ap;
} }
} }
...@@ -262,10 +238,13 @@ static int ieee80211_open(struct net_device *dev) ...@@ -262,10 +238,13 @@ static int ieee80211_open(struct net_device *dev)
return -ENOLINK; return -ENOLINK;
break; break;
case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_VLAN:
if (!sdata->u.vlan.ap) if (!sdata->bss)
return -ENOLINK; return -ENOLINK;
list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
break; break;
case IEEE80211_IF_TYPE_AP: case IEEE80211_IF_TYPE_AP:
sdata->bss = &sdata->u.ap;
break;
case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS: case IEEE80211_IF_TYPE_IBSS:
...@@ -283,14 +262,13 @@ static int ieee80211_open(struct net_device *dev) ...@@ -283,14 +262,13 @@ static int ieee80211_open(struct net_device *dev)
if (local->ops->start) if (local->ops->start)
res = local->ops->start(local_to_hw(local)); res = local->ops->start(local_to_hw(local));
if (res) if (res)
return res; goto err_del_bss;
need_hw_reconfig = 1; need_hw_reconfig = 1;
ieee80211_led_radio(local, local->hw.conf.radio_enabled); ieee80211_led_radio(local, local->hw.conf.radio_enabled);
} }
switch (sdata->vif.type) { switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_VLAN:
list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
/* no need to tell driver */ /* no need to tell driver */
break; break;
case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MNTR:
...@@ -404,6 +382,10 @@ static int ieee80211_open(struct net_device *dev) ...@@ -404,6 +382,10 @@ static int ieee80211_open(struct net_device *dev)
err_stop: err_stop:
if (!local->open_count && local->ops->stop) if (!local->open_count && local->ops->stop)
local->ops->stop(local_to_hw(local)); local->ops->stop(local_to_hw(local));
err_del_bss:
sdata->bss = NULL;
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
list_del(&sdata->u.vlan.list);
return res; return res;
} }
...@@ -486,7 +468,6 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -486,7 +468,6 @@ static int ieee80211_stop(struct net_device *dev)
switch (sdata->vif.type) { switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_VLAN:
list_del(&sdata->u.vlan.list); list_del(&sdata->u.vlan.list);
sdata->u.vlan.ap = NULL;
/* no need to tell driver */ /* no need to tell driver */
break; break;
case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MNTR:
...@@ -549,6 +530,8 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -549,6 +530,8 @@ static int ieee80211_stop(struct net_device *dev)
local->ops->remove_interface(local_to_hw(local), &conf); local->ops->remove_interface(local_to_hw(local), &conf);
} }
sdata->bss = NULL;
if (local->open_count == 0) { if (local->open_count == 0) {
if (netif_running(local->mdev)) if (netif_running(local->mdev))
dev_close(local->mdev); dev_close(local->mdev);
...@@ -1659,7 +1642,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1659,7 +1642,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
int result; int result;
enum ieee80211_band band; enum ieee80211_band band;
struct net_device *mdev; struct net_device *mdev;
struct ieee80211_sub_if_data *sdata; struct wireless_dev *mwdev;
/* /*
* generic code guarantees at least one band, * generic code guarantees at least one band,
...@@ -1699,8 +1682,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1699,8 +1682,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
hw->ampdu_queues = 0; hw->ampdu_queues = 0;
#endif #endif
/* for now, mdev needs sub_if_data :/ */ mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
"wmaster%d", ether_setup, "wmaster%d", ether_setup,
ieee80211_num_queues(hw)); ieee80211_num_queues(hw));
if (!mdev) if (!mdev)
...@@ -1709,13 +1691,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1709,13 +1691,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (ieee80211_num_queues(hw) > 1) if (ieee80211_num_queues(hw) > 1)
mdev->features |= NETIF_F_MULTI_QUEUE; mdev->features |= NETIF_F_MULTI_QUEUE;
sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mwdev = netdev_priv(mdev);
mdev->ieee80211_ptr = &sdata->wdev; mdev->ieee80211_ptr = mwdev;
sdata->wdev.wiphy = local->hw.wiphy; mwdev->wiphy = local->hw.wiphy;
local->mdev = mdev; local->mdev = mdev;
ieee80211_rx_bss_list_init(mdev); ieee80211_rx_bss_list_init(local);
mdev->hard_start_xmit = ieee80211_master_start_xmit; mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->open = ieee80211_master_open; mdev->open = ieee80211_master_open;
...@@ -1724,16 +1706,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1724,16 +1706,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
mdev->header_ops = &ieee80211_header_ops; mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list; mdev->set_multicast_list = ieee80211_master_set_multicast_list;
sdata->vif.type = IEEE80211_IF_TYPE_AP;
sdata->dev = mdev;
sdata->local = local;
sdata->u.ap.force_unicast_rateidx = -1;
sdata->u.ap.max_ratectrl_rateidx = -1;
ieee80211_if_sdata_init(sdata);
/* no RCU needed since we're still during init phase */
list_add_tail(&sdata->list, &local->interfaces);
name = wiphy_dev(local->hw.wiphy)->driver->name; name = wiphy_dev(local->hw.wiphy)->driver->name;
local->hw.workqueue = create_freezeable_workqueue(name); local->hw.workqueue = create_freezeable_workqueue(name);
if (!local->hw.workqueue) { if (!local->hw.workqueue) {
...@@ -1779,9 +1751,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1779,9 +1751,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (result < 0) if (result < 0)
goto fail_dev; goto fail_dev;
ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
result = ieee80211_init_rate_ctrl_alg(local, result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm); hw->rate_control_algorithm);
if (result < 0) { if (result < 0) {
...@@ -1801,7 +1770,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1801,7 +1770,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_install_qdisc(local->mdev); ieee80211_install_qdisc(local->mdev);
/* add one default STA interface */ /* add one default STA interface */
result = ieee80211_if_add(local->mdev, "wlan%d", NULL, result = ieee80211_if_add(local, "wlan%d", NULL,
IEEE80211_IF_TYPE_STA, NULL); IEEE80211_IF_TYPE_STA, NULL);
if (result) if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n", printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
...@@ -1817,7 +1786,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1817,7 +1786,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
fail_wep: fail_wep:
rate_control_deinitialize(local); rate_control_deinitialize(local);
fail_rate: fail_rate:
ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
unregister_netdevice(local->mdev); unregister_netdevice(local->mdev);
local->mdev = NULL; local->mdev = NULL;
fail_dev: fail_dev:
...@@ -1827,10 +1795,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -1827,10 +1795,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_del(local); debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue); destroy_workqueue(local->hw.workqueue);
fail_workqueue: fail_workqueue:
if (local->mdev != NULL) { if (local->mdev)
ieee80211_if_free(local->mdev); free_netdev(local->mdev);
local->mdev = NULL;
}
fail_mdev_alloc: fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy); wiphy_unregister(local->hw.wiphy);
return result; return result;
...@@ -1858,24 +1824,19 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ...@@ -1858,24 +1824,19 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
*/ */
/* /*
* First, we remove all non-master interfaces. Do this because they * First, we remove all virtual interfaces.
* may have bss pointer dependency on the master, and when we free
* the master these would be freed as well, breaking our list
* iteration completely.
*/ */
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
if (sdata->dev == local->mdev)
continue;
list_del(&sdata->list); list_del(&sdata->list);
__ieee80211_if_del(local, sdata); __ieee80211_if_del(local, sdata);
} }
/* then, finally, remove the master interface */ /* then, finally, remove the master interface */
__ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); unregister_netdevice(local->mdev);
rtnl_unlock(); rtnl_unlock();
ieee80211_rx_bss_list_deinit(local->mdev); ieee80211_rx_bss_list_deinit(local);
ieee80211_clear_tx_pending(local); ieee80211_clear_tx_pending(local);
sta_info_stop(local); sta_info_stop(local);
rate_control_deinitialize(local); rate_control_deinitialize(local);
...@@ -1892,8 +1853,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ...@@ -1892,8 +1853,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_unregister(local->hw.wiphy); wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local); ieee80211_wep_free(local);
ieee80211_led_exit(local); ieee80211_led_exit(local);
ieee80211_if_free(local->mdev); free_netdev(local->mdev);
local->mdev = NULL;
} }
EXPORT_SYMBOL(ieee80211_unregister_hw); EXPORT_SYMBOL(ieee80211_unregister_hw);
......
...@@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, ...@@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
static struct ieee80211_sta_bss * static struct ieee80211_sta_bss *
ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len); u8 *ssid, u8 ssid_len);
static void ieee80211_rx_bss_put(struct net_device *dev, static void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss); struct ieee80211_sta_bss *bss);
static int ieee80211_sta_find_ibss(struct net_device *dev, static int ieee80211_sta_find_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta); struct ieee80211_if_sta *ifsta);
...@@ -554,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev, ...@@ -554,7 +554,7 @@ static void ieee80211_set_associated(struct net_device *dev,
changed |= ieee80211_handle_bss_capability(sdata, bss); changed |= ieee80211_handle_bss_capability(sdata, bss);
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
} }
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
...@@ -760,7 +760,7 @@ static void ieee80211_send_assoc(struct net_device *dev, ...@@ -760,7 +760,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
(local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
} else { } else {
rates = ~0; rates = ~0;
rates_len = sband->n_bitrates; rates_len = sband->n_bitrates;
...@@ -992,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, ...@@ -992,7 +992,7 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
wep_privacy = !!ieee80211_sta_wep_configured(dev); wep_privacy = !!ieee80211_sta_wep_configured(dev);
privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
return 0; return 0;
...@@ -2094,7 +2094,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -2094,7 +2094,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
sta->last_signal = bss->signal; sta->last_signal = bss->signal;
sta->last_qual = bss->qual; sta->last_qual = bss->qual;
sta->last_noise = bss->noise; sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
} }
err = sta_info_insert(sta); err = sta_info_insert(sta);
...@@ -2212,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, ...@@ -2212,10 +2212,9 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
/* Caller must hold local->sta_bss_lock */ /* Caller must hold local->sta_bss_lock */
static void __ieee80211_rx_bss_hash_del(struct net_device *dev, static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss) struct ieee80211_sta_bss *bss)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *b, *prev = NULL; struct ieee80211_sta_bss *b, *prev = NULL;
b = local->sta_bss_hash[STA_HASH(bss->bssid)]; b = local->sta_bss_hash[STA_HASH(bss->bssid)];
while (b) { while (b) {
...@@ -2367,39 +2366,35 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) ...@@ -2367,39 +2366,35 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
} }
static void ieee80211_rx_bss_put(struct net_device *dev, static void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss) struct ieee80211_sta_bss *bss)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
local_bh_disable(); local_bh_disable();
if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
local_bh_enable(); local_bh_enable();
return; return;
} }
__ieee80211_rx_bss_hash_del(dev, bss); __ieee80211_rx_bss_hash_del(local, bss);
list_del(&bss->list); list_del(&bss->list);
spin_unlock_bh(&local->sta_bss_lock); spin_unlock_bh(&local->sta_bss_lock);
ieee80211_rx_bss_free(bss); ieee80211_rx_bss_free(bss);
} }
void ieee80211_rx_bss_list_init(struct net_device *dev) void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
spin_lock_init(&local->sta_bss_lock); spin_lock_init(&local->sta_bss_lock);
INIT_LIST_HEAD(&local->sta_bss_list); INIT_LIST_HEAD(&local->sta_bss_list);
} }
void ieee80211_rx_bss_list_deinit(struct net_device *dev) void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
{ {
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss, *tmp; struct ieee80211_sta_bss *bss, *tmp;
list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
} }
...@@ -2775,7 +2770,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, ...@@ -2775,7 +2770,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
*/ */
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
bss->probe_resp && beacon) { bss->probe_resp && beacon) {
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
return; return;
} }
...@@ -2918,7 +2913,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, ...@@ -2918,7 +2913,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
} }
} }
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
} }
...@@ -3578,7 +3573,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, ...@@ -3578,7 +3573,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
selected->ssid_len); selected->ssid_len);
ieee80211_sta_set_bssid(dev, selected->bssid); ieee80211_sta_set_bssid(dev, selected->bssid);
ieee80211_sta_def_wmm_params(dev, selected, 0); ieee80211_sta_def_wmm_params(dev, selected, 0);
ieee80211_rx_bss_put(dev, selected); ieee80211_rx_bss_put(local, selected);
ifsta->state = IEEE80211_AUTHENTICATE; ifsta->state = IEEE80211_AUTHENTICATE;
ieee80211_sta_reset_auth(dev, ifsta); ieee80211_sta_reset_auth(dev, ifsta);
return 0; return 0;
...@@ -3655,7 +3650,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, ...@@ -3655,7 +3650,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
} }
ret = ieee80211_sta_join_ibss(dev, ifsta, bss); ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
return ret; return ret;
} }
...@@ -3711,7 +3706,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, ...@@ -3711,7 +3706,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
" based on configured SSID\n", " based on configured SSID\n",
dev->name, print_mac(mac, bssid)); dev->name, print_mac(mac, bssid));
ret = ieee80211_sta_join_ibss(dev, ifsta, bss); ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(local, bss);
return ret; return ret;
} }
#ifdef CONFIG_MAC80211_IBSS_DEBUG #ifdef CONFIG_MAC80211_IBSS_DEBUG
...@@ -3907,11 +3902,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) ...@@ -3907,11 +3902,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
/* No need to wake the master device. */
if (sdata->dev == local->mdev)
continue;
/* Tell AP we're back */ /* Tell AP we're back */
if (sdata->vif.type == IEEE80211_IF_TYPE_STA && if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
...@@ -4077,12 +4067,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev, ...@@ -4077,12 +4067,6 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
/* Don't stop the master interface, otherwise we can't transmit
* probes! */
if (sdata->dev == local->mdev)
continue;
netif_stop_queue(sdata->dev); netif_stop_queue(sdata->dev);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA && if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
...@@ -4473,12 +4457,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw, ...@@ -4473,12 +4457,10 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
case IEEE80211_NOTIFY_RE_ASSOC: case IEEE80211_NOTIFY_RE_ASSOC:
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
continue;
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
ieee80211_sta_req_auth(sdata->dev,
&sdata->u.sta);
}
} }
rcu_read_unlock(); rcu_read_unlock();
break; break;
......
...@@ -259,8 +259,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, ...@@ -259,8 +259,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
/* Don't update the state if we're not controlling the rate. */ /* Don't update the state if we're not controlling the rate. */
sdata = sta->sdata; sdata = sta->sdata;
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { if (sdata->force_unicast_rateidx > -1) {
sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; sta->txrate_idx = sdata->max_ratectrl_rateidx;
goto unlock; goto unlock;
} }
...@@ -337,8 +337,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, ...@@ -337,8 +337,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
/* If a forced rate is in effect, select it. */ /* If a forced rate is in effect, select it. */
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) if (sdata->force_unicast_rateidx > -1)
sta->txrate_idx = sdata->bss->force_unicast_rateidx; sta->txrate_idx = sdata->force_unicast_rateidx;
rateidx = sta->txrate_idx; rateidx = sta->txrate_idx;
......
...@@ -647,8 +647,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) ...@@ -647,8 +647,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
sdata = sta->sdata; sdata = sta->sdata;
if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps);
atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
...@@ -667,8 +666,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) ...@@ -667,8 +666,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
sdata = sta->sdata; sdata = sta->sdata;
if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
...@@ -742,7 +740,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) ...@@ -742,7 +740,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->last_qual = rx->status->qual; sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise; sta->last_noise = rx->status->noise;
if (!ieee80211_has_morefrags(hdr->frame_control)) { if (!ieee80211_has_morefrags(hdr->frame_control) &&
(rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
/* Change STA power saving mode only in the end of a frame /* Change STA power saving mode only in the end of a frame
* exchange sequence */ * exchange sequence */
if (test_sta_flags(sta, WLAN_STA_PS) && if (test_sta_flags(sta, WLAN_STA_PS) &&
...@@ -1772,11 +1772,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, ...@@ -1772,11 +1772,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH; rx->flags &= ~IEEE80211_RX_RA_MATCH;
} }
if (sdata->dev == sdata->local->mdev &&
!(rx->flags & IEEE80211_RX_IN_SCAN))
/* do not receive anything via
* master device when not scanning */
return 0;
break; break;
case IEEE80211_IF_TYPE_WDS: case IEEE80211_IF_TYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control)) if (bssid || !ieee80211_is_data(hdr->frame_control))
......
...@@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta) ...@@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta)
/* notify driver */ /* notify driver */
if (local->ops->sta_notify) { if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
sdata = sdata->u.vlan.ap; sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif, local->ops->sta_notify(local_to_hw(local), &sdata->vif,
STA_NOTIFY_ADD, sta->addr); STA_NOTIFY_ADD, sta->addr);
...@@ -375,8 +377,10 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) ...@@ -375,8 +377,10 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
struct sta_info *sta) struct sta_info *sta)
{ {
if (bss) BUG_ON(!bss);
__bss_tim_set(bss, sta->aid);
__bss_tim_set(bss, sta->aid);
if (sta->local->ops->set_tim) { if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true; sta->local->tim_in_locked_section = true;
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
...@@ -388,6 +392,8 @@ void sta_info_set_tim_bit(struct sta_info *sta) ...@@ -388,6 +392,8 @@ void sta_info_set_tim_bit(struct sta_info *sta)
{ {
unsigned long flags; unsigned long flags;
BUG_ON(!sta->sdata->bss);
spin_lock_irqsave(&sta->local->sta_lock, flags); spin_lock_irqsave(&sta->local->sta_lock, flags);
__sta_info_set_tim_bit(sta->sdata->bss, sta); __sta_info_set_tim_bit(sta->sdata->bss, sta);
spin_unlock_irqrestore(&sta->local->sta_lock, flags); spin_unlock_irqrestore(&sta->local->sta_lock, flags);
...@@ -396,8 +402,10 @@ void sta_info_set_tim_bit(struct sta_info *sta) ...@@ -396,8 +402,10 @@ void sta_info_set_tim_bit(struct sta_info *sta)
static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
struct sta_info *sta) struct sta_info *sta)
{ {
if (bss) BUG_ON(!bss);
__bss_tim_clear(bss, sta->aid);
__bss_tim_clear(bss, sta->aid);
if (sta->local->ops->set_tim) { if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true; sta->local->tim_in_locked_section = true;
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
...@@ -409,6 +417,8 @@ void sta_info_clear_tim_bit(struct sta_info *sta) ...@@ -409,6 +417,8 @@ void sta_info_clear_tim_bit(struct sta_info *sta)
{ {
unsigned long flags; unsigned long flags;
BUG_ON(!sta->sdata->bss);
spin_lock_irqsave(&sta->local->sta_lock, flags); spin_lock_irqsave(&sta->local->sta_lock, flags);
__sta_info_clear_tim_bit(sta->sdata->bss, sta); __sta_info_clear_tim_bit(sta->sdata->bss, sta);
spin_unlock_irqrestore(&sta->local->sta_lock, flags); spin_unlock_irqrestore(&sta->local->sta_lock, flags);
...@@ -437,8 +447,9 @@ void __sta_info_unlink(struct sta_info **sta) ...@@ -437,8 +447,9 @@ void __sta_info_unlink(struct sta_info **sta)
list_del(&(*sta)->list); list_del(&(*sta)->list);
if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) { if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
if (sdata->bss) BUG_ON(!sdata->bss);
atomic_dec(&sdata->bss->num_sta_ps);
atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta); __sta_info_clear_tim_bit(sdata->bss, *sta);
} }
...@@ -446,7 +457,9 @@ void __sta_info_unlink(struct sta_info **sta) ...@@ -446,7 +457,9 @@ void __sta_info_unlink(struct sta_info **sta)
if (local->ops->sta_notify) { if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
sdata = sdata->u.vlan.ap; sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif, local->ops->sta_notify(local_to_hw(local), &sdata->vif,
STA_NOTIFY_REMOVE, (*sta)->addr); STA_NOTIFY_REMOVE, (*sta)->addr);
......
...@@ -303,8 +303,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) ...@@ -303,8 +303,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
struct ieee80211_if_ap *ap; struct ieee80211_if_ap *ap;
if (sdata->dev == local->mdev || if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
sdata->vif.type != IEEE80211_IF_TYPE_AP)
continue; continue;
ap = &sdata->u.ap; ap = &sdata->u.ap;
skb = skb_dequeue(&ap->ps_bc_buf); skb = skb_dequeue(&ap->ps_bc_buf);
...@@ -346,8 +345,12 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -346,8 +345,12 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
* This is done either by the hardware or us. * This is done either by the hardware or us.
*/ */
/* not AP/IBSS or ordered frame */ /* powersaving STAs only in AP/VLAN mode */
if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) if (!tx->sdata->bss)
return TX_CONTINUE;
/* no buffering for ordered frames */
if (tx->fc & IEEE80211_FCTL_ORDER)
return TX_CONTINUE; return TX_CONTINUE;
/* no stations in PS mode */ /* no stations in PS mode */
......
...@@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces( ...@@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces(
case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_MESH_POINT:
break; break;
} }
if (sdata->dev == local->mdev)
continue;
if (netif_running(sdata->dev)) if (netif_running(sdata->dev))
iterator(data, sdata->dev->dev_addr, iterator(data, sdata->dev->dev_addr,
&sdata->vif); &sdata->vif);
...@@ -463,8 +461,6 @@ void ieee80211_iterate_active_interfaces_atomic( ...@@ -463,8 +461,6 @@ void ieee80211_iterate_active_interfaces_atomic(
case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_MESH_POINT:
break; break;
} }
if (sdata->dev == local->mdev)
continue;
if (netif_running(sdata->dev)) if (netif_running(sdata->dev))
iterator(data, sdata->dev->dev_addr, iterator(data, sdata->dev->dev_addr,
&sdata->vif); &sdata->vif);
......
...@@ -627,16 +627,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, ...@@ -627,16 +627,14 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (!sdata->bss)
return -ENODEV;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
* target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 1 means only rate X
* target_rate = X, rate->fixed = 0 means all rates <= X */ * target_rate = X, rate->fixed = 0 means all rates <= X */
sdata->bss->max_ratectrl_rateidx = -1; sdata->max_ratectrl_rateidx = -1;
sdata->bss->force_unicast_rateidx = -1; sdata->force_unicast_rateidx = -1;
if (rate->value < 0) if (rate->value < 0)
return 0; return 0;
...@@ -645,9 +643,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, ...@@ -645,9 +643,9 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
int this_rate = brate->bitrate; int this_rate = brate->bitrate;
if (target_rate == this_rate) { if (target_rate == this_rate) {
sdata->bss->max_ratectrl_rateidx = i; sdata->max_ratectrl_rateidx = i;
if (rate->fixed) if (rate->fixed)
sdata->bss->force_unicast_rateidx = i; sdata->force_unicast_rateidx = i;
err = 0; err = 0;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment