diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-08-26 03:30:32 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-08-26 03:52:58 -0400 |
commit | a98655387762394371b88cdfb8215884757978ab (patch) | |
tree | 612c1221bc1d7f8e84260953a40a507c229dda13 /net/mac80211 | |
parent | bcdd822007e44b1da1ad5a62f20b75ee7d8da608 (diff) |
mac80211: fix change_interface queue assignments
Jouni reported that with mac80211_hwsim, multicast TX was causing
crashes due to invalid vif->cab_queue assignment. It turns out that
this is caused by change_interface() getting invoked and not having
the vif->type/vif->p2p assigned correctly before calling the queue
check (ieee80211_check_queues). Fix this by passing the 'external'
interface type to the function and adjusting it accordingly.
While at it, also fix the error path in change_interface, it wasn't
correctly resetting to the external type but using the internal one
instead.
Fortunately this affects on hwsim because all other drivers set the
vif->type/vif->p2p variables when changing iftype. This shouldn't
be needed, but almost all implementations actually do it for their
own internal handling.
Reported-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/iface.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7ca534bf4cea..fcecd633514e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -308,12 +308,13 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) | 311 | static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata, |
312 | enum nl80211_iftype iftype) | ||
312 | { | 313 | { |
313 | int n_queues = sdata->local->hw.queues; | 314 | int n_queues = sdata->local->hw.queues; |
314 | int i; | 315 | int i; |
315 | 316 | ||
316 | if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) { | 317 | if (iftype != NL80211_IFTYPE_P2P_DEVICE) { |
317 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { | 318 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
318 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == | 319 | if (WARN_ON_ONCE(sdata->vif.hw_queue[i] == |
319 | IEEE80211_INVAL_HW_QUEUE)) | 320 | IEEE80211_INVAL_HW_QUEUE)) |
@@ -324,8 +325,9 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata) | |||
324 | } | 325 | } |
325 | } | 326 | } |
326 | 327 | ||
327 | if ((sdata->vif.type != NL80211_IFTYPE_AP && | 328 | if ((iftype != NL80211_IFTYPE_AP && |
328 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT) || | 329 | iftype != NL80211_IFTYPE_P2P_GO && |
330 | iftype != NL80211_IFTYPE_MESH_POINT) || | ||
329 | !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) { | 331 | !(sdata->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) { |
330 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; | 332 | sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; |
331 | return 0; | 333 | return 0; |
@@ -408,7 +410,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) | |||
408 | return ret; | 410 | return ret; |
409 | } | 411 | } |
410 | 412 | ||
411 | ret = ieee80211_check_queues(sdata); | 413 | ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); |
412 | if (ret) { | 414 | if (ret) { |
413 | kfree(sdata); | 415 | kfree(sdata); |
414 | return ret; | 416 | return ret; |
@@ -592,7 +594,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
592 | res = drv_add_interface(local, sdata); | 594 | res = drv_add_interface(local, sdata); |
593 | if (res) | 595 | if (res) |
594 | goto err_stop; | 596 | goto err_stop; |
595 | res = ieee80211_check_queues(sdata); | 597 | res = ieee80211_check_queues(sdata, |
598 | ieee80211_vif_type_p2p(&sdata->vif)); | ||
596 | if (res) | 599 | if (res) |
597 | goto err_del_interface; | 600 | goto err_del_interface; |
598 | } | 601 | } |
@@ -1389,14 +1392,14 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1389 | 1392 | ||
1390 | ret = drv_change_interface(local, sdata, internal_type, p2p); | 1393 | ret = drv_change_interface(local, sdata, internal_type, p2p); |
1391 | if (ret) | 1394 | if (ret) |
1392 | type = sdata->vif.type; | 1395 | type = ieee80211_vif_type_p2p(&sdata->vif); |
1393 | 1396 | ||
1394 | /* | 1397 | /* |
1395 | * Ignore return value here, there's not much we can do since | 1398 | * Ignore return value here, there's not much we can do since |
1396 | * the driver changed the interface type internally already. | 1399 | * the driver changed the interface type internally already. |
1397 | * The warnings will hopefully make driver authors fix it :-) | 1400 | * The warnings will hopefully make driver authors fix it :-) |
1398 | */ | 1401 | */ |
1399 | ieee80211_check_queues(sdata); | 1402 | ieee80211_check_queues(sdata, type); |
1400 | 1403 | ||
1401 | ieee80211_setup_sdata(sdata, type); | 1404 | ieee80211_setup_sdata(sdata, type); |
1402 | 1405 | ||