diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/Kconfig | 9 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 27 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 2 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 8 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 16 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/iface.c | 124 | ||||
-rw-r--r-- | net/mac80211/main.c | 5 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 79 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 2 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.h | 11 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_debugfs.c | 41 | ||||
-rw-r--r-- | net/mac80211/rx.c | 9 | ||||
-rw-r--r-- | net/mac80211/scan.c | 71 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 2 | ||||
-rw-r--r-- | net/mac80211/status.c | 14 | ||||
-rw-r--r-- | net/mac80211/tx.c | 2 |
17 files changed, 337 insertions, 93 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index a952b7f8c648..334c359da5e8 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -15,8 +15,12 @@ comment "CFG80211 needs to be enabled for MAC80211" | |||
15 | 15 | ||
16 | if MAC80211 != n | 16 | if MAC80211 != n |
17 | 17 | ||
18 | config MAC80211_HAS_RC | ||
19 | def_bool n | ||
20 | |||
18 | config MAC80211_RC_PID | 21 | config MAC80211_RC_PID |
19 | bool "PID controller based rate control algorithm" if EMBEDDED | 22 | bool "PID controller based rate control algorithm" if EMBEDDED |
23 | select MAC80211_HAS_RC | ||
20 | ---help--- | 24 | ---help--- |
21 | This option enables a TX rate control algorithm for | 25 | This option enables a TX rate control algorithm for |
22 | mac80211 that uses a PID controller to select the TX | 26 | mac80211 that uses a PID controller to select the TX |
@@ -24,12 +28,14 @@ config MAC80211_RC_PID | |||
24 | 28 | ||
25 | config MAC80211_RC_MINSTREL | 29 | config MAC80211_RC_MINSTREL |
26 | bool "Minstrel" if EMBEDDED | 30 | bool "Minstrel" if EMBEDDED |
31 | select MAC80211_HAS_RC | ||
27 | default y | 32 | default y |
28 | ---help--- | 33 | ---help--- |
29 | This option enables the 'minstrel' TX rate control algorithm | 34 | This option enables the 'minstrel' TX rate control algorithm |
30 | 35 | ||
31 | choice | 36 | choice |
32 | prompt "Default rate control algorithm" | 37 | prompt "Default rate control algorithm" |
38 | depends on MAC80211_HAS_RC | ||
33 | default MAC80211_RC_DEFAULT_MINSTREL | 39 | default MAC80211_RC_DEFAULT_MINSTREL |
34 | ---help--- | 40 | ---help--- |
35 | This option selects the default rate control algorithm | 41 | This option selects the default rate control algorithm |
@@ -62,6 +68,9 @@ config MAC80211_RC_DEFAULT | |||
62 | 68 | ||
63 | endif | 69 | endif |
64 | 70 | ||
71 | comment "Some wireless drivers require a rate control algorithm" | ||
72 | depends on MAC80211_HAS_RC=n | ||
73 | |||
65 | config MAC80211_MESH | 74 | config MAC80211_MESH |
66 | bool "Enable mac80211 mesh networking (pre-802.11s) support" | 75 | bool "Enable mac80211 mesh networking (pre-802.11s) support" |
67 | depends on MAC80211 && EXPERIMENTAL | 76 | depends on MAC80211 && EXPERIMENTAL |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index edc872e22c9b..c41aaba839fa 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1403,6 +1403,32 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1403 | return 0; | 1403 | return 0; |
1404 | } | 1404 | } |
1405 | 1405 | ||
1406 | static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, | ||
1407 | struct net_device *dev, | ||
1408 | s32 rssi_thold, u32 rssi_hyst) | ||
1409 | { | ||
1410 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1411 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1412 | struct ieee80211_vif *vif = &sdata->vif; | ||
1413 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
1414 | |||
1415 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) | ||
1416 | return -EOPNOTSUPP; | ||
1417 | |||
1418 | if (rssi_thold == bss_conf->cqm_rssi_thold && | ||
1419 | rssi_hyst == bss_conf->cqm_rssi_hyst) | ||
1420 | return 0; | ||
1421 | |||
1422 | bss_conf->cqm_rssi_thold = rssi_thold; | ||
1423 | bss_conf->cqm_rssi_hyst = rssi_hyst; | ||
1424 | |||
1425 | /* tell the driver upon association, unless already associated */ | ||
1426 | if (sdata->u.mgd.associated) | ||
1427 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); | ||
1428 | |||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1406 | static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | 1432 | static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, |
1407 | struct net_device *dev, | 1433 | struct net_device *dev, |
1408 | const u8 *addr, | 1434 | const u8 *addr, |
@@ -1507,4 +1533,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1507 | .remain_on_channel = ieee80211_remain_on_channel, | 1533 | .remain_on_channel = ieee80211_remain_on_channel, |
1508 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | 1534 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, |
1509 | .action = ieee80211_action, | 1535 | .action = ieee80211_action, |
1536 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, | ||
1510 | }; | 1537 | }; |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index d92800bb2d2f..23e720034577 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -57,7 +57,6 @@ STA_FILE(tx_filtered, tx_filtered_count, LU); | |||
57 | STA_FILE(tx_retry_failed, tx_retry_failed, LU); | 57 | STA_FILE(tx_retry_failed, tx_retry_failed, LU); |
58 | STA_FILE(tx_retry_count, tx_retry_count, LU); | 58 | STA_FILE(tx_retry_count, tx_retry_count, LU); |
59 | STA_FILE(last_signal, last_signal, D); | 59 | STA_FILE(last_signal, last_signal, D); |
60 | STA_FILE(last_noise, last_noise, D); | ||
61 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); | 60 | STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); |
62 | 61 | ||
63 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | 62 | static ssize_t sta_flags_read(struct file *file, char __user *userbuf, |
@@ -289,7 +288,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) | |||
289 | DEBUGFS_ADD(tx_retry_failed); | 288 | DEBUGFS_ADD(tx_retry_failed); |
290 | DEBUGFS_ADD(tx_retry_count); | 289 | DEBUGFS_ADD(tx_retry_count); |
291 | DEBUGFS_ADD(last_signal); | 290 | DEBUGFS_ADD(last_signal); |
292 | DEBUGFS_ADD(last_noise); | ||
293 | DEBUGFS_ADD(wep_weak_iv_count); | 291 | DEBUGFS_ADD(wep_weak_iv_count); |
294 | DEBUGFS_ADD(ht_capa); | 292 | DEBUGFS_ADD(ht_capa); |
295 | } | 293 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c3d844093a2f..9179196da264 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -84,16 +84,14 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
84 | } | 84 | } |
85 | 85 | ||
86 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | 86 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, |
87 | int mc_count, | 87 | struct netdev_hw_addr_list *mc_list) |
88 | struct dev_addr_list *mc_list) | ||
89 | { | 88 | { |
90 | u64 ret = 0; | 89 | u64 ret = 0; |
91 | 90 | ||
92 | if (local->ops->prepare_multicast) | 91 | if (local->ops->prepare_multicast) |
93 | ret = local->ops->prepare_multicast(&local->hw, mc_count, | 92 | ret = local->ops->prepare_multicast(&local->hw, mc_list); |
94 | mc_list); | ||
95 | 93 | ||
96 | trace_drv_prepare_multicast(local, mc_count, ret); | 94 | trace_drv_prepare_multicast(local, mc_list->count, ret); |
97 | 95 | ||
98 | return ret; | 96 | return ret; |
99 | } | 97 | } |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index e2976da4e0d9..e6f3b0c7a71f 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -265,17 +265,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
265 | sta->sta.supp_rates[band] = supp_rates | | 265 | sta->sta.supp_rates[band] = supp_rates | |
266 | ieee80211_mandatory_rates(local, band); | 266 | ieee80211_mandatory_rates(local, band); |
267 | 267 | ||
268 | if (sta->sta.supp_rates[band] != prev_rates) { | ||
268 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 269 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
269 | if (sta->sta.supp_rates[band] != prev_rates) | ||
270 | printk(KERN_DEBUG "%s: updated supp_rates set " | 270 | printk(KERN_DEBUG "%s: updated supp_rates set " |
271 | "for %pM based on beacon info (0x%llx | " | 271 | "for %pM based on beacon/probe_response " |
272 | "0x%llx -> 0x%llx)\n", | 272 | "(0x%x -> 0x%x)\n", |
273 | sdata->name, | 273 | sdata->name, sta->sta.addr, |
274 | sta->sta.addr, | 274 | prev_rates, sta->sta.supp_rates[band]); |
275 | (unsigned long long) prev_rates, | ||
276 | (unsigned long long) supp_rates, | ||
277 | (unsigned long long) sta->sta.supp_rates[band]); | ||
278 | #endif | 275 | #endif |
276 | rate_control_rate_init(sta); | ||
277 | } | ||
279 | rcu_read_unlock(); | 278 | rcu_read_unlock(); |
280 | } else { | 279 | } else { |
281 | rcu_read_unlock(); | 280 | rcu_read_unlock(); |
@@ -371,6 +370,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
371 | sdata->name, mgmt->bssid); | 370 | sdata->name, mgmt->bssid); |
372 | #endif | 371 | #endif |
373 | ieee80211_sta_join_ibss(sdata, bss); | 372 | ieee80211_sta_join_ibss(sdata, bss); |
373 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
374 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 374 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
375 | supp_rates, GFP_KERNEL); | 375 | supp_rates, GFP_KERNEL); |
376 | } | 376 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 241533e1bc03..7fdacf9408b1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -327,7 +327,7 @@ struct ieee80211_if_managed { | |||
327 | struct work_struct work; | 327 | struct work_struct work; |
328 | struct work_struct monitor_work; | 328 | struct work_struct monitor_work; |
329 | struct work_struct chswitch_work; | 329 | struct work_struct chswitch_work; |
330 | struct work_struct beacon_loss_work; | 330 | struct work_struct beacon_connection_loss_work; |
331 | 331 | ||
332 | unsigned long probe_timeout; | 332 | unsigned long probe_timeout; |
333 | int probe_send_count; | 333 | int probe_send_count; |
@@ -646,8 +646,7 @@ struct ieee80211_local { | |||
646 | struct work_struct recalc_smps; | 646 | struct work_struct recalc_smps; |
647 | 647 | ||
648 | /* aggregated multicast list */ | 648 | /* aggregated multicast list */ |
649 | struct dev_addr_list *mc_list; | 649 | struct netdev_hw_addr_list mc_list; |
650 | int mc_count; | ||
651 | 650 | ||
652 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | 651 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ |
653 | 652 | ||
@@ -745,6 +744,7 @@ struct ieee80211_local { | |||
745 | int scan_channel_idx; | 744 | int scan_channel_idx; |
746 | int scan_ies_len; | 745 | int scan_ies_len; |
747 | 746 | ||
747 | unsigned long leave_oper_channel_time; | ||
748 | enum mac80211_scan_state next_scan_state; | 748 | enum mac80211_scan_state next_scan_state; |
749 | struct delayed_work scan_work; | 749 | struct delayed_work scan_work; |
750 | struct ieee80211_sub_if_data *scan_sdata; | 750 | struct ieee80211_sub_if_data *scan_sdata; |
@@ -1155,7 +1155,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1155 | int powersave); | 1155 | int powersave); |
1156 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1156 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1157 | struct ieee80211_hdr *hdr); | 1157 | struct ieee80211_hdr *hdr); |
1158 | void ieee80211_beacon_loss_work(struct work_struct *work); | 1158 | void ieee80211_beacon_connection_loss_work(struct work_struct *work); |
1159 | 1159 | ||
1160 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1160 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1161 | enum queue_stop_reason reason); | 1161 | enum queue_stop_reason reason); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e08fa8eda1b3..50deb017fd6e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -413,8 +413,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
413 | 413 | ||
414 | netif_addr_lock_bh(dev); | 414 | netif_addr_lock_bh(dev); |
415 | spin_lock_bh(&local->filter_lock); | 415 | spin_lock_bh(&local->filter_lock); |
416 | __dev_addr_unsync(&local->mc_list, &local->mc_count, | 416 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); |
417 | &dev->mc_list, &dev->mc_count); | ||
418 | spin_unlock_bh(&local->filter_lock); | 417 | spin_unlock_bh(&local->filter_lock); |
419 | netif_addr_unlock_bh(dev); | 418 | netif_addr_unlock_bh(dev); |
420 | 419 | ||
@@ -487,7 +486,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
487 | cancel_work_sync(&sdata->u.mgd.work); | 486 | cancel_work_sync(&sdata->u.mgd.work); |
488 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 487 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
489 | cancel_work_sync(&sdata->u.mgd.monitor_work); | 488 | cancel_work_sync(&sdata->u.mgd.monitor_work); |
490 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | 489 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); |
491 | 490 | ||
492 | /* | 491 | /* |
493 | * When we get here, the interface is marked down. | 492 | * When we get here, the interface is marked down. |
@@ -597,8 +596,7 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
597 | sdata->flags ^= IEEE80211_SDATA_PROMISC; | 596 | sdata->flags ^= IEEE80211_SDATA_PROMISC; |
598 | } | 597 | } |
599 | spin_lock_bh(&local->filter_lock); | 598 | spin_lock_bh(&local->filter_lock); |
600 | __dev_addr_sync(&local->mc_list, &local->mc_count, | 599 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); |
601 | &dev->mc_list, &dev->mc_count); | ||
602 | spin_unlock_bh(&local->filter_lock); | 600 | spin_unlock_bh(&local->filter_lock); |
603 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 601 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
604 | } | 602 | } |
@@ -816,6 +814,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
816 | return 0; | 814 | return 0; |
817 | } | 815 | } |
818 | 816 | ||
817 | static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||
818 | struct net_device *dev, | ||
819 | enum nl80211_iftype type) | ||
820 | { | ||
821 | struct ieee80211_sub_if_data *sdata; | ||
822 | u64 mask, start, addr, val, inc; | ||
823 | u8 *m; | ||
824 | u8 tmp_addr[ETH_ALEN]; | ||
825 | int i; | ||
826 | |||
827 | /* default ... something at least */ | ||
828 | memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | ||
829 | |||
830 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && | ||
831 | local->hw.wiphy->n_addresses <= 1) | ||
832 | return; | ||
833 | |||
834 | |||
835 | mutex_lock(&local->iflist_mtx); | ||
836 | |||
837 | switch (type) { | ||
838 | case NL80211_IFTYPE_MONITOR: | ||
839 | /* doesn't matter */ | ||
840 | break; | ||
841 | case NL80211_IFTYPE_WDS: | ||
842 | case NL80211_IFTYPE_AP_VLAN: | ||
843 | /* match up with an AP interface */ | ||
844 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
845 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
846 | continue; | ||
847 | memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); | ||
848 | break; | ||
849 | } | ||
850 | /* keep default if no AP interface present */ | ||
851 | break; | ||
852 | default: | ||
853 | /* assign a new address if possible -- try n_addresses first */ | ||
854 | for (i = 0; i < local->hw.wiphy->n_addresses; i++) { | ||
855 | bool used = false; | ||
856 | |||
857 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
858 | if (memcmp(local->hw.wiphy->addresses[i].addr, | ||
859 | sdata->vif.addr, ETH_ALEN) == 0) { | ||
860 | used = true; | ||
861 | break; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | if (!used) { | ||
866 | memcpy(dev->perm_addr, | ||
867 | local->hw.wiphy->addresses[i].addr, | ||
868 | ETH_ALEN); | ||
869 | break; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | /* try mask if available */ | ||
874 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) | ||
875 | break; | ||
876 | |||
877 | m = local->hw.wiphy->addr_mask; | ||
878 | mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
879 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
880 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
881 | |||
882 | if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { | ||
883 | /* not a contiguous mask ... not handled now! */ | ||
884 | printk(KERN_DEBUG "not contiguous\n"); | ||
885 | break; | ||
886 | } | ||
887 | |||
888 | m = local->hw.wiphy->perm_addr; | ||
889 | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
890 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
891 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
892 | |||
893 | inc = 1ULL<<__ffs64(mask); | ||
894 | val = (start & mask); | ||
895 | addr = (start & ~mask) | (val & mask); | ||
896 | do { | ||
897 | bool used = false; | ||
898 | |||
899 | tmp_addr[5] = addr >> 0*8; | ||
900 | tmp_addr[4] = addr >> 1*8; | ||
901 | tmp_addr[3] = addr >> 2*8; | ||
902 | tmp_addr[2] = addr >> 3*8; | ||
903 | tmp_addr[1] = addr >> 4*8; | ||
904 | tmp_addr[0] = addr >> 5*8; | ||
905 | |||
906 | val += inc; | ||
907 | |||
908 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
909 | if (memcmp(tmp_addr, sdata->vif.addr, | ||
910 | ETH_ALEN) == 0) { | ||
911 | used = true; | ||
912 | break; | ||
913 | } | ||
914 | } | ||
915 | |||
916 | if (!used) { | ||
917 | memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); | ||
918 | break; | ||
919 | } | ||
920 | addr = (start & ~mask) | (val & mask); | ||
921 | } while (addr != start); | ||
922 | |||
923 | break; | ||
924 | } | ||
925 | |||
926 | mutex_unlock(&local->iflist_mtx); | ||
927 | } | ||
928 | |||
819 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 929 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
820 | struct net_device **new_dev, enum nl80211_iftype type, | 930 | struct net_device **new_dev, enum nl80211_iftype type, |
821 | struct vif_params *params) | 931 | struct vif_params *params) |
@@ -845,8 +955,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
845 | if (ret < 0) | 955 | if (ret < 0) |
846 | goto fail; | 956 | goto fail; |
847 | 957 | ||
848 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 958 | ieee80211_assign_perm_addr(local, ndev, type); |
849 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | 959 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); |
850 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 960 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
851 | 961 | ||
852 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 962 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b887e484ae04..50c1b1ada884 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -71,7 +71,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
71 | spin_lock_bh(&local->filter_lock); | 71 | spin_lock_bh(&local->filter_lock); |
72 | changed_flags = local->filter_flags ^ new_flags; | 72 | changed_flags = local->filter_flags ^ new_flags; |
73 | 73 | ||
74 | mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); | 74 | mc = drv_prepare_multicast(local, &local->mc_list); |
75 | spin_unlock_bh(&local->filter_lock); | 75 | spin_unlock_bh(&local->filter_lock); |
76 | 76 | ||
77 | /* be a bit nasty */ | 77 | /* be a bit nasty */ |
@@ -388,6 +388,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
388 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | 388 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; |
389 | 389 | ||
390 | INIT_LIST_HEAD(&local->interfaces); | 390 | INIT_LIST_HEAD(&local->interfaces); |
391 | |||
392 | __hw_addr_init(&local->mc_list); | ||
393 | |||
391 | mutex_init(&local->iflist_mtx); | 394 | mutex_init(&local->iflist_mtx); |
392 | mutex_init(&local->scan_mtx); | 395 | mutex_init(&local->scan_mtx); |
393 | 396 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c8cd169fc10e..71ff42a0465b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -754,6 +754,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
754 | /* And the BSSID changed - we're associated now */ | 754 | /* And the BSSID changed - we're associated now */ |
755 | bss_info_changed |= BSS_CHANGED_BSSID; | 755 | bss_info_changed |= BSS_CHANGED_BSSID; |
756 | 756 | ||
757 | /* Tell the driver to monitor connection quality (if supported) */ | ||
758 | if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) && | ||
759 | sdata->vif.bss_conf.cqm_rssi_thold) | ||
760 | bss_info_changed |= BSS_CHANGED_CQM; | ||
761 | |||
757 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 762 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
758 | 763 | ||
759 | mutex_lock(&local->iflist_mtx); | 764 | mutex_lock(&local->iflist_mtx); |
@@ -855,6 +860,9 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
855 | if (is_multicast_ether_addr(hdr->addr1)) | 860 | if (is_multicast_ether_addr(hdr->addr1)) |
856 | return; | 861 | return; |
857 | 862 | ||
863 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
864 | return; | ||
865 | |||
858 | mod_timer(&sdata->u.mgd.conn_mon_timer, | 866 | mod_timer(&sdata->u.mgd.conn_mon_timer, |
859 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); | 867 | round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); |
860 | } | 868 | } |
@@ -932,23 +940,68 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
932 | mutex_unlock(&ifmgd->mtx); | 940 | mutex_unlock(&ifmgd->mtx); |
933 | } | 941 | } |
934 | 942 | ||
935 | void ieee80211_beacon_loss_work(struct work_struct *work) | 943 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) |
944 | { | ||
945 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
946 | struct ieee80211_local *local = sdata->local; | ||
947 | u8 bssid[ETH_ALEN]; | ||
948 | |||
949 | mutex_lock(&ifmgd->mtx); | ||
950 | if (!ifmgd->associated) { | ||
951 | mutex_unlock(&ifmgd->mtx); | ||
952 | return; | ||
953 | } | ||
954 | |||
955 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | ||
956 | |||
957 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | ||
958 | |||
959 | ieee80211_set_disassoc(sdata); | ||
960 | ieee80211_recalc_idle(local); | ||
961 | mutex_unlock(&ifmgd->mtx); | ||
962 | /* | ||
963 | * must be outside lock due to cfg80211, | ||
964 | * but that's not a problem. | ||
965 | */ | ||
966 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
967 | IEEE80211_STYPE_DEAUTH, | ||
968 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
969 | NULL); | ||
970 | } | ||
971 | |||
972 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) | ||
936 | { | 973 | { |
937 | struct ieee80211_sub_if_data *sdata = | 974 | struct ieee80211_sub_if_data *sdata = |
938 | container_of(work, struct ieee80211_sub_if_data, | 975 | container_of(work, struct ieee80211_sub_if_data, |
939 | u.mgd.beacon_loss_work); | 976 | u.mgd.beacon_connection_loss_work); |
940 | 977 | ||
941 | ieee80211_mgd_probe_ap(sdata, true); | 978 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
979 | __ieee80211_connection_loss(sdata); | ||
980 | else | ||
981 | ieee80211_mgd_probe_ap(sdata, true); | ||
942 | } | 982 | } |
943 | 983 | ||
944 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 984 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
945 | { | 985 | { |
946 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 986 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
987 | struct ieee80211_hw *hw = &sdata->local->hw; | ||
947 | 988 | ||
948 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); | 989 | WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR); |
990 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | ||
949 | } | 991 | } |
950 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 992 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
951 | 993 | ||
994 | void ieee80211_connection_loss(struct ieee80211_vif *vif) | ||
995 | { | ||
996 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
997 | struct ieee80211_hw *hw = &sdata->local->hw; | ||
998 | |||
999 | WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR)); | ||
1000 | ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); | ||
1001 | } | ||
1002 | EXPORT_SYMBOL(ieee80211_connection_loss); | ||
1003 | |||
1004 | |||
952 | static enum rx_mgmt_action __must_check | 1005 | static enum rx_mgmt_action __must_check |
953 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1006 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
954 | struct ieee80211_mgmt *mgmt, size_t len) | 1007 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1638,7 +1691,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
1638 | if (local->quiescing) | 1691 | if (local->quiescing) |
1639 | return; | 1692 | return; |
1640 | 1693 | ||
1641 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); | 1694 | ieee80211_queue_work(&sdata->local->hw, |
1695 | &sdata->u.mgd.beacon_connection_loss_work); | ||
1642 | } | 1696 | } |
1643 | 1697 | ||
1644 | static void ieee80211_sta_conn_mon_timer(unsigned long data) | 1698 | static void ieee80211_sta_conn_mon_timer(unsigned long data) |
@@ -1690,7 +1744,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
1690 | */ | 1744 | */ |
1691 | 1745 | ||
1692 | cancel_work_sync(&ifmgd->work); | 1746 | cancel_work_sync(&ifmgd->work); |
1693 | cancel_work_sync(&ifmgd->beacon_loss_work); | 1747 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
1694 | if (del_timer_sync(&ifmgd->timer)) | 1748 | if (del_timer_sync(&ifmgd->timer)) |
1695 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 1749 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
1696 | 1750 | ||
@@ -1724,7 +1778,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1724 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 1778 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
1725 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); | 1779 | INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); |
1726 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1780 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1727 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | 1781 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
1782 | ieee80211_beacon_connection_loss_work); | ||
1728 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 1783 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1729 | (unsigned long) sdata); | 1784 | (unsigned long) sdata); |
1730 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, | 1785 | setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, |
@@ -2136,3 +2191,13 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata, | |||
2136 | *cookie = (unsigned long) skb; | 2191 | *cookie = (unsigned long) skb; |
2137 | return 0; | 2192 | return 0; |
2138 | } | 2193 | } |
2194 | |||
2195 | void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | ||
2196 | enum nl80211_cqm_rssi_threshold_event rssi_event, | ||
2197 | gfp_t gfp) | ||
2198 | { | ||
2199 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
2200 | |||
2201 | cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp); | ||
2202 | } | ||
2203 | EXPORT_SYMBOL(ieee80211_cqm_rssi_notify); | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 818abfae9007..f65ce6dcc8e2 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -542,7 +542,7 @@ minstrel_free(void *priv) | |||
542 | kfree(priv); | 542 | kfree(priv); |
543 | } | 543 | } |
544 | 544 | ||
545 | static struct rate_control_ops mac80211_minstrel = { | 545 | struct rate_control_ops mac80211_minstrel = { |
546 | .name = "minstrel", | 546 | .name = "minstrel", |
547 | .tx_status = minstrel_tx_status, | 547 | .tx_status = minstrel_tx_status, |
548 | .get_rate = minstrel_get_rate, | 548 | .get_rate = minstrel_get_rate, |
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 38bf4168fc3a..0f5a83370aa6 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -80,7 +80,18 @@ struct minstrel_priv { | |||
80 | unsigned int lookaround_rate_mrr; | 80 | unsigned int lookaround_rate_mrr; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct minstrel_debugfs_info { | ||
84 | size_t len; | ||
85 | char buf[]; | ||
86 | }; | ||
87 | |||
88 | extern struct rate_control_ops mac80211_minstrel; | ||
83 | void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); | 89 | void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); |
84 | void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); | 90 | void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); |
85 | 91 | ||
92 | /* debugfs */ | ||
93 | int minstrel_stats_open(struct inode *inode, struct file *file); | ||
94 | ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); | ||
95 | int minstrel_stats_release(struct inode *inode, struct file *file); | ||
96 | |||
86 | #endif | 97 | #endif |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 0e1f12b1b6dd..241e76f3fdf2 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
@@ -53,21 +53,15 @@ | |||
53 | #include <net/mac80211.h> | 53 | #include <net/mac80211.h> |
54 | #include "rc80211_minstrel.h" | 54 | #include "rc80211_minstrel.h" |
55 | 55 | ||
56 | struct minstrel_stats_info { | 56 | int |
57 | struct minstrel_sta_info *mi; | ||
58 | char buf[4096]; | ||
59 | size_t len; | ||
60 | }; | ||
61 | |||
62 | static int | ||
63 | minstrel_stats_open(struct inode *inode, struct file *file) | 57 | minstrel_stats_open(struct inode *inode, struct file *file) |
64 | { | 58 | { |
65 | struct minstrel_sta_info *mi = inode->i_private; | 59 | struct minstrel_sta_info *mi = inode->i_private; |
66 | struct minstrel_stats_info *ms; | 60 | struct minstrel_debugfs_info *ms; |
67 | unsigned int i, tp, prob, eprob; | 61 | unsigned int i, tp, prob, eprob; |
68 | char *p; | 62 | char *p; |
69 | 63 | ||
70 | ms = kmalloc(sizeof(*ms), GFP_KERNEL); | 64 | ms = kmalloc(sizeof(*ms) + 4096, GFP_KERNEL); |
71 | if (!ms) | 65 | if (!ms) |
72 | return -ENOMEM; | 66 | return -ENOMEM; |
73 | 67 | ||
@@ -107,36 +101,19 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
107 | return 0; | 101 | return 0; |
108 | } | 102 | } |
109 | 103 | ||
110 | static ssize_t | 104 | ssize_t |
111 | minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *o) | 105 | minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) |
112 | { | 106 | { |
113 | struct minstrel_stats_info *ms; | 107 | struct minstrel_debugfs_info *ms; |
114 | char *src; | ||
115 | 108 | ||
116 | ms = file->private_data; | 109 | ms = file->private_data; |
117 | src = ms->buf; | 110 | return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len); |
118 | |||
119 | len = min(len, ms->len); | ||
120 | if (len <= *o) | ||
121 | return 0; | ||
122 | |||
123 | src += *o; | ||
124 | len -= *o; | ||
125 | *o += len; | ||
126 | |||
127 | if (copy_to_user(buf, src, len)) | ||
128 | return -EFAULT; | ||
129 | |||
130 | return len; | ||
131 | } | 111 | } |
132 | 112 | ||
133 | static int | 113 | int |
134 | minstrel_stats_release(struct inode *inode, struct file *file) | 114 | minstrel_stats_release(struct inode *inode, struct file *file) |
135 | { | 115 | { |
136 | struct minstrel_stats_info *ms = file->private_data; | 116 | kfree(file->private_data); |
137 | |||
138 | kfree(ms); | ||
139 | |||
140 | return 0; | 117 | return 0; |
141 | } | 118 | } |
142 | 119 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 04ea07f0e78a..e0c944fb6fc9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -179,14 +179,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
179 | pos++; | 179 | pos++; |
180 | } | 180 | } |
181 | 181 | ||
182 | /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ | ||
183 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { | ||
184 | *pos = status->noise; | ||
185 | rthdr->it_present |= | ||
186 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE); | ||
187 | pos++; | ||
188 | } | ||
189 | |||
190 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ | 182 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ |
191 | 183 | ||
192 | /* IEEE80211_RADIOTAP_ANTENNA */ | 184 | /* IEEE80211_RADIOTAP_ANTENNA */ |
@@ -1078,7 +1070,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1078 | sta->rx_fragments++; | 1070 | sta->rx_fragments++; |
1079 | sta->rx_bytes += rx->skb->len; | 1071 | sta->rx_bytes += rx->skb->len; |
1080 | sta->last_signal = status->signal; | 1072 | sta->last_signal = status->signal; |
1081 | sta->last_noise = status->noise; | ||
1082 | 1073 | ||
1083 | /* | 1074 | /* |
1084 | * Change STA power saving mode only at the end of a frame | 1075 | * Change STA power saving mode only at the end of a frame |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 85507bd9e341..1ce4ce8af80f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -14,6 +14,8 @@ | |||
14 | 14 | ||
15 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
17 | #include <linux/pm_qos_params.h> | ||
18 | #include <net/sch_generic.h> | ||
17 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
18 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
19 | 21 | ||
@@ -322,6 +324,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
322 | 324 | ||
323 | ieee80211_offchannel_stop_beaconing(local); | 325 | ieee80211_offchannel_stop_beaconing(local); |
324 | 326 | ||
327 | local->leave_oper_channel_time = 0; | ||
325 | local->next_scan_state = SCAN_DECISION; | 328 | local->next_scan_state = SCAN_DECISION; |
326 | local->scan_channel_idx = 0; | 329 | local->scan_channel_idx = 0; |
327 | 330 | ||
@@ -426,11 +429,28 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
426 | return rc; | 429 | return rc; |
427 | } | 430 | } |
428 | 431 | ||
432 | static unsigned long | ||
433 | ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) | ||
434 | { | ||
435 | /* | ||
436 | * TODO: channel switching also consumes quite some time, | ||
437 | * add that delay as well to get a better estimation | ||
438 | */ | ||
439 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
440 | return IEEE80211_PASSIVE_CHANNEL_TIME; | ||
441 | return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; | ||
442 | } | ||
443 | |||
429 | static int ieee80211_scan_state_decision(struct ieee80211_local *local, | 444 | static int ieee80211_scan_state_decision(struct ieee80211_local *local, |
430 | unsigned long *next_delay) | 445 | unsigned long *next_delay) |
431 | { | 446 | { |
432 | bool associated = false; | 447 | bool associated = false; |
448 | bool tx_empty = true; | ||
449 | bool bad_latency; | ||
450 | bool listen_int_exceeded; | ||
451 | unsigned long min_beacon_int = 0; | ||
433 | struct ieee80211_sub_if_data *sdata; | 452 | struct ieee80211_sub_if_data *sdata; |
453 | struct ieee80211_channel *next_chan; | ||
434 | 454 | ||
435 | /* if no more bands/channels left, complete scan and advance to the idle state */ | 455 | /* if no more bands/channels left, complete scan and advance to the idle state */ |
436 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 456 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
@@ -438,7 +458,11 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
438 | return 1; | 458 | return 1; |
439 | } | 459 | } |
440 | 460 | ||
441 | /* check if at least one STA interface is associated */ | 461 | /* |
462 | * check if at least one STA interface is associated, | ||
463 | * check if at least one STA interface has pending tx frames | ||
464 | * and grab the lowest used beacon interval | ||
465 | */ | ||
442 | mutex_lock(&local->iflist_mtx); | 466 | mutex_lock(&local->iflist_mtx); |
443 | list_for_each_entry(sdata, &local->interfaces, list) { | 467 | list_for_each_entry(sdata, &local->interfaces, list) { |
444 | if (!ieee80211_sdata_running(sdata)) | 468 | if (!ieee80211_sdata_running(sdata)) |
@@ -447,7 +471,16 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
447 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 471 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
448 | if (sdata->u.mgd.associated) { | 472 | if (sdata->u.mgd.associated) { |
449 | associated = true; | 473 | associated = true; |
450 | break; | 474 | |
475 | if (sdata->vif.bss_conf.beacon_int < | ||
476 | min_beacon_int || min_beacon_int == 0) | ||
477 | min_beacon_int = | ||
478 | sdata->vif.bss_conf.beacon_int; | ||
479 | |||
480 | if (!qdisc_all_tx_empty(sdata->dev)) { | ||
481 | tx_empty = false; | ||
482 | break; | ||
483 | } | ||
451 | } | 484 | } |
452 | } | 485 | } |
453 | } | 486 | } |
@@ -456,11 +489,34 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
456 | if (local->scan_channel) { | 489 | if (local->scan_channel) { |
457 | /* | 490 | /* |
458 | * we're currently scanning a different channel, let's | 491 | * we're currently scanning a different channel, let's |
459 | * switch back to the operating channel now if at least | 492 | * see if we can scan another channel without interfering |
460 | * one interface is associated. Otherwise just scan the | 493 | * with the current traffic situation. |
461 | * next channel | 494 | * |
495 | * Since we don't know if the AP has pending frames for us | ||
496 | * we can only check for our tx queues and use the current | ||
497 | * pm_qos requirements for rx. Hence, if no tx traffic occurs | ||
498 | * at all we will scan as many channels in a row as the pm_qos | ||
499 | * latency allows us to. Additionally we also check for the | ||
500 | * currently negotiated listen interval to prevent losing | ||
501 | * frames unnecessarily. | ||
502 | * | ||
503 | * Otherwise switch back to the operating channel. | ||
462 | */ | 504 | */ |
463 | if (associated) | 505 | next_chan = local->scan_req->channels[local->scan_channel_idx]; |
506 | |||
507 | bad_latency = time_after(jiffies + | ||
508 | ieee80211_scan_get_channel_time(next_chan), | ||
509 | local->leave_oper_channel_time + | ||
510 | usecs_to_jiffies(pm_qos_requirement(PM_QOS_NETWORK_LATENCY))); | ||
511 | |||
512 | listen_int_exceeded = time_after(jiffies + | ||
513 | ieee80211_scan_get_channel_time(next_chan), | ||
514 | local->leave_oper_channel_time + | ||
515 | usecs_to_jiffies(min_beacon_int * 1024) * | ||
516 | local->hw.conf.listen_interval); | ||
517 | |||
518 | if (associated && ( !tx_empty || bad_latency || | ||
519 | listen_int_exceeded)) | ||
464 | local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; | 520 | local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; |
465 | else | 521 | else |
466 | local->next_scan_state = SCAN_SET_CHANNEL; | 522 | local->next_scan_state = SCAN_SET_CHANNEL; |
@@ -492,6 +548,9 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca | |||
492 | else | 548 | else |
493 | *next_delay = HZ / 10; | 549 | *next_delay = HZ / 10; |
494 | 550 | ||
551 | /* remember when we left the operating channel */ | ||
552 | local->leave_oper_channel_time = jiffies; | ||
553 | |||
495 | /* advance to the next channel to be scanned */ | 554 | /* advance to the next channel to be scanned */ |
496 | local->next_scan_state = SCAN_SET_CHANNEL; | 555 | local->next_scan_state = SCAN_SET_CHANNEL; |
497 | } | 556 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 822d84522937..2b635909de5c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -200,7 +200,6 @@ struct sta_ampdu_mlme { | |||
200 | * @rx_fragments: number of received MPDUs | 200 | * @rx_fragments: number of received MPDUs |
201 | * @rx_dropped: number of dropped MPDUs from this STA | 201 | * @rx_dropped: number of dropped MPDUs from this STA |
202 | * @last_signal: signal of last received frame from this STA | 202 | * @last_signal: signal of last received frame from this STA |
203 | * @last_noise: noise of last received frame from this STA | ||
204 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) | 203 | * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) |
205 | * @tx_filtered_count: number of frames the hardware filtered for this STA | 204 | * @tx_filtered_count: number of frames the hardware filtered for this STA |
206 | * @tx_retry_failed: number of frames that failed retry | 205 | * @tx_retry_failed: number of frames that failed retry |
@@ -267,7 +266,6 @@ struct sta_info { | |||
267 | unsigned long rx_fragments; | 266 | unsigned long rx_fragments; |
268 | unsigned long rx_dropped; | 267 | unsigned long rx_dropped; |
269 | int last_signal; | 268 | int last_signal; |
270 | int last_noise; | ||
271 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; | 269 | __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; |
272 | 270 | ||
273 | /* Updated from TX status path only, no locking requirements */ | 271 | /* Updated from TX status path only, no locking requirements */ |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 56d5b9a6ec5b..11805a3a626f 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -171,7 +171,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
171 | struct net_device *prev_dev = NULL; | 171 | struct net_device *prev_dev = NULL; |
172 | struct sta_info *sta, *tmp; | 172 | struct sta_info *sta, *tmp; |
173 | int retry_count = -1, i; | 173 | int retry_count = -1, i; |
174 | bool injected; | 174 | bool send_to_cooked; |
175 | 175 | ||
176 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 176 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
177 | /* the HW cannot have attempted that rate */ | 177 | /* the HW cannot have attempted that rate */ |
@@ -296,11 +296,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
296 | /* this was a transmitted frame, but now we want to reuse it */ | 296 | /* this was a transmitted frame, but now we want to reuse it */ |
297 | skb_orphan(skb); | 297 | skb_orphan(skb); |
298 | 298 | ||
299 | /* Need to make a copy before skb->cb gets cleared */ | ||
300 | send_to_cooked = !!(info->flags & IEEE80211_TX_CTL_INJECTED) || | ||
301 | (type != IEEE80211_FTYPE_DATA); | ||
302 | |||
299 | /* | 303 | /* |
300 | * This is a bit racy but we can avoid a lot of work | 304 | * This is a bit racy but we can avoid a lot of work |
301 | * with this test... | 305 | * with this test... |
302 | */ | 306 | */ |
303 | if (!local->monitors && !local->cooked_mntrs) { | 307 | if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) { |
304 | dev_kfree_skb(skb); | 308 | dev_kfree_skb(skb); |
305 | return; | 309 | return; |
306 | } | 310 | } |
@@ -345,9 +349,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
345 | /* for now report the total retry_count */ | 349 | /* for now report the total retry_count */ |
346 | rthdr->data_retries = retry_count; | 350 | rthdr->data_retries = retry_count; |
347 | 351 | ||
348 | /* Need to make a copy before skb->cb gets cleared */ | ||
349 | injected = !!(info->flags & IEEE80211_TX_CTL_INJECTED); | ||
350 | |||
351 | /* XXX: is this sufficient for BPF? */ | 352 | /* XXX: is this sufficient for BPF? */ |
352 | skb_set_mac_header(skb, 0); | 353 | skb_set_mac_header(skb, 0); |
353 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 354 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -362,8 +363,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
362 | continue; | 363 | continue; |
363 | 364 | ||
364 | if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && | 365 | if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && |
365 | !injected && | 366 | !send_to_cooked) |
366 | (type == IEEE80211_FTYPE_DATA)) | ||
367 | continue; | 367 | continue; |
368 | 368 | ||
369 | if (prev_dev) { | 369 | if (prev_dev) { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index cfc473e1b050..db25fa9ef135 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2011,14 +2011,12 @@ void ieee80211_tx_pending(unsigned long data) | |||
2011 | while (!skb_queue_empty(&local->pending[i])) { | 2011 | while (!skb_queue_empty(&local->pending[i])) { |
2012 | struct sk_buff *skb = __skb_dequeue(&local->pending[i]); | 2012 | struct sk_buff *skb = __skb_dequeue(&local->pending[i]); |
2013 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2013 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2014 | struct ieee80211_sub_if_data *sdata; | ||
2015 | 2014 | ||
2016 | if (WARN_ON(!info->control.vif)) { | 2015 | if (WARN_ON(!info->control.vif)) { |
2017 | kfree_skb(skb); | 2016 | kfree_skb(skb); |
2018 | continue; | 2017 | continue; |
2019 | } | 2018 | } |
2020 | 2019 | ||
2021 | sdata = vif_to_sdata(info->control.vif); | ||
2022 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | 2020 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, |
2023 | flags); | 2021 | flags); |
2024 | 2022 | ||