aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c174
1 files changed, 147 insertions, 27 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1afa9ec81fe8..910729fc18cd 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -339,7 +339,6 @@ static int ieee80211_stop(struct net_device *dev)
339{ 339{
340 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 340 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
341 struct ieee80211_local *local = sdata->local; 341 struct ieee80211_local *local = sdata->local;
342 struct sta_info *sta;
343 unsigned long flags; 342 unsigned long flags;
344 struct sk_buff *skb, *tmp; 343 struct sk_buff *skb, *tmp;
345 u32 hw_reconf_flags = 0; 344 u32 hw_reconf_flags = 0;
@@ -356,18 +355,6 @@ static int ieee80211_stop(struct net_device *dev)
356 ieee80211_work_purge(sdata); 355 ieee80211_work_purge(sdata);
357 356
358 /* 357 /*
359 * Now delete all active aggregation sessions.
360 */
361 rcu_read_lock();
362
363 list_for_each_entry_rcu(sta, &local->sta_list, list) {
364 if (sta->sdata == sdata)
365 ieee80211_sta_tear_down_BA_sessions(sta);
366 }
367
368 rcu_read_unlock();
369
370 /*
371 * Remove all stations associated with this interface. 358 * Remove all stations associated with this interface.
372 * 359 *
373 * This must be done before calling ops->remove_interface() 360 * This must be done before calling ops->remove_interface()
@@ -473,27 +460,14 @@ static int ieee80211_stop(struct net_device *dev)
473 * whether the interface is running, which, at this point, 460 * whether the interface is running, which, at this point,
474 * it no longer is. 461 * it no longer is.
475 */ 462 */
476 cancel_work_sync(&sdata->u.mgd.work);
477 cancel_work_sync(&sdata->u.mgd.chswitch_work); 463 cancel_work_sync(&sdata->u.mgd.chswitch_work);
478 cancel_work_sync(&sdata->u.mgd.monitor_work); 464 cancel_work_sync(&sdata->u.mgd.monitor_work);
479 cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); 465 cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
480 466
481 /*
482 * When we get here, the interface is marked down.
483 * Call synchronize_rcu() to wait for the RX path
484 * should it be using the interface and enqueuing
485 * frames at this very time on another CPU.
486 */
487 synchronize_rcu();
488 skb_queue_purge(&sdata->u.mgd.skb_queue);
489 /* fall through */ 467 /* fall through */
490 case NL80211_IFTYPE_ADHOC: 468 case NL80211_IFTYPE_ADHOC:
491 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 469 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
492 del_timer_sync(&sdata->u.ibss.timer); 470 del_timer_sync(&sdata->u.ibss.timer);
493 cancel_work_sync(&sdata->u.ibss.work);
494 synchronize_rcu();
495 skb_queue_purge(&sdata->u.ibss.skb_queue);
496 }
497 /* fall through */ 471 /* fall through */
498 case NL80211_IFTYPE_MESH_POINT: 472 case NL80211_IFTYPE_MESH_POINT:
499 if (ieee80211_vif_is_mesh(&sdata->vif)) { 473 if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -508,6 +482,16 @@ static int ieee80211_stop(struct net_device *dev)
508 } 482 }
509 /* fall through */ 483 /* fall through */
510 default: 484 default:
485 flush_work(&sdata->work);
486 /*
487 * When we get here, the interface is marked down.
488 * Call synchronize_rcu() to wait for the RX path
489 * should it be using the interface and enqueuing
490 * frames at this very time on another CPU.
491 */
492 synchronize_rcu();
493 skb_queue_purge(&sdata->skb_queue);
494
511 if (local->scan_sdata == sdata) 495 if (local->scan_sdata == sdata)
512 ieee80211_scan_cancel(local); 496 ieee80211_scan_cancel(local);
513 497
@@ -717,6 +701,136 @@ static void ieee80211_if_setup(struct net_device *dev)
717 dev->destructor = free_netdev; 701 dev->destructor = free_netdev;
718} 702}
719 703
704static void ieee80211_iface_work(struct work_struct *work)
705{
706 struct ieee80211_sub_if_data *sdata =
707 container_of(work, struct ieee80211_sub_if_data, work);
708 struct ieee80211_local *local = sdata->local;
709 struct sk_buff *skb;
710 struct sta_info *sta;
711 struct ieee80211_ra_tid *ra_tid;
712
713 if (!ieee80211_sdata_running(sdata))
714 return;
715
716 if (local->scanning)
717 return;
718
719 /*
720 * ieee80211_queue_work() should have picked up most cases,
721 * here we'll pick the rest.
722 */
723 if (WARN(local->suspended,
724 "interface work scheduled while going to suspend\n"))
725 return;
726
727 /* first process frames */
728 while ((skb = skb_dequeue(&sdata->skb_queue))) {
729 struct ieee80211_mgmt *mgmt = (void *)skb->data;
730
731 if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) {
732 ra_tid = (void *)&skb->cb;
733 ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra,
734 ra_tid->tid);
735 } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) {
736 ra_tid = (void *)&skb->cb;
737 ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra,
738 ra_tid->tid);
739 } else if (ieee80211_is_action(mgmt->frame_control) &&
740 mgmt->u.action.category == WLAN_CATEGORY_BACK) {
741 int len = skb->len;
742
743 mutex_lock(&local->sta_mtx);
744 sta = sta_info_get(sdata, mgmt->sa);
745 if (sta) {
746 switch (mgmt->u.action.u.addba_req.action_code) {
747 case WLAN_ACTION_ADDBA_REQ:
748 ieee80211_process_addba_request(
749 local, sta, mgmt, len);
750 break;
751 case WLAN_ACTION_ADDBA_RESP:
752 ieee80211_process_addba_resp(local, sta,
753 mgmt, len);
754 break;
755 case WLAN_ACTION_DELBA:
756 ieee80211_process_delba(sdata, sta,
757 mgmt, len);
758 break;
759 default:
760 WARN_ON(1);
761 break;
762 }
763 }
764 mutex_unlock(&local->sta_mtx);
765 } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
766 struct ieee80211_hdr *hdr = (void *)mgmt;
767 /*
768 * So the frame isn't mgmt, but frame_control
769 * is at the right place anyway, of course, so
770 * the if statement is correct.
771 *
772 * Warn if we have other data frame types here,
773 * they must not get here.
774 */
775 WARN_ON(hdr->frame_control &
776 cpu_to_le16(IEEE80211_STYPE_NULLFUNC));
777 WARN_ON(!(hdr->seq_ctrl &
778 cpu_to_le16(IEEE80211_SCTL_FRAG)));
779 /*
780 * This was a fragment of a frame, received while
781 * a block-ack session was active. That cannot be
782 * right, so terminate the session.
783 */
784 mutex_lock(&local->sta_mtx);
785 sta = sta_info_get(sdata, mgmt->sa);
786 if (sta) {
787 u16 tid = *ieee80211_get_qos_ctl(hdr) &
788 IEEE80211_QOS_CTL_TID_MASK;
789
790 __ieee80211_stop_rx_ba_session(
791 sta, tid, WLAN_BACK_RECIPIENT,
792 WLAN_REASON_QSTA_REQUIRE_SETUP);
793 }
794 mutex_unlock(&local->sta_mtx);
795 } else switch (sdata->vif.type) {
796 case NL80211_IFTYPE_STATION:
797 ieee80211_sta_rx_queued_mgmt(sdata, skb);
798 break;
799 case NL80211_IFTYPE_ADHOC:
800 ieee80211_ibss_rx_queued_mgmt(sdata, skb);
801 break;
802 case NL80211_IFTYPE_MESH_POINT:
803 if (!ieee80211_vif_is_mesh(&sdata->vif))
804 break;
805 ieee80211_mesh_rx_queued_mgmt(sdata, skb);
806 break;
807 default:
808 WARN(1, "frame for unexpected interface type");
809 break;
810 }
811
812 kfree_skb(skb);
813 }
814
815 /* then other type-dependent work */
816 switch (sdata->vif.type) {
817 case NL80211_IFTYPE_STATION:
818 ieee80211_sta_work(sdata);
819 break;
820 case NL80211_IFTYPE_ADHOC:
821 ieee80211_ibss_work(sdata);
822 break;
823 case NL80211_IFTYPE_MESH_POINT:
824 if (!ieee80211_vif_is_mesh(&sdata->vif))
825 break;
826 ieee80211_mesh_work(sdata);
827 break;
828 default:
829 break;
830 }
831}
832
833
720/* 834/*
721 * Helper function to initialise an interface to a specific type. 835 * Helper function to initialise an interface to a specific type.
722 */ 836 */
@@ -734,6 +848,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
734 /* only monitor differs */ 848 /* only monitor differs */
735 sdata->dev->type = ARPHRD_ETHER; 849 sdata->dev->type = ARPHRD_ETHER;
736 850
851 skb_queue_head_init(&sdata->skb_queue);
852 INIT_WORK(&sdata->work, ieee80211_iface_work);
853
737 switch (type) { 854 switch (type) {
738 case NL80211_IFTYPE_AP: 855 case NL80211_IFTYPE_AP:
739 skb_queue_head_init(&sdata->u.ap.ps_bc_buf); 856 skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
@@ -959,6 +1076,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
959 sdata->wdev.wiphy = local->hw.wiphy; 1076 sdata->wdev.wiphy = local->hw.wiphy;
960 sdata->local = local; 1077 sdata->local = local;
961 sdata->dev = ndev; 1078 sdata->dev = ndev;
1079#ifdef CONFIG_INET
1080 sdata->arp_filter_state = true;
1081#endif
962 1082
963 for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) 1083 for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
964 skb_queue_head_init(&sdata->fragments[i].skb_list); 1084 skb_queue_head_init(&sdata->fragments[i].skb_list);