diff options
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r-- | net/mac80211/iface.c | 190 |
1 files changed, 151 insertions, 39 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 50deb017fd6..ebbe264e2b0 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -249,6 +249,8 @@ static int ieee80211_open(struct net_device *dev) | |||
249 | local->fif_other_bss++; | 249 | local->fif_other_bss++; |
250 | 250 | ||
251 | ieee80211_configure_filter(local); | 251 | ieee80211_configure_filter(local); |
252 | |||
253 | netif_carrier_on(dev); | ||
252 | break; | 254 | break; |
253 | default: | 255 | default: |
254 | res = drv_add_interface(local, &sdata->vif); | 256 | res = drv_add_interface(local, &sdata->vif); |
@@ -268,7 +270,6 @@ static int ieee80211_open(struct net_device *dev) | |||
268 | 270 | ||
269 | changed |= ieee80211_reset_erp_info(sdata); | 271 | changed |= ieee80211_reset_erp_info(sdata); |
270 | ieee80211_bss_info_change_notify(sdata, changed); | 272 | ieee80211_bss_info_change_notify(sdata, changed); |
271 | ieee80211_enable_keys(sdata); | ||
272 | 273 | ||
273 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 274 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
274 | netif_carrier_off(dev); | 275 | netif_carrier_off(dev); |
@@ -321,15 +322,6 @@ static int ieee80211_open(struct net_device *dev) | |||
321 | 322 | ||
322 | ieee80211_recalc_ps(local, -1); | 323 | ieee80211_recalc_ps(local, -1); |
323 | 324 | ||
324 | /* | ||
325 | * ieee80211_sta_work is disabled while network interface | ||
326 | * is down. Therefore, some configuration changes may not | ||
327 | * yet be effective. Trigger execution of ieee80211_sta_work | ||
328 | * to fix this. | ||
329 | */ | ||
330 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
331 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); | ||
332 | |||
333 | netif_tx_start_all_queues(dev); | 325 | netif_tx_start_all_queues(dev); |
334 | 326 | ||
335 | return 0; | 327 | return 0; |
@@ -349,7 +341,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
349 | { | 341 | { |
350 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 342 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
351 | struct ieee80211_local *local = sdata->local; | 343 | struct ieee80211_local *local = sdata->local; |
352 | struct sta_info *sta; | ||
353 | unsigned long flags; | 344 | unsigned long flags; |
354 | struct sk_buff *skb, *tmp; | 345 | struct sk_buff *skb, *tmp; |
355 | u32 hw_reconf_flags = 0; | 346 | u32 hw_reconf_flags = 0; |
@@ -366,18 +357,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
366 | ieee80211_work_purge(sdata); | 357 | ieee80211_work_purge(sdata); |
367 | 358 | ||
368 | /* | 359 | /* |
369 | * Now delete all active aggregation sessions. | ||
370 | */ | ||
371 | rcu_read_lock(); | ||
372 | |||
373 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
374 | if (sta->sdata == sdata) | ||
375 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
376 | } | ||
377 | |||
378 | rcu_read_unlock(); | ||
379 | |||
380 | /* | ||
381 | * Remove all stations associated with this interface. | 360 | * Remove all stations associated with this interface. |
382 | * | 361 | * |
383 | * This must be done before calling ops->remove_interface() | 362 | * This must be done before calling ops->remove_interface() |
@@ -483,27 +462,14 @@ static int ieee80211_stop(struct net_device *dev) | |||
483 | * whether the interface is running, which, at this point, | 462 | * whether the interface is running, which, at this point, |
484 | * it no longer is. | 463 | * it no longer is. |
485 | */ | 464 | */ |
486 | cancel_work_sync(&sdata->u.mgd.work); | ||
487 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 465 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
488 | cancel_work_sync(&sdata->u.mgd.monitor_work); | 466 | cancel_work_sync(&sdata->u.mgd.monitor_work); |
489 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); | 467 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); |
490 | 468 | ||
491 | /* | ||
492 | * When we get here, the interface is marked down. | ||
493 | * Call synchronize_rcu() to wait for the RX path | ||
494 | * should it be using the interface and enqueuing | ||
495 | * frames at this very time on another CPU. | ||
496 | */ | ||
497 | synchronize_rcu(); | ||
498 | skb_queue_purge(&sdata->u.mgd.skb_queue); | ||
499 | /* fall through */ | 469 | /* fall through */ |
500 | case NL80211_IFTYPE_ADHOC: | 470 | case NL80211_IFTYPE_ADHOC: |
501 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 471 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
502 | del_timer_sync(&sdata->u.ibss.timer); | 472 | del_timer_sync(&sdata->u.ibss.timer); |
503 | cancel_work_sync(&sdata->u.ibss.work); | ||
504 | synchronize_rcu(); | ||
505 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
506 | } | ||
507 | /* fall through */ | 473 | /* fall through */ |
508 | case NL80211_IFTYPE_MESH_POINT: | 474 | case NL80211_IFTYPE_MESH_POINT: |
509 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -518,6 +484,16 @@ static int ieee80211_stop(struct net_device *dev) | |||
518 | } | 484 | } |
519 | /* fall through */ | 485 | /* fall through */ |
520 | default: | 486 | default: |
487 | flush_work(&sdata->work); | ||
488 | /* | ||
489 | * When we get here, the interface is marked down. | ||
490 | * Call synchronize_rcu() to wait for the RX path | ||
491 | * should it be using the interface and enqueuing | ||
492 | * frames at this very time on another CPU. | ||
493 | */ | ||
494 | synchronize_rcu(); | ||
495 | skb_queue_purge(&sdata->skb_queue); | ||
496 | |||
521 | if (local->scan_sdata == sdata) | 497 | if (local->scan_sdata == sdata) |
522 | ieee80211_scan_cancel(local); | 498 | ieee80211_scan_cancel(local); |
523 | 499 | ||
@@ -531,8 +507,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
531 | BSS_CHANGED_BEACON_ENABLED); | 507 | BSS_CHANGED_BEACON_ENABLED); |
532 | } | 508 | } |
533 | 509 | ||
534 | /* disable all keys for as long as this netdev is down */ | 510 | /* free all remaining keys, there shouldn't be any */ |
535 | ieee80211_disable_keys(sdata); | 511 | ieee80211_free_keys(sdata); |
536 | drv_remove_interface(local, &sdata->vif); | 512 | drv_remove_interface(local, &sdata->vif); |
537 | } | 513 | } |
538 | 514 | ||
@@ -727,6 +703,136 @@ static void ieee80211_if_setup(struct net_device *dev) | |||
727 | dev->destructor = free_netdev; | 703 | dev->destructor = free_netdev; |
728 | } | 704 | } |
729 | 705 | ||
706 | static void ieee80211_iface_work(struct work_struct *work) | ||
707 | { | ||
708 | struct ieee80211_sub_if_data *sdata = | ||
709 | container_of(work, struct ieee80211_sub_if_data, work); | ||
710 | struct ieee80211_local *local = sdata->local; | ||
711 | struct sk_buff *skb; | ||
712 | struct sta_info *sta; | ||
713 | struct ieee80211_ra_tid *ra_tid; | ||
714 | |||
715 | if (!ieee80211_sdata_running(sdata)) | ||
716 | return; | ||
717 | |||
718 | if (local->scanning) | ||
719 | return; | ||
720 | |||
721 | /* | ||
722 | * ieee80211_queue_work() should have picked up most cases, | ||
723 | * here we'll pick the rest. | ||
724 | */ | ||
725 | if (WARN(local->suspended, | ||
726 | "interface work scheduled while going to suspend\n")) | ||
727 | return; | ||
728 | |||
729 | /* first process frames */ | ||
730 | while ((skb = skb_dequeue(&sdata->skb_queue))) { | ||
731 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
732 | |||
733 | if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) { | ||
734 | ra_tid = (void *)&skb->cb; | ||
735 | ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra, | ||
736 | ra_tid->tid); | ||
737 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) { | ||
738 | ra_tid = (void *)&skb->cb; | ||
739 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, | ||
740 | ra_tid->tid); | ||
741 | } else if (ieee80211_is_action(mgmt->frame_control) && | ||
742 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | ||
743 | int len = skb->len; | ||
744 | |||
745 | mutex_lock(&local->sta_mtx); | ||
746 | sta = sta_info_get_bss(sdata, mgmt->sa); | ||
747 | if (sta) { | ||
748 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
749 | case WLAN_ACTION_ADDBA_REQ: | ||
750 | ieee80211_process_addba_request( | ||
751 | local, sta, mgmt, len); | ||
752 | break; | ||
753 | case WLAN_ACTION_ADDBA_RESP: | ||
754 | ieee80211_process_addba_resp(local, sta, | ||
755 | mgmt, len); | ||
756 | break; | ||
757 | case WLAN_ACTION_DELBA: | ||
758 | ieee80211_process_delba(sdata, sta, | ||
759 | mgmt, len); | ||
760 | break; | ||
761 | default: | ||
762 | WARN_ON(1); | ||
763 | break; | ||
764 | } | ||
765 | } | ||
766 | mutex_unlock(&local->sta_mtx); | ||
767 | } else if (ieee80211_is_data_qos(mgmt->frame_control)) { | ||
768 | struct ieee80211_hdr *hdr = (void *)mgmt; | ||
769 | /* | ||
770 | * So the frame isn't mgmt, but frame_control | ||
771 | * is at the right place anyway, of course, so | ||
772 | * the if statement is correct. | ||
773 | * | ||
774 | * Warn if we have other data frame types here, | ||
775 | * they must not get here. | ||
776 | */ | ||
777 | WARN_ON(hdr->frame_control & | ||
778 | cpu_to_le16(IEEE80211_STYPE_NULLFUNC)); | ||
779 | WARN_ON(!(hdr->seq_ctrl & | ||
780 | cpu_to_le16(IEEE80211_SCTL_FRAG))); | ||
781 | /* | ||
782 | * This was a fragment of a frame, received while | ||
783 | * a block-ack session was active. That cannot be | ||
784 | * right, so terminate the session. | ||
785 | */ | ||
786 | mutex_lock(&local->sta_mtx); | ||
787 | sta = sta_info_get_bss(sdata, mgmt->sa); | ||
788 | if (sta) { | ||
789 | u16 tid = *ieee80211_get_qos_ctl(hdr) & | ||
790 | IEEE80211_QOS_CTL_TID_MASK; | ||
791 | |||
792 | __ieee80211_stop_rx_ba_session( | ||
793 | sta, tid, WLAN_BACK_RECIPIENT, | ||
794 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
795 | } | ||
796 | mutex_unlock(&local->sta_mtx); | ||
797 | } else switch (sdata->vif.type) { | ||
798 | case NL80211_IFTYPE_STATION: | ||
799 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
800 | break; | ||
801 | case NL80211_IFTYPE_ADHOC: | ||
802 | ieee80211_ibss_rx_queued_mgmt(sdata, skb); | ||
803 | break; | ||
804 | case NL80211_IFTYPE_MESH_POINT: | ||
805 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
806 | break; | ||
807 | ieee80211_mesh_rx_queued_mgmt(sdata, skb); | ||
808 | break; | ||
809 | default: | ||
810 | WARN(1, "frame for unexpected interface type"); | ||
811 | break; | ||
812 | } | ||
813 | |||
814 | kfree_skb(skb); | ||
815 | } | ||
816 | |||
817 | /* then other type-dependent work */ | ||
818 | switch (sdata->vif.type) { | ||
819 | case NL80211_IFTYPE_STATION: | ||
820 | ieee80211_sta_work(sdata); | ||
821 | break; | ||
822 | case NL80211_IFTYPE_ADHOC: | ||
823 | ieee80211_ibss_work(sdata); | ||
824 | break; | ||
825 | case NL80211_IFTYPE_MESH_POINT: | ||
826 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
827 | break; | ||
828 | ieee80211_mesh_work(sdata); | ||
829 | break; | ||
830 | default: | ||
831 | break; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | |||
730 | /* | 836 | /* |
731 | * Helper function to initialise an interface to a specific type. | 837 | * Helper function to initialise an interface to a specific type. |
732 | */ | 838 | */ |
@@ -744,6 +850,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
744 | /* only monitor differs */ | 850 | /* only monitor differs */ |
745 | sdata->dev->type = ARPHRD_ETHER; | 851 | sdata->dev->type = ARPHRD_ETHER; |
746 | 852 | ||
853 | skb_queue_head_init(&sdata->skb_queue); | ||
854 | INIT_WORK(&sdata->work, ieee80211_iface_work); | ||
855 | |||
747 | switch (type) { | 856 | switch (type) { |
748 | case NL80211_IFTYPE_AP: | 857 | case NL80211_IFTYPE_AP: |
749 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 858 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
@@ -969,6 +1078,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
969 | sdata->wdev.wiphy = local->hw.wiphy; | 1078 | sdata->wdev.wiphy = local->hw.wiphy; |
970 | sdata->local = local; | 1079 | sdata->local = local; |
971 | sdata->dev = ndev; | 1080 | sdata->dev = ndev; |
1081 | #ifdef CONFIG_INET | ||
1082 | sdata->arp_filter_state = true; | ||
1083 | #endif | ||
972 | 1084 | ||
973 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) | 1085 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) |
974 | skb_queue_head_init(&sdata->fragments[i].skb_list); | 1086 | skb_queue_head_init(&sdata->fragments[i].skb_list); |