aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-07-09 08:40:34 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-07-14 14:30:06 -0400
commit3e122be089e6fb8d3f322416da4cdbb80ce12927 (patch)
tree087db56fcbe05e9a8e2caa874262c81267c27573 /net/mac80211/iface.c
parent500c11973233437cbfd298b9d41ba942550aec76 (diff)
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: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c64
1 files changed, 13 insertions, 51 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index eeb16926aa7d..f2aefd4b8637 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -27,6 +27,9 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
27 skb_queue_head_init(&sdata->fragments[i].skb_list); 27 skb_queue_head_init(&sdata->fragments[i].skb_list);
28 28
29 INIT_LIST_HEAD(&sdata->key_list); 29 INIT_LIST_HEAD(&sdata->key_list);
30
31 sdata->force_unicast_rateidx = -1;
32 sdata->max_ratectrl_rateidx = -1;
30} 33}
31 34
32static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) 35static 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} 41}
39 42
40/* Must be called with rtnl lock held. */ 43/* Must be called with rtnl lock held. */
41int ieee80211_if_add(struct net_device *dev, const char *name, 44int ieee80211_if_add(struct ieee80211_local *local, const char *name,
42 struct net_device **new_dev, int type, 45 struct net_device **new_dev, int type,
43 struct vif_params *params) 46 struct vif_params *params)
44{ 47{
45 struct net_device *ndev; 48 struct net_device *ndev;
46 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
47 struct ieee80211_sub_if_data *sdata = NULL; 49 struct ieee80211_sub_if_data *sdata = NULL;
48 int ret; 50 int ret;
49 51
@@ -67,13 +69,10 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
67 goto fail; 69 goto fail;
68 70
69 memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); 71 memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
70 ndev->base_addr = dev->base_addr;
71 ndev->irq = dev->irq;
72 ndev->mem_start = dev->mem_start;
73 ndev->mem_end = dev->mem_end;
74 SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); 72 SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
75 73
76 sdata = IEEE80211_DEV_TO_SUB_IF(ndev); 74 /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
75 sdata = netdev_priv(ndev);
77 ndev->ieee80211_ptr = &sdata->wdev; 76 ndev->ieee80211_ptr = &sdata->wdev;
78 sdata->wdev.wiphy = local->hw.wiphy; 77 sdata->wdev.wiphy = local->hw.wiphy;
79 sdata->vif.type = IEEE80211_IF_TYPE_AP; 78 sdata->vif.type = IEEE80211_IF_TYPE_AP;
@@ -117,14 +116,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
117 int oldtype = sdata->vif.type; 116 int oldtype = sdata->vif.type;
118 117
119 /* 118 /*
120 * We need to call this function on the master interface
121 * which already has a hard_start_xmit routine assigned
122 * which must not be changed.
123 */
124 if (dev != sdata->local->mdev)
125 dev->hard_start_xmit = ieee80211_subif_start_xmit;
126
127 /*
128 * Called even when register_netdevice fails, it would 119 * Called even when register_netdevice fails, it would
129 * oops if assigned before initialising the rest. 120 * oops if assigned before initialising the rest.
130 */ 121 */
@@ -138,22 +129,16 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
138 129
139 switch (type) { 130 switch (type) {
140 case IEEE80211_IF_TYPE_WDS: 131 case IEEE80211_IF_TYPE_WDS:
141 /* nothing special */
142 break;
143 case IEEE80211_IF_TYPE_VLAN: 132 case IEEE80211_IF_TYPE_VLAN:
144 sdata->u.vlan.ap = NULL; 133 /* nothing special */
145 break; 134 break;
146 case IEEE80211_IF_TYPE_AP: 135 case IEEE80211_IF_TYPE_AP:
147 sdata->u.ap.force_unicast_rateidx = -1;
148 sdata->u.ap.max_ratectrl_rateidx = -1;
149 skb_queue_head_init(&sdata->u.ap.ps_bc_buf); 136 skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
150 sdata->bss = &sdata->u.ap;
151 INIT_LIST_HEAD(&sdata->u.ap.vlans); 137 INIT_LIST_HEAD(&sdata->u.ap.vlans);
152 break; 138 break;
153 case IEEE80211_IF_TYPE_MESH_POINT: 139 case IEEE80211_IF_TYPE_MESH_POINT:
154 case IEEE80211_IF_TYPE_STA: 140 case IEEE80211_IF_TYPE_STA:
155 case IEEE80211_IF_TYPE_IBSS: { 141 case IEEE80211_IF_TYPE_IBSS: {
156 struct ieee80211_sub_if_data *msdata;
157 struct ieee80211_if_sta *ifsta; 142 struct ieee80211_if_sta *ifsta;
158 143
159 ifsta = &sdata->u.sta; 144 ifsta = &sdata->u.sta;
@@ -171,9 +156,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
171 if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) 156 if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
172 ifsta->flags |= IEEE80211_STA_WMM_ENABLED; 157 ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
173 158
174 msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
175 sdata->bss = &msdata->u.ap;
176
177 if (ieee80211_vif_is_mesh(&sdata->vif)) 159 if (ieee80211_vif_is_mesh(&sdata->vif))
178 ieee80211_mesh_init_sdata(sdata); 160 ieee80211_mesh_init_sdata(sdata);
179 break; 161 break;
@@ -215,27 +197,8 @@ void ieee80211_if_reinit(struct net_device *dev)
215 WARN_ON(1); 197 WARN_ON(1);
216 break; 198 break;
217 case IEEE80211_IF_TYPE_AP: { 199 case IEEE80211_IF_TYPE_AP: {
218 /* Remove all virtual interfaces that use this BSS
219 * as their sdata->bss */
220 struct ieee80211_sub_if_data *tsdata, *n;
221 struct beacon_data *beacon; 200 struct beacon_data *beacon;
222 201
223 list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
224 if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
225 printk(KERN_DEBUG "%s: removing virtual "
226 "interface %s because its BSS interface"
227 " is being removed\n",
228 sdata->dev->name, tsdata->dev->name);
229 list_del_rcu(&tsdata->list);
230 /*
231 * We have lots of time and can afford
232 * to sync for each interface
233 */
234 synchronize_rcu();
235 __ieee80211_if_del(local, tsdata);
236 }
237 }
238
239 beacon = sdata->u.ap.beacon; 202 beacon = sdata->u.ap.beacon;
240 rcu_assign_pointer(sdata->u.ap.beacon, NULL); 203 rcu_assign_pointer(sdata->u.ap.beacon, NULL);
241 synchronize_rcu(); 204 synchronize_rcu();
@@ -249,6 +212,7 @@ void ieee80211_if_reinit(struct net_device *dev)
249 break; 212 break;
250 } 213 }
251 case IEEE80211_IF_TYPE_WDS: 214 case IEEE80211_IF_TYPE_WDS:
215 case IEEE80211_IF_TYPE_VLAN:
252 /* nothing to do */ 216 /* nothing to do */
253 break; 217 break;
254 case IEEE80211_IF_TYPE_MESH_POINT: 218 case IEEE80211_IF_TYPE_MESH_POINT:
@@ -269,9 +233,6 @@ void ieee80211_if_reinit(struct net_device *dev)
269 case IEEE80211_IF_TYPE_MNTR: 233 case IEEE80211_IF_TYPE_MNTR:
270 dev->type = ARPHRD_ETHER; 234 dev->type = ARPHRD_ETHER;
271 break; 235 break;
272 case IEEE80211_IF_TYPE_VLAN:
273 sdata->u.vlan.ap = NULL;
274 break;
275 } 236 }
276 237
277 flushed = sta_info_flush(local, sdata); 238 flushed = sta_info_flush(local, sdata);
@@ -289,8 +250,10 @@ void __ieee80211_if_del(struct ieee80211_local *local,
289 250
290 ieee80211_debugfs_remove_netdev(sdata); 251 ieee80211_debugfs_remove_netdev(sdata);
291 unregister_netdevice(dev); 252 unregister_netdevice(dev);
292 /* Except master interface, the net_device will be freed by 253 /*
293 * net_device->destructor (i. e. ieee80211_if_free). */ 254 * The net_device will be freed by its destructor,
255 * i.e. ieee80211_if_free.
256 */
294} 257}
295 258
296/* Must be called with rtnl lock held. */ 259/* 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 266
304 list_for_each_entry_safe(sdata, n, &local->interfaces, list) { 267 list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
305 if ((sdata->vif.type == id || id == -1) && 268 if ((sdata->vif.type == id || id == -1) &&
306 strcmp(name, sdata->dev->name) == 0 && 269 strcmp(name, sdata->dev->name) == 0) {
307 sdata->dev != local->mdev) {
308 list_del_rcu(&sdata->list); 270 list_del_rcu(&sdata->list);
309 synchronize_rcu(); 271 synchronize_rcu();
310 __ieee80211_if_del(local, sdata); 272 __ieee80211_if_del(local, sdata);