aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-08-21 04:56:56 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-21 04:56:56 -0400
commitf8f2109d4f6c525f893f6f2901ae62372e83245e (patch)
treee20b095973d45eb2360ffa157ad161536c2ddbe9 /net
parentbb81b2ddfa194b6d12761a350b5b5985cecae0a9 (diff)
parenta2c3f6567c9ac327f1ef1272551f3a7595ec885e (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.c6
-rw-r--r--net/mac80211/driver-ops.h24
-rw-r--r--net/mac80211/driver-trace.h36
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/iface.c15
-rw-r--r--net/mac80211/main.c32
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_hwmp.c21
-rw-r--r--net/mac80211/rc80211_minstrel.c16
-rw-r--r--net/mac80211/rc80211_pid_algo.c16
-rw-r--r--net/mac80211/rx.c8
-rw-r--r--net/mac80211/scan.c16
-rw-r--r--net/mac80211/util.c2
-rw-r--r--net/wireless/core.c98
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/mlme.c9
-rw-r--r--net/wireless/sme.c29
-rw-r--r--net/wireless/wext-compat.c1
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 */
119IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
120IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
119IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); 121IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
120IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); 122IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
121IEEE80211_IF_FILE(dropped_frames_no_route, 123IEEE80211_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
328static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) 332static 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
58static 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
58static inline void drv_configure_filter(struct ieee80211_local *local, 73static 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
70static inline int drv_set_tim(struct ieee80211_local *local, 86static 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
194TRACE_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
194TRACE_EVENT(drv_configure_filter, 218TRACE_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
214struct mesh_stats { 214struct 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 */
54void ieee80211_configure_filter(struct ieee80211_local *local) 53void 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
99static 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
97int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) 107int 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
239u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) 246u32 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}
926EXPORT_SYMBOL(ieee80211_register_hw); 936EXPORT_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,
226void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); 226void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
227int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); 227int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
228void ieee80211s_init(void); 228void ieee80211s_init(void);
229void ieee80211s_update_metric(struct ieee80211_local *local,
230 struct sta_info *stainfo, struct sk_buff *skb);
229void ieee80211s_stop(void); 231void ieee80211s_stop(void);
230void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); 232void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
231ieee80211_rx_result 233ieee80211_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
204void 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
204static u32 airtime_link_metric_get(struct ieee80211_local *local, 222static 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
356static void *rate_control_pid_alloc(struct ieee80211_hw *hw, 342static 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}
611EXPORT_SYMBOL(wiphy_unregister); 627EXPORT_SYMBOL(wiphy_unregister);
@@ -636,6 +652,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
636} 652}
637EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); 653EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
638 654
655static 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
639static int cfg80211_netdev_notifier_call(struct notifier_block * nb, 680static 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}
774EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
774 775
775int cfg80211_wext_giwfreq(struct net_device *dev, 776int cfg80211_wext_giwfreq(struct net_device *dev,
776 struct iw_request_info *info, 777 struct iw_request_info *info,