mac80211: keep a separate list of monitor interfaces that are up
authorJohannes Berg <johannes.berg@intel.com>
Thu, 13 Apr 2017 11:28:18 +0000 (13:28 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 18 Apr 2017 09:00:13 +0000 (11:00 +0200)
In addition to keeping monitor interfaces on the regular list of
interfaces, keep those that are up and not in cooked mode on a
separate list. This saves having to iterate all interfaces when
delivering to monitor interfaces.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/rx.c

index 0e718437d080e7258efe75bcba26ce65990671ce..cf6d5abb65a3c4d64564ed923ed0a319f8088899 100644 (file)
@@ -839,6 +839,8 @@ struct txq_info {
 struct ieee80211_if_mntr {
        u32 flags;
        u8 mu_follow_addr[ETH_ALEN] __aligned(2);
+
+       struct list_head list;
 };
 
 /**
@@ -1259,6 +1261,7 @@ struct ieee80211_local {
 
        /* see iface.c */
        struct list_head interfaces;
+       struct list_head mon_list; /* only that are IFF_UP && !cooked */
        struct mutex iflist_mtx;
 
        /*
index 40813dd3301c600978374e259953ca5d661022ce..02d4d6a29b75c7425362da0c17871b9afedd74d0 100644 (file)
@@ -676,7 +676,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_WDS:
                /* Create STA entry for the WDS peer */
                sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
                                     GFP_KERNEL);
@@ -697,8 +698,17 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 
                rate_control_rate_init(sta);
                netif_carrier_on(dev);
-       } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+               break;
+       case NL80211_IFTYPE_P2P_DEVICE:
                rcu_assign_pointer(local->p2p_sdata, sdata);
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
+                       break;
+               list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list);
+               break;
+       default:
+               break;
        }
 
        /*
@@ -816,6 +826,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
                cancel_work_sync(&sdata->u.ap.request_smps_work);
                break;
+       case NL80211_IFTYPE_MONITOR:
+               if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
+                       break;
+               list_del_rcu(&sdata->u.mntr.list);
+               break;
        default:
                break;
        }
index 56fb47953b72420b3ceb4e3f5d27dc9c4d23928b..ae408a96c407839bb518acbcf753cde6edd2a2ba 100644 (file)
@@ -603,6 +603,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                ARRAY_SIZE(local->ext_capa);
 
        INIT_LIST_HEAD(&local->interfaces);
+       INIT_LIST_HEAD(&local->mon_list);
 
        __hw_addr_init(&local->mc_list);
 
index e35c42ebb7a57720dd23cb186d1569f8bdc06e99..638dc63a51bf287a083d0099145db3bfe0ba77dd 100644 (file)
@@ -593,16 +593,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
 
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
-                       continue;
-
-               if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
-                       continue;
-
-               if (!ieee80211_sdata_running(sdata))
-                       continue;
-
+       list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
                if (prev_dev) {
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2) {