diff options
author | David S. Miller <davem@davemloft.net> | 2009-08-21 04:56:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-21 04:56:56 -0400 |
commit | f8f2109d4f6c525f893f6f2901ae62372e83245e (patch) | |
tree | e20b095973d45eb2360ffa157ad161536c2ddbe9 /net | |
parent | bb81b2ddfa194b6d12761a350b5b5985cecae0a9 (diff) | |
parent | a2c3f6567c9ac327f1ef1272551f3a7595ec885e (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/debugfs_netdev.c | 6 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 24 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 36 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 9 | ||||
-rw-r--r-- | net/mac80211/iface.c | 15 | ||||
-rw-r--r-- | net/mac80211/main.c | 32 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 21 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 16 | ||||
-rw-r--r-- | net/mac80211/rc80211_pid_algo.c | 16 | ||||
-rw-r--r-- | net/mac80211/rx.c | 8 | ||||
-rw-r--r-- | net/mac80211/scan.c | 16 | ||||
-rw-r--r-- | net/mac80211/util.c | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 98 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/mlme.c | 9 | ||||
-rw-r--r-- | net/wireless/sme.c | 29 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 1 |
18 files changed, 225 insertions, 117 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e9ec6cae2d39..61234e79022b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -116,6 +116,8 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | |||
116 | 116 | ||
117 | #ifdef CONFIG_MAC80211_MESH | 117 | #ifdef CONFIG_MAC80211_MESH |
118 | /* Mesh stats attributes */ | 118 | /* Mesh stats attributes */ |
119 | IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); | ||
120 | IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); | ||
119 | IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); | 121 | IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); |
120 | IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); | 122 | IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); |
121 | IEEE80211_IF_FILE(dropped_frames_no_route, | 123 | IEEE80211_IF_FILE(dropped_frames_no_route, |
@@ -205,6 +207,8 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) | |||
205 | { | 207 | { |
206 | sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", | 208 | sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", |
207 | sdata->debugfsdir); | 209 | sdata->debugfsdir); |
210 | MESHSTATS_ADD(fwded_mcast); | ||
211 | MESHSTATS_ADD(fwded_unicast); | ||
208 | MESHSTATS_ADD(fwded_frames); | 212 | MESHSTATS_ADD(fwded_frames); |
209 | MESHSTATS_ADD(dropped_frames_ttl); | 213 | MESHSTATS_ADD(dropped_frames_ttl); |
210 | MESHSTATS_ADD(dropped_frames_no_route); | 214 | MESHSTATS_ADD(dropped_frames_no_route); |
@@ -327,6 +331,8 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) | |||
327 | 331 | ||
328 | static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) | 332 | static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) |
329 | { | 333 | { |
334 | MESHSTATS_DEL(fwded_mcast); | ||
335 | MESHSTATS_DEL(fwded_unicast); | ||
330 | MESHSTATS_DEL(fwded_frames); | 336 | MESHSTATS_DEL(fwded_frames); |
331 | MESHSTATS_DEL(dropped_frames_ttl); | 337 | MESHSTATS_DEL(dropped_frames_ttl); |
332 | MESHSTATS_DEL(dropped_frames_no_route); | 338 | MESHSTATS_DEL(dropped_frames_no_route); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4100c361a99d..d231c9323ad1 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
55 | trace_drv_bss_info_changed(local, vif, info, changed); | 55 | trace_drv_bss_info_changed(local, vif, info, changed); |
56 | } | 56 | } |
57 | 57 | ||
58 | static inline u64 drv_prepare_multicast(struct ieee80211_local *local, | ||
59 | int mc_count, | ||
60 | struct dev_addr_list *mc_list) | ||
61 | { | ||
62 | u64 ret = 0; | ||
63 | |||
64 | if (local->ops->prepare_multicast) | ||
65 | ret = local->ops->prepare_multicast(&local->hw, mc_count, | ||
66 | mc_list); | ||
67 | |||
68 | trace_drv_prepare_multicast(local, mc_count, ret); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
58 | static inline void drv_configure_filter(struct ieee80211_local *local, | 73 | static inline void drv_configure_filter(struct ieee80211_local *local, |
59 | unsigned int changed_flags, | 74 | unsigned int changed_flags, |
60 | unsigned int *total_flags, | 75 | unsigned int *total_flags, |
61 | int mc_count, | 76 | u64 multicast) |
62 | struct dev_addr_list *mc_list) | ||
63 | { | 77 | { |
78 | might_sleep(); | ||
79 | |||
64 | local->ops->configure_filter(&local->hw, changed_flags, total_flags, | 80 | local->ops->configure_filter(&local->hw, changed_flags, total_flags, |
65 | mc_count, mc_list); | 81 | multicast); |
66 | trace_drv_configure_filter(local, changed_flags, total_flags, | 82 | trace_drv_configure_filter(local, changed_flags, total_flags, |
67 | mc_count); | 83 | multicast); |
68 | } | 84 | } |
69 | 85 | ||
70 | static inline int drv_set_tim(struct ieee80211_local *local, | 86 | static inline int drv_set_tim(struct ieee80211_local *local, |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 5a10da2d70fd..37b9051afcf3 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed, | |||
191 | ) | 191 | ) |
192 | ); | 192 | ); |
193 | 193 | ||
194 | TRACE_EVENT(drv_prepare_multicast, | ||
195 | TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret), | ||
196 | |||
197 | TP_ARGS(local, mc_count, ret), | ||
198 | |||
199 | TP_STRUCT__entry( | ||
200 | LOCAL_ENTRY | ||
201 | __field(int, mc_count) | ||
202 | __field(u64, ret) | ||
203 | ), | ||
204 | |||
205 | TP_fast_assign( | ||
206 | LOCAL_ASSIGN; | ||
207 | __entry->mc_count = mc_count; | ||
208 | __entry->ret = ret; | ||
209 | ), | ||
210 | |||
211 | TP_printk( | ||
212 | LOCAL_PR_FMT " prepare mc (%d): %llx", | ||
213 | LOCAL_PR_ARG, __entry->mc_count, | ||
214 | (unsigned long long) __entry->ret | ||
215 | ) | ||
216 | ); | ||
217 | |||
194 | TRACE_EVENT(drv_configure_filter, | 218 | TRACE_EVENT(drv_configure_filter, |
195 | TP_PROTO(struct ieee80211_local *local, | 219 | TP_PROTO(struct ieee80211_local *local, |
196 | unsigned int changed_flags, | 220 | unsigned int changed_flags, |
197 | unsigned int *total_flags, | 221 | unsigned int *total_flags, |
198 | int mc_count), | 222 | u64 multicast), |
199 | 223 | ||
200 | TP_ARGS(local, changed_flags, total_flags, mc_count), | 224 | TP_ARGS(local, changed_flags, total_flags, multicast), |
201 | 225 | ||
202 | TP_STRUCT__entry( | 226 | TP_STRUCT__entry( |
203 | LOCAL_ENTRY | 227 | LOCAL_ENTRY |
204 | __field(unsigned int, changed) | 228 | __field(unsigned int, changed) |
205 | __field(unsigned int, total) | 229 | __field(unsigned int, total) |
206 | __field(int, mc) | 230 | __field(u64, multicast) |
207 | ), | 231 | ), |
208 | 232 | ||
209 | TP_fast_assign( | 233 | TP_fast_assign( |
210 | LOCAL_ASSIGN; | 234 | LOCAL_ASSIGN; |
211 | __entry->changed = changed_flags; | 235 | __entry->changed = changed_flags; |
212 | __entry->total = *total_flags; | 236 | __entry->total = *total_flags; |
213 | __entry->mc = mc_count; | 237 | __entry->multicast = multicast; |
214 | ), | 238 | ), |
215 | 239 | ||
216 | TP_printk( | 240 | TP_printk( |
217 | LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", | 241 | LOCAL_PR_FMT " changed:%#x total:%#x", |
218 | LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc | 242 | LOCAL_PR_ARG, __entry->changed, __entry->total |
219 | ) | 243 | ) |
220 | ); | 244 | ); |
221 | 245 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a6abc7dfd903..93e618a980d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -212,7 +212,9 @@ struct ieee80211_if_vlan { | |||
212 | }; | 212 | }; |
213 | 213 | ||
214 | struct mesh_stats { | 214 | struct mesh_stats { |
215 | __u32 fwded_frames; /* Mesh forwarded frames */ | 215 | __u32 fwded_mcast; /* Mesh forwarded multicast frames */ |
216 | __u32 fwded_unicast; /* Mesh forwarded unicast frames */ | ||
217 | __u32 fwded_frames; /* Mesh total forwarded frames */ | ||
216 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ | 218 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ |
217 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ | 219 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ |
218 | atomic_t estab_plinks; | 220 | atomic_t estab_plinks; |
@@ -506,6 +508,8 @@ struct ieee80211_sub_if_data { | |||
506 | #ifdef CONFIG_MAC80211_MESH | 508 | #ifdef CONFIG_MAC80211_MESH |
507 | struct dentry *mesh_stats_dir; | 509 | struct dentry *mesh_stats_dir; |
508 | struct { | 510 | struct { |
511 | struct dentry *fwded_mcast; | ||
512 | struct dentry *fwded_unicast; | ||
509 | struct dentry *fwded_frames; | 513 | struct dentry *fwded_frames; |
510 | struct dentry *dropped_frames_ttl; | 514 | struct dentry *dropped_frames_ttl; |
511 | struct dentry *dropped_frames_no_route; | 515 | struct dentry *dropped_frames_no_route; |
@@ -636,6 +640,9 @@ struct ieee80211_local { | |||
636 | /* protects the aggregated multicast list and filter calls */ | 640 | /* protects the aggregated multicast list and filter calls */ |
637 | spinlock_t filter_lock; | 641 | spinlock_t filter_lock; |
638 | 642 | ||
643 | /* used for uploading changed mc list */ | ||
644 | struct work_struct reconfig_filter; | ||
645 | |||
639 | /* aggregated multicast list */ | 646 | /* aggregated multicast list */ |
640 | struct dev_addr_list *mc_list; | 647 | struct dev_addr_list *mc_list; |
641 | int mc_count; | 648 | int mc_count; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e8fb03b91a44..b161301056df 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev) | |||
227 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | 227 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) |
228 | local->fif_other_bss++; | 228 | local->fif_other_bss++; |
229 | 229 | ||
230 | spin_lock_bh(&local->filter_lock); | ||
231 | ieee80211_configure_filter(local); | 230 | ieee80211_configure_filter(local); |
232 | spin_unlock_bh(&local->filter_lock); | ||
233 | break; | 231 | break; |
234 | default: | 232 | default: |
235 | conf.vif = &sdata->vif; | 233 | conf.vif = &sdata->vif; |
@@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev) | |||
241 | 239 | ||
242 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 240 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
243 | local->fif_other_bss++; | 241 | local->fif_other_bss++; |
244 | spin_lock_bh(&local->filter_lock); | ||
245 | ieee80211_configure_filter(local); | 242 | ieee80211_configure_filter(local); |
246 | spin_unlock_bh(&local->filter_lock); | ||
247 | 243 | ||
248 | ieee80211_start_mesh(sdata); | 244 | ieee80211_start_mesh(sdata); |
249 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { | 245 | } else if (sdata->vif.type == NL80211_IFTYPE_AP) { |
250 | local->fif_pspoll++; | 246 | local->fif_pspoll++; |
251 | 247 | ||
252 | spin_lock_bh(&local->filter_lock); | ||
253 | ieee80211_configure_filter(local); | 248 | ieee80211_configure_filter(local); |
254 | spin_unlock_bh(&local->filter_lock); | ||
255 | } | 249 | } |
256 | 250 | ||
257 | changed |= ieee80211_reset_erp_info(sdata); | 251 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev) | |||
404 | spin_lock_bh(&local->filter_lock); | 398 | spin_lock_bh(&local->filter_lock); |
405 | __dev_addr_unsync(&local->mc_list, &local->mc_count, | 399 | __dev_addr_unsync(&local->mc_list, &local->mc_count, |
406 | &dev->mc_list, &dev->mc_count); | 400 | &dev->mc_list, &dev->mc_count); |
407 | ieee80211_configure_filter(local); | ||
408 | spin_unlock_bh(&local->filter_lock); | 401 | spin_unlock_bh(&local->filter_lock); |
409 | netif_addr_unlock_bh(dev); | 402 | netif_addr_unlock_bh(dev); |
410 | 403 | ||
404 | ieee80211_configure_filter(local); | ||
405 | |||
411 | del_timer_sync(&local->dynamic_ps_timer); | 406 | del_timer_sync(&local->dynamic_ps_timer); |
412 | cancel_work_sync(&local->dynamic_ps_enable_work); | 407 | cancel_work_sync(&local->dynamic_ps_enable_work); |
413 | 408 | ||
@@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
458 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) | 453 | if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) |
459 | local->fif_other_bss--; | 454 | local->fif_other_bss--; |
460 | 455 | ||
461 | spin_lock_bh(&local->filter_lock); | ||
462 | ieee80211_configure_filter(local); | 456 | ieee80211_configure_filter(local); |
463 | spin_unlock_bh(&local->filter_lock); | ||
464 | break; | 457 | break; |
465 | case NL80211_IFTYPE_STATION: | 458 | case NL80211_IFTYPE_STATION: |
466 | del_timer_sync(&sdata->u.mgd.chswitch_timer); | 459 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
@@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
503 | local->fif_other_bss--; | 496 | local->fif_other_bss--; |
504 | atomic_dec(&local->iff_allmultis); | 497 | atomic_dec(&local->iff_allmultis); |
505 | 498 | ||
506 | spin_lock_bh(&local->filter_lock); | ||
507 | ieee80211_configure_filter(local); | 499 | ieee80211_configure_filter(local); |
508 | spin_unlock_bh(&local->filter_lock); | ||
509 | 500 | ||
510 | ieee80211_stop_mesh(sdata); | 501 | ieee80211_stop_mesh(sdata); |
511 | } | 502 | } |
@@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
622 | spin_lock_bh(&local->filter_lock); | 613 | spin_lock_bh(&local->filter_lock); |
623 | __dev_addr_sync(&local->mc_list, &local->mc_count, | 614 | __dev_addr_sync(&local->mc_list, &local->mc_count, |
624 | &dev->mc_list, &dev->mc_count); | 615 | &dev->mc_list, &dev->mc_count); |
625 | ieee80211_configure_filter(local); | ||
626 | spin_unlock_bh(&local->filter_lock); | 616 | spin_unlock_bh(&local->filter_lock); |
617 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | ||
627 | } | 618 | } |
628 | 619 | ||
629 | /* | 620 | /* |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b03fd84777fa..dd3b0816614d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr { | |||
50 | } __attribute__ ((packed)); | 50 | } __attribute__ ((packed)); |
51 | 51 | ||
52 | 52 | ||
53 | /* must be called under mdev tx lock */ | ||
54 | void ieee80211_configure_filter(struct ieee80211_local *local) | 53 | void ieee80211_configure_filter(struct ieee80211_local *local) |
55 | { | 54 | { |
55 | u64 mc; | ||
56 | unsigned int changed_flags; | 56 | unsigned int changed_flags; |
57 | unsigned int new_flags = 0; | 57 | unsigned int new_flags = 0; |
58 | 58 | ||
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
62 | if (atomic_read(&local->iff_allmultis)) | 62 | if (atomic_read(&local->iff_allmultis)) |
63 | new_flags |= FIF_ALLMULTI; | 63 | new_flags |= FIF_ALLMULTI; |
64 | 64 | ||
65 | if (local->monitors) | 65 | if (local->monitors || local->scanning) |
66 | new_flags |= FIF_BCN_PRBRESP_PROMISC; | 66 | new_flags |= FIF_BCN_PRBRESP_PROMISC; |
67 | 67 | ||
68 | if (local->fif_fcsfail) | 68 | if (local->fif_fcsfail) |
@@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
80 | if (local->fif_pspoll) | 80 | if (local->fif_pspoll) |
81 | new_flags |= FIF_PSPOLL; | 81 | new_flags |= FIF_PSPOLL; |
82 | 82 | ||
83 | spin_lock_bh(&local->filter_lock); | ||
83 | changed_flags = local->filter_flags ^ new_flags; | 84 | changed_flags = local->filter_flags ^ new_flags; |
84 | 85 | ||
86 | mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); | ||
87 | spin_unlock_bh(&local->filter_lock); | ||
88 | |||
85 | /* be a bit nasty */ | 89 | /* be a bit nasty */ |
86 | new_flags |= (1<<31); | 90 | new_flags |= (1<<31); |
87 | 91 | ||
88 | drv_configure_filter(local, changed_flags, &new_flags, | 92 | drv_configure_filter(local, changed_flags, &new_flags, mc); |
89 | local->mc_count, | ||
90 | local->mc_list); | ||
91 | 93 | ||
92 | WARN_ON(new_flags & (1<<31)); | 94 | WARN_ON(new_flags & (1<<31)); |
93 | 95 | ||
94 | local->filter_flags = new_flags & ~(1<<31); | 96 | local->filter_flags = new_flags & ~(1<<31); |
95 | } | 97 | } |
96 | 98 | ||
99 | static void ieee80211_reconfig_filter(struct work_struct *work) | ||
100 | { | ||
101 | struct ieee80211_local *local = | ||
102 | container_of(work, struct ieee80211_local, reconfig_filter); | ||
103 | |||
104 | ieee80211_configure_filter(local); | ||
105 | } | ||
106 | |||
97 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 107 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) |
98 | { | 108 | { |
99 | struct ieee80211_channel *chan, *scan_chan; | 109 | struct ieee80211_channel *chan, *scan_chan; |
@@ -231,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
231 | 241 | ||
232 | drv_bss_info_changed(local, &sdata->vif, | 242 | drv_bss_info_changed(local, &sdata->vif, |
233 | &sdata->vif.bss_conf, changed); | 243 | &sdata->vif.bss_conf, changed); |
234 | |||
235 | /* DEPRECATED */ | ||
236 | local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; | ||
237 | } | 244 | } |
238 | 245 | ||
239 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 246 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
@@ -475,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
475 | } | 482 | } |
476 | 483 | ||
477 | rate_control_tx_status(local, sband, sta, skb); | 484 | rate_control_tx_status(local, sband, sta, skb); |
485 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
486 | ieee80211s_update_metric(local, sta, skb); | ||
478 | } | 487 | } |
479 | 488 | ||
480 | rcu_read_unlock(); | 489 | rcu_read_unlock(); |
@@ -677,7 +686,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
677 | local->hw.max_rates = 1; | 686 | local->hw.max_rates = 1; |
678 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 687 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
679 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 688 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
680 | local->hw.conf.radio_enabled = true; | ||
681 | local->user_power_level = -1; | 689 | local->user_power_level = -1; |
682 | 690 | ||
683 | INIT_LIST_HEAD(&local->interfaces); | 691 | INIT_LIST_HEAD(&local->interfaces); |
@@ -692,6 +700,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
692 | 700 | ||
693 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 701 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
694 | 702 | ||
703 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | ||
704 | |||
695 | INIT_WORK(&local->dynamic_ps_enable_work, | 705 | INIT_WORK(&local->dynamic_ps_enable_work, |
696 | ieee80211_dynamic_ps_enable_work); | 706 | ieee80211_dynamic_ps_enable_work); |
697 | INIT_WORK(&local->dynamic_ps_disable_work, | 707 | INIT_WORK(&local->dynamic_ps_disable_work, |
@@ -920,7 +930,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
920 | fail_workqueue: | 930 | fail_workqueue: |
921 | wiphy_unregister(local->hw.wiphy); | 931 | wiphy_unregister(local->hw.wiphy); |
922 | fail_wiphy_register: | 932 | fail_wiphy_register: |
923 | kfree(local->int_scan_req->channels); | 933 | kfree(local->int_scan_req); |
924 | return result; | 934 | return result; |
925 | } | 935 | } |
926 | EXPORT_SYMBOL(ieee80211_register_hw); | 936 | EXPORT_SYMBOL(ieee80211_register_hw); |
@@ -946,6 +956,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
946 | 956 | ||
947 | rtnl_unlock(); | 957 | rtnl_unlock(); |
948 | 958 | ||
959 | cancel_work_sync(&local->reconfig_filter); | ||
960 | |||
949 | ieee80211_clear_tx_pending(local); | 961 | ieee80211_clear_tx_pending(local); |
950 | sta_info_stop(local); | 962 | sta_info_stop(local); |
951 | rate_control_deinitialize(local); | 963 | rate_control_deinitialize(local); |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index eb23fc639b2b..dd1c19319f0a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -226,6 +226,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, | |||
226 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 226 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
227 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); | 227 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); |
228 | void ieee80211s_init(void); | 228 | void ieee80211s_init(void); |
229 | void ieee80211s_update_metric(struct ieee80211_local *local, | ||
230 | struct sta_info *stainfo, struct sk_buff *skb); | ||
229 | void ieee80211s_stop(void); | 231 | void ieee80211s_stop(void); |
230 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | 232 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); |
231 | ieee80211_rx_result | 233 | ieee80211_rx_result |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ef1efd362691..e12a786e26b8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -201,6 +201,24 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | |||
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | void ieee80211s_update_metric(struct ieee80211_local *local, | ||
205 | struct sta_info *stainfo, struct sk_buff *skb) | ||
206 | { | ||
207 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); | ||
208 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
209 | int failed; | ||
210 | |||
211 | if (!ieee80211_is_data(hdr->frame_control)) | ||
212 | return; | ||
213 | |||
214 | failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); | ||
215 | |||
216 | /* moving average, scaled to 100 */ | ||
217 | stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); | ||
218 | if (stainfo->fail_avg > 95) | ||
219 | mesh_plink_broken(stainfo); | ||
220 | } | ||
221 | |||
204 | static u32 airtime_link_metric_get(struct ieee80211_local *local, | 222 | static u32 airtime_link_metric_get(struct ieee80211_local *local, |
205 | struct sta_info *sta) | 223 | struct sta_info *sta) |
206 | { | 224 | { |
@@ -479,6 +497,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
479 | hopcount, ttl, cpu_to_le32(lifetime), | 497 | hopcount, ttl, cpu_to_le32(lifetime), |
480 | cpu_to_le32(metric), cpu_to_le32(preq_id), | 498 | cpu_to_le32(metric), cpu_to_le32(preq_id), |
481 | sdata); | 499 | sdata); |
500 | ifmsh->mshstats.fwded_mcast++; | ||
482 | ifmsh->mshstats.fwded_frames++; | 501 | ifmsh->mshstats.fwded_frames++; |
483 | } | 502 | } |
484 | } | 503 | } |
@@ -537,6 +556,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
537 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 556 | cpu_to_le32(lifetime), cpu_to_le32(metric), |
538 | 0, sdata); | 557 | 0, sdata); |
539 | rcu_read_unlock(); | 558 | rcu_read_unlock(); |
559 | |||
560 | sdata->u.mesh.mshstats.fwded_unicast++; | ||
540 | sdata->u.mesh.mshstats.fwded_frames++; | 561 | sdata->u.mesh.mshstats.fwded_frames++; |
541 | return; | 562 | return; |
542 | 563 | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 007164919e02..7c5142988bbb 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -51,7 +51,6 @@ | |||
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" | ||
55 | #include "rate.h" | 54 | #include "rate.h" |
56 | #include "rc80211_minstrel.h" | 55 | #include "rc80211_minstrel.h" |
57 | 56 | ||
@@ -156,16 +155,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
156 | struct sk_buff *skb) | 155 | struct sk_buff *skb) |
157 | { | 156 | { |
158 | struct minstrel_sta_info *mi = priv_sta; | 157 | struct minstrel_sta_info *mi = priv_sta; |
159 | struct minstrel_priv *mp = (struct minstrel_priv *)priv; | ||
160 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 158 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
161 | struct ieee80211_tx_rate *ar = info->status.rates; | 159 | struct ieee80211_tx_rate *ar = info->status.rates; |
162 | struct ieee80211_local *local = hw_to_local(mp->hw); | ||
163 | struct sta_info *si; | ||
164 | int i, ndx; | 160 | int i, ndx; |
165 | int success; | 161 | int success; |
166 | 162 | ||
167 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | 163 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); |
168 | si = sta_info_get(local, sta->addr); | ||
169 | 164 | ||
170 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 165 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
171 | if (ar[i].idx < 0) | 166 | if (ar[i].idx < 0) |
@@ -177,17 +172,8 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
177 | 172 | ||
178 | mi->r[ndx].attempts += ar[i].count; | 173 | mi->r[ndx].attempts += ar[i].count; |
179 | 174 | ||
180 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { | 175 | if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) |
181 | mi->r[ndx].success += success; | 176 | 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 | } | ||
191 | } | 177 | } |
192 | 178 | ||
193 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) | 179 | if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 8c053be9dc24..699d3ed869c4 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -169,19 +169,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
169 | * still a good measurement and copy it. */ | 169 | * still a good measurement and copy it. */ |
170 | if (unlikely(spinfo->tx_num_xmit == 0)) | 170 | if (unlikely(spinfo->tx_num_xmit == 0)) |
171 | pf = spinfo->last_pf; | 171 | pf = spinfo->last_pf; |
172 | else { | 172 | else |
173 | /* XXX: BAD HACK!!! */ | ||
174 | struct sta_info *si = container_of(sta, struct sta_info, sta); | ||
175 | |||
176 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; | 173 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; |
177 | 174 | ||
178 | if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100) | ||
179 | mesh_plink_broken(si); | ||
180 | pf <<= RC_PID_ARITH_SHIFT; | ||
181 | si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) | ||
182 | >> RC_PID_ARITH_SHIFT; | ||
183 | } | ||
184 | |||
185 | spinfo->tx_num_xmit = 0; | 175 | spinfo->tx_num_xmit = 0; |
186 | spinfo->tx_num_failed = 0; | 176 | spinfo->tx_num_failed = 0; |
187 | 177 | ||
@@ -311,7 +301,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
311 | struct rc_pid_sta_info *spinfo = priv_sta; | 301 | struct rc_pid_sta_info *spinfo = priv_sta; |
312 | struct rc_pid_info *pinfo = priv; | 302 | struct rc_pid_info *pinfo = priv; |
313 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | 303 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; |
314 | struct sta_info *si; | ||
315 | int i, j, tmp; | 304 | int i, j, tmp; |
316 | bool s; | 305 | bool s; |
317 | 306 | ||
@@ -348,9 +337,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
348 | } | 337 | } |
349 | 338 | ||
350 | spinfo->txrate_idx = rate_lowest_index(sband, sta); | 339 | spinfo->txrate_idx = rate_lowest_index(sband, sta); |
351 | /* HACK */ | ||
352 | si = container_of(sta, struct sta_info, sta); | ||
353 | si->fail_avg = 0; | ||
354 | } | 340 | } |
355 | 341 | ||
356 | static void *rate_control_pid_alloc(struct ieee80211_hw *hw, | 342 | static void *rate_control_pid_alloc(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4cd9e45b1443..7065fd7e7ba2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1550,7 +1550,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1550 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1550 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1551 | info->control.vif = &rx->sdata->vif; | 1551 | info->control.vif = &rx->sdata->vif; |
1552 | ieee80211_select_queue(local, fwd_skb); | 1552 | ieee80211_select_queue(local, fwd_skb); |
1553 | if (!is_multicast_ether_addr(fwd_hdr->addr1)) { | 1553 | if (is_multicast_ether_addr(fwd_hdr->addr1)) |
1554 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, | ||
1555 | fwded_mcast); | ||
1556 | else { | ||
1554 | int err; | 1557 | int err; |
1555 | /* | 1558 | /* |
1556 | * Save TA to addr1 to send TA a path error if a | 1559 | * Save TA to addr1 to send TA a path error if a |
@@ -1564,6 +1567,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1564 | * later to the pending skb queue. */ | 1567 | * later to the pending skb queue. */ |
1565 | if (err) | 1568 | if (err) |
1566 | return RX_DROP_MONITOR; | 1569 | return RX_DROP_MONITOR; |
1570 | |||
1571 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, | ||
1572 | fwded_unicast); | ||
1567 | } | 1573 | } |
1568 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, | 1574 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, |
1569 | fwded_frames); | 1575 | fwded_frames); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e091cbc3434f..1e04be6b9129 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
292 | if (was_hw_scan) | 292 | if (was_hw_scan) |
293 | goto done; | 293 | goto done; |
294 | 294 | ||
295 | spin_lock_bh(&local->filter_lock); | 295 | ieee80211_configure_filter(local); |
296 | local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; | ||
297 | drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, | ||
298 | &local->filter_flags, | ||
299 | local->mc_count, | ||
300 | local->mc_list); | ||
301 | spin_unlock_bh(&local->filter_lock); | ||
302 | 296 | ||
303 | drv_sw_scan_complete(local); | 297 | drv_sw_scan_complete(local); |
304 | 298 | ||
@@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
376 | local->next_scan_state = SCAN_DECISION; | 370 | local->next_scan_state = SCAN_DECISION; |
377 | local->scan_channel_idx = 0; | 371 | local->scan_channel_idx = 0; |
378 | 372 | ||
379 | spin_lock_bh(&local->filter_lock); | 373 | ieee80211_configure_filter(local); |
380 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | ||
381 | drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, | ||
382 | &local->filter_flags, | ||
383 | local->mc_count, | ||
384 | local->mc_list); | ||
385 | spin_unlock_bh(&local->filter_lock); | ||
386 | 374 | ||
387 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | 375 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ |
388 | ieee80211_queue_delayed_work(&local->hw, | 376 | ieee80211_queue_delayed_work(&local->hw, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e55d57f559ec..5eb306377c63 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1076 | /* reconfigure hardware */ | 1076 | /* reconfigure hardware */ |
1077 | ieee80211_hw_config(local, ~0); | 1077 | ieee80211_hw_config(local, ~0); |
1078 | 1078 | ||
1079 | spin_lock_bh(&local->filter_lock); | ||
1080 | ieee80211_configure_filter(local); | 1079 | ieee80211_configure_filter(local); |
1081 | spin_unlock_bh(&local->filter_lock); | ||
1082 | 1080 | ||
1083 | /* Finally also reconfigure all the BSS information */ | 1081 | /* Finally also reconfigure all the BSS information */ |
1084 | list_for_each_entry(sdata, &local->interfaces, list) { | 1082 | list_for_each_entry(sdata, &local->interfaces, list) { |
diff --git a/net/wireless/core.c b/net/wireless/core.c index bc99e4ec7463..154e1e294cb9 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/notifier.h> | 13 | #include <linux/notifier.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/etherdevice.h> | ||
15 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
16 | #include <net/genetlink.h> | 17 | #include <net/genetlink.h> |
17 | #include <net/cfg80211.h> | 18 | #include <net/cfg80211.h> |
@@ -309,7 +310,8 @@ static void cfg80211_process_events(struct wireless_dev *wdev) | |||
309 | switch (ev->type) { | 310 | switch (ev->type) { |
310 | case EVENT_CONNECT_RESULT: | 311 | case EVENT_CONNECT_RESULT: |
311 | __cfg80211_connect_result( | 312 | __cfg80211_connect_result( |
312 | wdev->netdev, ev->cr.bssid, | 313 | wdev->netdev, is_zero_ether_addr(ev->cr.bssid) ? |
314 | NULL : ev->cr.bssid, | ||
313 | ev->cr.req_ie, ev->cr.req_ie_len, | 315 | ev->cr.req_ie, ev->cr.req_ie_len, |
314 | ev->cr.resp_ie, ev->cr.resp_ie_len, | 316 | ev->cr.resp_ie, ev->cr.resp_ie_len, |
315 | ev->cr.status, | 317 | ev->cr.status, |
@@ -430,6 +432,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
430 | INIT_WORK(&rdev->conn_work, cfg80211_conn_work); | 432 | INIT_WORK(&rdev->conn_work, cfg80211_conn_work); |
431 | INIT_WORK(&rdev->event_work, cfg80211_event_work); | 433 | INIT_WORK(&rdev->event_work, cfg80211_event_work); |
432 | 434 | ||
435 | init_waitqueue_head(&rdev->dev_wait); | ||
436 | |||
433 | /* | 437 | /* |
434 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. | 438 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. |
435 | * Fragmentation and RTS threshold are disabled by default with the | 439 | * Fragmentation and RTS threshold are disabled by default with the |
@@ -574,7 +578,23 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
574 | /* protect the device list */ | 578 | /* protect the device list */ |
575 | mutex_lock(&cfg80211_mutex); | 579 | mutex_lock(&cfg80211_mutex); |
576 | 580 | ||
581 | wait_event(rdev->dev_wait, ({ | ||
582 | int __count; | ||
583 | mutex_lock(&rdev->devlist_mtx); | ||
584 | __count = rdev->opencount; | ||
585 | mutex_unlock(&rdev->devlist_mtx); | ||
586 | __count == 0;})); | ||
587 | |||
588 | mutex_lock(&rdev->devlist_mtx); | ||
577 | BUG_ON(!list_empty(&rdev->netdev_list)); | 589 | BUG_ON(!list_empty(&rdev->netdev_list)); |
590 | mutex_unlock(&rdev->devlist_mtx); | ||
591 | |||
592 | /* | ||
593 | * First remove the hardware from everywhere, this makes | ||
594 | * it impossible to find from userspace. | ||
595 | */ | ||
596 | cfg80211_debugfs_rdev_del(rdev); | ||
597 | list_del(&rdev->list); | ||
578 | 598 | ||
579 | /* | 599 | /* |
580 | * Try to grab rdev->mtx. If a command is still in progress, | 600 | * Try to grab rdev->mtx. If a command is still in progress, |
@@ -582,21 +602,18 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
582 | * down the device already. We wait for this command to complete | 602 | * down the device already. We wait for this command to complete |
583 | * before unlinking the item from the list. | 603 | * before unlinking the item from the list. |
584 | * Note: as codified by the BUG_ON above we cannot get here if | 604 | * Note: as codified by the BUG_ON above we cannot get here if |
585 | * a virtual interface is still associated. Hence, we can only | 605 | * a virtual interface is still present. Hence, we can only get |
586 | * get to lock contention here if userspace issues a command | 606 | * to lock contention here if userspace issues a command that |
587 | * that identified the hardware by wiphy index. | 607 | * identified the hardware by wiphy index. |
588 | */ | 608 | */ |
589 | mutex_lock(&rdev->mtx); | 609 | cfg80211_lock_rdev(rdev); |
590 | /* unlock again before freeing */ | 610 | /* nothing */ |
591 | mutex_unlock(&rdev->mtx); | 611 | cfg80211_unlock_rdev(rdev); |
592 | |||
593 | cfg80211_debugfs_rdev_del(rdev); | ||
594 | 612 | ||
595 | /* If this device got a regulatory hint tell core its | 613 | /* If this device got a regulatory hint tell core its |
596 | * free to listen now to a new shiny device regulatory hint */ | 614 | * free to listen now to a new shiny device regulatory hint */ |
597 | reg_device_remove(wiphy); | 615 | reg_device_remove(wiphy); |
598 | 616 | ||
599 | list_del(&rdev->list); | ||
600 | cfg80211_rdev_list_generation++; | 617 | cfg80211_rdev_list_generation++; |
601 | device_del(&rdev->wiphy.dev); | 618 | device_del(&rdev->wiphy.dev); |
602 | debugfs_remove(rdev->wiphy.debugfsdir); | 619 | debugfs_remove(rdev->wiphy.debugfsdir); |
@@ -605,7 +622,6 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
605 | 622 | ||
606 | flush_work(&rdev->scan_done_wk); | 623 | flush_work(&rdev->scan_done_wk); |
607 | cancel_work_sync(&rdev->conn_work); | 624 | cancel_work_sync(&rdev->conn_work); |
608 | kfree(rdev->scan_req); | ||
609 | flush_work(&rdev->event_work); | 625 | flush_work(&rdev->event_work); |
610 | } | 626 | } |
611 | EXPORT_SYMBOL(wiphy_unregister); | 627 | EXPORT_SYMBOL(wiphy_unregister); |
@@ -636,6 +652,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) | |||
636 | } | 652 | } |
637 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); | 653 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
638 | 654 | ||
655 | static void wdev_cleanup_work(struct work_struct *work) | ||
656 | { | ||
657 | struct wireless_dev *wdev; | ||
658 | struct cfg80211_registered_device *rdev; | ||
659 | |||
660 | wdev = container_of(work, struct wireless_dev, cleanup_work); | ||
661 | rdev = wiphy_to_dev(wdev->wiphy); | ||
662 | |||
663 | cfg80211_lock_rdev(rdev); | ||
664 | |||
665 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { | ||
666 | rdev->scan_req->aborted = true; | ||
667 | ___cfg80211_scan_done(rdev); | ||
668 | } | ||
669 | |||
670 | cfg80211_unlock_rdev(rdev); | ||
671 | |||
672 | mutex_lock(&rdev->devlist_mtx); | ||
673 | rdev->opencount--; | ||
674 | mutex_unlock(&rdev->devlist_mtx); | ||
675 | wake_up(&rdev->dev_wait); | ||
676 | |||
677 | dev_put(wdev->netdev); | ||
678 | } | ||
679 | |||
639 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | 680 | static int cfg80211_netdev_notifier_call(struct notifier_block * nb, |
640 | unsigned long state, | 681 | unsigned long state, |
641 | void *ndev) | 682 | void *ndev) |
@@ -653,7 +694,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
653 | 694 | ||
654 | switch (state) { | 695 | switch (state) { |
655 | case NETDEV_REGISTER: | 696 | case NETDEV_REGISTER: |
697 | /* | ||
698 | * NB: cannot take rdev->mtx here because this may be | ||
699 | * called within code protected by it when interfaces | ||
700 | * are added with nl80211. | ||
701 | */ | ||
656 | mutex_init(&wdev->mtx); | 702 | mutex_init(&wdev->mtx); |
703 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | ||
657 | INIT_LIST_HEAD(&wdev->event_list); | 704 | INIT_LIST_HEAD(&wdev->event_list); |
658 | spin_lock_init(&wdev->event_lock); | 705 | spin_lock_init(&wdev->event_lock); |
659 | mutex_lock(&rdev->devlist_mtx); | 706 | mutex_lock(&rdev->devlist_mtx); |
@@ -708,8 +755,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
708 | default: | 755 | default: |
709 | break; | 756 | break; |
710 | } | 757 | } |
758 | dev_hold(dev); | ||
759 | schedule_work(&wdev->cleanup_work); | ||
711 | break; | 760 | break; |
712 | case NETDEV_UP: | 761 | case NETDEV_UP: |
762 | /* | ||
763 | * If we have a really quick DOWN/UP succession we may | ||
764 | * have this work still pending ... cancel it and see | ||
765 | * if it was pending, in which case we need to account | ||
766 | * for some of the work it would have done. | ||
767 | */ | ||
768 | if (cancel_work_sync(&wdev->cleanup_work)) { | ||
769 | mutex_lock(&rdev->devlist_mtx); | ||
770 | rdev->opencount--; | ||
771 | mutex_unlock(&rdev->devlist_mtx); | ||
772 | dev_put(dev); | ||
773 | } | ||
713 | #ifdef CONFIG_WIRELESS_EXT | 774 | #ifdef CONFIG_WIRELESS_EXT |
714 | cfg80211_lock_rdev(rdev); | 775 | cfg80211_lock_rdev(rdev); |
715 | mutex_lock(&rdev->devlist_mtx); | 776 | mutex_lock(&rdev->devlist_mtx); |
@@ -725,18 +786,17 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
725 | break; | 786 | break; |
726 | } | 787 | } |
727 | wdev_unlock(wdev); | 788 | wdev_unlock(wdev); |
789 | rdev->opencount++; | ||
728 | mutex_unlock(&rdev->devlist_mtx); | 790 | mutex_unlock(&rdev->devlist_mtx); |
729 | cfg80211_unlock_rdev(rdev); | 791 | cfg80211_unlock_rdev(rdev); |
730 | #endif | 792 | #endif |
731 | break; | 793 | break; |
732 | case NETDEV_UNREGISTER: | 794 | case NETDEV_UNREGISTER: |
733 | cfg80211_lock_rdev(rdev); | 795 | /* |
734 | 796 | * NB: cannot take rdev->mtx here because this may be | |
735 | if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { | 797 | * called within code protected by it when interfaces |
736 | rdev->scan_req->aborted = true; | 798 | * are removed with nl80211. |
737 | ___cfg80211_scan_done(rdev); | 799 | */ |
738 | } | ||
739 | |||
740 | mutex_lock(&rdev->devlist_mtx); | 800 | mutex_lock(&rdev->devlist_mtx); |
741 | /* | 801 | /* |
742 | * It is possible to get NETDEV_UNREGISTER | 802 | * It is possible to get NETDEV_UNREGISTER |
@@ -749,13 +809,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
749 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 809 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
750 | list_del_init(&wdev->list); | 810 | list_del_init(&wdev->list); |
751 | rdev->devlist_generation++; | 811 | rdev->devlist_generation++; |
752 | mutex_destroy(&wdev->mtx); | ||
753 | #ifdef CONFIG_WIRELESS_EXT | 812 | #ifdef CONFIG_WIRELESS_EXT |
754 | kfree(wdev->wext.keys); | 813 | kfree(wdev->wext.keys); |
755 | #endif | 814 | #endif |
756 | } | 815 | } |
757 | mutex_unlock(&rdev->devlist_mtx); | 816 | mutex_unlock(&rdev->devlist_mtx); |
758 | cfg80211_unlock_rdev(rdev); | ||
759 | break; | 817 | break; |
760 | case NETDEV_PRE_UP: | 818 | case NETDEV_PRE_UP: |
761 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 819 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index c603f5286326..f565432ae22f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -50,6 +50,8 @@ struct cfg80211_registered_device { | |||
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 | int devlist_generation; |
53 | int opencount; /* also protected by devlist_mtx */ | ||
54 | wait_queue_head_t dev_wait; | ||
53 | 55 | ||
54 | /* BSSes/scanning */ | 56 | /* BSSes/scanning */ |
55 | spinlock_t bss_lock; | 57 | spinlock_t bss_lock; |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da64071ceb84..79d2eec54cec 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -96,6 +96,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
96 | WARN_ON(!bss); | 96 | WARN_ON(!bss); |
97 | } | 97 | } |
98 | 98 | ||
99 | if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { | ||
100 | /* | ||
101 | * This is for the userspace SME, the CONNECTING | ||
102 | * state will be changed to CONNECTED by | ||
103 | * __cfg80211_connect_result() below. | ||
104 | */ | ||
105 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
106 | } | ||
107 | |||
99 | /* this consumes one bss reference (unless bss is NULL) */ | 108 | /* this consumes one bss reference (unless bss is NULL) */ |
100 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 109 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
101 | status_code, | 110 | status_code, |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 8e2ef54ea714..4a8289f9b4f0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -351,15 +351,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
351 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 351 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
352 | return; | 352 | return; |
353 | 353 | ||
354 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | 354 | if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) |
355 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, | 355 | return; |
356 | |||
357 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | ||
356 | bssid, req_ie, req_ie_len, | 358 | bssid, req_ie, req_ie_len, |
357 | resp_ie, resp_ie_len, GFP_KERNEL); | 359 | resp_ie, resp_ie_len, |
358 | else | 360 | status, GFP_KERNEL); |
359 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | ||
360 | bssid, req_ie, req_ie_len, | ||
361 | resp_ie, resp_ie_len, | ||
362 | status, GFP_KERNEL); | ||
363 | 361 | ||
364 | #ifdef CONFIG_WIRELESS_EXT | 362 | #ifdef CONFIG_WIRELESS_EXT |
365 | if (wextev) { | 363 | if (wextev) { |
@@ -392,18 +390,13 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
392 | wdev->current_bss = NULL; | 390 | wdev->current_bss = NULL; |
393 | } | 391 | } |
394 | 392 | ||
395 | if (status == WLAN_STATUS_SUCCESS && | ||
396 | wdev->sme_state == CFG80211_SME_IDLE) | ||
397 | goto success; | ||
398 | |||
399 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | ||
400 | return; | ||
401 | |||
402 | if (wdev->conn) | 393 | if (wdev->conn) |
403 | wdev->conn->state = CFG80211_CONN_IDLE; | 394 | wdev->conn->state = CFG80211_CONN_IDLE; |
404 | 395 | ||
405 | if (status != WLAN_STATUS_SUCCESS) { | 396 | if (status != WLAN_STATUS_SUCCESS) { |
406 | wdev->sme_state = CFG80211_SME_IDLE; | 397 | wdev->sme_state = CFG80211_SME_IDLE; |
398 | if (wdev->conn) | ||
399 | kfree(wdev->conn->ie); | ||
407 | kfree(wdev->conn); | 400 | kfree(wdev->conn); |
408 | wdev->conn = NULL; | 401 | wdev->conn = NULL; |
409 | kfree(wdev->connect_keys); | 402 | kfree(wdev->connect_keys); |
@@ -412,7 +405,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
412 | return; | 405 | return; |
413 | } | 406 | } |
414 | 407 | ||
415 | success: | ||
416 | if (!bss) | 408 | if (!bss) |
417 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | 409 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, |
418 | wdev->ssid, wdev->ssid_len, | 410 | wdev->ssid, wdev->ssid_len, |
@@ -458,7 +450,8 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
458 | return; | 450 | return; |
459 | 451 | ||
460 | ev->type = EVENT_CONNECT_RESULT; | 452 | ev->type = EVENT_CONNECT_RESULT; |
461 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | 453 | if (bssid) |
454 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | ||
462 | ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); | 455 | ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); |
463 | ev->cr.req_ie_len = req_ie_len; | 456 | ev->cr.req_ie_len = req_ie_len; |
464 | memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); | 457 | memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); |
@@ -789,6 +782,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
789 | } | 782 | } |
790 | } | 783 | } |
791 | if (err) { | 784 | if (err) { |
785 | kfree(wdev->conn->ie); | ||
792 | kfree(wdev->conn); | 786 | kfree(wdev->conn); |
793 | wdev->conn = NULL; | 787 | wdev->conn = NULL; |
794 | wdev->sme_state = CFG80211_SME_IDLE; | 788 | wdev->sme_state = CFG80211_SME_IDLE; |
@@ -858,6 +852,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
858 | (wdev->conn->state == CFG80211_CONN_SCANNING || | 852 | (wdev->conn->state == CFG80211_CONN_SCANNING || |
859 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { | 853 | wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { |
860 | wdev->sme_state = CFG80211_SME_IDLE; | 854 | wdev->sme_state = CFG80211_SME_IDLE; |
855 | kfree(wdev->conn->ie); | ||
861 | kfree(wdev->conn); | 856 | kfree(wdev->conn); |
862 | wdev->conn = NULL; | 857 | wdev->conn = NULL; |
863 | wdev->ssid_len = 0; | 858 | wdev->ssid_len = 0; |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index c44917492210..c12029b1def0 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -771,6 +771,7 @@ int cfg80211_wext_siwfreq(struct net_device *dev, | |||
771 | return err; | 771 | return err; |
772 | } | 772 | } |
773 | } | 773 | } |
774 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq); | ||
774 | 775 | ||
775 | int cfg80211_wext_giwfreq(struct net_device *dev, | 776 | int cfg80211_wext_giwfreq(struct net_device *dev, |
776 | struct iw_request_info *info, | 777 | struct iw_request_info *info, |