aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-17 01:29:24 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:57 -0400
commit0ec3ca445931ff0e7ad6ac61d6c5d2aaafe7a9f5 (patch)
treea9e5fab14a3f928df6536a913ca8aba5e0ab2632
parent4150c57212ad134765dd78c654a4b9906252b66d (diff)
[PATCH] mac80211: validate VLAN interfaces better
This patch changes mac80211 to verify that VLAN interfaces are valid and not bother drivers about them any more. VLAN interfaces are now only valid when an AP interface is up with the same MAC address, and are automatically turned off when the AP interface is set down. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Jouni Malinen <j@w1.fi> Signed-off-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/mac80211.h17
-rw-r--r--net/mac80211/debugfs_netdev.c5
-rw-r--r--net/mac80211/ieee80211.c54
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/ieee80211_iface.c5
5 files changed, 65 insertions, 22 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 855754d4c50d..494a4c022a9b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -442,16 +442,17 @@ struct ieee80211_conf {
442 * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode. 442 * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
443 * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode. 443 * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
444 * @IEEE80211_IF_TYPE_WDS: interface in WDS mode. 444 * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
445 * @IEEE80211_IF_TYPE_VLAN: not used. 445 * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers
446 * will never see this type.
446 */ 447 */
447enum ieee80211_if_types { 448enum ieee80211_if_types {
448 IEEE80211_IF_TYPE_AP = 0x00000000, 449 IEEE80211_IF_TYPE_AP,
449 IEEE80211_IF_TYPE_MGMT = 0x00000001, 450 IEEE80211_IF_TYPE_MGMT,
450 IEEE80211_IF_TYPE_STA = 0x00000002, 451 IEEE80211_IF_TYPE_STA,
451 IEEE80211_IF_TYPE_IBSS = 0x00000003, 452 IEEE80211_IF_TYPE_IBSS,
452 IEEE80211_IF_TYPE_MNTR = 0x00000004, 453 IEEE80211_IF_TYPE_MNTR,
453 IEEE80211_IF_TYPE_WDS = 0x5A580211, 454 IEEE80211_IF_TYPE_WDS,
454 IEEE80211_IF_TYPE_VLAN = 0x00080211, 455 IEEE80211_IF_TYPE_VLAN,
455}; 456};
456 457
457/** 458/**
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index c9948fa58e08..f0e6ab7eb624 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -162,9 +162,6 @@ __IEEE80211_IF_FILE(beacon_tail_len);
162/* WDS attributes */ 162/* WDS attributes */
163IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); 163IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
164 164
165/* VLAN attributes */
166IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
167
168#define DEBUGFS_ADD(name, type)\ 165#define DEBUGFS_ADD(name, type)\
169 sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ 166 sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
170 sdata->debugfsdir, sdata, &name##_ops); 167 sdata->debugfsdir, sdata, &name##_ops);
@@ -223,7 +220,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
223 DEBUGFS_ADD(drop_unencrypted, vlan); 220 DEBUGFS_ADD(drop_unencrypted, vlan);
224 DEBUGFS_ADD(eapol, vlan); 221 DEBUGFS_ADD(eapol, vlan);
225 DEBUGFS_ADD(ieee8021_x, vlan); 222 DEBUGFS_ADD(ieee8021_x, vlan);
226 DEBUGFS_ADD(vlan_id, vlan);
227} 223}
228 224
229static void add_monitor_files(struct ieee80211_sub_if_data *sdata) 225static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -317,7 +313,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
317 DEBUGFS_DEL(drop_unencrypted, vlan); 313 DEBUGFS_DEL(drop_unencrypted, vlan);
318 DEBUGFS_DEL(eapol, vlan); 314 DEBUGFS_DEL(eapol, vlan);
319 DEBUGFS_DEL(ieee8021_x, vlan); 315 DEBUGFS_DEL(ieee8021_x, vlan);
320 DEBUGFS_DEL(vlan_id, vlan);
321} 316}
322 317
323static void del_monitor_files(struct ieee80211_sub_if_data *sdata) 318static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 319ec2a1d84f..4e345f82f044 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -314,22 +314,43 @@ static int ieee80211_open(struct net_device *dev)
314 int res; 314 int res;
315 315
316 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 316 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
317
317 read_lock(&local->sub_if_lock); 318 read_lock(&local->sub_if_lock);
318 list_for_each_entry(nsdata, &local->sub_if_list, list) { 319 list_for_each_entry(nsdata, &local->sub_if_list, list) {
319 struct net_device *ndev = nsdata->dev; 320 struct net_device *ndev = nsdata->dev;
320 321
321 if (ndev != dev && ndev != local->mdev && netif_running(ndev) && 322 if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
322 compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && 323 compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
323 !identical_mac_addr_allowed(sdata->type, nsdata->type)) { 324 /*
324 read_unlock(&local->sub_if_lock); 325 * check whether it may have the same address
325 return -ENOTUNIQ; 326 */
327 if (!identical_mac_addr_allowed(sdata->type,
328 nsdata->type)) {
329 read_unlock(&local->sub_if_lock);
330 return -ENOTUNIQ;
331 }
332
333 /*
334 * can only add VLANs to enabled APs
335 */
336 if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
337 nsdata->type == IEEE80211_IF_TYPE_AP &&
338 netif_running(nsdata->dev))
339 sdata->u.vlan.ap = nsdata;
326 } 340 }
327 } 341 }
328 read_unlock(&local->sub_if_lock); 342 read_unlock(&local->sub_if_lock);
329 343
330 if (sdata->type == IEEE80211_IF_TYPE_WDS && 344 switch (sdata->type) {
331 is_zero_ether_addr(sdata->u.wds.remote_addr)) 345 case IEEE80211_IF_TYPE_WDS:
332 return -ENOLINK; 346 if (is_zero_ether_addr(sdata->u.wds.remote_addr))
347 return -ENOLINK;
348 break;
349 case IEEE80211_IF_TYPE_VLAN:
350 if (!sdata->u.vlan.ap)
351 return -ENOLINK;
352 break;
353 }
333 354
334 if (local->open_count == 0) { 355 if (local->open_count == 0) {
335 res = 0; 356 res = 0;
@@ -340,6 +361,10 @@ static int ieee80211_open(struct net_device *dev)
340 } 361 }
341 362
342 switch (sdata->type) { 363 switch (sdata->type) {
364 case IEEE80211_IF_TYPE_VLAN:
365 list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
366 /* no need to tell driver */
367 break;
343 case IEEE80211_IF_TYPE_MNTR: 368 case IEEE80211_IF_TYPE_MNTR:
344 /* must be before the call to ieee80211_configure_filter */ 369 /* must be before the call to ieee80211_configure_filter */
345 local->monitors++; 370 local->monitors++;
@@ -407,9 +432,24 @@ static int ieee80211_stop(struct net_device *dev)
407 432
408 dev_mc_unsync(local->mdev, dev); 433 dev_mc_unsync(local->mdev, dev);
409 434
435 /* down all dependent devices, that is VLANs */
436 if (sdata->type == IEEE80211_IF_TYPE_AP) {
437 struct ieee80211_sub_if_data *vlan, *tmp;
438
439 list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
440 u.vlan.list)
441 dev_close(vlan->dev);
442 WARN_ON(!list_empty(&sdata->u.ap.vlans));
443 }
444
410 local->open_count--; 445 local->open_count--;
411 446
412 switch (sdata->type) { 447 switch (sdata->type) {
448 case IEEE80211_IF_TYPE_VLAN:
449 list_del(&sdata->u.vlan.list);
450 sdata->u.vlan.ap = NULL;
451 /* no need to tell driver */
452 break;
413 case IEEE80211_IF_TYPE_MNTR: 453 case IEEE80211_IF_TYPE_MNTR:
414 local->monitors--; 454 local->monitors--;
415 if (local->monitors == 0) { 455 if (local->monitors == 0) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 74deecd09677..1a43f3e9b6bd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -191,6 +191,8 @@ struct ieee80211_if_ap {
191 u8 *beacon_head, *beacon_tail; 191 u8 *beacon_head, *beacon_tail;
192 int beacon_head_len, beacon_tail_len; 192 int beacon_head_len, beacon_tail_len;
193 193
194 struct list_head vlans;
195
194 u8 ssid[IEEE80211_MAX_SSID_LEN]; 196 u8 ssid[IEEE80211_MAX_SSID_LEN];
195 size_t ssid_len; 197 size_t ssid_len;
196 u8 *generic_elem; 198 u8 *generic_elem;
@@ -214,7 +216,8 @@ struct ieee80211_if_wds {
214}; 216};
215 217
216struct ieee80211_if_vlan { 218struct ieee80211_if_vlan {
217 u8 id; 219 struct ieee80211_sub_if_data *ap;
220 struct list_head list;
218}; 221};
219 222
220/* flags used in struct ieee80211_if_sta.flags */ 223/* flags used in struct ieee80211_if_sta.flags */
@@ -377,7 +380,6 @@ struct ieee80211_sub_if_data {
377 struct dentry *drop_unencrypted; 380 struct dentry *drop_unencrypted;
378 struct dentry *eapol; 381 struct dentry *eapol;
379 struct dentry *ieee8021_x; 382 struct dentry *ieee8021_x;
380 struct dentry *vlan_id;
381 } vlan; 383 } vlan;
382 struct { 384 struct {
383 struct dentry *mode; 385 struct dentry *mode;
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index f9c74bb09d31..4590205fdf4b 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -164,6 +164,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
164 sdata->bss = NULL; 164 sdata->bss = NULL;
165 break; 165 break;
166 case IEEE80211_IF_TYPE_VLAN: 166 case IEEE80211_IF_TYPE_VLAN:
167 sdata->u.vlan.ap = NULL;
167 break; 168 break;
168 case IEEE80211_IF_TYPE_AP: 169 case IEEE80211_IF_TYPE_AP:
169 sdata->u.ap.dtim_period = 2; 170 sdata->u.ap.dtim_period = 2;
@@ -171,6 +172,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
171 sdata->u.ap.max_ratectrl_rateidx = -1; 172 sdata->u.ap.max_ratectrl_rateidx = -1;
172 skb_queue_head_init(&sdata->u.ap.ps_bc_buf); 173 skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
173 sdata->bss = &sdata->u.ap; 174 sdata->bss = &sdata->u.ap;
175 INIT_LIST_HEAD(&sdata->u.ap.vlans);
174 break; 176 break;
175 case IEEE80211_IF_TYPE_STA: 177 case IEEE80211_IF_TYPE_STA:
176 case IEEE80211_IF_TYPE_IBSS: { 178 case IEEE80211_IF_TYPE_IBSS: {
@@ -284,6 +286,9 @@ void ieee80211_if_reinit(struct net_device *dev)
284 case IEEE80211_IF_TYPE_MNTR: 286 case IEEE80211_IF_TYPE_MNTR:
285 dev->type = ARPHRD_ETHER; 287 dev->type = ARPHRD_ETHER;
286 break; 288 break;
289 case IEEE80211_IF_TYPE_VLAN:
290 sdata->u.vlan.ap = NULL;
291 break;
287 } 292 }
288 293
289 /* remove all STAs that are bound to this virtual interface */ 294 /* remove all STAs that are bound to this virtual interface */