aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-04-16 22:37:51 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-16 22:37:51 -0400
commit8c95b4773dd8d0415269ffad7301ef96d75be8ee (patch)
tree996401ce91c2a652fcff690e2c8bf88f2014d307 /net
parentbcff122d478b774f4fd5262f35eedebe2f2fb274 (diff)
parent30b89b0f5e1313c8a5a039abeaa89248b6338d81 (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.26
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c22
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/key.c101
-rw-r--r--net/mac80211/key.h11
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/mlme.c144
-rw-r--r--net/mac80211/wext.c8
7 files changed, 204 insertions, 96 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8af576c1d2f1..699d97b8de5e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -33,6 +33,8 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
33 case NL80211_IFTYPE_MESH_POINT: 33 case NL80211_IFTYPE_MESH_POINT:
34 return IEEE80211_IF_TYPE_MESH_POINT; 34 return IEEE80211_IF_TYPE_MESH_POINT;
35#endif 35#endif
36 case NL80211_IFTYPE_WDS:
37 return IEEE80211_IF_TYPE_WDS;
36 default: 38 default:
37 return IEEE80211_IF_TYPE_INVALID; 39 return IEEE80211_IF_TYPE_INVALID;
38 } 40 }
@@ -718,12 +720,18 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
718 struct sta_info *sta; 720 struct sta_info *sta;
719 721
720 if (mac) { 722 if (mac) {
723 rcu_read_lock();
724
721 /* XXX: get sta belonging to dev */ 725 /* XXX: get sta belonging to dev */
722 sta = sta_info_get(local, mac); 726 sta = sta_info_get(local, mac);
723 if (!sta) 727 if (!sta) {
728 rcu_read_unlock();
724 return -ENOENT; 729 return -ENOENT;
730 }
725 731
726 sta_info_unlink(&sta); 732 sta_info_unlink(&sta);
733 rcu_read_unlock();
734
727 sta_info_destroy(sta); 735 sta_info_destroy(sta);
728 } else 736 } else
729 sta_info_flush(local, sdata); 737 sta_info_flush(local, sdata);
@@ -740,17 +748,23 @@ static int ieee80211_change_station(struct wiphy *wiphy,
740 struct sta_info *sta; 748 struct sta_info *sta;
741 struct ieee80211_sub_if_data *vlansdata; 749 struct ieee80211_sub_if_data *vlansdata;
742 750
751 rcu_read_lock();
752
743 /* XXX: get sta belonging to dev */ 753 /* XXX: get sta belonging to dev */
744 sta = sta_info_get(local, mac); 754 sta = sta_info_get(local, mac);
745 if (!sta) 755 if (!sta) {
756 rcu_read_unlock();
746 return -ENOENT; 757 return -ENOENT;
758 }
747 759
748 if (params->vlan && params->vlan != sta->sdata->dev) { 760 if (params->vlan && params->vlan != sta->sdata->dev) {
749 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); 761 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
750 762
751 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || 763 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
752 vlansdata->vif.type != IEEE80211_IF_TYPE_AP) 764 vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
765 rcu_read_unlock();
753 return -EINVAL; 766 return -EINVAL;
767 }
754 768
755 sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); 769 sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
756 ieee80211_send_layer2_update(sta); 770 ieee80211_send_layer2_update(sta);
@@ -758,6 +772,8 @@ static int ieee80211_change_station(struct wiphy *wiphy,
758 772
759 sta_apply_parameters(local, sta, params); 773 sta_apply_parameters(local, sta, params);
760 774
775 rcu_read_unlock();
776
761 return 0; 777 return 0;
762} 778}
763 779
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c642538e8282..8e53ce7ed444 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -102,7 +102,7 @@ struct ieee80211_sta_bss {
102 u64 timestamp; 102 u64 timestamp;
103 int beacon_int; 103 int beacon_int;
104 104
105 int probe_resp; 105 bool probe_resp;
106 unsigned long last_update; 106 unsigned long last_update;
107 107
108 /* during assocation, we save an ERP value from a probe response so 108 /* during assocation, we save an ERP value from a probe response so
@@ -600,8 +600,7 @@ struct ieee80211_local {
600 /* 600 /*
601 * The lock only protects the list, hash, timer and counter 601 * The lock only protects the list, hash, timer and counter
602 * against manipulation, reads are done in RCU. Additionally, 602 * against manipulation, reads are done in RCU. Additionally,
603 * the lock protects each BSS's TIM bitmap, a few items in 603 * the lock protects each BSS's TIM bitmap.
604 * STA info structures and various key pointers.
605 */ 604 */
606 spinlock_t sta_lock; 605 spinlock_t sta_lock;
607 unsigned long num_sta; 606 unsigned long num_sta;
@@ -635,6 +634,13 @@ struct ieee80211_local {
635 634
636 struct list_head interfaces; 635 struct list_head interfaces;
637 636
637 /*
638 * Key lock, protects sdata's key_list and sta_info's
639 * key pointers (write access, they're RCU.)
640 */
641 spinlock_t key_lock;
642
643
638 bool sta_sw_scanning; 644 bool sta_sw_scanning;
639 bool sta_hw_scanning; 645 bool sta_hw_scanning;
640 int scan_channel_idx; 646 int scan_channel_idx;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 711e36e54ff8..150d66dbda9d 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -74,9 +74,12 @@ static void add_todo(struct ieee80211_key *key, u32 flag)
74 74
75 spin_lock(&todo_lock); 75 spin_lock(&todo_lock);
76 key->flags |= flag; 76 key->flags |= flag;
77 /* only add if not already added */ 77 /*
78 if (list_empty(&key->todo)) 78 * Remove again if already on the list so that we move it to the end.
79 list_add(&key->todo, &todo_list); 79 */
80 if (!list_empty(&key->todo))
81 list_del(&key->todo);
82 list_add_tail(&key->todo, &todo_list);
80 schedule_work(&todo_work); 83 schedule_work(&todo_work);
81 spin_unlock(&todo_lock); 84 spin_unlock(&todo_lock);
82} 85}
@@ -210,9 +213,9 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
210{ 213{
211 unsigned long flags; 214 unsigned long flags;
212 215
213 spin_lock_irqsave(&sdata->local->sta_lock, flags); 216 spin_lock_irqsave(&sdata->local->key_lock, flags);
214 __ieee80211_set_default_key(sdata, idx); 217 __ieee80211_set_default_key(sdata, idx);
215 spin_unlock_irqrestore(&sdata->local->sta_lock, flags); 218 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
216} 219}
217 220
218 221
@@ -339,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
339 } 342 }
340 } 343 }
341 344
342 spin_lock_irqsave(&sdata->local->sta_lock, flags); 345 spin_lock_irqsave(&sdata->local->key_lock, flags);
343 346
344 if (sta) 347 if (sta)
345 old_key = sta->key; 348 old_key = sta->key;
@@ -348,68 +351,81 @@ void ieee80211_key_link(struct ieee80211_key *key,
348 351
349 __ieee80211_key_replace(sdata, sta, old_key, key); 352 __ieee80211_key_replace(sdata, sta, old_key, key);
350 353
351 spin_unlock_irqrestore(&sdata->local->sta_lock, flags); 354 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
352 355
353 /* free old key later */ 356 /* free old key later */
354 add_todo(old_key, KEY_FLAG_TODO_DELETE); 357 add_todo(old_key, KEY_FLAG_TODO_DELETE);
355 358
356 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); 359 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
357 if (netif_running(sdata->dev)) 360 if (netif_running(sdata->dev))
358 add_todo(key, KEY_FLAG_TODO_HWACCEL); 361 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
359} 362}
360 363
361void ieee80211_key_free(struct ieee80211_key *key) 364static void __ieee80211_key_free(struct ieee80211_key *key)
362{ 365{
363 unsigned long flags;
364
365 if (!key)
366 return;
367
368 /* 366 /*
369 * Replace key with nothingness if it was ever used. 367 * Replace key with nothingness if it was ever used.
370 */ 368 */
371 if (key->sdata) { 369 if (key->sdata)
372 spin_lock_irqsave(&key->sdata->local->sta_lock, flags);
373 __ieee80211_key_replace(key->sdata, key->sta, 370 __ieee80211_key_replace(key->sdata, key->sta,
374 key, NULL); 371 key, NULL);
375 spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags);
376 }
377 372
378 add_todo(key, KEY_FLAG_TODO_DELETE); 373 add_todo(key, KEY_FLAG_TODO_DELETE);
379} 374}
380 375
381void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) 376void ieee80211_key_free(struct ieee80211_key *key)
382{ 377{
383 struct ieee80211_key *key; 378 unsigned long flags;
384
385 might_sleep();
386 379
387 if (WARN_ON(!netif_running(sdata->dev))) 380 if (!key)
388 return; 381 return;
389 382
390 ieee80211_key_lock(); 383 spin_lock_irqsave(&key->sdata->local->key_lock, flags);
384 __ieee80211_key_free(key);
385 spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
386}
387
388/*
389 * To be safe against concurrent manipulations of the list (which shouldn't
390 * actually happen) we need to hold the spinlock. But under the spinlock we
391 * can't actually do much, so we defer processing to the todo list. Then run
392 * the todo list to be sure the operation and possibly previously pending
393 * operations are completed.
394 */
395static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
396 u32 todo_flags)
397{
398 struct ieee80211_key *key;
399 unsigned long flags;
391 400
401 might_sleep();
402
403 spin_lock_irqsave(&sdata->local->key_lock, flags);
392 list_for_each_entry(key, &sdata->key_list, list) 404 list_for_each_entry(key, &sdata->key_list, list)
393 ieee80211_key_enable_hw_accel(key); 405 add_todo(key, todo_flags);
406 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
394 407
395 ieee80211_key_unlock(); 408 ieee80211_key_todo();
396} 409}
397 410
398void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) 411void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
399{ 412{
400 struct ieee80211_key *key; 413 ASSERT_RTNL();
401 414
402 might_sleep(); 415 if (WARN_ON(!netif_running(sdata->dev)))
416 return;
403 417
404 ieee80211_key_lock(); 418 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
419}
405 420
406 list_for_each_entry(key, &sdata->key_list, list) 421void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
407 ieee80211_key_disable_hw_accel(key); 422{
423 ASSERT_RTNL();
408 424
409 ieee80211_key_unlock(); 425 ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
410} 426}
411 427
412static void __ieee80211_key_free(struct ieee80211_key *key) 428static void __ieee80211_key_destroy(struct ieee80211_key *key)
413{ 429{
414 if (!key) 430 if (!key)
415 return; 431 return;
@@ -440,7 +456,8 @@ static void __ieee80211_key_todo(void)
440 list_del_init(&key->todo); 456 list_del_init(&key->todo);
441 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | 457 todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
442 KEY_FLAG_TODO_DEFKEY | 458 KEY_FLAG_TODO_DEFKEY |
443 KEY_FLAG_TODO_HWACCEL | 459 KEY_FLAG_TODO_HWACCEL_ADD |
460 KEY_FLAG_TODO_HWACCEL_REMOVE |
444 KEY_FLAG_TODO_DELETE); 461 KEY_FLAG_TODO_DELETE);
445 key->flags &= ~todoflags; 462 key->flags &= ~todoflags;
446 spin_unlock(&todo_lock); 463 spin_unlock(&todo_lock);
@@ -456,12 +473,16 @@ static void __ieee80211_key_todo(void)
456 ieee80211_debugfs_key_add_default(key->sdata); 473 ieee80211_debugfs_key_add_default(key->sdata);
457 work_done = true; 474 work_done = true;
458 } 475 }
459 if (todoflags & KEY_FLAG_TODO_HWACCEL) { 476 if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
460 ieee80211_key_enable_hw_accel(key); 477 ieee80211_key_enable_hw_accel(key);
461 work_done = true; 478 work_done = true;
462 } 479 }
480 if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
481 ieee80211_key_disable_hw_accel(key);
482 work_done = true;
483 }
463 if (todoflags & KEY_FLAG_TODO_DELETE) { 484 if (todoflags & KEY_FLAG_TODO_DELETE) {
464 __ieee80211_key_free(key); 485 __ieee80211_key_destroy(key);
465 work_done = true; 486 work_done = true;
466 } 487 }
467 488
@@ -482,14 +503,16 @@ void ieee80211_key_todo(void)
482void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 503void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
483{ 504{
484 struct ieee80211_key *key, *tmp; 505 struct ieee80211_key *key, *tmp;
485 LIST_HEAD(tmp_list); 506 unsigned long flags;
486 507
487 ieee80211_key_lock(); 508 ieee80211_key_lock();
488 509
489 ieee80211_debugfs_key_remove_default(sdata); 510 ieee80211_debugfs_key_remove_default(sdata);
490 511
512 spin_lock_irqsave(&sdata->local->key_lock, flags);
491 list_for_each_entry_safe(key, tmp, &sdata->key_list, list) 513 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
492 ieee80211_key_free(key); 514 __ieee80211_key_free(key);
515 spin_unlock_irqrestore(&sdata->local->key_lock, flags);
493 516
494 __ieee80211_key_todo(); 517 __ieee80211_key_todo();
495 518
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 5d48518985b3..f52c3df1fe9a 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -54,16 +54,19 @@ struct sta_info;
54 * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an 54 * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
55 * RCU grace period, no longer be reachable other than from the 55 * RCU grace period, no longer be reachable other than from the
56 * todo list. 56 * todo list.
57 * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. 57 * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
58 * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
59 * acceleration.
58 * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. 60 * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
59 * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. 61 * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
60 */ 62 */
61enum ieee80211_internal_key_flags { 63enum ieee80211_internal_key_flags {
62 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), 64 KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
63 KEY_FLAG_TODO_DELETE = BIT(1), 65 KEY_FLAG_TODO_DELETE = BIT(1),
64 KEY_FLAG_TODO_HWACCEL = BIT(2), 66 KEY_FLAG_TODO_HWACCEL_ADD = BIT(2),
65 KEY_FLAG_TODO_DEFKEY = BIT(3), 67 KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
66 KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), 68 KEY_FLAG_TODO_DEFKEY = BIT(4),
69 KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
67}; 70};
68 71
69struct ieee80211_key { 72struct ieee80211_key {
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index bfcbcf5353ad..e9a978979d38 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1587,6 +1587,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
1587 1587
1588 INIT_LIST_HEAD(&local->interfaces); 1588 INIT_LIST_HEAD(&local->interfaces);
1589 1589
1590 spin_lock_init(&local->key_lock);
1591
1590 INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); 1592 INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
1591 1593
1592 sta_info_init(local); 1594 sta_info_init(local);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bdaab1391d4e..6b75cb6c6300 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -350,14 +350,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
350 } 350 }
351} 351}
352 352
353 353static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata,
354static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, 354 bool use_protection,
355 u8 erp_value) 355 bool use_short_preamble)
356{ 356{
357 struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; 357 struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
358 struct ieee80211_if_sta *ifsta = &sdata->u.sta; 358 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
359 bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
360 bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
361 DECLARE_MAC_BUF(mac); 359 DECLARE_MAC_BUF(mac);
362 u32 changed = 0; 360 u32 changed = 0;
363 361
@@ -388,6 +386,32 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
388 return changed; 386 return changed;
389} 387}
390 388
389static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata,
390 u8 erp_value)
391{
392 bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
393 bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0;
394
395 return ieee80211_handle_protect_preamb(sdata,
396 use_protection, use_short_preamble);
397}
398
399static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
400 struct ieee80211_sta_bss *bss)
401{
402 u32 changed = 0;
403
404 if (bss->has_erp_value)
405 changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value);
406 else {
407 u16 capab = bss->capability;
408 changed |= ieee80211_handle_protect_preamb(sdata, false,
409 (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
410 }
411
412 return changed;
413}
414
391int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, 415int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
392 struct ieee80211_ht_info *ht_info) 416 struct ieee80211_ht_info *ht_info)
393{ 417{
@@ -511,9 +535,7 @@ static void ieee80211_set_associated(struct net_device *dev,
511 sdata->bss_conf.beacon_int = bss->beacon_int; 535 sdata->bss_conf.beacon_int = bss->beacon_int;
512 sdata->bss_conf.timestamp = bss->timestamp; 536 sdata->bss_conf.timestamp = bss->timestamp;
513 537
514 if (bss->has_erp_value) 538 changed |= ieee80211_handle_bss_capability(sdata, bss);
515 changed |= ieee80211_handle_erp_ie(
516 sdata, bss->erp_value);
517 539
518 ieee80211_rx_bss_put(dev, bss); 540 ieee80211_rx_bss_put(dev, bss);
519 } 541 }
@@ -2566,22 +2588,29 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2566#endif 2588#endif
2567 } 2589 }
2568 2590
2569 bss->band = rx_status->band;
2570
2571 if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
2572 bss->probe_resp && beacon) {
2573 /* STA mode:
2574 * Do not allow beacon to override data from Probe Response. */
2575 ieee80211_rx_bss_put(dev, bss);
2576 return;
2577 }
2578
2579 /* save the ERP value so that it is available at association time */ 2591 /* save the ERP value so that it is available at association time */
2580 if (elems.erp_info && elems.erp_info_len >= 1) { 2592 if (elems.erp_info && elems.erp_info_len >= 1) {
2581 bss->erp_value = elems.erp_info[0]; 2593 bss->erp_value = elems.erp_info[0];
2582 bss->has_erp_value = 1; 2594 bss->has_erp_value = 1;
2583 } 2595 }
2584 2596
2597 if (elems.ht_cap_elem &&
2598 (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
2599 memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
2600 kfree(bss->ht_ie);
2601 bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
2602 if (bss->ht_ie) {
2603 memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
2604 elems.ht_cap_elem_len + 2);
2605 bss->ht_ie_len = elems.ht_cap_elem_len + 2;
2606 } else
2607 bss->ht_ie_len = 0;
2608 } else if (!elems.ht_cap_elem && bss->ht_ie) {
2609 kfree(bss->ht_ie);
2610 bss->ht_ie = NULL;
2611 bss->ht_ie_len = 0;
2612 }
2613
2585 bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); 2614 bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
2586 bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); 2615 bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
2587 2616
@@ -2603,6 +2632,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2603 bss->supp_rates_len += clen; 2632 bss->supp_rates_len += clen;
2604 } 2633 }
2605 2634
2635 bss->band = rx_status->band;
2636
2637 bss->timestamp = beacon_timestamp;
2638 bss->last_update = jiffies;
2639 bss->rssi = rx_status->ssi;
2640 bss->signal = rx_status->signal;
2641 bss->noise = rx_status->noise;
2642 if (!beacon && !bss->probe_resp)
2643 bss->probe_resp = true;
2644
2645 /*
2646 * In STA mode, the remaining parameters should not be overridden
2647 * by beacons because they're not necessarily accurate there.
2648 */
2649 if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
2650 bss->probe_resp && beacon) {
2651 ieee80211_rx_bss_put(dev, bss);
2652 return;
2653 }
2654
2606 if (elems.wpa && 2655 if (elems.wpa &&
2607 (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || 2656 (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
2608 memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { 2657 memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
@@ -2635,6 +2684,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2635 bss->rsn_ie_len = 0; 2684 bss->rsn_ie_len = 0;
2636 } 2685 }
2637 2686
2687 /*
2688 * Cf.
2689 * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC
2690 *
2691 * quoting:
2692 *
2693 * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia
2694 * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi
2695 * Alliance (September 1, 2004) is incorporated by reference herein.
2696 * The inclusion of the WMM Parameters in probe responses and
2697 * association responses is mandatory for WMM enabled networks. The
2698 * inclusion of the WMM Parameters in beacons, however, is optional.
2699 */
2700
2638 if (elems.wmm_param && 2701 if (elems.wmm_param &&
2639 (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || 2702 (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
2640 memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { 2703 memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
@@ -2651,30 +2714,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2651 bss->wmm_ie = NULL; 2714 bss->wmm_ie = NULL;
2652 bss->wmm_ie_len = 0; 2715 bss->wmm_ie_len = 0;
2653 } 2716 }
2654 if (elems.ht_cap_elem &&
2655 (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len ||
2656 memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) {
2657 kfree(bss->ht_ie);
2658 bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC);
2659 if (bss->ht_ie) {
2660 memcpy(bss->ht_ie, elems.ht_cap_elem - 2,
2661 elems.ht_cap_elem_len + 2);
2662 bss->ht_ie_len = elems.ht_cap_elem_len + 2;
2663 } else
2664 bss->ht_ie_len = 0;
2665 } else if (!elems.ht_cap_elem && bss->ht_ie) {
2666 kfree(bss->ht_ie);
2667 bss->ht_ie = NULL;
2668 bss->ht_ie_len = 0;
2669 }
2670
2671 bss->timestamp = beacon_timestamp;
2672 bss->last_update = jiffies;
2673 bss->rssi = rx_status->ssi;
2674 bss->signal = rx_status->signal;
2675 bss->noise = rx_status->noise;
2676 if (!beacon)
2677 bss->probe_resp++;
2678 2717
2679 /* check if we need to merge IBSS */ 2718 /* check if we need to merge IBSS */
2680 if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && 2719 if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
@@ -2775,8 +2814,24 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
2775 2814
2776 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); 2815 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
2777 2816
2817 if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
2818 ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
2819 elems.wmm_param_len);
2820 }
2821
2822 /* Do not send changes to driver if we are scanning. This removes
2823 * requirement that driver's bss_info_changed function needs to be
2824 * atomic. */
2825 if (local->sta_sw_scanning || local->sta_hw_scanning)
2826 return;
2827
2778 if (elems.erp_info && elems.erp_info_len >= 1) 2828 if (elems.erp_info && elems.erp_info_len >= 1)
2779 changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); 2829 changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]);
2830 else {
2831 u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info);
2832 changed |= ieee80211_handle_protect_preamb(sdata, false,
2833 (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0);
2834 }
2780 2835
2781 if (elems.ht_cap_elem && elems.ht_info_elem && 2836 if (elems.ht_cap_elem && elems.ht_info_elem &&
2782 elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { 2837 elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
@@ -2789,11 +2844,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
2789 &bss_info); 2844 &bss_info);
2790 } 2845 }
2791 2846
2792 if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
2793 ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
2794 elems.wmm_param_len);
2795 }
2796
2797 ieee80211_bss_info_change_notify(sdata, changed); 2847 ieee80211_bss_info_change_notify(sdata, changed);
2798} 2848}
2799 2849
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 69aed16faff3..76e1de1dc735 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -236,6 +236,9 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
236 case IW_MODE_ADHOC: 236 case IW_MODE_ADHOC:
237 type = IEEE80211_IF_TYPE_IBSS; 237 type = IEEE80211_IF_TYPE_IBSS;
238 break; 238 break;
239 case IW_MODE_REPEAT:
240 type = IEEE80211_IF_TYPE_WDS;
241 break;
239 case IW_MODE_MONITOR: 242 case IW_MODE_MONITOR:
240 type = IEEE80211_IF_TYPE_MNTR; 243 type = IEEE80211_IF_TYPE_MNTR;
241 break; 244 break;
@@ -980,6 +983,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
980 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 983 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
981 struct sta_info *sta = NULL; 984 struct sta_info *sta = NULL;
982 985
986 rcu_read_lock();
987
983 if (sdata->vif.type == IEEE80211_IF_TYPE_STA || 988 if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
984 sdata->vif.type == IEEE80211_IF_TYPE_IBSS) 989 sdata->vif.type == IEEE80211_IF_TYPE_IBSS)
985 sta = sta_info_get(local, sdata->u.sta.bssid); 990 sta = sta_info_get(local, sdata->u.sta.bssid);
@@ -996,6 +1001,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
996 wstats->qual.noise = sta->last_noise; 1001 wstats->qual.noise = sta->last_noise;
997 wstats->qual.updated = local->wstats_flags; 1002 wstats->qual.updated = local->wstats_flags;
998 } 1003 }
1004
1005 rcu_read_unlock();
1006
999 return wstats; 1007 return wstats;
1000} 1008}
1001 1009