diff options
-rw-r--r-- | include/net/mac80211.h | 17 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 5 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 54 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 5 |
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 | */ |
447 | enum ieee80211_if_types { | 448 | enum 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 */ |
163 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 163 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
164 | 164 | ||
165 | /* VLAN attributes */ | ||
166 | IEEE80211_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 | ||
229 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | 225 | static 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 | ||
323 | static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | 318 | static 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 | ||
216 | struct ieee80211_if_vlan { | 218 | struct 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 */ |