diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-14 15:29:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-14 15:29:17 -0400 |
commit | a8519de4a030d130e0d18147a2af3112b7951e0b (patch) | |
tree | 59f89418cf7f311d896c38ff774398e052b709d8 /net | |
parent | 5c16807d3d196203d2d3c9fae51ac7e422091904 (diff) | |
parent | 560ad81b6c90e0fddc4d6c280f16ddf18d47eeb1 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/Kconfig | 8 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 4 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 6 | ||||
-rw-r--r-- | net/mac80211/main.c | 16 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 145 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 30 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 17 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 151 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 31 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 16 | ||||
-rw-r--r-- | net/mac80211/rx.c | 45 | ||||
-rw-r--r-- | net/mac80211/scan.c | 10 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/mac80211/tx.c | 158 | ||||
-rw-r--r-- | net/wireless/Makefile | 3 | ||||
-rw-r--r-- | net/wireless/chan.c | 89 | ||||
-rw-r--r-- | net/wireless/core.c | 21 | ||||
-rw-r--r-- | net/wireless/core.h | 14 | ||||
-rw-r--r-- | net/wireless/ibss.c | 61 | ||||
-rw-r--r-- | net/wireless/mlme.c | 17 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 88 | ||||
-rw-r--r-- | net/wireless/reg.c | 5 | ||||
-rw-r--r-- | net/wireless/scan.c | 31 | ||||
-rw-r--r-- | net/wireless/sme.c | 104 | ||||
-rw-r--r-- | net/wireless/util.c | 16 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 55 | ||||
-rw-r--r-- | net/wireless/wext-compat.h | 3 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 83 |
29 files changed, 801 insertions, 430 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 7dd77b6d4c9a..9db4ff836a3d 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -66,12 +66,12 @@ endmenu | |||
66 | config MAC80211_MESH | 66 | config MAC80211_MESH |
67 | bool "Enable mac80211 mesh networking (pre-802.11s) support" | 67 | bool "Enable mac80211 mesh networking (pre-802.11s) support" |
68 | depends on MAC80211 && EXPERIMENTAL | 68 | depends on MAC80211 && EXPERIMENTAL |
69 | depends on BROKEN | ||
70 | ---help--- | 69 | ---help--- |
71 | This options enables support of Draft 802.11s mesh networking. | 70 | This options enables support of Draft 802.11s mesh networking. |
72 | The implementation is based on Draft 1.08 of the Mesh Networking | 71 | The implementation is based on Draft 2.08 of the Mesh Networking |
73 | amendment. For more information visit http://o11s.org/. | 72 | amendment. However, no compliance with that draft is claimed or even |
74 | 73 | possible, as drafts leave a number of identifiers to be defined after | |
74 | ratification. For more information visit http://o11s.org/. | ||
75 | 75 | ||
76 | config MAC80211_LEDS | 76 | config MAC80211_LEDS |
77 | bool "Enable LED triggers" | 77 | bool "Enable LED triggers" |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bbf5007799b..5608f6c68413 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -323,6 +323,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
323 | { | 323 | { |
324 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 324 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
325 | 325 | ||
326 | sinfo->generation = sdata->local->sta_generation; | ||
327 | |||
326 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 328 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
327 | STATION_INFO_RX_BYTES | | 329 | STATION_INFO_RX_BYTES | |
328 | STATION_INFO_TX_BYTES | | 330 | STATION_INFO_TX_BYTES | |
@@ -909,6 +911,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
909 | else | 911 | else |
910 | memset(next_hop, 0, ETH_ALEN); | 912 | memset(next_hop, 0, ETH_ALEN); |
911 | 913 | ||
914 | pinfo->generation = mesh_paths_generation; | ||
915 | |||
912 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 916 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
913 | MPATH_INFO_DSN | | 917 | MPATH_INFO_DSN | |
914 | MPATH_INFO_METRIC | | 918 | MPATH_INFO_METRIC | |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 630a438180fd..a6abc7dfd903 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -284,6 +284,7 @@ struct ieee80211_if_managed { | |||
284 | 284 | ||
285 | struct mutex mtx; | 285 | struct mutex mtx; |
286 | struct ieee80211_bss *associated; | 286 | struct ieee80211_bss *associated; |
287 | struct ieee80211_mgd_work *old_associate_work; | ||
287 | struct list_head work_list; | 288 | struct list_head work_list; |
288 | 289 | ||
289 | u8 bssid[ETH_ALEN]; | 290 | u8 bssid[ETH_ALEN]; |
@@ -354,7 +355,7 @@ struct ieee80211_if_mesh { | |||
354 | 355 | ||
355 | unsigned long timers_running; | 356 | unsigned long timers_running; |
356 | 357 | ||
357 | bool housekeeping; | 358 | unsigned long wrkq_flags; |
358 | 359 | ||
359 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 360 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
360 | size_t mesh_id_len; | 361 | size_t mesh_id_len; |
@@ -677,6 +678,7 @@ struct ieee80211_local { | |||
677 | struct list_head sta_list; | 678 | struct list_head sta_list; |
678 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 679 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
679 | struct timer_list sta_cleanup; | 680 | struct timer_list sta_cleanup; |
681 | int sta_generation; | ||
680 | 682 | ||
681 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 683 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
682 | struct tasklet_struct tx_pending_tasklet; | 684 | struct tasklet_struct tx_pending_tasklet; |
@@ -713,7 +715,7 @@ struct ieee80211_local { | |||
713 | struct mutex scan_mtx; | 715 | struct mutex scan_mtx; |
714 | unsigned long scanning; | 716 | unsigned long scanning; |
715 | struct cfg80211_ssid scan_ssid; | 717 | struct cfg80211_ssid scan_ssid; |
716 | struct cfg80211_scan_request int_scan_req; | 718 | struct cfg80211_scan_request *int_scan_req; |
717 | struct cfg80211_scan_request *scan_req; | 719 | struct cfg80211_scan_request *scan_req; |
718 | struct ieee80211_channel *scan_channel; | 720 | struct ieee80211_channel *scan_channel; |
719 | const u8 *orig_ies; | 721 | const u8 *orig_ies; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c4f8e122ed6..b03fd84777fa 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -765,9 +765,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
765 | supp_ht = supp_ht || sband->ht_cap.ht_supported; | 765 | supp_ht = supp_ht || sband->ht_cap.ht_supported; |
766 | } | 766 | } |
767 | 767 | ||
768 | local->int_scan_req.n_channels = channels; | 768 | local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + |
769 | local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); | 769 | sizeof(void *) * channels, GFP_KERNEL); |
770 | if (!local->int_scan_req.channels) | 770 | if (!local->int_scan_req) |
771 | return -ENOMEM; | 771 | return -ENOMEM; |
772 | 772 | ||
773 | /* if low-level driver supports AP, we also support VLAN */ | 773 | /* if low-level driver supports AP, we also support VLAN */ |
@@ -882,13 +882,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
882 | 882 | ||
883 | /* alloc internal scan request */ | 883 | /* alloc internal scan request */ |
884 | i = 0; | 884 | i = 0; |
885 | local->int_scan_req.ssids = &local->scan_ssid; | 885 | local->int_scan_req->ssids = &local->scan_ssid; |
886 | local->int_scan_req.n_ssids = 1; | 886 | local->int_scan_req->n_ssids = 1; |
887 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 887 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
888 | if (!hw->wiphy->bands[band]) | 888 | if (!hw->wiphy->bands[band]) |
889 | continue; | 889 | continue; |
890 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | 890 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { |
891 | local->int_scan_req.channels[i] = | 891 | local->int_scan_req->channels[i] = |
892 | &hw->wiphy->bands[band]->channels[j]; | 892 | &hw->wiphy->bands[band]->channels[j]; |
893 | i++; | 893 | i++; |
894 | } | 894 | } |
@@ -920,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
920 | fail_workqueue: | 920 | fail_workqueue: |
921 | wiphy_unregister(local->hw.wiphy); | 921 | wiphy_unregister(local->hw.wiphy); |
922 | fail_wiphy_register: | 922 | fail_wiphy_register: |
923 | kfree(local->int_scan_req.channels); | 923 | kfree(local->int_scan_req->channels); |
924 | return result; | 924 | return result; |
925 | } | 925 | } |
926 | EXPORT_SYMBOL(ieee80211_register_hw); | 926 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -962,7 +962,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
962 | wiphy_unregister(local->hw.wiphy); | 962 | wiphy_unregister(local->hw.wiphy); |
963 | ieee80211_wep_free(local); | 963 | ieee80211_wep_free(local); |
964 | ieee80211_led_exit(local); | 964 | ieee80211_led_exit(local); |
965 | kfree(local->int_scan_req.channels); | 965 | kfree(local->int_scan_req); |
966 | } | 966 | } |
967 | EXPORT_SYMBOL(ieee80211_unregister_hw); | 967 | EXPORT_SYMBOL(ieee80211_unregister_hw); |
968 | 968 | ||
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2f4f518ab45c..3185e18c8214 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -47,14 +47,14 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
47 | struct ieee80211_local *local = sdata->local; | 47 | struct ieee80211_local *local = sdata->local; |
48 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 48 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
49 | 49 | ||
50 | ifmsh->housekeeping = true; | 50 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; |
51 | 51 | ||
52 | if (local->quiescing) { | 52 | if (local->quiescing) { |
53 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 53 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
54 | return; | 54 | return; |
55 | } | 55 | } |
56 | 56 | ||
57 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 57 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
58 | } | 58 | } |
59 | 59 | ||
60 | /** | 60 | /** |
@@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order) | |||
320 | return newtbl; | 320 | return newtbl; |
321 | } | 321 | } |
322 | 322 | ||
323 | static void __mesh_table_free(struct mesh_table *tbl) | ||
324 | { | ||
325 | kfree(tbl->hash_buckets); | ||
326 | kfree(tbl->hashwlock); | ||
327 | kfree(tbl); | ||
328 | } | ||
329 | |||
330 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | ||
331 | { | ||
332 | struct hlist_head *mesh_hash; | ||
333 | struct hlist_node *p, *q; | ||
334 | int i; | ||
335 | |||
336 | mesh_hash = tbl->hash_buckets; | ||
337 | for (i = 0; i <= tbl->hash_mask; i++) { | ||
338 | spin_lock(&tbl->hashwlock[i]); | ||
339 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | ||
340 | tbl->free_node(p, free_leafs); | ||
341 | atomic_dec(&tbl->entries); | ||
342 | } | ||
343 | spin_unlock(&tbl->hashwlock[i]); | ||
344 | } | ||
345 | __mesh_table_free(tbl); | ||
346 | } | ||
347 | 323 | ||
348 | static void ieee80211_mesh_path_timer(unsigned long data) | 324 | static void ieee80211_mesh_path_timer(unsigned long data) |
349 | { | 325 | { |
@@ -357,63 +333,79 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
357 | return; | 333 | return; |
358 | } | 334 | } |
359 | 335 | ||
360 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 336 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
361 | } | 337 | } |
362 | 338 | ||
363 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | 339 | /** |
364 | { | 340 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
365 | struct mesh_table *newtbl; | 341 | * @hdr: 802.11 frame header |
366 | struct hlist_head *oldhash; | 342 | * @fc: frame control field |
367 | struct hlist_node *p, *q; | 343 | * @meshda: destination address in the mesh |
368 | int i; | 344 | * @meshsa: source address address in the mesh. Same as TA, as frame is |
369 | 345 | * locally originated. | |
370 | if (atomic_read(&tbl->entries) | 346 | * |
371 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) | 347 | * Return the length of the 802.11 (does not include a mesh control header) |
372 | goto endgrow; | 348 | */ |
373 | 349 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char | |
374 | newtbl = mesh_table_alloc(tbl->size_order + 1); | 350 | *meshda, char *meshsa) { |
375 | if (!newtbl) | 351 | if (is_multicast_ether_addr(meshda)) { |
376 | goto endgrow; | 352 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
377 | 353 | /* DA TA SA */ | |
378 | newtbl->free_node = tbl->free_node; | 354 | memcpy(hdr->addr1, meshda, ETH_ALEN); |
379 | newtbl->mean_chain_len = tbl->mean_chain_len; | 355 | memcpy(hdr->addr2, meshsa, ETH_ALEN); |
380 | newtbl->copy_node = tbl->copy_node; | 356 | memcpy(hdr->addr3, meshsa, ETH_ALEN); |
381 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | 357 | return 24; |
382 | 358 | } else { | |
383 | oldhash = tbl->hash_buckets; | 359 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | |
384 | for (i = 0; i <= tbl->hash_mask; i++) | 360 | IEEE80211_FCTL_TODS); |
385 | hlist_for_each(p, &oldhash[i]) | 361 | /* RA TA DA SA */ |
386 | if (tbl->copy_node(p, newtbl) < 0) | 362 | memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ |
387 | goto errcopy; | 363 | memcpy(hdr->addr2, meshsa, ETH_ALEN); |
388 | 364 | memcpy(hdr->addr3, meshda, ETH_ALEN); | |
389 | return newtbl; | 365 | memcpy(hdr->addr4, meshsa, ETH_ALEN); |
390 | 366 | return 30; | |
391 | errcopy: | ||
392 | for (i = 0; i <= newtbl->hash_mask; i++) { | ||
393 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) | ||
394 | tbl->free_node(p, 0); | ||
395 | } | 367 | } |
396 | __mesh_table_free(newtbl); | ||
397 | endgrow: | ||
398 | return NULL; | ||
399 | } | 368 | } |
400 | 369 | ||
401 | /** | 370 | /** |
402 | * ieee80211_new_mesh_header - create a new mesh header | 371 | * ieee80211_new_mesh_header - create a new mesh header |
403 | * @meshhdr: uninitialized mesh header | 372 | * @meshhdr: uninitialized mesh header |
404 | * @sdata: mesh interface to be used | 373 | * @sdata: mesh interface to be used |
374 | * @addr4: addr4 of the mesh frame (1st in ae header) | ||
375 | * may be NULL | ||
376 | * @addr5: addr5 of the mesh frame (1st or 2nd in ae header) | ||
377 | * may be NULL unless addr6 is present | ||
378 | * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header) | ||
379 | * may be NULL unless addr5 is present | ||
405 | * | 380 | * |
406 | * Return the header length. | 381 | * Return the header length. |
407 | */ | 382 | */ |
408 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 383 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
409 | struct ieee80211_sub_if_data *sdata) | 384 | struct ieee80211_sub_if_data *sdata, char *addr4, |
385 | char *addr5, char *addr6) | ||
410 | { | 386 | { |
411 | meshhdr->flags = 0; | 387 | int aelen = 0; |
388 | memset(meshhdr, 0, sizeof(meshhdr)); | ||
412 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 389 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
413 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); | 390 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); |
414 | sdata->u.mesh.mesh_seqnum++; | 391 | sdata->u.mesh.mesh_seqnum++; |
415 | 392 | if (addr4) { | |
416 | return 6; | 393 | meshhdr->flags |= MESH_FLAGS_AE_A4; |
394 | aelen += ETH_ALEN; | ||
395 | memcpy(meshhdr->eaddr1, addr4, ETH_ALEN); | ||
396 | } | ||
397 | if (addr5 && addr6) { | ||
398 | meshhdr->flags |= MESH_FLAGS_AE_A5_A6; | ||
399 | aelen += 2 * ETH_ALEN; | ||
400 | if (!addr4) { | ||
401 | memcpy(meshhdr->eaddr1, addr5, ETH_ALEN); | ||
402 | memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); | ||
403 | } else { | ||
404 | memcpy(meshhdr->eaddr2, addr5, ETH_ALEN); | ||
405 | memcpy(meshhdr->eaddr3, addr6, ETH_ALEN); | ||
406 | } | ||
407 | } | ||
408 | return 6 + aelen; | ||
417 | } | 409 | } |
418 | 410 | ||
419 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | 411 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, |
@@ -433,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
433 | if (free_plinks != sdata->u.mesh.accepting_plinks) | 425 | if (free_plinks != sdata->u.mesh.accepting_plinks) |
434 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 426 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); |
435 | 427 | ||
436 | ifmsh->housekeeping = false; | ||
437 | mod_timer(&ifmsh->housekeeping_timer, | 428 | mod_timer(&ifmsh->housekeeping_timer, |
438 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 429 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
439 | } | 430 | } |
@@ -470,10 +461,12 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
470 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 461 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
471 | struct ieee80211_local *local = sdata->local; | 462 | struct ieee80211_local *local = sdata->local; |
472 | 463 | ||
473 | ifmsh->housekeeping = true; | 464 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; |
474 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 465 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
466 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | ||
475 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 467 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
476 | BSS_CHANGED_BEACON_ENABLED); | 468 | BSS_CHANGED_BEACON_ENABLED | |
469 | BSS_CHANGED_BEACON_INT); | ||
477 | } | 470 | } |
478 | 471 | ||
479 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 472 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
@@ -608,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
608 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) | 601 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) |
609 | mesh_path_start_discovery(sdata); | 602 | mesh_path_start_discovery(sdata); |
610 | 603 | ||
611 | if (ifmsh->housekeeping) | 604 | if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) |
605 | mesh_mpath_table_grow(); | ||
606 | |||
607 | if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) | ||
608 | mesh_mpp_table_grow(); | ||
609 | |||
610 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | ||
612 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 611 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
613 | } | 612 | } |
614 | 613 | ||
@@ -619,7 +618,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | |||
619 | rcu_read_lock(); | 618 | rcu_read_lock(); |
620 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | 619 | list_for_each_entry_rcu(sdata, &local->interfaces, list) |
621 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 620 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
622 | ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); | 621 | ieee80211_queue_work(&local->hw, &sdata->u.mesh.work); |
623 | rcu_read_unlock(); | 622 | rcu_read_unlock(); |
624 | } | 623 | } |
625 | 624 | ||
@@ -692,7 +691,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
692 | case IEEE80211_STYPE_PROBE_RESP: | 691 | case IEEE80211_STYPE_PROBE_RESP: |
693 | case IEEE80211_STYPE_BEACON: | 692 | case IEEE80211_STYPE_BEACON: |
694 | skb_queue_tail(&ifmsh->skb_queue, skb); | 693 | skb_queue_tail(&ifmsh->skb_queue, skb); |
695 | ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); | 694 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
696 | return RX_QUEUED; | 695 | return RX_QUEUED; |
697 | } | 696 | } |
698 | 697 | ||
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2a2ed182cb7e..eb23fc639b2b 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -44,6 +44,23 @@ enum mesh_path_flags { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks | ||
48 | * | ||
49 | * | ||
50 | * | ||
51 | * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks | ||
52 | * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs | ||
53 | * to grow. | ||
54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | ||
55 | * grow | ||
56 | */ | ||
57 | enum mesh_deferred_task_flags { | ||
58 | MESH_WORK_HOUSEKEEPING, | ||
59 | MESH_WORK_GROW_MPATH_TABLE, | ||
60 | MESH_WORK_GROW_MPP_TABLE, | ||
61 | }; | ||
62 | |||
63 | /** | ||
47 | * struct mesh_path - mac80211 mesh path structure | 64 | * struct mesh_path - mac80211 mesh path structure |
48 | * | 65 | * |
49 | * @dst: mesh path destination mac address | 66 | * @dst: mesh path destination mac address |
@@ -61,7 +78,7 @@ enum mesh_path_flags { | |||
61 | * retry | 78 | * retry |
62 | * @discovery_retries: number of discovery retries | 79 | * @discovery_retries: number of discovery retries |
63 | * @flags: mesh path flags, as specified on &enum mesh_path_flags | 80 | * @flags: mesh path flags, as specified on &enum mesh_path_flags |
64 | * @state_lock: mesh pat state lock | 81 | * @state_lock: mesh path state lock |
65 | * | 82 | * |
66 | * | 83 | * |
67 | * The combination of dst and sdata is unique in the mesh path table. Since the | 84 | * The combination of dst and sdata is unique in the mesh path table. Since the |
@@ -174,6 +191,7 @@ struct mesh_rmc { | |||
174 | */ | 191 | */ |
175 | #define MESH_PATH_REFRESH_TIME 1000 | 192 | #define MESH_PATH_REFRESH_TIME 1000 |
176 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | 193 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) |
194 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | ||
177 | 195 | ||
178 | #define MESH_MAX_PREQ_RETRIES 4 | 196 | #define MESH_MAX_PREQ_RETRIES 4 |
179 | #define MESH_PATH_EXPIRE (600 * HZ) | 197 | #define MESH_PATH_EXPIRE (600 * HZ) |
@@ -193,8 +211,11 @@ struct mesh_rmc { | |||
193 | 211 | ||
194 | /* Public interfaces */ | 212 | /* Public interfaces */ |
195 | /* Various */ | 213 | /* Various */ |
214 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | ||
215 | char *da, char *sa); | ||
196 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 216 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
197 | struct ieee80211_sub_if_data *sdata); | 217 | struct ieee80211_sub_if_data *sdata, char *addr4, |
218 | char *addr5, char *addr6); | ||
198 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 219 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
199 | struct ieee80211_sub_if_data *sdata); | 220 | struct ieee80211_sub_if_data *sdata); |
200 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 221 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
@@ -246,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
246 | /* Mesh tables */ | 267 | /* Mesh tables */ |
247 | struct mesh_table *mesh_table_alloc(int size_order); | 268 | struct mesh_table *mesh_table_alloc(int size_order); |
248 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | 269 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); |
249 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl); | 270 | void mesh_mpath_table_grow(void); |
271 | void mesh_mpp_table_grow(void); | ||
250 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 272 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, |
251 | struct mesh_table *tbl); | 273 | struct mesh_table *tbl); |
252 | /* Mesh paths */ | 274 | /* Mesh paths */ |
@@ -265,6 +287,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
265 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 287 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
266 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 288 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
267 | 289 | ||
290 | extern int mesh_paths_generation; | ||
291 | |||
268 | #ifdef CONFIG_MAC80211_MESH | 292 | #ifdef CONFIG_MAC80211_MESH |
269 | extern int mesh_allocated; | 293 | extern int mesh_allocated; |
270 | 294 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 11ab71a68ff9..ef1efd362691 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -397,7 +397,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
397 | 397 | ||
398 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | 398 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
399 | struct ieee80211_mgmt *mgmt, | 399 | struct ieee80211_mgmt *mgmt, |
400 | u8 *preq_elem, u32 metric) { | 400 | u8 *preq_elem, u32 metric) |
401 | { | ||
401 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 402 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
402 | struct mesh_path *mpath; | 403 | struct mesh_path *mpath; |
403 | u8 *dst_addr, *orig_addr; | 404 | u8 *dst_addr, *orig_addr; |
@@ -430,7 +431,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
430 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | 431 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || |
431 | DSN_LT(mpath->dsn, dst_dsn)) { | 432 | DSN_LT(mpath->dsn, dst_dsn)) { |
432 | mpath->dsn = dst_dsn; | 433 | mpath->dsn = dst_dsn; |
433 | mpath->flags &= MESH_PATH_DSN_VALID; | 434 | mpath->flags |= MESH_PATH_DSN_VALID; |
434 | } else if ((!(dst_flags & MP_F_DO)) && | 435 | } else if ((!(dst_flags & MP_F_DO)) && |
435 | (mpath->flags & MESH_PATH_ACTIVE)) { | 436 | (mpath->flags & MESH_PATH_ACTIVE)) { |
436 | reply = true; | 437 | reply = true; |
@@ -660,14 +661,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
660 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 661 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
661 | 662 | ||
662 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) | 663 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) |
663 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 664 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
664 | 665 | ||
665 | else if (time_before(jiffies, ifmsh->last_preq)) { | 666 | else if (time_before(jiffies, ifmsh->last_preq)) { |
666 | /* avoid long wait if did not send preqs for a long time | 667 | /* avoid long wait if did not send preqs for a long time |
667 | * and jiffies wrapped around | 668 | * and jiffies wrapped around |
668 | */ | 669 | */ |
669 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; | 670 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; |
670 | ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); | 671 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
671 | } else | 672 | } else |
672 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + | 673 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + |
673 | min_preq_int_jiff(sdata)); | 674 | min_preq_int_jiff(sdata)); |
@@ -791,7 +792,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
791 | } | 792 | } |
792 | 793 | ||
793 | if (mpath->flags & MESH_PATH_ACTIVE) { | 794 | if (mpath->flags & MESH_PATH_ACTIVE) { |
794 | if (time_after(jiffies, mpath->exp_time - | 795 | if (time_after(jiffies, mpath->exp_time + |
795 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) | 796 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) |
796 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, | 797 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, |
797 | ETH_ALEN) | 798 | ETH_ALEN) |
@@ -810,10 +811,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
810 | } | 811 | } |
811 | 812 | ||
812 | if (skb_queue_len(&mpath->frame_queue) >= | 813 | if (skb_queue_len(&mpath->frame_queue) >= |
813 | MESH_FRAME_QUEUE_LEN) { | 814 | MESH_FRAME_QUEUE_LEN) |
814 | skb_to_free = mpath->frame_queue.next; | 815 | skb_to_free = skb_dequeue(&mpath->frame_queue); |
815 | skb_unlink(skb_to_free, &mpath->frame_queue); | ||
816 | } | ||
817 | 816 | ||
818 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 817 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
819 | skb_queue_tail(&mpath->frame_queue, skb); | 818 | skb_queue_tail(&mpath->frame_queue, skb); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 04b9e4d61b8e..751c4d0e2b36 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -38,6 +38,71 @@ struct mpath_node { | |||
38 | static struct mesh_table *mesh_paths; | 38 | static struct mesh_table *mesh_paths; |
39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
40 | 40 | ||
41 | int mesh_paths_generation; | ||
42 | static void __mesh_table_free(struct mesh_table *tbl) | ||
43 | { | ||
44 | kfree(tbl->hash_buckets); | ||
45 | kfree(tbl->hashwlock); | ||
46 | kfree(tbl); | ||
47 | } | ||
48 | |||
49 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs) | ||
50 | { | ||
51 | struct hlist_head *mesh_hash; | ||
52 | struct hlist_node *p, *q; | ||
53 | int i; | ||
54 | |||
55 | mesh_hash = tbl->hash_buckets; | ||
56 | for (i = 0; i <= tbl->hash_mask; i++) { | ||
57 | spin_lock(&tbl->hashwlock[i]); | ||
58 | hlist_for_each_safe(p, q, &mesh_hash[i]) { | ||
59 | tbl->free_node(p, free_leafs); | ||
60 | atomic_dec(&tbl->entries); | ||
61 | } | ||
62 | spin_unlock(&tbl->hashwlock[i]); | ||
63 | } | ||
64 | __mesh_table_free(tbl); | ||
65 | } | ||
66 | |||
67 | static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | ||
68 | { | ||
69 | struct mesh_table *newtbl; | ||
70 | struct hlist_head *oldhash; | ||
71 | struct hlist_node *p, *q; | ||
72 | int i; | ||
73 | |||
74 | if (atomic_read(&tbl->entries) | ||
75 | < tbl->mean_chain_len * (tbl->hash_mask + 1)) | ||
76 | goto endgrow; | ||
77 | |||
78 | newtbl = mesh_table_alloc(tbl->size_order + 1); | ||
79 | if (!newtbl) | ||
80 | goto endgrow; | ||
81 | |||
82 | newtbl->free_node = tbl->free_node; | ||
83 | newtbl->mean_chain_len = tbl->mean_chain_len; | ||
84 | newtbl->copy_node = tbl->copy_node; | ||
85 | atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); | ||
86 | |||
87 | oldhash = tbl->hash_buckets; | ||
88 | for (i = 0; i <= tbl->hash_mask; i++) | ||
89 | hlist_for_each(p, &oldhash[i]) | ||
90 | if (tbl->copy_node(p, newtbl) < 0) | ||
91 | goto errcopy; | ||
92 | |||
93 | return newtbl; | ||
94 | |||
95 | errcopy: | ||
96 | for (i = 0; i <= newtbl->hash_mask; i++) { | ||
97 | hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) | ||
98 | tbl->free_node(p, 0); | ||
99 | } | ||
100 | __mesh_table_free(newtbl); | ||
101 | endgrow: | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | |||
41 | /* This lock will have the grow table function as writer and add / delete nodes | 106 | /* This lock will have the grow table function as writer and add / delete nodes |
42 | * as readers. When reading the table (i.e. doing lookups) we are well protected | 107 | * as readers. When reading the table (i.e. doing lookups) we are well protected |
43 | * by RCU | 108 | * by RCU |
@@ -185,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data | |||
185 | */ | 250 | */ |
186 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | 251 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) |
187 | { | 252 | { |
253 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
254 | struct ieee80211_local *local = sdata->local; | ||
188 | struct mesh_path *mpath, *new_mpath; | 255 | struct mesh_path *mpath, *new_mpath; |
189 | struct mpath_node *node, *new_node; | 256 | struct mpath_node *node, *new_node; |
190 | struct hlist_head *bucket; | 257 | struct hlist_head *bucket; |
@@ -193,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
193 | int err = 0; | 260 | int err = 0; |
194 | u32 hash_idx; | 261 | u32 hash_idx; |
195 | 262 | ||
196 | might_sleep(); | ||
197 | |||
198 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 263 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) |
199 | /* never add ourselves as neighbours */ | 264 | /* never add ourselves as neighbours */ |
200 | return -ENOTSUPP; | 265 | return -ENOTSUPP; |
@@ -206,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
206 | return -ENOSPC; | 271 | return -ENOSPC; |
207 | 272 | ||
208 | err = -ENOMEM; | 273 | err = -ENOMEM; |
209 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); | 274 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
210 | if (!new_mpath) | 275 | if (!new_mpath) |
211 | goto err_path_alloc; | 276 | goto err_path_alloc; |
212 | 277 | ||
213 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | 278 | new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
214 | if (!new_node) | 279 | if (!new_node) |
215 | goto err_node_alloc; | 280 | goto err_node_alloc; |
216 | 281 | ||
@@ -243,23 +308,13 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | |||
243 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) | 308 | mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) |
244 | grow = 1; | 309 | grow = 1; |
245 | 310 | ||
311 | mesh_paths_generation++; | ||
312 | |||
246 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 313 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
247 | read_unlock(&pathtbl_resize_lock); | 314 | read_unlock(&pathtbl_resize_lock); |
248 | if (grow) { | 315 | if (grow) { |
249 | struct mesh_table *oldtbl, *newtbl; | 316 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
250 | 317 | ieee80211_queue_work(&local->hw, &ifmsh->work); | |
251 | write_lock(&pathtbl_resize_lock); | ||
252 | oldtbl = mesh_paths; | ||
253 | newtbl = mesh_table_grow(mesh_paths); | ||
254 | if (!newtbl) { | ||
255 | write_unlock(&pathtbl_resize_lock); | ||
256 | return 0; | ||
257 | } | ||
258 | rcu_assign_pointer(mesh_paths, newtbl); | ||
259 | write_unlock(&pathtbl_resize_lock); | ||
260 | |||
261 | synchronize_rcu(); | ||
262 | mesh_table_free(oldtbl, false); | ||
263 | } | 318 | } |
264 | return 0; | 319 | return 0; |
265 | 320 | ||
@@ -274,9 +329,46 @@ err_path_alloc: | |||
274 | return err; | 329 | return err; |
275 | } | 330 | } |
276 | 331 | ||
332 | void mesh_mpath_table_grow(void) | ||
333 | { | ||
334 | struct mesh_table *oldtbl, *newtbl; | ||
335 | |||
336 | write_lock(&pathtbl_resize_lock); | ||
337 | oldtbl = mesh_paths; | ||
338 | newtbl = mesh_table_grow(mesh_paths); | ||
339 | if (!newtbl) { | ||
340 | write_unlock(&pathtbl_resize_lock); | ||
341 | return; | ||
342 | } | ||
343 | rcu_assign_pointer(mesh_paths, newtbl); | ||
344 | write_unlock(&pathtbl_resize_lock); | ||
345 | |||
346 | synchronize_rcu(); | ||
347 | mesh_table_free(oldtbl, false); | ||
348 | } | ||
349 | |||
350 | void mesh_mpp_table_grow(void) | ||
351 | { | ||
352 | struct mesh_table *oldtbl, *newtbl; | ||
353 | |||
354 | write_lock(&pathtbl_resize_lock); | ||
355 | oldtbl = mpp_paths; | ||
356 | newtbl = mesh_table_grow(mpp_paths); | ||
357 | if (!newtbl) { | ||
358 | write_unlock(&pathtbl_resize_lock); | ||
359 | return; | ||
360 | } | ||
361 | rcu_assign_pointer(mpp_paths, newtbl); | ||
362 | write_unlock(&pathtbl_resize_lock); | ||
363 | |||
364 | synchronize_rcu(); | ||
365 | mesh_table_free(oldtbl, false); | ||
366 | } | ||
277 | 367 | ||
278 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | 368 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) |
279 | { | 369 | { |
370 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
371 | struct ieee80211_local *local = sdata->local; | ||
280 | struct mesh_path *mpath, *new_mpath; | 372 | struct mesh_path *mpath, *new_mpath; |
281 | struct mpath_node *node, *new_node; | 373 | struct mpath_node *node, *new_node; |
282 | struct hlist_head *bucket; | 374 | struct hlist_head *bucket; |
@@ -285,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
285 | int err = 0; | 377 | int err = 0; |
286 | u32 hash_idx; | 378 | u32 hash_idx; |
287 | 379 | ||
288 | might_sleep(); | ||
289 | |||
290 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) | 380 | if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) |
291 | /* never add ourselves as neighbours */ | 381 | /* never add ourselves as neighbours */ |
292 | return -ENOTSUPP; | 382 | return -ENOTSUPP; |
@@ -295,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
295 | return -ENOTSUPP; | 385 | return -ENOTSUPP; |
296 | 386 | ||
297 | err = -ENOMEM; | 387 | err = -ENOMEM; |
298 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); | 388 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
299 | if (!new_mpath) | 389 | if (!new_mpath) |
300 | goto err_path_alloc; | 390 | goto err_path_alloc; |
301 | 391 | ||
302 | new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); | 392 | new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
303 | if (!new_node) | 393 | if (!new_node) |
304 | goto err_node_alloc; | 394 | goto err_node_alloc; |
305 | 395 | ||
@@ -333,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | |||
333 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); | 423 | spin_unlock(&mpp_paths->hashwlock[hash_idx]); |
334 | read_unlock(&pathtbl_resize_lock); | 424 | read_unlock(&pathtbl_resize_lock); |
335 | if (grow) { | 425 | if (grow) { |
336 | struct mesh_table *oldtbl, *newtbl; | 426 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
337 | 427 | ieee80211_queue_work(&local->hw, &ifmsh->work); | |
338 | write_lock(&pathtbl_resize_lock); | ||
339 | oldtbl = mpp_paths; | ||
340 | newtbl = mesh_table_grow(mpp_paths); | ||
341 | if (!newtbl) { | ||
342 | write_unlock(&pathtbl_resize_lock); | ||
343 | return 0; | ||
344 | } | ||
345 | rcu_assign_pointer(mpp_paths, newtbl); | ||
346 | write_unlock(&pathtbl_resize_lock); | ||
347 | |||
348 | synchronize_rcu(); | ||
349 | mesh_table_free(oldtbl, false); | ||
350 | } | 428 | } |
351 | return 0; | 429 | return 0; |
352 | 430 | ||
@@ -484,6 +562,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) | |||
484 | 562 | ||
485 | err = -ENXIO; | 563 | err = -ENXIO; |
486 | enddel: | 564 | enddel: |
565 | mesh_paths_generation++; | ||
487 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); | 566 | spin_unlock(&mesh_paths->hashwlock[hash_idx]); |
488 | read_unlock(&pathtbl_resize_lock); | 567 | read_unlock(&pathtbl_resize_lock); |
489 | return err; | 568 | return err; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index cb14253587f1..ffcbad75e09b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -409,7 +409,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
409 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; | 409 | baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; |
410 | if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { | 410 | if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { |
411 | baseaddr += 4; | 411 | baseaddr += 4; |
412 | baselen -= 4; | 412 | baselen += 4; |
413 | } | 413 | } |
414 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); | 414 | ieee802_11_parse_elems(baseaddr, len - baselen, &elems); |
415 | if (!elems.peer_link) { | 415 | if (!elems.peer_link) { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5a1ee0445f..c374d2d73fa4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -880,10 +880,11 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
880 | } | 880 | } |
881 | 881 | ||
882 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 882 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
883 | struct ieee80211_bss *bss, | 883 | struct ieee80211_mgd_work *wk, |
884 | u32 bss_info_changed) | 884 | u32 bss_info_changed) |
885 | { | 885 | { |
886 | struct ieee80211_local *local = sdata->local; | 886 | struct ieee80211_local *local = sdata->local; |
887 | struct ieee80211_bss *bss = wk->bss; | ||
887 | 888 | ||
888 | bss_info_changed |= BSS_CHANGED_ASSOC; | 889 | bss_info_changed |= BSS_CHANGED_ASSOC; |
889 | /* set timing information */ | 890 | /* set timing information */ |
@@ -896,6 +897,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
896 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 897 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
897 | 898 | ||
898 | sdata->u.mgd.associated = bss; | 899 | sdata->u.mgd.associated = bss; |
900 | sdata->u.mgd.old_associate_work = wk; | ||
899 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); | 901 | memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); |
900 | 902 | ||
901 | /* just to be sure */ | 903 | /* just to be sure */ |
@@ -1010,7 +1012,8 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
1010 | return RX_MGMT_NONE; | 1012 | return RX_MGMT_NONE; |
1011 | } | 1013 | } |
1012 | 1014 | ||
1013 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | 1015 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
1016 | bool deauth) | ||
1014 | { | 1017 | { |
1015 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1018 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1016 | struct ieee80211_local *local = sdata->local; | 1019 | struct ieee80211_local *local = sdata->local; |
@@ -1028,6 +1031,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
1028 | ifmgd->associated = NULL; | 1031 | ifmgd->associated = NULL; |
1029 | memset(ifmgd->bssid, 0, ETH_ALEN); | 1032 | memset(ifmgd->bssid, 0, ETH_ALEN); |
1030 | 1033 | ||
1034 | if (deauth) { | ||
1035 | kfree(ifmgd->old_associate_work); | ||
1036 | ifmgd->old_associate_work = NULL; | ||
1037 | } else { | ||
1038 | struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; | ||
1039 | |||
1040 | wk->state = IEEE80211_MGD_STATE_IDLE; | ||
1041 | list_add(&wk->list, &ifmgd->work_list); | ||
1042 | } | ||
1043 | |||
1031 | /* | 1044 | /* |
1032 | * we need to commit the associated = NULL change because the | 1045 | * we need to commit the associated = NULL change because the |
1033 | * scan code uses that to determine whether this iface should | 1046 | * scan code uses that to determine whether this iface should |
@@ -1345,7 +1358,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1345 | sdata->dev->name, bssid, reason_code); | 1358 | sdata->dev->name, bssid, reason_code); |
1346 | 1359 | ||
1347 | if (!wk) { | 1360 | if (!wk) { |
1348 | ieee80211_set_disassoc(sdata); | 1361 | ieee80211_set_disassoc(sdata, true); |
1349 | } else { | 1362 | } else { |
1350 | list_del(&wk->list); | 1363 | list_del(&wk->list); |
1351 | kfree(wk); | 1364 | kfree(wk); |
@@ -1378,7 +1391,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1378 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1391 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1379 | sdata->dev->name, reason_code); | 1392 | sdata->dev->name, reason_code); |
1380 | 1393 | ||
1381 | ieee80211_set_disassoc(sdata); | 1394 | ieee80211_set_disassoc(sdata, false); |
1382 | return RX_MGMT_CFG80211_DISASSOC; | 1395 | return RX_MGMT_CFG80211_DISASSOC; |
1383 | } | 1396 | } |
1384 | 1397 | ||
@@ -1581,7 +1594,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1581 | * ieee80211_set_associated() will tell the driver */ | 1594 | * ieee80211_set_associated() will tell the driver */ |
1582 | bss_conf->aid = aid; | 1595 | bss_conf->aid = aid; |
1583 | bss_conf->assoc_capability = capab_info; | 1596 | bss_conf->assoc_capability = capab_info; |
1584 | ieee80211_set_associated(sdata, wk->bss, changed); | 1597 | /* this will take ownership of wk */ |
1598 | ieee80211_set_associated(sdata, wk, changed); | ||
1585 | 1599 | ||
1586 | /* | 1600 | /* |
1587 | * Start timer to probe the connection to the AP now. | 1601 | * Start timer to probe the connection to the AP now. |
@@ -1590,7 +1604,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1590 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1604 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1591 | mod_beacon_timer(sdata); | 1605 | mod_beacon_timer(sdata); |
1592 | 1606 | ||
1593 | kfree(wk); | ||
1594 | return RX_MGMT_CFG80211_ASSOC; | 1607 | return RX_MGMT_CFG80211_ASSOC; |
1595 | } | 1608 | } |
1596 | 1609 | ||
@@ -2096,7 +2109,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2096 | printk(KERN_DEBUG "No probe response from AP %pM" | 2109 | printk(KERN_DEBUG "No probe response from AP %pM" |
2097 | " after %dms, disconnecting.\n", | 2110 | " after %dms, disconnecting.\n", |
2098 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2111 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
2099 | ieee80211_set_disassoc(sdata); | 2112 | ieee80211_set_disassoc(sdata, true); |
2100 | mutex_unlock(&ifmgd->mtx); | 2113 | mutex_unlock(&ifmgd->mtx); |
2101 | /* | 2114 | /* |
2102 | * must be outside lock due to cfg80211, | 2115 | * must be outside lock due to cfg80211, |
@@ -2500,7 +2513,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2500 | 2513 | ||
2501 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 2514 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { |
2502 | bssid = req->bss->bssid; | 2515 | bssid = req->bss->bssid; |
2503 | ieee80211_set_disassoc(sdata); | 2516 | ieee80211_set_disassoc(sdata, true); |
2504 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | 2517 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { |
2505 | if (&wk->bss->cbss == req->bss) { | 2518 | if (&wk->bss->cbss == req->bss) { |
2506 | bssid = req->bss->bssid; | 2519 | bssid = req->bss->bssid; |
@@ -2552,7 +2565,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2552 | return -ENOLINK; | 2565 | return -ENOLINK; |
2553 | } | 2566 | } |
2554 | 2567 | ||
2555 | ieee80211_set_disassoc(sdata); | 2568 | ieee80211_set_disassoc(sdata, false); |
2556 | 2569 | ||
2557 | mutex_unlock(&ifmgd->mtx); | 2570 | mutex_unlock(&ifmgd->mtx); |
2558 | 2571 | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7c5142988bbb..007164919e02 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/random.h> | 51 | #include <linux/random.h> |
52 | #include <linux/ieee80211.h> | 52 | #include <linux/ieee80211.h> |
53 | #include <net/mac80211.h> | 53 | #include <net/mac80211.h> |
54 | #include "mesh.h" | ||
54 | #include "rate.h" | 55 | #include "rate.h" |
55 | #include "rc80211_minstrel.h" | 56 | #include "rc80211_minstrel.h" |
56 | 57 | ||
@@ -155,12 +156,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
155 | struct sk_buff *skb) | 156 | struct sk_buff *skb) |
156 | { | 157 | { |
157 | struct minstrel_sta_info *mi = priv_sta; | 158 | struct minstrel_sta_info *mi = priv_sta; |
159 | struct minstrel_priv *mp = (struct minstrel_priv *)priv; | ||
158 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 160 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
159 | struct ieee80211_tx_rate *ar = info->status.rates; | 161 | struct ieee80211_tx_rate *ar = info->status.rates; |
162 | struct ieee80211_local *local = hw_to_local(mp->hw); | ||
163 | struct sta_info *si; | ||
160 | int i, ndx; | 164 | int i, ndx; |
161 | int success; | 165 | int success; |
162 | 166 | ||
163 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | 167 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); |
168 | si = sta_info_get(local, sta->addr); | ||
164 | 169 | ||
165 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 170 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
166 | if (ar[i].idx < 0) | 171 | if (ar[i].idx < 0) |
@@ -172,8 +177,17 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
172 | 177 | ||
173 | mi->r[ndx].attempts += ar[i].count; | 178 | mi->r[ndx].attempts += ar[i].count; |
174 | 179 | ||
175 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) | 180 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { |
176 | mi->r[ndx].success += success; | 181 | mi->r[ndx].success += success; |
182 | if (si) { | ||
183 | si->fail_avg = (18050 - mi->r[ndx].probability) | ||
184 | / 180; | ||
185 | WARN_ON(si->fail_avg > 100); | ||
186 | if (si->fail_avg == 100 && | ||
187 | ieee80211_vif_is_mesh(&si->sdata->vif)) | ||
188 | mesh_plink_broken(si); | ||
189 | } | ||
190 | } | ||
177 | } | 191 | } |
178 | 192 | ||
179 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) | 193 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 25a669c86e14..4cd9e45b1443 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
489 | { | 489 | { |
490 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 490 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
491 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); | 491 | unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); |
492 | char *dev_addr = rx->dev->dev_addr; | ||
492 | 493 | ||
493 | if (ieee80211_is_data(hdr->frame_control)) { | 494 | if (ieee80211_is_data(hdr->frame_control)) { |
494 | if (!ieee80211_has_a4(hdr->frame_control)) | 495 | if (is_multicast_ether_addr(hdr->addr1)) { |
495 | return RX_DROP_MONITOR; | 496 | if (ieee80211_has_tods(hdr->frame_control) || |
496 | if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) | 497 | !ieee80211_has_fromds(hdr->frame_control)) |
497 | return RX_DROP_MONITOR; | 498 | return RX_DROP_MONITOR; |
499 | if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0) | ||
500 | return RX_DROP_MONITOR; | ||
501 | } else { | ||
502 | if (!ieee80211_has_a4(hdr->frame_control)) | ||
503 | return RX_DROP_MONITOR; | ||
504 | if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0) | ||
505 | return RX_DROP_MONITOR; | ||
506 | } | ||
498 | } | 507 | } |
499 | 508 | ||
500 | /* If there is not an established peer link and this is not a peer link | 509 | /* If there is not an established peer link and this is not a peer link |
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
527 | 536 | ||
528 | if (ieee80211_is_data(hdr->frame_control) && | 537 | if (ieee80211_is_data(hdr->frame_control) && |
529 | is_multicast_ether_addr(hdr->addr1) && | 538 | is_multicast_ether_addr(hdr->addr1) && |
530 | mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata)) | 539 | mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata)) |
531 | return RX_DROP_MONITOR; | 540 | return RX_DROP_MONITOR; |
532 | #undef msh_h_get | 541 | #undef msh_h_get |
533 | 542 | ||
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1495 | /* illegal frame */ | 1504 | /* illegal frame */ |
1496 | return RX_DROP_MONITOR; | 1505 | return RX_DROP_MONITOR; |
1497 | 1506 | ||
1498 | if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ | 1507 | if (!is_multicast_ether_addr(hdr->addr1) && |
1508 | (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { | ||
1499 | struct mesh_path *mppath; | 1509 | struct mesh_path *mppath; |
1500 | 1510 | ||
1501 | rcu_read_lock(); | 1511 | rcu_read_lock(); |
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1512 | rcu_read_unlock(); | 1522 | rcu_read_unlock(); |
1513 | } | 1523 | } |
1514 | 1524 | ||
1515 | if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) | 1525 | /* Frame has reached destination. Don't forward */ |
1526 | if (!is_multicast_ether_addr(hdr->addr1) && | ||
1527 | compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) | ||
1516 | return RX_CONTINUE; | 1528 | return RX_CONTINUE; |
1517 | 1529 | ||
1518 | mesh_hdr->ttl--; | 1530 | mesh_hdr->ttl--; |
@@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1532 | rx->dev->name); | 1544 | rx->dev->name); |
1533 | 1545 | ||
1534 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; | 1546 | fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; |
1535 | /* | ||
1536 | * Save TA to addr1 to send TA a path error if a | ||
1537 | * suitable next hop is not found | ||
1538 | */ | ||
1539 | memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); | ||
1540 | memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); | 1547 | memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); |
1541 | info = IEEE80211_SKB_CB(fwd_skb); | 1548 | info = IEEE80211_SKB_CB(fwd_skb); |
1542 | memset(info, 0, sizeof(*info)); | 1549 | memset(info, 0, sizeof(*info)); |
1543 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1550 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1544 | info->control.vif = &rx->sdata->vif; | 1551 | info->control.vif = &rx->sdata->vif; |
1545 | ieee80211_select_queue(local, fwd_skb); | 1552 | ieee80211_select_queue(local, fwd_skb); |
1546 | if (is_multicast_ether_addr(fwd_hdr->addr3)) | 1553 | if (!is_multicast_ether_addr(fwd_hdr->addr1)) { |
1547 | memcpy(fwd_hdr->addr1, fwd_hdr->addr3, | 1554 | int err; |
1555 | /* | ||
1556 | * Save TA to addr1 to send TA a path error if a | ||
1557 | * suitable next hop is not found | ||
1558 | */ | ||
1559 | memcpy(fwd_hdr->addr1, fwd_hdr->addr2, | ||
1548 | ETH_ALEN); | 1560 | ETH_ALEN); |
1549 | else { | 1561 | err = mesh_nexthop_lookup(fwd_skb, sdata); |
1550 | int err = mesh_nexthop_lookup(fwd_skb, sdata); | ||
1551 | /* Failed to immediately resolve next hop: | 1562 | /* Failed to immediately resolve next hop: |
1552 | * fwded frame was dropped or will be added | 1563 | * fwded frame was dropped or will be added |
1553 | * later to the pending skb queue. */ | 1564 | * later to the pending skb queue. */ |
@@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1560 | } | 1571 | } |
1561 | } | 1572 | } |
1562 | 1573 | ||
1563 | if (is_multicast_ether_addr(hdr->addr3) || | 1574 | if (is_multicast_ether_addr(hdr->addr1) || |
1564 | rx->dev->flags & IFF_PROMISC) | 1575 | rx->dev->flags & IFF_PROMISC) |
1565 | return RX_CONTINUE; | 1576 | return RX_CONTINUE; |
1566 | else | 1577 | else |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 244f53f3c8b4..e091cbc3434f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -277,7 +277,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
277 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) | 277 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) |
278 | ieee80211_restore_scan_ies(local); | 278 | ieee80211_restore_scan_ies(local); |
279 | 279 | ||
280 | if (local->scan_req != &local->int_scan_req) | 280 | if (local->scan_req != local->int_scan_req) |
281 | cfg80211_scan_done(local->scan_req, aborted); | 281 | cfg80211_scan_done(local->scan_req, aborted); |
282 | local->scan_req = NULL; | 282 | local->scan_req = NULL; |
283 | 283 | ||
@@ -423,7 +423,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
423 | local->scan_req = req; | 423 | local->scan_req = req; |
424 | local->scan_sdata = sdata; | 424 | local->scan_sdata = sdata; |
425 | 425 | ||
426 | if (req != &local->int_scan_req && | 426 | if (req != local->int_scan_req && |
427 | sdata->vif.type == NL80211_IFTYPE_STATION && | 427 | sdata->vif.type == NL80211_IFTYPE_STATION && |
428 | !list_empty(&ifmgd->work_list)) { | 428 | !list_empty(&ifmgd->work_list)) { |
429 | /* actually wait for the work it's doing to finish/time out */ | 429 | /* actually wait for the work it's doing to finish/time out */ |
@@ -743,10 +743,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
743 | if (local->scan_req) | 743 | if (local->scan_req) |
744 | goto unlock; | 744 | goto unlock; |
745 | 745 | ||
746 | memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); | 746 | memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); |
747 | local->int_scan_req.ssids[0].ssid_len = ssid_len; | 747 | local->int_scan_req->ssids[0].ssid_len = ssid_len; |
748 | 748 | ||
749 | ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); | 749 | ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); |
750 | unlock: | 750 | unlock: |
751 | mutex_unlock(&local->scan_mtx); | 751 | mutex_unlock(&local->scan_mtx); |
752 | return ret; | 752 | return ret; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a360bceeba59..eec001491e66 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -349,6 +349,7 @@ int sta_info_insert(struct sta_info *sta) | |||
349 | goto out_free; | 349 | goto out_free; |
350 | } | 350 | } |
351 | list_add(&sta->list, &local->sta_list); | 351 | list_add(&sta->list, &local->sta_list); |
352 | local->sta_generation++; | ||
352 | local->num_sta++; | 353 | local->num_sta++; |
353 | sta_info_hash_add(local, sta); | 354 | sta_info_hash_add(local, sta); |
354 | 355 | ||
@@ -485,6 +486,7 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
485 | } | 486 | } |
486 | 487 | ||
487 | local->num_sta--; | 488 | local->num_sta--; |
489 | local->sta_generation++; | ||
488 | 490 | ||
489 | if (local->ops->sta_notify) { | 491 | if (local->ops->sta_notify) { |
490 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 492 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cffaa046b33..0c08d1e60cb5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) | 317 | if (!atomic_read(&tx->sdata->bss->num_sta_ps)) |
318 | return TX_CONTINUE; | 318 | return TX_CONTINUE; |
319 | 319 | ||
320 | /* buffered in hardware */ | ||
321 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { | ||
322 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
323 | |||
324 | return TX_CONTINUE; | ||
325 | } | ||
326 | |||
320 | /* buffered in mac80211 */ | 327 | /* buffered in mac80211 */ |
321 | if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { | 328 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
322 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 329 | purge_old_ps_buffers(tx->local); |
323 | purge_old_ps_buffers(tx->local); | 330 | |
324 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= | 331 | if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { |
325 | AP_MAX_BC_BUFFER) { | ||
326 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 332 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
327 | if (net_ratelimit()) { | 333 | if (net_ratelimit()) |
328 | printk(KERN_DEBUG "%s: BC TX buffer full - " | 334 | printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", |
329 | "dropping the oldest frame\n", | 335 | tx->dev->name); |
330 | tx->dev->name); | ||
331 | } | ||
332 | #endif | 336 | #endif |
333 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); | 337 | dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); |
334 | } else | 338 | } else |
335 | tx->local->total_ps_buffered++; | 339 | tx->local->total_ps_buffered++; |
336 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); | ||
337 | return TX_QUEUED; | ||
338 | } | ||
339 | 340 | ||
340 | /* buffered in hardware */ | 341 | skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); |
341 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | ||
342 | 342 | ||
343 | return TX_CONTINUE; | 343 | return TX_QUEUED; |
344 | } | 344 | } |
345 | 345 | ||
346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, | 346 | static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, |
@@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
700 | /* for pure STA mode without beacons, we can do it */ | 700 | /* for pure STA mode without beacons, we can do it */ |
701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); | 701 | hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); |
702 | tx->sdata->sequence_number += 0x10; | 702 | tx->sdata->sequence_number += 0x10; |
703 | tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; | ||
704 | return TX_CONTINUE; | 703 | return TX_CONTINUE; |
705 | } | 704 | } |
706 | 705 | ||
@@ -844,6 +843,23 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
844 | } | 843 | } |
845 | 844 | ||
846 | static ieee80211_tx_result debug_noinline | 845 | static ieee80211_tx_result debug_noinline |
846 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
847 | { | ||
848 | struct sk_buff *skb = tx->skb; | ||
849 | |||
850 | if (!tx->sta) | ||
851 | return TX_CONTINUE; | ||
852 | |||
853 | tx->sta->tx_packets++; | ||
854 | do { | ||
855 | tx->sta->tx_fragments++; | ||
856 | tx->sta->tx_bytes += skb->len; | ||
857 | } while ((skb = skb->next)); | ||
858 | |||
859 | return TX_CONTINUE; | ||
860 | } | ||
861 | |||
862 | static ieee80211_tx_result debug_noinline | ||
847 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | 863 | ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) |
848 | { | 864 | { |
849 | if (!tx->key) | 865 | if (!tx->key) |
@@ -887,23 +903,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | |||
887 | return TX_CONTINUE; | 903 | return TX_CONTINUE; |
888 | } | 904 | } |
889 | 905 | ||
890 | static ieee80211_tx_result debug_noinline | ||
891 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | ||
892 | { | ||
893 | struct sk_buff *skb = tx->skb; | ||
894 | |||
895 | if (!tx->sta) | ||
896 | return TX_CONTINUE; | ||
897 | |||
898 | tx->sta->tx_packets++; | ||
899 | do { | ||
900 | tx->sta->tx_fragments++; | ||
901 | tx->sta->tx_bytes += skb->len; | ||
902 | } while ((skb = skb->next)); | ||
903 | |||
904 | return TX_CONTINUE; | ||
905 | } | ||
906 | |||
907 | /* actual transmit path */ | 906 | /* actual transmit path */ |
908 | 907 | ||
909 | /* | 908 | /* |
@@ -1154,6 +1153,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1154 | next = skb->next; | 1153 | next = skb->next; |
1155 | len = skb->len; | 1154 | len = skb->len; |
1156 | 1155 | ||
1156 | if (next) | ||
1157 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | ||
1158 | |||
1157 | sdata = vif_to_sdata(info->control.vif); | 1159 | sdata = vif_to_sdata(info->control.vif); |
1158 | 1160 | ||
1159 | switch (sdata->vif.type) { | 1161 | switch (sdata->vif.type) { |
@@ -1210,9 +1212,9 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1210 | CALL_TXH(ieee80211_tx_h_sequence) | 1212 | CALL_TXH(ieee80211_tx_h_sequence) |
1211 | CALL_TXH(ieee80211_tx_h_fragment) | 1213 | CALL_TXH(ieee80211_tx_h_fragment) |
1212 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1214 | /* handlers after fragment must be aware of tx info fragmentation! */ |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1213 | CALL_TXH(ieee80211_tx_h_encrypt) | 1216 | CALL_TXH(ieee80211_tx_h_encrypt) |
1214 | CALL_TXH(ieee80211_tx_h_calculate_duration) | 1217 | CALL_TXH(ieee80211_tx_h_calculate_duration) |
1215 | CALL_TXH(ieee80211_tx_h_stats) | ||
1216 | #undef CALL_TXH | 1218 | #undef CALL_TXH |
1217 | 1219 | ||
1218 | txh_done: | 1220 | txh_done: |
@@ -1410,16 +1412,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1412 | ||
1411 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | 1413 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; |
1412 | 1414 | ||
1413 | if (ieee80211_vif_is_mesh(&sdata->vif) && | 1415 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
1414 | ieee80211_is_data(hdr->frame_control)) { | ||
1415 | if (is_multicast_ether_addr(hdr->addr3)) | ||
1416 | memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); | ||
1417 | else | ||
1418 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1419 | dev_put(sdata->dev); | ||
1420 | return; | ||
1421 | } | ||
1422 | } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | ||
1423 | int hdrlen; | 1416 | int hdrlen; |
1424 | u16 len_rthdr; | 1417 | u16 len_rthdr; |
1425 | 1418 | ||
@@ -1476,6 +1469,15 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1476 | 1469 | ||
1477 | info->control.vif = &sdata->vif; | 1470 | info->control.vif = &sdata->vif; |
1478 | 1471 | ||
1472 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
1473 | ieee80211_is_data(hdr->frame_control) && | ||
1474 | !is_multicast_ether_addr(hdr->addr1)) | ||
1475 | if (mesh_nexthop_lookup(skb, sdata)) { | ||
1476 | /* skb queued: don't free */ | ||
1477 | dev_put(sdata->dev); | ||
1478 | return; | ||
1479 | } | ||
1480 | |||
1479 | ieee80211_select_queue(local, skb); | 1481 | ieee80211_select_queue(local, skb); |
1480 | ieee80211_tx(sdata, skb, false); | 1482 | ieee80211_tx(sdata, skb, false); |
1481 | dev_put(sdata->dev); | 1483 | dev_put(sdata->dev); |
@@ -1617,52 +1619,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1617 | break; | 1619 | break; |
1618 | #ifdef CONFIG_MAC80211_MESH | 1620 | #ifdef CONFIG_MAC80211_MESH |
1619 | case NL80211_IFTYPE_MESH_POINT: | 1621 | case NL80211_IFTYPE_MESH_POINT: |
1620 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | ||
1621 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { | 1622 | if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { |
1622 | /* Do not send frames with mesh_ttl == 0 */ | 1623 | /* Do not send frames with mesh_ttl == 0 */ |
1623 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 1624 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
1624 | ret = NETDEV_TX_OK; | 1625 | ret = NETDEV_TX_OK; |
1625 | goto fail; | 1626 | goto fail; |
1626 | } | 1627 | } |
1627 | memset(&mesh_hdr, 0, sizeof(mesh_hdr)); | ||
1628 | 1628 | ||
1629 | if (compare_ether_addr(dev->dev_addr, | 1629 | if (compare_ether_addr(dev->dev_addr, |
1630 | skb->data + ETH_ALEN) == 0) { | 1630 | skb->data + ETH_ALEN) == 0) { |
1631 | /* RA TA DA SA */ | 1631 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, |
1632 | memset(hdr.addr1, 0, ETH_ALEN); | 1632 | skb->data, skb->data + ETH_ALEN); |
1633 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | 1633 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, |
1634 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1634 | sdata, NULL, NULL, NULL); |
1635 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1636 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); | ||
1637 | } else { | 1635 | } else { |
1638 | /* packet from other interface */ | 1636 | /* packet from other interface */ |
1639 | struct mesh_path *mppath; | 1637 | struct mesh_path *mppath; |
1638 | int is_mesh_mcast = 1; | ||
1639 | char *mesh_da; | ||
1640 | 1640 | ||
1641 | memset(hdr.addr1, 0, ETH_ALEN); | 1641 | rcu_read_lock(); |
1642 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1643 | memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN); | ||
1644 | |||
1645 | if (is_multicast_ether_addr(skb->data)) | 1642 | if (is_multicast_ether_addr(skb->data)) |
1646 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1643 | /* DA TA mSA AE:SA */ |
1644 | mesh_da = skb->data; | ||
1647 | else { | 1645 | else { |
1648 | rcu_read_lock(); | ||
1649 | mppath = mpp_path_lookup(skb->data, sdata); | 1646 | mppath = mpp_path_lookup(skb->data, sdata); |
1650 | if (mppath) | 1647 | if (mppath) { |
1651 | memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); | 1648 | /* RA TA mDA mSA AE:DA SA */ |
1652 | else | 1649 | mesh_da = mppath->mpp; |
1653 | memset(hdr.addr3, 0xff, ETH_ALEN); | 1650 | is_mesh_mcast = 0; |
1654 | rcu_read_unlock(); | 1651 | } else |
1652 | /* DA TA mSA AE:SA */ | ||
1653 | mesh_da = dev->broadcast; | ||
1655 | } | 1654 | } |
1655 | hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, | ||
1656 | mesh_da, dev->dev_addr); | ||
1657 | rcu_read_unlock(); | ||
1658 | if (is_mesh_mcast) | ||
1659 | meshhdrlen = | ||
1660 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1661 | sdata, | ||
1662 | skb->data + ETH_ALEN, | ||
1663 | NULL, | ||
1664 | NULL); | ||
1665 | else | ||
1666 | meshhdrlen = | ||
1667 | ieee80211_new_mesh_header(&mesh_hdr, | ||
1668 | sdata, | ||
1669 | NULL, | ||
1670 | skb->data, | ||
1671 | skb->data + ETH_ALEN); | ||
1656 | 1672 | ||
1657 | mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6; | ||
1658 | mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | ||
1659 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum); | ||
1660 | memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN); | ||
1661 | memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1662 | sdata->u.mesh.mesh_seqnum++; | ||
1663 | meshhdrlen = 18; | ||
1664 | } | 1673 | } |
1665 | hdrlen = 30; | ||
1666 | break; | 1674 | break; |
1667 | #endif | 1675 | #endif |
1668 | case NL80211_IFTYPE_STATION: | 1676 | case NL80211_IFTYPE_STATION: |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index d74cc77fa57a..3ecaa9179977 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,7 +5,8 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
9 | cfg80211-y += mlme.o ibss.o sme.o chan.o | ||
9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 10 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o | 11 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o |
11 | 12 | ||
diff --git a/net/wireless/chan.c b/net/wireless/chan.c new file mode 100644 index 000000000000..a46ac6c9b365 --- /dev/null +++ b/net/wireless/chan.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * This file contains helper code to handle channel | ||
3 | * settings and keeping track of what is possible at | ||
4 | * any point in time. | ||
5 | * | ||
6 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
7 | */ | ||
8 | |||
9 | #include <net/cfg80211.h> | ||
10 | #include "core.h" | ||
11 | |||
12 | struct ieee80211_channel * | ||
13 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
14 | struct wireless_dev *for_wdev) | ||
15 | { | ||
16 | struct wireless_dev *wdev; | ||
17 | struct ieee80211_channel *result = NULL; | ||
18 | |||
19 | WARN_ON(!mutex_is_locked(&rdev->devlist_mtx)); | ||
20 | |||
21 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | ||
22 | if (wdev == for_wdev) | ||
23 | continue; | ||
24 | |||
25 | /* | ||
26 | * Lock manually to tell lockdep about allowed | ||
27 | * nesting here if for_wdev->mtx is held already. | ||
28 | * This is ok as it's all under the rdev devlist | ||
29 | * mutex and as such can only be done once at any | ||
30 | * given time. | ||
31 | */ | ||
32 | mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING); | ||
33 | if (wdev->current_bss) | ||
34 | result = wdev->current_bss->pub.channel; | ||
35 | wdev_unlock(wdev); | ||
36 | |||
37 | if (result) | ||
38 | break; | ||
39 | } | ||
40 | |||
41 | return result; | ||
42 | } | ||
43 | |||
44 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
45 | struct wireless_dev *for_wdev, | ||
46 | int freq, enum nl80211_channel_type channel_type) | ||
47 | { | ||
48 | struct ieee80211_channel *chan; | ||
49 | struct ieee80211_sta_ht_cap *ht_cap; | ||
50 | int result; | ||
51 | |||
52 | if (rdev_fixed_channel(rdev, for_wdev)) | ||
53 | return -EBUSY; | ||
54 | |||
55 | if (!rdev->ops->set_channel) | ||
56 | return -EOPNOTSUPP; | ||
57 | |||
58 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
59 | |||
60 | /* Primary channel not allowed */ | ||
61 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (channel_type == NL80211_CHAN_HT40MINUS && | ||
65 | chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
66 | return -EINVAL; | ||
67 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
68 | chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
69 | return -EINVAL; | ||
70 | |||
71 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
72 | |||
73 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
74 | if (!ht_cap->ht_supported) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
78 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); | ||
83 | if (result) | ||
84 | return result; | ||
85 | |||
86 | rdev->channel = chan; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 1e189306560d..bc99e4ec7463 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -32,6 +32,7 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
32 | * only read the list, and that can happen quite | 32 | * only read the list, and that can happen quite |
33 | * often because we need to do it for each command */ | 33 | * often because we need to do it for each command */ |
34 | LIST_HEAD(cfg80211_rdev_list); | 34 | LIST_HEAD(cfg80211_rdev_list); |
35 | int cfg80211_rdev_list_generation; | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * This is used to protect the cfg80211_rdev_list | 38 | * This is used to protect the cfg80211_rdev_list |
@@ -411,6 +412,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
411 | rdev->wiphy.dev.class = &ieee80211_class; | 412 | rdev->wiphy.dev.class = &ieee80211_class; |
412 | rdev->wiphy.dev.platform_data = rdev; | 413 | rdev->wiphy.dev.platform_data = rdev; |
413 | 414 | ||
415 | rdev->wiphy.ps_default = CONFIG_CFG80211_DEFAULT_PS_VALUE; | ||
416 | |||
414 | wiphy_net_set(&rdev->wiphy, &init_net); | 417 | wiphy_net_set(&rdev->wiphy, &init_net); |
415 | 418 | ||
416 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; | 419 | rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block; |
@@ -511,6 +514,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
511 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 514 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
512 | 515 | ||
513 | list_add(&rdev->list, &cfg80211_rdev_list); | 516 | list_add(&rdev->list, &cfg80211_rdev_list); |
517 | cfg80211_rdev_list_generation++; | ||
514 | 518 | ||
515 | mutex_unlock(&cfg80211_mutex); | 519 | mutex_unlock(&cfg80211_mutex); |
516 | 520 | ||
@@ -593,13 +597,14 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
593 | reg_device_remove(wiphy); | 597 | reg_device_remove(wiphy); |
594 | 598 | ||
595 | list_del(&rdev->list); | 599 | list_del(&rdev->list); |
600 | cfg80211_rdev_list_generation++; | ||
596 | device_del(&rdev->wiphy.dev); | 601 | device_del(&rdev->wiphy.dev); |
597 | debugfs_remove(rdev->wiphy.debugfsdir); | 602 | debugfs_remove(rdev->wiphy.debugfsdir); |
598 | 603 | ||
599 | mutex_unlock(&cfg80211_mutex); | 604 | mutex_unlock(&cfg80211_mutex); |
600 | 605 | ||
606 | flush_work(&rdev->scan_done_wk); | ||
601 | cancel_work_sync(&rdev->conn_work); | 607 | cancel_work_sync(&rdev->conn_work); |
602 | cancel_work_sync(&rdev->scan_done_wk); | ||
603 | kfree(rdev->scan_req); | 608 | kfree(rdev->scan_req); |
604 | flush_work(&rdev->event_work); | 609 | flush_work(&rdev->event_work); |
605 | } | 610 | } |
@@ -653,6 +658,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
653 | spin_lock_init(&wdev->event_lock); | 658 | spin_lock_init(&wdev->event_lock); |
654 | mutex_lock(&rdev->devlist_mtx); | 659 | mutex_lock(&rdev->devlist_mtx); |
655 | list_add(&wdev->list, &rdev->netdev_list); | 660 | list_add(&wdev->list, &rdev->netdev_list); |
661 | rdev->devlist_generation++; | ||
656 | /* can only change netns with wiphy */ | 662 | /* can only change netns with wiphy */ |
657 | dev->features |= NETIF_F_NETNS_LOCAL; | 663 | dev->features |= NETIF_F_NETNS_LOCAL; |
658 | 664 | ||
@@ -670,7 +676,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
670 | wdev->wext.default_key = -1; | 676 | wdev->wext.default_key = -1; |
671 | wdev->wext.default_mgmt_key = -1; | 677 | wdev->wext.default_mgmt_key = -1; |
672 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 678 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
673 | wdev->wext.ps = CONFIG_CFG80211_DEFAULT_PS_VALUE; | 679 | wdev->wext.ps = wdev->wiphy->ps_default; |
674 | wdev->wext.ps_timeout = 100; | 680 | wdev->wext.ps_timeout = 100; |
675 | if (rdev->ops->set_power_mgmt) | 681 | if (rdev->ops->set_power_mgmt) |
676 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 682 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
@@ -706,6 +712,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
706 | case NETDEV_UP: | 712 | case NETDEV_UP: |
707 | #ifdef CONFIG_WIRELESS_EXT | 713 | #ifdef CONFIG_WIRELESS_EXT |
708 | cfg80211_lock_rdev(rdev); | 714 | cfg80211_lock_rdev(rdev); |
715 | mutex_lock(&rdev->devlist_mtx); | ||
709 | wdev_lock(wdev); | 716 | wdev_lock(wdev); |
710 | switch (wdev->iftype) { | 717 | switch (wdev->iftype) { |
711 | case NL80211_IFTYPE_ADHOC: | 718 | case NL80211_IFTYPE_ADHOC: |
@@ -718,10 +725,18 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
718 | break; | 725 | break; |
719 | } | 726 | } |
720 | wdev_unlock(wdev); | 727 | wdev_unlock(wdev); |
728 | mutex_unlock(&rdev->devlist_mtx); | ||
721 | cfg80211_unlock_rdev(rdev); | 729 | cfg80211_unlock_rdev(rdev); |
722 | #endif | 730 | #endif |
723 | break; | 731 | break; |
724 | case NETDEV_UNREGISTER: | 732 | case NETDEV_UNREGISTER: |
733 | cfg80211_lock_rdev(rdev); | ||
734 | |||
735 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { | ||
736 | rdev->scan_req->aborted = true; | ||
737 | ___cfg80211_scan_done(rdev); | ||
738 | } | ||
739 | |||
725 | mutex_lock(&rdev->devlist_mtx); | 740 | mutex_lock(&rdev->devlist_mtx); |
726 | /* | 741 | /* |
727 | * It is possible to get NETDEV_UNREGISTER | 742 | * It is possible to get NETDEV_UNREGISTER |
@@ -733,12 +748,14 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
733 | if (!list_empty(&wdev->list)) { | 748 | if (!list_empty(&wdev->list)) { |
734 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 749 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
735 | list_del_init(&wdev->list); | 750 | list_del_init(&wdev->list); |
751 | rdev->devlist_generation++; | ||
736 | mutex_destroy(&wdev->mtx); | 752 | mutex_destroy(&wdev->mtx); |
737 | #ifdef CONFIG_WIRELESS_EXT | 753 | #ifdef CONFIG_WIRELESS_EXT |
738 | kfree(wdev->wext.keys); | 754 | kfree(wdev->wext.keys); |
739 | #endif | 755 | #endif |
740 | } | 756 | } |
741 | mutex_unlock(&rdev->devlist_mtx); | 757 | mutex_unlock(&rdev->devlist_mtx); |
758 | cfg80211_unlock_rdev(rdev); | ||
742 | break; | 759 | break; |
743 | case NETDEV_PRE_UP: | 760 | case NETDEV_PRE_UP: |
744 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 761 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 325c17e6198c..c603f5286326 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -49,6 +49,7 @@ struct cfg80211_registered_device { | |||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | struct list_head netdev_list; | 51 | struct list_head netdev_list; |
52 | int devlist_generation; | ||
52 | 53 | ||
53 | /* BSSes/scanning */ | 54 | /* BSSes/scanning */ |
54 | spinlock_t bss_lock; | 55 | spinlock_t bss_lock; |
@@ -101,6 +102,7 @@ bool wiphy_idx_valid(int wiphy_idx) | |||
101 | 102 | ||
102 | extern struct mutex cfg80211_mutex; | 103 | extern struct mutex cfg80211_mutex; |
103 | extern struct list_head cfg80211_rdev_list; | 104 | extern struct list_head cfg80211_rdev_list; |
105 | extern int cfg80211_rdev_list_generation; | ||
104 | 106 | ||
105 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) | 107 | #define assert_cfg80211_lock() WARN_ON(!mutex_is_locked(&cfg80211_mutex)) |
106 | 108 | ||
@@ -335,7 +337,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
335 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 337 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
336 | struct net_device *dev, | 338 | struct net_device *dev, |
337 | struct cfg80211_connect_params *connect, | 339 | struct cfg80211_connect_params *connect, |
338 | struct cfg80211_cached_keys *connkeys); | 340 | struct cfg80211_cached_keys *connkeys, |
341 | const u8 *prev_bssid); | ||
339 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 342 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, | 343 | struct net_device *dev, |
341 | struct cfg80211_connect_params *connect, | 344 | struct cfg80211_connect_params *connect, |
@@ -353,6 +356,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
353 | struct wireless_dev *wdev); | 356 | struct wireless_dev *wdev); |
354 | 357 | ||
355 | void cfg80211_conn_work(struct work_struct *work); | 358 | void cfg80211_conn_work(struct work_struct *work); |
359 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); | ||
356 | 360 | ||
357 | /* internal helpers */ | 361 | /* internal helpers */ |
358 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 362 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
@@ -364,6 +368,14 @@ void cfg80211_sme_scan_done(struct net_device *dev); | |||
364 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 368 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
365 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 369 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
366 | void __cfg80211_scan_done(struct work_struct *wk); | 370 | void __cfg80211_scan_done(struct work_struct *wk); |
371 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); | ||
367 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 372 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
368 | 373 | ||
374 | struct ieee80211_channel * | ||
375 | rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||
376 | struct wireless_dev *for_wdev); | ||
377 | int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||
378 | struct wireless_dev *for_wdev, | ||
379 | int freq, enum nl80211_channel_type channel_type); | ||
380 | |||
369 | #endif /* __NET_WIRELESS_CORE_H */ | 381 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 4d7a084b35e2..42840a01be74 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
78 | struct cfg80211_cached_keys *connkeys) | 78 | struct cfg80211_cached_keys *connkeys) |
79 | { | 79 | { |
80 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 80 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
81 | struct ieee80211_channel *chan; | ||
81 | int err; | 82 | int err; |
82 | 83 | ||
83 | ASSERT_WDEV_LOCK(wdev); | 84 | ASSERT_WDEV_LOCK(wdev); |
84 | 85 | ||
86 | chan = rdev_fixed_channel(rdev, wdev); | ||
87 | if (chan && chan != params->channel) | ||
88 | return -EBUSY; | ||
89 | |||
85 | if (wdev->ssid_len) | 90 | if (wdev->ssid_len) |
86 | return -EALREADY; | 91 | return -EALREADY; |
87 | 92 | ||
@@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
112 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 117 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
113 | int err; | 118 | int err; |
114 | 119 | ||
120 | mutex_lock(&rdev->devlist_mtx); | ||
115 | wdev_lock(wdev); | 121 | wdev_lock(wdev); |
116 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); | 122 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); |
117 | wdev_unlock(wdev); | 123 | wdev_unlock(wdev); |
124 | mutex_unlock(&rdev->devlist_mtx); | ||
118 | 125 | ||
119 | return err; | 126 | return err; |
120 | } | 127 | } |
@@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
264 | 271 | ||
265 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | 272 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, |
266 | struct iw_request_info *info, | 273 | struct iw_request_info *info, |
267 | struct iw_freq *freq, char *extra) | 274 | struct iw_freq *wextfreq, char *extra) |
268 | { | 275 | { |
269 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 276 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
270 | struct ieee80211_channel *chan; | 277 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
271 | int err; | 278 | struct ieee80211_channel *chan = NULL; |
279 | int err, freq; | ||
272 | 280 | ||
273 | /* call only for ibss! */ | 281 | /* call only for ibss! */ |
274 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 282 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
275 | return -EINVAL; | 283 | return -EINVAL; |
276 | 284 | ||
277 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 285 | if (!rdev->ops->join_ibss) |
278 | return -EOPNOTSUPP; | 286 | return -EOPNOTSUPP; |
279 | 287 | ||
280 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 288 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
281 | if (chan && IS_ERR(chan)) | 289 | if (freq < 0) |
282 | return PTR_ERR(chan); | 290 | return freq; |
283 | 291 | ||
284 | if (chan && | 292 | if (freq) { |
285 | (chan->flags & IEEE80211_CHAN_NO_IBSS || | 293 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
286 | chan->flags & IEEE80211_CHAN_DISABLED)) | 294 | if (!chan) |
287 | return -EINVAL; | 295 | return -EINVAL; |
296 | if (chan->flags & IEEE80211_CHAN_NO_IBSS || | ||
297 | chan->flags & IEEE80211_CHAN_DISABLED) | ||
298 | return -EINVAL; | ||
299 | } | ||
288 | 300 | ||
289 | if (wdev->wext.ibss.channel == chan) | 301 | if (wdev->wext.ibss.channel == chan) |
290 | return 0; | 302 | return 0; |
@@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
292 | wdev_lock(wdev); | 304 | wdev_lock(wdev); |
293 | err = 0; | 305 | err = 0; |
294 | if (wdev->ssid_len) | 306 | if (wdev->ssid_len) |
295 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 307 | err = __cfg80211_leave_ibss(rdev, dev, true); |
296 | dev, true); | ||
297 | wdev_unlock(wdev); | 308 | wdev_unlock(wdev); |
298 | 309 | ||
299 | if (err) | 310 | if (err) |
@@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
307 | wdev->wext.ibss.channel_fixed = false; | 318 | wdev->wext.ibss.channel_fixed = false; |
308 | } | 319 | } |
309 | 320 | ||
321 | mutex_lock(&rdev->devlist_mtx); | ||
310 | wdev_lock(wdev); | 322 | wdev_lock(wdev); |
311 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 323 | err = cfg80211_ibss_wext_join(rdev, wdev); |
312 | wdev_unlock(wdev); | 324 | wdev_unlock(wdev); |
325 | mutex_unlock(&rdev->devlist_mtx); | ||
313 | 326 | ||
314 | return err; | 327 | return err; |
315 | } | 328 | } |
@@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
347 | struct iw_point *data, char *ssid) | 360 | struct iw_point *data, char *ssid) |
348 | { | 361 | { |
349 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 362 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
363 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
350 | size_t len = data->length; | 364 | size_t len = data->length; |
351 | int err; | 365 | int err; |
352 | 366 | ||
@@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
354 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 368 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
355 | return -EINVAL; | 369 | return -EINVAL; |
356 | 370 | ||
357 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 371 | if (!rdev->ops->join_ibss) |
358 | return -EOPNOTSUPP; | 372 | return -EOPNOTSUPP; |
359 | 373 | ||
360 | wdev_lock(wdev); | 374 | wdev_lock(wdev); |
361 | err = 0; | 375 | err = 0; |
362 | if (wdev->ssid_len) | 376 | if (wdev->ssid_len) |
363 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 377 | err = __cfg80211_leave_ibss(rdev, dev, true); |
364 | dev, true); | ||
365 | wdev_unlock(wdev); | 378 | wdev_unlock(wdev); |
366 | 379 | ||
367 | if (err) | 380 | if (err) |
@@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
375 | memcpy(wdev->wext.ibss.ssid, ssid, len); | 388 | memcpy(wdev->wext.ibss.ssid, ssid, len); |
376 | wdev->wext.ibss.ssid_len = len; | 389 | wdev->wext.ibss.ssid_len = len; |
377 | 390 | ||
391 | mutex_lock(&rdev->devlist_mtx); | ||
378 | wdev_lock(wdev); | 392 | wdev_lock(wdev); |
379 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 393 | err = cfg80211_ibss_wext_join(rdev, wdev); |
380 | wdev_unlock(wdev); | 394 | wdev_unlock(wdev); |
395 | mutex_unlock(&rdev->devlist_mtx); | ||
381 | 396 | ||
382 | return err; | 397 | return err; |
383 | } | 398 | } |
@@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
414 | struct sockaddr *ap_addr, char *extra) | 429 | struct sockaddr *ap_addr, char *extra) |
415 | { | 430 | { |
416 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 431 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
432 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
417 | u8 *bssid = ap_addr->sa_data; | 433 | u8 *bssid = ap_addr->sa_data; |
418 | int err; | 434 | int err; |
419 | 435 | ||
@@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
421 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) | 437 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) |
422 | return -EINVAL; | 438 | return -EINVAL; |
423 | 439 | ||
424 | if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) | 440 | if (!rdev->ops->join_ibss) |
425 | return -EOPNOTSUPP; | 441 | return -EOPNOTSUPP; |
426 | 442 | ||
427 | if (ap_addr->sa_family != ARPHRD_ETHER) | 443 | if (ap_addr->sa_family != ARPHRD_ETHER) |
@@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
443 | wdev_lock(wdev); | 459 | wdev_lock(wdev); |
444 | err = 0; | 460 | err = 0; |
445 | if (wdev->ssid_len) | 461 | if (wdev->ssid_len) |
446 | err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), | 462 | err = __cfg80211_leave_ibss(rdev, dev, true); |
447 | dev, true); | ||
448 | wdev_unlock(wdev); | 463 | wdev_unlock(wdev); |
449 | 464 | ||
450 | if (err) | 465 | if (err) |
@@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
456 | } else | 471 | } else |
457 | wdev->wext.ibss.bssid = NULL; | 472 | wdev->wext.ibss.bssid = NULL; |
458 | 473 | ||
474 | mutex_lock(&rdev->devlist_mtx); | ||
459 | wdev_lock(wdev); | 475 | wdev_lock(wdev); |
460 | err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); | 476 | err = cfg80211_ibss_wext_join(rdev, wdev); |
461 | wdev_unlock(wdev); | 477 | wdev_unlock(wdev); |
478 | mutex_unlock(&rdev->devlist_mtx); | ||
462 | 479 | ||
463 | return err; | 480 | return err; |
464 | } | 481 | } |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 525e8e247b30..da64071ceb84 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -67,6 +67,16 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
67 | 67 | ||
68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 68 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
69 | 69 | ||
70 | /* | ||
71 | * This is a bit of a hack, we don't notify userspace of | ||
72 | * a (re-)association reply if we tried to send a reassoc | ||
73 | * and got a reject -- we only try again with an assoc | ||
74 | * frame instead of reassoc. | ||
75 | */ | ||
76 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | ||
77 | cfg80211_sme_failed_reassoc(wdev)) | ||
78 | goto out; | ||
79 | |||
70 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 80 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
71 | 81 | ||
72 | if (status_code == WLAN_STATUS_SUCCESS) { | 82 | if (status_code == WLAN_STATUS_SUCCESS) { |
@@ -97,6 +107,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
97 | cfg80211_put_bss(&bss->pub); | 107 | cfg80211_put_bss(&bss->pub); |
98 | } | 108 | } |
99 | 109 | ||
110 | out: | ||
100 | wdev_unlock(wdev); | 111 | wdev_unlock(wdev); |
101 | } | 112 | } |
102 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 113 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
@@ -149,7 +160,7 @@ static void __cfg80211_send_deauth(struct net_device *dev, | |||
149 | 160 | ||
150 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 161 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
151 | 162 | ||
152 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 163 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
153 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 164 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
154 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 165 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
155 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 166 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
@@ -198,7 +209,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
198 | return; | 209 | return; |
199 | 210 | ||
200 | if (wdev->current_bss && | 211 | if (wdev->current_bss && |
201 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { | 212 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { |
202 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | 213 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
203 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) | 214 | if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) |
204 | continue; | 215 | continue; |
@@ -215,7 +226,7 @@ static void __cfg80211_send_disassoc(struct net_device *dev, | |||
215 | 226 | ||
216 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 227 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
217 | 228 | ||
218 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 229 | from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0; |
219 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 230 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
220 | } | 231 | } |
221 | 232 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0cd548267d4a..a8aaadeb6773 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -408,6 +408,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 408 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 409 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
410 | 410 | ||
411 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
412 | cfg80211_rdev_list_generation); | ||
413 | |||
411 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | 414 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, |
412 | dev->wiphy.retry_short); | 415 | dev->wiphy.retry_short); |
413 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | 416 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, |
@@ -701,15 +704,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
701 | 704 | ||
702 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 705 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
703 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 706 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
704 | struct ieee80211_channel *chan; | ||
705 | struct ieee80211_sta_ht_cap *ht_cap; | ||
706 | u32 freq; | 707 | u32 freq; |
707 | 708 | ||
708 | if (!rdev->ops->set_channel) { | ||
709 | result = -EOPNOTSUPP; | ||
710 | goto bad_res; | ||
711 | } | ||
712 | |||
713 | result = -EINVAL; | 709 | result = -EINVAL; |
714 | 710 | ||
715 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 711 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -723,42 +719,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
723 | } | 719 | } |
724 | 720 | ||
725 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 721 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
726 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||
727 | |||
728 | /* Primary channel not allowed */ | ||
729 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||
730 | goto bad_res; | ||
731 | |||
732 | if (channel_type == NL80211_CHAN_HT40MINUS && | ||
733 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) | ||
734 | goto bad_res; | ||
735 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
736 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) | ||
737 | goto bad_res; | ||
738 | |||
739 | /* | ||
740 | * At this point we know if that if HT40 was requested | ||
741 | * we are allowed to use it and the extension channel | ||
742 | * exists. | ||
743 | */ | ||
744 | |||
745 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
746 | |||
747 | /* no HT capabilities or intolerant */ | ||
748 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
749 | if (!ht_cap->ht_supported) | ||
750 | goto bad_res; | ||
751 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
752 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | ||
753 | goto bad_res; | ||
754 | } | ||
755 | 722 | ||
756 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 723 | mutex_lock(&rdev->devlist_mtx); |
757 | channel_type); | 724 | result = rdev_set_freq(rdev, NULL, freq, channel_type); |
725 | mutex_unlock(&rdev->devlist_mtx); | ||
758 | if (result) | 726 | if (result) |
759 | goto bad_res; | 727 | goto bad_res; |
760 | |||
761 | rdev->channel = chan; | ||
762 | } | 728 | } |
763 | 729 | ||
764 | changed = 0; | 730 | changed = 0; |
@@ -862,6 +828,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
862 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 828 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
863 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 829 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
864 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 830 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
831 | |||
832 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, | ||
833 | rdev->devlist_generation ^ | ||
834 | (cfg80211_rdev_list_generation << 2)); | ||
835 | |||
865 | return genlmsg_end(msg, hdr); | 836 | return genlmsg_end(msg, hdr); |
866 | 837 | ||
867 | nla_put_failure: | 838 | nla_put_failure: |
@@ -875,12 +846,12 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
875 | int if_idx = 0; | 846 | int if_idx = 0; |
876 | int wp_start = cb->args[0]; | 847 | int wp_start = cb->args[0]; |
877 | int if_start = cb->args[1]; | 848 | int if_start = cb->args[1]; |
878 | struct cfg80211_registered_device *dev; | 849 | struct cfg80211_registered_device *rdev; |
879 | struct wireless_dev *wdev; | 850 | struct wireless_dev *wdev; |
880 | 851 | ||
881 | mutex_lock(&cfg80211_mutex); | 852 | mutex_lock(&cfg80211_mutex); |
882 | list_for_each_entry(dev, &cfg80211_rdev_list, list) { | 853 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
883 | if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk))) | 854 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
884 | continue; | 855 | continue; |
885 | if (wp_idx < wp_start) { | 856 | if (wp_idx < wp_start) { |
886 | wp_idx++; | 857 | wp_idx++; |
@@ -888,21 +859,21 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
888 | } | 859 | } |
889 | if_idx = 0; | 860 | if_idx = 0; |
890 | 861 | ||
891 | mutex_lock(&dev->devlist_mtx); | 862 | mutex_lock(&rdev->devlist_mtx); |
892 | list_for_each_entry(wdev, &dev->netdev_list, list) { | 863 | list_for_each_entry(wdev, &rdev->netdev_list, list) { |
893 | if (if_idx < if_start) { | 864 | if (if_idx < if_start) { |
894 | if_idx++; | 865 | if_idx++; |
895 | continue; | 866 | continue; |
896 | } | 867 | } |
897 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 868 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
898 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 869 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
899 | dev, wdev->netdev) < 0) { | 870 | rdev, wdev->netdev) < 0) { |
900 | mutex_unlock(&dev->devlist_mtx); | 871 | mutex_unlock(&rdev->devlist_mtx); |
901 | goto out; | 872 | goto out; |
902 | } | 873 | } |
903 | if_idx++; | 874 | if_idx++; |
904 | } | 875 | } |
905 | mutex_unlock(&dev->devlist_mtx); | 876 | mutex_unlock(&rdev->devlist_mtx); |
906 | 877 | ||
907 | wp_idx++; | 878 | wp_idx++; |
908 | } | 879 | } |
@@ -1653,6 +1624,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1653 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1624 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1654 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 1625 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
1655 | 1626 | ||
1627 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, sinfo->generation); | ||
1628 | |||
1656 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 1629 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
1657 | if (!sinfoattr) | 1630 | if (!sinfoattr) |
1658 | goto nla_put_failure; | 1631 | goto nla_put_failure; |
@@ -2138,6 +2111,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2138 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | 2111 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); |
2139 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | 2112 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); |
2140 | 2113 | ||
2114 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, pinfo->generation); | ||
2115 | |||
2141 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | 2116 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); |
2142 | if (!pinfoattr) | 2117 | if (!pinfoattr) |
2143 | goto nla_put_failure; | 2118 | goto nla_put_failure; |
@@ -3027,10 +3002,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3027 | goto out; | 3002 | goto out; |
3028 | } | 3003 | } |
3029 | 3004 | ||
3030 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
3031 | request->n_channels = n_channels; | 3005 | request->n_channels = n_channels; |
3032 | if (n_ssids) | 3006 | if (n_ssids) |
3033 | request->ssids = (void *)(request->channels + n_channels); | 3007 | request->ssids = (void *)&request->channels[n_channels]; |
3034 | request->n_ssids = n_ssids; | 3008 | request->n_ssids = n_ssids; |
3035 | if (ie_len) { | 3009 | if (ie_len) { |
3036 | if (request->ssids) | 3010 | if (request->ssids) |
@@ -3127,8 +3101,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3127 | if (!hdr) | 3101 | if (!hdr) |
3128 | return -1; | 3102 | return -1; |
3129 | 3103 | ||
3130 | NLA_PUT_U32(msg, NL80211_ATTR_SCAN_GENERATION, | 3104 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3131 | rdev->bss_generation); | ||
3132 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3105 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3133 | 3106 | ||
3134 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); | 3107 | bss = nla_nest_start(msg, NL80211_ATTR_BSS); |
@@ -3453,7 +3426,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3453 | struct cfg80211_registered_device *rdev; | 3426 | struct cfg80211_registered_device *rdev; |
3454 | struct net_device *dev; | 3427 | struct net_device *dev; |
3455 | struct cfg80211_crypto_settings crypto; | 3428 | struct cfg80211_crypto_settings crypto; |
3456 | struct ieee80211_channel *chan; | 3429 | struct ieee80211_channel *chan, *fixedchan; |
3457 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3430 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
3458 | int err, ssid_len, ie_len = 0; | 3431 | int err, ssid_len, ie_len = 0; |
3459 | bool use_mfp = false; | 3432 | bool use_mfp = false; |
@@ -3496,6 +3469,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3496 | goto out; | 3469 | goto out; |
3497 | } | 3470 | } |
3498 | 3471 | ||
3472 | mutex_lock(&rdev->devlist_mtx); | ||
3473 | fixedchan = rdev_fixed_channel(rdev, NULL); | ||
3474 | if (fixedchan && chan != fixedchan) { | ||
3475 | err = -EBUSY; | ||
3476 | mutex_unlock(&rdev->devlist_mtx); | ||
3477 | goto out; | ||
3478 | } | ||
3479 | mutex_unlock(&rdev->devlist_mtx); | ||
3480 | |||
3499 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | 3481 | ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); |
3500 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | 3482 | ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); |
3501 | 3483 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0f61ae613f3b..f256dfffbf46 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1018,7 +1018,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1018 | map_regdom_flags(reg_rule->flags) | bw_flags; | 1018 | map_regdom_flags(reg_rule->flags) | bw_flags; |
1019 | chan->max_antenna_gain = chan->orig_mag = | 1019 | chan->max_antenna_gain = chan->orig_mag = |
1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1020 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1021 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1022 | chan->max_power = chan->orig_mpwr = | 1021 | chan->max_power = chan->orig_mpwr = |
1023 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1022 | (int) MBM_TO_DBM(power_rule->max_eirp); |
1024 | return; | 1023 | return; |
@@ -1027,7 +1026,6 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
1027 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); | 1026 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
1028 | chan->max_antenna_gain = min(chan->orig_mag, | 1027 | chan->max_antenna_gain = min(chan->orig_mag, |
1029 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 1028 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
1030 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1031 | if (chan->orig_mpwr) | 1029 | if (chan->orig_mpwr) |
1032 | chan->max_power = min(chan->orig_mpwr, | 1030 | chan->max_power = min(chan->orig_mpwr, |
1033 | (int) MBM_TO_DBM(power_rule->max_eirp)); | 1031 | (int) MBM_TO_DBM(power_rule->max_eirp)); |
@@ -1329,7 +1327,6 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1329 | 1327 | ||
1330 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | 1328 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; |
1331 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1329 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1332 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); | ||
1333 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 1330 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
1334 | } | 1331 | } |
1335 | 1332 | ||
@@ -1427,7 +1424,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1427 | if (last_wiphy != wiphy) { | 1424 | if (last_wiphy != wiphy) { |
1428 | /* | 1425 | /* |
1429 | * Two cards with two APs claiming different | 1426 | * Two cards with two APs claiming different |
1430 | * different Country IE alpha2s. We could | 1427 | * Country IE alpha2s. We could |
1431 | * intersect them, but that seems unlikely | 1428 | * intersect them, but that seems unlikely |
1432 | * to be correct. Reject second one for now. | 1429 | * to be correct. Reject second one for now. |
1433 | */ | 1430 | */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0ccf3a07dc02..fe575a24c95c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -18,19 +18,14 @@ | |||
18 | 18 | ||
19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) | 19 | #define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) |
20 | 20 | ||
21 | void __cfg80211_scan_done(struct work_struct *wk) | 21 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) |
22 | { | 22 | { |
23 | struct cfg80211_registered_device *rdev; | ||
24 | struct cfg80211_scan_request *request; | 23 | struct cfg80211_scan_request *request; |
25 | struct net_device *dev; | 24 | struct net_device *dev; |
26 | #ifdef CONFIG_WIRELESS_EXT | 25 | #ifdef CONFIG_WIRELESS_EXT |
27 | union iwreq_data wrqu; | 26 | union iwreq_data wrqu; |
28 | #endif | 27 | #endif |
29 | 28 | ||
30 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
31 | scan_done_wk); | ||
32 | |||
33 | mutex_lock(&rdev->mtx); | ||
34 | request = rdev->scan_req; | 29 | request = rdev->scan_req; |
35 | 30 | ||
36 | dev = request->dev; | 31 | dev = request->dev; |
@@ -43,9 +38,9 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
43 | cfg80211_sme_scan_done(dev); | 38 | cfg80211_sme_scan_done(dev); |
44 | 39 | ||
45 | if (request->aborted) | 40 | if (request->aborted) |
46 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | 41 | nl80211_send_scan_aborted(rdev, dev); |
47 | else | 42 | else |
48 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | 43 | nl80211_send_scan_done(rdev, dev); |
49 | 44 | ||
50 | #ifdef CONFIG_WIRELESS_EXT | 45 | #ifdef CONFIG_WIRELESS_EXT |
51 | if (!request->aborted) { | 46 | if (!request->aborted) { |
@@ -57,11 +52,22 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
57 | 52 | ||
58 | dev_put(dev); | 53 | dev_put(dev); |
59 | 54 | ||
60 | cfg80211_unlock_rdev(rdev); | 55 | rdev->scan_req = NULL; |
61 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | ||
62 | kfree(request); | 56 | kfree(request); |
63 | } | 57 | } |
64 | 58 | ||
59 | void __cfg80211_scan_done(struct work_struct *wk) | ||
60 | { | ||
61 | struct cfg80211_registered_device *rdev; | ||
62 | |||
63 | rdev = container_of(wk, struct cfg80211_registered_device, | ||
64 | scan_done_wk); | ||
65 | |||
66 | cfg80211_lock_rdev(rdev); | ||
67 | ___cfg80211_scan_done(rdev); | ||
68 | cfg80211_unlock_rdev(rdev); | ||
69 | } | ||
70 | |||
65 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 71 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
66 | { | 72 | { |
67 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 73 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
@@ -562,6 +568,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
562 | spin_lock_bh(&dev->bss_lock); | 568 | spin_lock_bh(&dev->bss_lock); |
563 | 569 | ||
564 | list_del(&bss->list); | 570 | list_del(&bss->list); |
571 | dev->bss_generation++; | ||
565 | rb_erase(&bss->rbn, &dev->bss_tree); | 572 | rb_erase(&bss->rbn, &dev->bss_tree); |
566 | 573 | ||
567 | spin_unlock_bh(&dev->bss_lock); | 574 | spin_unlock_bh(&dev->bss_lock); |
@@ -611,8 +618,8 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
611 | 618 | ||
612 | creq->wiphy = wiphy; | 619 | creq->wiphy = wiphy; |
613 | creq->dev = dev; | 620 | creq->dev = dev; |
614 | creq->ssids = (void *)(creq + 1); | 621 | /* SSIDs come after channels */ |
615 | creq->channels = (void *)(creq->ssids + 1); | 622 | creq->ssids = (void *)&creq->channels[n_channels]; |
616 | creq->n_channels = n_channels; | 623 | creq->n_channels = n_channels; |
617 | creq->n_ssids = 1; | 624 | creq->n_ssids = 1; |
618 | 625 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8a7dcbf90602..8e2ef54ea714 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -27,10 +27,10 @@ struct cfg80211_conn { | |||
27 | CFG80211_CONN_ASSOCIATE_NEXT, | 27 | CFG80211_CONN_ASSOCIATE_NEXT, |
28 | CFG80211_CONN_ASSOCIATING, | 28 | CFG80211_CONN_ASSOCIATING, |
29 | } state; | 29 | } state; |
30 | u8 bssid[ETH_ALEN]; | 30 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
31 | u8 *ie; | 31 | u8 *ie; |
32 | size_t ie_len; | 32 | size_t ie_len; |
33 | bool auto_auth; | 33 | bool auto_auth, prev_bssid_valid; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | 36 | ||
@@ -65,7 +65,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
65 | if (!request) | 65 | if (!request) |
66 | return -ENOMEM; | 66 | return -ENOMEM; |
67 | 67 | ||
68 | request->channels = (void *)((char *)request + sizeof(*request)); | ||
69 | if (wdev->conn->params.channel) | 68 | if (wdev->conn->params.channel) |
70 | request->channels[0] = wdev->conn->params.channel; | 69 | request->channels[0] = wdev->conn->params.channel; |
71 | else { | 70 | else { |
@@ -82,7 +81,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
82 | } | 81 | } |
83 | } | 82 | } |
84 | request->n_channels = n_channels; | 83 | request->n_channels = n_channels; |
85 | request->ssids = (void *)(request->channels + n_channels); | 84 | request->ssids = (void *)&request->channels[n_channels]; |
86 | request->n_ssids = 1; | 85 | request->n_ssids = 1; |
87 | 86 | ||
88 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, | 87 | memcpy(request->ssids[0].ssid, wdev->conn->params.ssid, |
@@ -110,6 +109,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
110 | { | 109 | { |
111 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 110 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
112 | struct cfg80211_connect_params *params; | 111 | struct cfg80211_connect_params *params; |
112 | const u8 *prev_bssid = NULL; | ||
113 | int err; | 113 | int err; |
114 | 114 | ||
115 | ASSERT_WDEV_LOCK(wdev); | 115 | ASSERT_WDEV_LOCK(wdev); |
@@ -135,15 +135,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
135 | case CFG80211_CONN_ASSOCIATE_NEXT: | 135 | case CFG80211_CONN_ASSOCIATE_NEXT: |
136 | BUG_ON(!rdev->ops->assoc); | 136 | BUG_ON(!rdev->ops->assoc); |
137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 137 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
138 | /* | 138 | if (wdev->conn->prev_bssid_valid) |
139 | * We could, later, implement roaming here and then actually | 139 | prev_bssid = wdev->conn->prev_bssid; |
140 | * set prev_bssid to non-NULL. But then we need to be aware | ||
141 | * that some APs don't like that -- so we'd need to retry | ||
142 | * the association. | ||
143 | */ | ||
144 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, | 140 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, |
145 | params->channel, params->bssid, | 141 | params->channel, params->bssid, |
146 | NULL, | 142 | prev_bssid, |
147 | params->ssid, params->ssid_len, | 143 | params->ssid, params->ssid_len, |
148 | params->ie, params->ie_len, | 144 | params->ie, params->ie_len, |
149 | false, ¶ms->crypto); | 145 | false, ¶ms->crypto); |
@@ -256,9 +252,11 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
256 | { | 252 | { |
257 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 253 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
258 | 254 | ||
255 | mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
259 | wdev_lock(wdev); | 256 | wdev_lock(wdev); |
260 | __cfg80211_sme_scan_done(dev); | 257 | __cfg80211_sme_scan_done(dev); |
261 | wdev_unlock(wdev); | 258 | wdev_unlock(wdev); |
259 | mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx); | ||
262 | } | 260 | } |
263 | 261 | ||
264 | void cfg80211_sme_rx_auth(struct net_device *dev, | 262 | void cfg80211_sme_rx_auth(struct net_device *dev, |
@@ -314,6 +312,28 @@ void cfg80211_sme_rx_auth(struct net_device *dev, | |||
314 | } | 312 | } |
315 | } | 313 | } |
316 | 314 | ||
315 | bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) | ||
316 | { | ||
317 | struct wiphy *wiphy = wdev->wiphy; | ||
318 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
319 | |||
320 | if (WARN_ON(!wdev->conn)) | ||
321 | return false; | ||
322 | |||
323 | if (!wdev->conn->prev_bssid_valid) | ||
324 | return false; | ||
325 | |||
326 | /* | ||
327 | * Some stupid APs don't accept reassoc, so we | ||
328 | * need to fall back to trying regular assoc. | ||
329 | */ | ||
330 | wdev->conn->prev_bssid_valid = false; | ||
331 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; | ||
332 | schedule_work(&rdev->conn_work); | ||
333 | |||
334 | return true; | ||
335 | } | ||
336 | |||
317 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 337 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
318 | const u8 *req_ie, size_t req_ie_len, | 338 | const u8 *req_ie, size_t req_ie_len, |
319 | const u8 *resp_ie, size_t resp_ie_len, | 339 | const u8 *resp_ie, size_t resp_ie_len, |
@@ -357,8 +377,11 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
357 | 377 | ||
358 | memset(&wrqu, 0, sizeof(wrqu)); | 378 | memset(&wrqu, 0, sizeof(wrqu)); |
359 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 379 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
360 | if (bssid && status == WLAN_STATUS_SUCCESS) | 380 | if (bssid && status == WLAN_STATUS_SUCCESS) { |
361 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 381 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
382 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
383 | wdev->wext.prev_bssid_valid = true; | ||
384 | } | ||
362 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 385 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
363 | } | 386 | } |
364 | #endif | 387 | #endif |
@@ -509,6 +532,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | |||
509 | memset(&wrqu, 0, sizeof(wrqu)); | 532 | memset(&wrqu, 0, sizeof(wrqu)); |
510 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 533 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
511 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 534 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
535 | memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | ||
536 | wdev->wext.prev_bssid_valid = true; | ||
512 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); | 537 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
513 | #endif | 538 | #endif |
514 | } | 539 | } |
@@ -570,10 +595,30 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
570 | wdev->ssid_len = 0; | 595 | wdev->ssid_len = 0; |
571 | 596 | ||
572 | if (wdev->conn) { | 597 | if (wdev->conn) { |
598 | const u8 *bssid; | ||
599 | int ret; | ||
600 | |||
573 | kfree(wdev->conn->ie); | 601 | kfree(wdev->conn->ie); |
574 | wdev->conn->ie = NULL; | 602 | wdev->conn->ie = NULL; |
575 | kfree(wdev->conn); | 603 | kfree(wdev->conn); |
576 | wdev->conn = NULL; | 604 | wdev->conn = NULL; |
605 | |||
606 | /* | ||
607 | * If this disconnect was due to a disassoc, we | ||
608 | * we might still have an auth BSS around. For | ||
609 | * the userspace SME that's currently expected, | ||
610 | * but for the kernel SME (nl80211 CONNECT or | ||
611 | * wireless extensions) we want to clear up all | ||
612 | * state. | ||
613 | */ | ||
614 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | ||
615 | if (!wdev->auth_bsses[i]) | ||
616 | continue; | ||
617 | bssid = wdev->auth_bsses[i]->pub.bssid; | ||
618 | ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | ||
619 | WLAN_REASON_DEAUTH_LEAVING); | ||
620 | WARN(ret, "deauth failed: %d\n", ret); | ||
621 | } | ||
577 | } | 622 | } |
578 | 623 | ||
579 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); | 624 | nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); |
@@ -621,9 +666,11 @@ EXPORT_SYMBOL(cfg80211_disconnected); | |||
621 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 666 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
622 | struct net_device *dev, | 667 | struct net_device *dev, |
623 | struct cfg80211_connect_params *connect, | 668 | struct cfg80211_connect_params *connect, |
624 | struct cfg80211_cached_keys *connkeys) | 669 | struct cfg80211_cached_keys *connkeys, |
670 | const u8 *prev_bssid) | ||
625 | { | 671 | { |
626 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 672 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
673 | struct ieee80211_channel *chan; | ||
627 | int err; | 674 | int err; |
628 | 675 | ||
629 | ASSERT_WDEV_LOCK(wdev); | 676 | ASSERT_WDEV_LOCK(wdev); |
@@ -631,6 +678,10 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
631 | if (wdev->sme_state != CFG80211_SME_IDLE) | 678 | if (wdev->sme_state != CFG80211_SME_IDLE) |
632 | return -EALREADY; | 679 | return -EALREADY; |
633 | 680 | ||
681 | chan = rdev_fixed_channel(rdev, wdev); | ||
682 | if (chan && chan != connect->channel) | ||
683 | return -EBUSY; | ||
684 | |||
634 | if (WARN_ON(wdev->connect_keys)) { | 685 | if (WARN_ON(wdev->connect_keys)) { |
635 | kfree(wdev->connect_keys); | 686 | kfree(wdev->connect_keys); |
636 | wdev->connect_keys = NULL; | 687 | wdev->connect_keys = NULL; |
@@ -638,14 +689,28 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
638 | 689 | ||
639 | if (connkeys && connkeys->def >= 0) { | 690 | if (connkeys && connkeys->def >= 0) { |
640 | int idx; | 691 | int idx; |
692 | u32 cipher; | ||
641 | 693 | ||
642 | idx = connkeys->def; | 694 | idx = connkeys->def; |
695 | cipher = connkeys->params[idx].cipher; | ||
643 | /* If given a WEP key we may need it for shared key auth */ | 696 | /* If given a WEP key we may need it for shared key auth */ |
644 | if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 || | 697 | if (cipher == WLAN_CIPHER_SUITE_WEP40 || |
645 | connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) { | 698 | cipher == WLAN_CIPHER_SUITE_WEP104) { |
646 | connect->key_idx = idx; | 699 | connect->key_idx = idx; |
647 | connect->key = connkeys->params[idx].key; | 700 | connect->key = connkeys->params[idx].key; |
648 | connect->key_len = connkeys->params[idx].key_len; | 701 | connect->key_len = connkeys->params[idx].key_len; |
702 | |||
703 | /* | ||
704 | * If ciphers are not set (e.g. when going through | ||
705 | * iwconfig), we have to set them appropriately here. | ||
706 | */ | ||
707 | if (connect->crypto.cipher_group == 0) | ||
708 | connect->crypto.cipher_group = cipher; | ||
709 | |||
710 | if (connect->crypto.n_ciphers_pairwise == 0) { | ||
711 | connect->crypto.n_ciphers_pairwise = 1; | ||
712 | connect->crypto.ciphers_pairwise[0] = cipher; | ||
713 | } | ||
649 | } | 714 | } |
650 | } | 715 | } |
651 | 716 | ||
@@ -701,6 +766,11 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
701 | wdev->sme_state = CFG80211_SME_CONNECTING; | 766 | wdev->sme_state = CFG80211_SME_CONNECTING; |
702 | wdev->connect_keys = connkeys; | 767 | wdev->connect_keys = connkeys; |
703 | 768 | ||
769 | if (prev_bssid) { | ||
770 | memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN); | ||
771 | wdev->conn->prev_bssid_valid = true; | ||
772 | } | ||
773 | |||
704 | /* we're good if we have both BSSID and channel */ | 774 | /* we're good if we have both BSSID and channel */ |
705 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { | 775 | if (wdev->conn->params.bssid && wdev->conn->params.channel) { |
706 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; | 776 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
@@ -751,9 +821,11 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
751 | { | 821 | { |
752 | int err; | 822 | int err; |
753 | 823 | ||
824 | mutex_lock(&rdev->devlist_mtx); | ||
754 | wdev_lock(dev->ieee80211_ptr); | 825 | wdev_lock(dev->ieee80211_ptr); |
755 | err = __cfg80211_connect(rdev, dev, connect, connkeys); | 826 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); |
756 | wdev_unlock(dev->ieee80211_ptr); | 827 | wdev_unlock(dev->ieee80211_ptr); |
828 | mutex_unlock(&rdev->devlist_mtx); | ||
757 | 829 | ||
758 | return err; | 830 | return err; |
759 | } | 831 | } |
diff --git a/net/wireless/util.c b/net/wireless/util.c index ba387d85dcfd..693275a16a26 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
274 | switch (ae) { | 274 | switch (ae) { |
275 | case 0: | 275 | case 0: |
276 | return 6; | 276 | return 6; |
277 | case 1: | 277 | case MESH_FLAGS_AE_A4: |
278 | return 12; | 278 | return 12; |
279 | case 2: | 279 | case MESH_FLAGS_AE_A5_A6: |
280 | return 18; | 280 | return 18; |
281 | case 3: | 281 | case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6): |
282 | return 24; | 282 | return 24; |
283 | default: | 283 | default: |
284 | return 6; | 284 | return 6; |
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
333 | } | 333 | } |
334 | break; | 334 | break; |
335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | 335 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): |
336 | if (iftype != NL80211_IFTYPE_STATION || | 336 | if ((iftype != NL80211_IFTYPE_STATION && |
337 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
337 | (is_multicast_ether_addr(dst) && | 338 | (is_multicast_ether_addr(dst) && |
338 | !compare_ether_addr(src, addr))) | 339 | !compare_ether_addr(src, addr))) |
339 | return -1; | 340 | return -1; |
341 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||
342 | struct ieee80211s_hdr *meshdr = | ||
343 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
344 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
345 | if (meshdr->flags & MESH_FLAGS_AE_A4) | ||
346 | memcpy(src, meshdr->eaddr1, ETH_ALEN); | ||
347 | } | ||
340 | break; | 348 | break; |
341 | case cpu_to_le16(0): | 349 | case cpu_to_le16(0): |
342 | if (iftype != NL80211_IFTYPE_ADHOC) | 350 | if (iftype != NL80211_IFTYPE_ADHOC) |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index e4e90e249bab..c44917492210 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -267,39 +267,26 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); | |||
267 | * @wiphy: the wiphy | 267 | * @wiphy: the wiphy |
268 | * @freq: the wext freq encoding | 268 | * @freq: the wext freq encoding |
269 | * | 269 | * |
270 | * Returns a channel, %NULL for auto, or an ERR_PTR for errors! | 270 | * Returns a frequency, or a negative error code, or 0 for auto. |
271 | */ | 271 | */ |
272 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 272 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq) |
273 | struct iw_freq *freq) | ||
274 | { | 273 | { |
275 | struct ieee80211_channel *chan; | ||
276 | int f; | ||
277 | |||
278 | /* | 274 | /* |
279 | * Parse frequency - return NULL for auto and | 275 | * Parse frequency - return 0 for auto and |
280 | * -EINVAL for impossible things. | 276 | * -EINVAL for impossible things. |
281 | */ | 277 | */ |
282 | if (freq->e == 0) { | 278 | if (freq->e == 0) { |
283 | if (freq->m < 0) | 279 | if (freq->m < 0) |
284 | return NULL; | 280 | return 0; |
285 | f = ieee80211_channel_to_frequency(freq->m); | 281 | return ieee80211_channel_to_frequency(freq->m); |
286 | } else { | 282 | } else { |
287 | int i, div = 1000000; | 283 | int i, div = 1000000; |
288 | for (i = 0; i < freq->e; i++) | 284 | for (i = 0; i < freq->e; i++) |
289 | div /= 10; | 285 | div /= 10; |
290 | if (div <= 0) | 286 | if (div <= 0) |
291 | return ERR_PTR(-EINVAL); | 287 | return -EINVAL; |
292 | f = freq->m / div; | 288 | return freq->m / div; |
293 | } | 289 | } |
294 | |||
295 | /* | ||
296 | * Look up channel struct and return -EINVAL when | ||
297 | * it cannot be found. | ||
298 | */ | ||
299 | chan = ieee80211_get_channel(wiphy, f); | ||
300 | if (!chan) | ||
301 | return ERR_PTR(-EINVAL); | ||
302 | return chan; | ||
303 | } | 290 | } |
304 | 291 | ||
305 | int cfg80211_wext_siwrts(struct net_device *dev, | 292 | int cfg80211_wext_siwrts(struct net_device *dev, |
@@ -761,33 +748,29 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | |||
761 | 748 | ||
762 | int cfg80211_wext_siwfreq(struct net_device *dev, | 749 | int cfg80211_wext_siwfreq(struct net_device *dev, |
763 | struct iw_request_info *info, | 750 | struct iw_request_info *info, |
764 | struct iw_freq *freq, char *extra) | 751 | struct iw_freq *wextfreq, char *extra) |
765 | { | 752 | { |
766 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 753 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
767 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 754 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
768 | struct ieee80211_channel *chan; | 755 | int freq, err; |
769 | int err; | ||
770 | 756 | ||
771 | switch (wdev->iftype) { | 757 | switch (wdev->iftype) { |
772 | case NL80211_IFTYPE_STATION: | 758 | case NL80211_IFTYPE_STATION: |
773 | return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); | 759 | return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra); |
774 | case NL80211_IFTYPE_ADHOC: | 760 | case NL80211_IFTYPE_ADHOC: |
775 | return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); | 761 | return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra); |
776 | default: | 762 | default: |
777 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 763 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
778 | if (!chan) | 764 | if (freq < 0) |
765 | return freq; | ||
766 | if (freq == 0) | ||
779 | return -EINVAL; | 767 | return -EINVAL; |
780 | if (IS_ERR(chan)) | 768 | mutex_lock(&rdev->devlist_mtx); |
781 | return PTR_ERR(chan); | 769 | err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT); |
782 | err = rdev->ops->set_channel(wdev->wiphy, chan, | 770 | mutex_unlock(&rdev->devlist_mtx); |
783 | NL80211_CHAN_NO_HT); | 771 | return err; |
784 | if (err) | ||
785 | return err; | ||
786 | rdev->channel = chan; | ||
787 | return 0; | ||
788 | } | 772 | } |
789 | } | 773 | } |
790 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); | ||
791 | 774 | ||
792 | int cfg80211_wext_giwfreq(struct net_device *dev, | 775 | int cfg80211_wext_giwfreq(struct net_device *dev, |
793 | struct iw_request_info *info, | 776 | struct iw_request_info *info, |
diff --git a/net/wireless/wext-compat.h b/net/wireless/wext-compat.h index 9a3774749589..20b3daef6964 100644 --- a/net/wireless/wext-compat.h +++ b/net/wireless/wext-compat.h | |||
@@ -42,8 +42,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, | |||
42 | struct iw_request_info *info, | 42 | struct iw_request_info *info, |
43 | struct iw_point *data, char *ssid); | 43 | struct iw_point *data, char *ssid); |
44 | 44 | ||
45 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 45 | int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq); |
46 | struct iw_freq *freq); | ||
47 | 46 | ||
48 | 47 | ||
49 | extern const struct iw_handler_def cfg80211_wext_handler; | 48 | extern const struct iw_handler_def cfg80211_wext_handler; |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 7bacbd1c2af6..d16cd9ea4d00 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -15,6 +15,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
15 | struct wireless_dev *wdev) | 15 | struct wireless_dev *wdev) |
16 | { | 16 | { |
17 | struct cfg80211_cached_keys *ck = NULL; | 17 | struct cfg80211_cached_keys *ck = NULL; |
18 | const u8 *prev_bssid = NULL; | ||
18 | int err, i; | 19 | int err, i; |
19 | 20 | ||
20 | ASSERT_RDEV_LOCK(rdev); | 21 | ASSERT_RDEV_LOCK(rdev); |
@@ -42,8 +43,12 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
42 | for (i = 0; i < 6; i++) | 43 | for (i = 0; i < 6; i++) |
43 | ck->params[i].key = ck->data[i]; | 44 | ck->params[i].key = ck->data[i]; |
44 | } | 45 | } |
46 | |||
47 | if (wdev->wext.prev_bssid_valid) | ||
48 | prev_bssid = wdev->wext.prev_bssid; | ||
49 | |||
45 | err = __cfg80211_connect(rdev, wdev->netdev, | 50 | err = __cfg80211_connect(rdev, wdev->netdev, |
46 | &wdev->wext.connect, ck); | 51 | &wdev->wext.connect, ck, prev_bssid); |
47 | if (err) | 52 | if (err) |
48 | kfree(ck); | 53 | kfree(ck); |
49 | 54 | ||
@@ -52,25 +57,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
52 | 57 | ||
53 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | 58 | int cfg80211_mgd_wext_siwfreq(struct net_device *dev, |
54 | struct iw_request_info *info, | 59 | struct iw_request_info *info, |
55 | struct iw_freq *freq, char *extra) | 60 | struct iw_freq *wextfreq, char *extra) |
56 | { | 61 | { |
57 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 62 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
58 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 63 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
59 | struct ieee80211_channel *chan; | 64 | struct ieee80211_channel *chan = NULL; |
60 | int err; | 65 | int err, freq; |
61 | 66 | ||
62 | /* call only for station! */ | 67 | /* call only for station! */ |
63 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 68 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
64 | return -EINVAL; | 69 | return -EINVAL; |
65 | 70 | ||
66 | chan = cfg80211_wext_freq(wdev->wiphy, freq); | 71 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
67 | if (chan && IS_ERR(chan)) | 72 | if (freq < 0) |
68 | return PTR_ERR(chan); | 73 | return freq; |
69 | 74 | ||
70 | if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) | 75 | if (freq) { |
71 | return -EINVAL; | 76 | chan = ieee80211_get_channel(wdev->wiphy, freq); |
77 | if (!chan) | ||
78 | return -EINVAL; | ||
79 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
80 | return -EINVAL; | ||
81 | } | ||
72 | 82 | ||
73 | cfg80211_lock_rdev(rdev); | 83 | cfg80211_lock_rdev(rdev); |
84 | mutex_lock(&rdev->devlist_mtx); | ||
74 | wdev_lock(wdev); | 85 | wdev_lock(wdev); |
75 | 86 | ||
76 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 87 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -84,9 +95,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
84 | /* if SSID set, we'll try right again, avoid event */ | 95 | /* if SSID set, we'll try right again, avoid event */ |
85 | if (wdev->wext.connect.ssid_len) | 96 | if (wdev->wext.connect.ssid_len) |
86 | event = false; | 97 | event = false; |
87 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 98 | err = __cfg80211_disconnect(rdev, dev, |
88 | dev, WLAN_REASON_DEAUTH_LEAVING, | 99 | WLAN_REASON_DEAUTH_LEAVING, event); |
89 | event); | ||
90 | if (err) | 100 | if (err) |
91 | goto out; | 101 | goto out; |
92 | } | 102 | } |
@@ -95,17 +105,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
95 | wdev->wext.connect.channel = chan; | 105 | wdev->wext.connect.channel = chan; |
96 | 106 | ||
97 | /* SSID is not set, we just want to switch channel */ | 107 | /* SSID is not set, we just want to switch channel */ |
98 | if (wdev->wext.connect.ssid_len && chan) { | 108 | if (chan && !wdev->wext.connect.ssid_len) { |
99 | err = -EOPNOTSUPP; | 109 | err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); |
100 | if (rdev->ops->set_channel) | ||
101 | err = rdev->ops->set_channel(wdev->wiphy, chan, | ||
102 | NL80211_CHAN_NO_HT); | ||
103 | goto out; | 110 | goto out; |
104 | } | 111 | } |
105 | 112 | ||
106 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 113 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
107 | out: | 114 | out: |
108 | wdev_unlock(wdev); | 115 | wdev_unlock(wdev); |
116 | mutex_unlock(&rdev->devlist_mtx); | ||
109 | cfg80211_unlock_rdev(rdev); | 117 | cfg80211_unlock_rdev(rdev); |
110 | return err; | 118 | return err; |
111 | } | 119 | } |
@@ -143,6 +151,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
143 | struct iw_point *data, char *ssid) | 151 | struct iw_point *data, char *ssid) |
144 | { | 152 | { |
145 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 153 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
154 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
146 | size_t len = data->length; | 155 | size_t len = data->length; |
147 | int err; | 156 | int err; |
148 | 157 | ||
@@ -157,7 +166,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
157 | if (len > 0 && ssid[len - 1] == '\0') | 166 | if (len > 0 && ssid[len - 1] == '\0') |
158 | len--; | 167 | len--; |
159 | 168 | ||
160 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 169 | cfg80211_lock_rdev(rdev); |
170 | mutex_lock(&rdev->devlist_mtx); | ||
161 | wdev_lock(wdev); | 171 | wdev_lock(wdev); |
162 | 172 | ||
163 | err = 0; | 173 | err = 0; |
@@ -173,23 +183,24 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
173 | /* if SSID set now, we'll try to connect, avoid event */ | 183 | /* if SSID set now, we'll try to connect, avoid event */ |
174 | if (len) | 184 | if (len) |
175 | event = false; | 185 | event = false; |
176 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 186 | err = __cfg80211_disconnect(rdev, dev, |
177 | dev, WLAN_REASON_DEAUTH_LEAVING, | 187 | WLAN_REASON_DEAUTH_LEAVING, event); |
178 | event); | ||
179 | if (err) | 188 | if (err) |
180 | goto out; | 189 | goto out; |
181 | } | 190 | } |
182 | 191 | ||
192 | wdev->wext.prev_bssid_valid = false; | ||
183 | wdev->wext.connect.ssid = wdev->wext.ssid; | 193 | wdev->wext.connect.ssid = wdev->wext.ssid; |
184 | memcpy(wdev->wext.ssid, ssid, len); | 194 | memcpy(wdev->wext.ssid, ssid, len); |
185 | wdev->wext.connect.ssid_len = len; | 195 | wdev->wext.connect.ssid_len = len; |
186 | 196 | ||
187 | wdev->wext.connect.crypto.control_port = false; | 197 | wdev->wext.connect.crypto.control_port = false; |
188 | 198 | ||
189 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 199 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
190 | out: | 200 | out: |
191 | wdev_unlock(wdev); | 201 | wdev_unlock(wdev); |
192 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 202 | mutex_unlock(&rdev->devlist_mtx); |
203 | cfg80211_unlock_rdev(rdev); | ||
193 | return err; | 204 | return err; |
194 | } | 205 | } |
195 | 206 | ||
@@ -206,7 +217,15 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, | |||
206 | data->flags = 0; | 217 | data->flags = 0; |
207 | 218 | ||
208 | wdev_lock(wdev); | 219 | wdev_lock(wdev); |
209 | if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | 220 | if (wdev->current_bss) { |
221 | const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, | ||
222 | WLAN_EID_SSID); | ||
223 | if (ie) { | ||
224 | data->flags = 1; | ||
225 | data->length = ie[1]; | ||
226 | memcpy(ssid, ie + 2, data->length); | ||
227 | } | ||
228 | } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { | ||
210 | data->flags = 1; | 229 | data->flags = 1; |
211 | data->length = wdev->wext.connect.ssid_len; | 230 | data->length = wdev->wext.connect.ssid_len; |
212 | memcpy(ssid, wdev->wext.connect.ssid, data->length); | 231 | memcpy(ssid, wdev->wext.connect.ssid, data->length); |
@@ -222,6 +241,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
222 | struct sockaddr *ap_addr, char *extra) | 241 | struct sockaddr *ap_addr, char *extra) |
223 | { | 242 | { |
224 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 243 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
244 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
225 | u8 *bssid = ap_addr->sa_data; | 245 | u8 *bssid = ap_addr->sa_data; |
226 | int err; | 246 | int err; |
227 | 247 | ||
@@ -236,7 +256,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
236 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) | 256 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) |
237 | bssid = NULL; | 257 | bssid = NULL; |
238 | 258 | ||
239 | cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); | 259 | cfg80211_lock_rdev(rdev); |
260 | mutex_lock(&rdev->devlist_mtx); | ||
240 | wdev_lock(wdev); | 261 | wdev_lock(wdev); |
241 | 262 | ||
242 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 263 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -250,9 +271,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
250 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) | 271 | compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) |
251 | goto out; | 272 | goto out; |
252 | 273 | ||
253 | err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), | 274 | err = __cfg80211_disconnect(rdev, dev, |
254 | dev, WLAN_REASON_DEAUTH_LEAVING, | 275 | WLAN_REASON_DEAUTH_LEAVING, false); |
255 | false); | ||
256 | if (err) | 276 | if (err) |
257 | goto out; | 277 | goto out; |
258 | } | 278 | } |
@@ -263,10 +283,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
263 | } else | 283 | } else |
264 | wdev->wext.connect.bssid = NULL; | 284 | wdev->wext.connect.bssid = NULL; |
265 | 285 | ||
266 | err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); | 286 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
267 | out: | 287 | out: |
268 | wdev_unlock(wdev); | 288 | wdev_unlock(wdev); |
269 | cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); | 289 | mutex_unlock(&rdev->devlist_mtx); |
290 | cfg80211_unlock_rdev(rdev); | ||
270 | return err; | 291 | return err; |
271 | } | 292 | } |
272 | 293 | ||