diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 130 |
1 files changed, 86 insertions, 44 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 915e77769312..dd6564321369 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "mesh.h" | 31 | #include "mesh.h" |
32 | #include "wme.h" | 32 | #include "wme.h" |
33 | #include "led.h" | 33 | #include "led.h" |
34 | #include "wep.h" | ||
34 | 35 | ||
35 | /* privid for wiphys to determine whether they belong to us or not */ | 36 | /* privid for wiphys to determine whether they belong to us or not */ |
36 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 37 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
@@ -274,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
274 | 275 | ||
275 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 276 | __clear_bit(reason, &local->queue_stop_reasons[queue]); |
276 | 277 | ||
277 | if (!skb_queue_empty(&local->pending[queue]) && | ||
278 | local->queue_stop_reasons[queue] == | ||
279 | BIT(IEEE80211_QUEUE_STOP_REASON_PENDING)) | ||
280 | tasklet_schedule(&local->tx_pending_tasklet); | ||
281 | |||
282 | if (local->queue_stop_reasons[queue] != 0) | 278 | if (local->queue_stop_reasons[queue] != 0) |
283 | /* someone still has this queue stopped */ | 279 | /* someone still has this queue stopped */ |
284 | return; | 280 | return; |
285 | 281 | ||
286 | netif_wake_subqueue(local->mdev, queue); | 282 | if (!skb_queue_empty(&local->pending[queue])) |
283 | tasklet_schedule(&local->tx_pending_tasklet); | ||
287 | } | 284 | } |
288 | 285 | ||
289 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 286 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -312,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
312 | if (WARN_ON(queue >= hw->queues)) | 309 | if (WARN_ON(queue >= hw->queues)) |
313 | return; | 310 | return; |
314 | 311 | ||
315 | /* | ||
316 | * Only stop if it was previously running, this is necessary | ||
317 | * for correct pending packets handling because there we may | ||
318 | * start (but not wake) the queue and rely on that. | ||
319 | */ | ||
320 | if (!local->queue_stop_reasons[queue]) | ||
321 | netif_stop_subqueue(local->mdev, queue); | ||
322 | |||
323 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 312 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
324 | } | 313 | } |
325 | 314 | ||
@@ -347,11 +336,16 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
347 | struct ieee80211_hw *hw = &local->hw; | 336 | struct ieee80211_hw *hw = &local->hw; |
348 | unsigned long flags; | 337 | unsigned long flags; |
349 | int queue = skb_get_queue_mapping(skb); | 338 | int queue = skb_get_queue_mapping(skb); |
339 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
340 | |||
341 | if (WARN_ON(!info->control.vif)) { | ||
342 | kfree(skb); | ||
343 | return; | ||
344 | } | ||
350 | 345 | ||
351 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 346 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
352 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 347 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
353 | __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); | 348 | __skb_queue_tail(&local->pending[queue], skb); |
354 | skb_queue_tail(&local->pending[queue], skb); | ||
355 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 349 | __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
356 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 350 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
357 | } | 351 | } |
@@ -370,18 +364,21 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
370 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 364 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
371 | 365 | ||
372 | while ((skb = skb_dequeue(skbs))) { | 366 | while ((skb = skb_dequeue(skbs))) { |
367 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
368 | |||
369 | if (WARN_ON(!info->control.vif)) { | ||
370 | kfree(skb); | ||
371 | continue; | ||
372 | } | ||
373 | |||
373 | ret++; | 374 | ret++; |
374 | queue = skb_get_queue_mapping(skb); | 375 | queue = skb_get_queue_mapping(skb); |
375 | skb_queue_tail(&local->pending[queue], skb); | 376 | __skb_queue_tail(&local->pending[queue], skb); |
376 | } | 377 | } |
377 | 378 | ||
378 | for (i = 0; i < hw->queues; i++) { | 379 | for (i = 0; i < hw->queues; i++) |
379 | if (ret) | ||
380 | __ieee80211_stop_queue(hw, i, | ||
381 | IEEE80211_QUEUE_STOP_REASON_PENDING); | ||
382 | __ieee80211_wake_queue(hw, i, | 380 | __ieee80211_wake_queue(hw, i, |
383 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 381 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
384 | } | ||
385 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 382 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
386 | 383 | ||
387 | return ret; | 384 | return ret; |
@@ -412,11 +409,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues); | |||
412 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 409 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
413 | { | 410 | { |
414 | struct ieee80211_local *local = hw_to_local(hw); | 411 | struct ieee80211_local *local = hw_to_local(hw); |
412 | unsigned long flags; | ||
413 | int ret; | ||
415 | 414 | ||
416 | if (WARN_ON(queue >= hw->queues)) | 415 | if (WARN_ON(queue >= hw->queues)) |
417 | return true; | 416 | return true; |
418 | 417 | ||
419 | return __netif_subqueue_stopped(local->mdev, queue); | 418 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
419 | ret = !!local->queue_stop_reasons[queue]; | ||
420 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
421 | return ret; | ||
420 | } | 422 | } |
421 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 423 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
422 | 424 | ||
@@ -509,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
509 | } | 511 | } |
510 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); | 512 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); |
511 | 513 | ||
514 | /* | ||
515 | * Nothing should have been stuffed into the workqueue during | ||
516 | * the suspend->resume cycle. If this WARN is seen then there | ||
517 | * is a bug with either the driver suspend or something in | ||
518 | * mac80211 stuffing into the workqueue which we haven't yet | ||
519 | * cleared during mac80211's suspend cycle. | ||
520 | */ | ||
521 | static bool ieee80211_can_queue_work(struct ieee80211_local *local) | ||
522 | { | ||
523 | if (WARN(local->suspended, "queueing ieee80211 work while " | ||
524 | "going to suspend\n")) | ||
525 | return false; | ||
526 | |||
527 | return true; | ||
528 | } | ||
529 | |||
530 | void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) | ||
531 | { | ||
532 | struct ieee80211_local *local = hw_to_local(hw); | ||
533 | |||
534 | if (!ieee80211_can_queue_work(local)) | ||
535 | return; | ||
536 | |||
537 | queue_work(local->workqueue, work); | ||
538 | } | ||
539 | EXPORT_SYMBOL(ieee80211_queue_work); | ||
540 | |||
541 | void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, | ||
542 | struct delayed_work *dwork, | ||
543 | unsigned long delay) | ||
544 | { | ||
545 | struct ieee80211_local *local = hw_to_local(hw); | ||
546 | |||
547 | if (!ieee80211_can_queue_work(local)) | ||
548 | return; | ||
549 | |||
550 | queue_delayed_work(local->workqueue, dwork, delay); | ||
551 | } | ||
552 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); | ||
553 | |||
512 | void ieee802_11_parse_elems(u8 *start, size_t len, | 554 | void ieee802_11_parse_elems(u8 *start, size_t len, |
513 | struct ieee802_11_elems *elems) | 555 | struct ieee802_11_elems *elems) |
514 | { | 556 | { |
@@ -760,20 +802,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
760 | ieee80211_set_wmm_default(sdata); | 802 | ieee80211_set_wmm_default(sdata); |
761 | } | 803 | } |
762 | 804 | ||
763 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
764 | int encrypt) | ||
765 | { | ||
766 | skb->dev = sdata->local->mdev; | ||
767 | skb_set_mac_header(skb, 0); | ||
768 | skb_set_network_header(skb, 0); | ||
769 | skb_set_transport_header(skb, 0); | ||
770 | |||
771 | skb->iif = sdata->dev->ifindex; | ||
772 | skb->do_not_encrypt = !encrypt; | ||
773 | |||
774 | dev_queue_xmit(skb); | ||
775 | } | ||
776 | |||
777 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | 805 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
778 | enum ieee80211_band band) | 806 | enum ieee80211_band band) |
779 | { | 807 | { |
@@ -804,12 +832,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
804 | 832 | ||
805 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 833 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
806 | u16 transaction, u16 auth_alg, | 834 | u16 transaction, u16 auth_alg, |
807 | u8 *extra, size_t extra_len, | 835 | u8 *extra, size_t extra_len, const u8 *bssid, |
808 | const u8 *bssid, int encrypt) | 836 | const u8 *key, u8 key_len, u8 key_idx) |
809 | { | 837 | { |
810 | struct ieee80211_local *local = sdata->local; | 838 | struct ieee80211_local *local = sdata->local; |
811 | struct sk_buff *skb; | 839 | struct sk_buff *skb; |
812 | struct ieee80211_mgmt *mgmt; | 840 | struct ieee80211_mgmt *mgmt; |
841 | int err; | ||
813 | 842 | ||
814 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 843 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
815 | sizeof(*mgmt) + 6 + extra_len); | 844 | sizeof(*mgmt) + 6 + extra_len); |
@@ -824,8 +853,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
824 | memset(mgmt, 0, 24 + 6); | 853 | memset(mgmt, 0, 24 + 6); |
825 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 854 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
826 | IEEE80211_STYPE_AUTH); | 855 | IEEE80211_STYPE_AUTH); |
827 | if (encrypt) | ||
828 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
829 | memcpy(mgmt->da, bssid, ETH_ALEN); | 856 | memcpy(mgmt->da, bssid, ETH_ALEN); |
830 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 857 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
831 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | 858 | memcpy(mgmt->bssid, bssid, ETH_ALEN); |
@@ -835,7 +862,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
835 | if (extra) | 862 | if (extra) |
836 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 863 | memcpy(skb_put(skb, extra_len), extra, extra_len); |
837 | 864 | ||
838 | ieee80211_tx_skb(sdata, skb, encrypt); | 865 | if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { |
866 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
867 | err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); | ||
868 | WARN_ON(err); | ||
869 | } | ||
870 | |||
871 | ieee80211_tx_skb(sdata, skb, 0); | ||
839 | } | 872 | } |
840 | 873 | ||
841 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 874 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
@@ -974,6 +1007,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
974 | return supp_rates; | 1007 | return supp_rates; |
975 | } | 1008 | } |
976 | 1009 | ||
1010 | void ieee80211_stop_device(struct ieee80211_local *local) | ||
1011 | { | ||
1012 | ieee80211_led_radio(local, false); | ||
1013 | |||
1014 | cancel_work_sync(&local->reconfig_filter); | ||
1015 | drv_stop(local); | ||
1016 | |||
1017 | flush_workqueue(local->workqueue); | ||
1018 | } | ||
1019 | |||
977 | int ieee80211_reconfig(struct ieee80211_local *local) | 1020 | int ieee80211_reconfig(struct ieee80211_local *local) |
978 | { | 1021 | { |
979 | struct ieee80211_hw *hw = &local->hw; | 1022 | struct ieee80211_hw *hw = &local->hw; |
@@ -1043,9 +1086,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1043 | /* reconfigure hardware */ | 1086 | /* reconfigure hardware */ |
1044 | ieee80211_hw_config(local, ~0); | 1087 | ieee80211_hw_config(local, ~0); |
1045 | 1088 | ||
1046 | netif_addr_lock_bh(local->mdev); | ||
1047 | ieee80211_configure_filter(local); | 1089 | ieee80211_configure_filter(local); |
1048 | netif_addr_unlock_bh(local->mdev); | ||
1049 | 1090 | ||
1050 | /* Finally also reconfigure all the BSS information */ | 1091 | /* Finally also reconfigure all the BSS information */ |
1051 | list_for_each_entry(sdata, &local->interfaces, list) { | 1092 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -1121,3 +1162,4 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1121 | #endif | 1162 | #endif |
1122 | return 0; | 1163 | return 0; |
1123 | } | 1164 | } |
1165 | |||