diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-03 09:41:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-09 16:01:02 -0500 |
commit | 7b7eab6fc1bc8852d9649541b59283cd89cc526f (patch) | |
tree | 7b071ee01187bc3ee843c86b88189cc4eab73cf1 | |
parent | 6e3e939f3b1bf8534b32ad09ff199d88800835a0 (diff) |
mac80211: verify virtual interfaces in driver API
The driver is never informed about monitor or
AP_VLAN interfaces, so whenever we pass those
to it later this is a bug. Verify we don't as
there are some cases where this could happen.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/driver-ops.h | 68 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 6 | ||||
-rw-r--r-- | net/mac80211/pm.c | 2 | ||||
-rw-r--r-- | net/mac80211/util.c | 2 |
5 files changed, 69 insertions, 11 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 5f165d7eb2db..b12ed52732c8 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -5,6 +5,11 @@ | |||
5 | #include "ieee80211_i.h" | 5 | #include "ieee80211_i.h" |
6 | #include "driver-trace.h" | 6 | #include "driver-trace.h" |
7 | 7 | ||
8 | static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) | ||
9 | { | ||
10 | WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)); | ||
11 | } | ||
12 | |||
8 | static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) | 13 | static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) |
9 | { | 14 | { |
10 | local->ops->tx(&local->hw, skb); | 15 | local->ops->tx(&local->hw, skb); |
@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local) | |||
69 | #endif | 74 | #endif |
70 | 75 | ||
71 | static inline int drv_add_interface(struct ieee80211_local *local, | 76 | static inline int drv_add_interface(struct ieee80211_local *local, |
72 | struct ieee80211_vif *vif) | 77 | struct ieee80211_sub_if_data *sdata) |
73 | { | 78 | { |
74 | int ret; | 79 | int ret; |
75 | 80 | ||
76 | might_sleep(); | 81 | might_sleep(); |
77 | 82 | ||
78 | trace_drv_add_interface(local, vif_to_sdata(vif)); | 83 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
79 | ret = local->ops->add_interface(&local->hw, vif); | 84 | sdata->vif.type == NL80211_IFTYPE_MONITOR)) |
85 | return -EINVAL; | ||
86 | |||
87 | trace_drv_add_interface(local, sdata); | ||
88 | ret = local->ops->add_interface(&local->hw, &sdata->vif); | ||
80 | trace_drv_return_int(local, ret); | 89 | trace_drv_return_int(local, ret); |
90 | |||
91 | if (ret == 0) | ||
92 | sdata->flags |= IEEE80211_SDATA_IN_DRIVER; | ||
93 | |||
81 | return ret; | 94 | return ret; |
82 | } | 95 | } |
83 | 96 | ||
@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local, | |||
89 | 102 | ||
90 | might_sleep(); | 103 | might_sleep(); |
91 | 104 | ||
105 | check_sdata_in_driver(sdata); | ||
106 | |||
92 | trace_drv_change_interface(local, sdata, type, p2p); | 107 | trace_drv_change_interface(local, sdata, type, p2p); |
93 | ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); | 108 | ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); |
94 | trace_drv_return_int(local, ret); | 109 | trace_drv_return_int(local, ret); |
@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local, | |||
96 | } | 111 | } |
97 | 112 | ||
98 | static inline void drv_remove_interface(struct ieee80211_local *local, | 113 | static inline void drv_remove_interface(struct ieee80211_local *local, |
99 | struct ieee80211_vif *vif) | 114 | struct ieee80211_sub_if_data *sdata) |
100 | { | 115 | { |
101 | might_sleep(); | 116 | might_sleep(); |
102 | 117 | ||
103 | trace_drv_remove_interface(local, vif_to_sdata(vif)); | 118 | check_sdata_in_driver(sdata); |
104 | local->ops->remove_interface(&local->hw, vif); | 119 | |
120 | trace_drv_remove_interface(local, sdata); | ||
121 | local->ops->remove_interface(&local->hw, &sdata->vif); | ||
122 | sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER; | ||
105 | trace_drv_return_void(local); | 123 | trace_drv_return_void(local); |
106 | } | 124 | } |
107 | 125 | ||
@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
124 | { | 142 | { |
125 | might_sleep(); | 143 | might_sleep(); |
126 | 144 | ||
145 | check_sdata_in_driver(sdata); | ||
146 | |||
127 | trace_drv_bss_info_changed(local, sdata, info, changed); | 147 | trace_drv_bss_info_changed(local, sdata, info, changed); |
128 | if (local->ops->bss_info_changed) | 148 | if (local->ops->bss_info_changed) |
129 | local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); | 149 | local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); |
@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local, | |||
139 | 159 | ||
140 | might_sleep(); | 160 | might_sleep(); |
141 | 161 | ||
162 | check_sdata_in_driver(sdata); | ||
163 | |||
142 | trace_drv_tx_sync(local, sdata, bssid, type); | 164 | trace_drv_tx_sync(local, sdata, bssid, type); |
143 | if (local->ops->tx_sync) | 165 | if (local->ops->tx_sync) |
144 | ret = local->ops->tx_sync(&local->hw, &sdata->vif, | 166 | ret = local->ops->tx_sync(&local->hw, &sdata->vif, |
@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local, | |||
154 | { | 176 | { |
155 | might_sleep(); | 177 | might_sleep(); |
156 | 178 | ||
179 | check_sdata_in_driver(sdata); | ||
180 | |||
157 | trace_drv_finish_tx_sync(local, sdata, bssid, type); | 181 | trace_drv_finish_tx_sync(local, sdata, bssid, type); |
158 | if (local->ops->finish_tx_sync) | 182 | if (local->ops->finish_tx_sync) |
159 | local->ops->finish_tx_sync(&local->hw, &sdata->vif, | 183 | local->ops->finish_tx_sync(&local->hw, &sdata->vif, |
@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local, | |||
211 | 235 | ||
212 | might_sleep(); | 236 | might_sleep(); |
213 | 237 | ||
238 | check_sdata_in_driver(sdata); | ||
239 | |||
214 | trace_drv_set_key(local, cmd, sdata, sta, key); | 240 | trace_drv_set_key(local, cmd, sdata, sta, key); |
215 | ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); | 241 | ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); |
216 | trace_drv_return_int(local, ret); | 242 | trace_drv_return_int(local, ret); |
@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | |||
228 | if (sta) | 254 | if (sta) |
229 | ista = &sta->sta; | 255 | ista = &sta->sta; |
230 | 256 | ||
257 | check_sdata_in_driver(sdata); | ||
258 | |||
231 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); | 259 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); |
232 | if (local->ops->update_tkip_key) | 260 | if (local->ops->update_tkip_key) |
233 | local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, | 261 | local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, |
@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local, | |||
243 | 271 | ||
244 | might_sleep(); | 272 | might_sleep(); |
245 | 273 | ||
274 | check_sdata_in_driver(sdata); | ||
275 | |||
246 | trace_drv_hw_scan(local, sdata); | 276 | trace_drv_hw_scan(local, sdata); |
247 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); | 277 | ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); |
248 | trace_drv_return_int(local, ret); | 278 | trace_drv_return_int(local, ret); |
@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local, | |||
254 | { | 284 | { |
255 | might_sleep(); | 285 | might_sleep(); |
256 | 286 | ||
287 | check_sdata_in_driver(sdata); | ||
288 | |||
257 | trace_drv_cancel_hw_scan(local, sdata); | 289 | trace_drv_cancel_hw_scan(local, sdata); |
258 | local->ops->cancel_hw_scan(&local->hw, &sdata->vif); | 290 | local->ops->cancel_hw_scan(&local->hw, &sdata->vif); |
259 | trace_drv_return_void(local); | 291 | trace_drv_return_void(local); |
@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local, | |||
269 | 301 | ||
270 | might_sleep(); | 302 | might_sleep(); |
271 | 303 | ||
304 | check_sdata_in_driver(sdata); | ||
305 | |||
272 | trace_drv_sched_scan_start(local, sdata); | 306 | trace_drv_sched_scan_start(local, sdata); |
273 | ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, | 307 | ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, |
274 | req, ies); | 308 | req, ies); |
@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local, | |||
281 | { | 315 | { |
282 | might_sleep(); | 316 | might_sleep(); |
283 | 317 | ||
318 | check_sdata_in_driver(sdata); | ||
319 | |||
284 | trace_drv_sched_scan_stop(local, sdata); | 320 | trace_drv_sched_scan_stop(local, sdata); |
285 | local->ops->sched_scan_stop(&local->hw, &sdata->vif); | 321 | local->ops->sched_scan_stop(&local->hw, &sdata->vif); |
286 | trace_drv_return_void(local); | 322 | trace_drv_return_void(local); |
@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local, | |||
377 | enum sta_notify_cmd cmd, | 413 | enum sta_notify_cmd cmd, |
378 | struct ieee80211_sta *sta) | 414 | struct ieee80211_sta *sta) |
379 | { | 415 | { |
416 | check_sdata_in_driver(sdata); | ||
417 | |||
380 | trace_drv_sta_notify(local, sdata, cmd, sta); | 418 | trace_drv_sta_notify(local, sdata, cmd, sta); |
381 | if (local->ops->sta_notify) | 419 | if (local->ops->sta_notify) |
382 | local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); | 420 | local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); |
@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local, | |||
391 | 429 | ||
392 | might_sleep(); | 430 | might_sleep(); |
393 | 431 | ||
432 | check_sdata_in_driver(sdata); | ||
433 | |||
394 | trace_drv_sta_add(local, sdata, sta); | 434 | trace_drv_sta_add(local, sdata, sta); |
395 | if (local->ops->sta_add) | 435 | if (local->ops->sta_add) |
396 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); | 436 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); |
@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local, | |||
406 | { | 446 | { |
407 | might_sleep(); | 447 | might_sleep(); |
408 | 448 | ||
449 | check_sdata_in_driver(sdata); | ||
450 | |||
409 | trace_drv_sta_remove(local, sdata, sta); | 451 | trace_drv_sta_remove(local, sdata, sta); |
410 | if (local->ops->sta_remove) | 452 | if (local->ops->sta_remove) |
411 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); | 453 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); |
@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
421 | 463 | ||
422 | might_sleep(); | 464 | might_sleep(); |
423 | 465 | ||
466 | check_sdata_in_driver(sdata); | ||
467 | |||
424 | trace_drv_conf_tx(local, sdata, queue, params); | 468 | trace_drv_conf_tx(local, sdata, queue, params); |
425 | if (local->ops->conf_tx) | 469 | if (local->ops->conf_tx) |
426 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, | 470 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local, | |||
436 | 480 | ||
437 | might_sleep(); | 481 | might_sleep(); |
438 | 482 | ||
483 | check_sdata_in_driver(sdata); | ||
484 | |||
439 | trace_drv_get_tsf(local, sdata); | 485 | trace_drv_get_tsf(local, sdata); |
440 | if (local->ops->get_tsf) | 486 | if (local->ops->get_tsf) |
441 | ret = local->ops->get_tsf(&local->hw, &sdata->vif); | 487 | ret = local->ops->get_tsf(&local->hw, &sdata->vif); |
@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, | |||
449 | { | 495 | { |
450 | might_sleep(); | 496 | might_sleep(); |
451 | 497 | ||
498 | check_sdata_in_driver(sdata); | ||
499 | |||
452 | trace_drv_set_tsf(local, sdata, tsf); | 500 | trace_drv_set_tsf(local, sdata, tsf); |
453 | if (local->ops->set_tsf) | 501 | if (local->ops->set_tsf) |
454 | local->ops->set_tsf(&local->hw, &sdata->vif, tsf); | 502 | local->ops->set_tsf(&local->hw, &sdata->vif, tsf); |
@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local, | |||
460 | { | 508 | { |
461 | might_sleep(); | 509 | might_sleep(); |
462 | 510 | ||
511 | check_sdata_in_driver(sdata); | ||
512 | |||
463 | trace_drv_reset_tsf(local, sdata); | 513 | trace_drv_reset_tsf(local, sdata); |
464 | if (local->ops->reset_tsf) | 514 | if (local->ops->reset_tsf) |
465 | local->ops->reset_tsf(&local->hw, &sdata->vif); | 515 | local->ops->reset_tsf(&local->hw, &sdata->vif); |
@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, | |||
489 | 539 | ||
490 | might_sleep(); | 540 | might_sleep(); |
491 | 541 | ||
542 | check_sdata_in_driver(sdata); | ||
543 | |||
492 | trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); | 544 | trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); |
493 | 545 | ||
494 | if (local->ops->ampdu_action) | 546 | if (local->ops->ampdu_action) |
@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local, | |||
644 | 696 | ||
645 | might_sleep(); | 697 | might_sleep(); |
646 | 698 | ||
699 | check_sdata_in_driver(sdata); | ||
700 | |||
647 | trace_drv_set_bitrate_mask(local, sdata, mask); | 701 | trace_drv_set_bitrate_mask(local, sdata, mask); |
648 | if (local->ops->set_bitrate_mask) | 702 | if (local->ops->set_bitrate_mask) |
649 | ret = local->ops->set_bitrate_mask(&local->hw, | 703 | ret = local->ops->set_bitrate_mask(&local->hw, |
@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, | |||
657 | struct ieee80211_sub_if_data *sdata, | 711 | struct ieee80211_sub_if_data *sdata, |
658 | struct cfg80211_gtk_rekey_data *data) | 712 | struct cfg80211_gtk_rekey_data *data) |
659 | { | 713 | { |
714 | check_sdata_in_driver(sdata); | ||
715 | |||
660 | trace_drv_set_rekey_data(local, sdata, data); | 716 | trace_drv_set_rekey_data(local, sdata, data); |
661 | if (local->ops->set_rekey_data) | 717 | if (local->ops->set_rekey_data) |
662 | local->ops->set_rekey_data(&local->hw, &sdata->vif, data); | 718 | local->ops->set_rekey_data(&local->hw, &sdata->vif, data); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e2447096c94a..386330c89baf 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -543,6 +543,7 @@ struct ieee80211_if_mesh { | |||
543 | * associated stations and deliver multicast frames both | 543 | * associated stations and deliver multicast frames both |
544 | * back to wireless media and to the local net stack. | 544 | * back to wireless media and to the local net stack. |
545 | * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. | 545 | * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. |
546 | * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver | ||
546 | */ | 547 | */ |
547 | enum ieee80211_sub_if_data_flags { | 548 | enum ieee80211_sub_if_data_flags { |
548 | IEEE80211_SDATA_ALLMULTI = BIT(0), | 549 | IEEE80211_SDATA_ALLMULTI = BIT(0), |
@@ -550,6 +551,7 @@ enum ieee80211_sub_if_data_flags { | |||
550 | IEEE80211_SDATA_OPERATING_GMODE = BIT(2), | 551 | IEEE80211_SDATA_OPERATING_GMODE = BIT(2), |
551 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), | 552 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), |
552 | IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), | 553 | IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), |
554 | IEEE80211_SDATA_IN_DRIVER = BIT(5), | ||
553 | }; | 555 | }; |
554 | 556 | ||
555 | /** | 557 | /** |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 33a974663f79..4ee624c543cb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -265,7 +265,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
265 | break; | 265 | break; |
266 | default: | 266 | default: |
267 | if (coming_up) { | 267 | if (coming_up) { |
268 | res = drv_add_interface(local, &sdata->vif); | 268 | res = drv_add_interface(local, sdata); |
269 | if (res) | 269 | if (res) |
270 | goto err_stop; | 270 | goto err_stop; |
271 | } | 271 | } |
@@ -345,7 +345,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) | |||
345 | 345 | ||
346 | return 0; | 346 | return 0; |
347 | err_del_interface: | 347 | err_del_interface: |
348 | drv_remove_interface(local, &sdata->vif); | 348 | drv_remove_interface(local, sdata); |
349 | err_stop: | 349 | err_stop: |
350 | if (!local->open_count) | 350 | if (!local->open_count) |
351 | drv_stop(local); | 351 | drv_stop(local); |
@@ -520,7 +520,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
520 | ieee80211_free_keys(sdata); | 520 | ieee80211_free_keys(sdata); |
521 | 521 | ||
522 | if (going_down) | 522 | if (going_down) |
523 | drv_remove_interface(local, &sdata->vif); | 523 | drv_remove_interface(local, sdata); |
524 | } | 524 | } |
525 | 525 | ||
526 | sdata->bss = NULL; | 526 | sdata->bss = NULL; |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9ee7164b207c..596efaf50e09 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
125 | ieee80211_bss_info_change_notify(sdata, | 125 | ieee80211_bss_info_change_notify(sdata, |
126 | BSS_CHANGED_BEACON_ENABLED); | 126 | BSS_CHANGED_BEACON_ENABLED); |
127 | 127 | ||
128 | drv_remove_interface(local, &sdata->vif); | 128 | drv_remove_interface(local, sdata); |
129 | } | 129 | } |
130 | 130 | ||
131 | /* stop hardware - this must stop RX */ | 131 | /* stop hardware - this must stop RX */ |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 83c482177ecb..98ca5479324b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1006,7 +1006,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1006 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 1006 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
1007 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 1007 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1008 | ieee80211_sdata_running(sdata)) | 1008 | ieee80211_sdata_running(sdata)) |
1009 | res = drv_add_interface(local, &sdata->vif); | 1009 | res = drv_add_interface(local, sdata); |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | /* add STAs back */ | 1012 | /* add STAs back */ |