mac80211: Send control port frames over nl80211
authorDenis Kenzior <denkenz@gmail.com>
Mon, 26 Mar 2018 17:52:51 +0000 (12:52 -0500)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 29 Mar 2018 12:08:30 +0000 (14:08 +0200)
If userspace requested control port frames to go over 80211, then do so.
The control packets are intercepted just prior to delivery of the packet
to the underlying network device.

Pre-authentication type frames (protocol: 0x88c7) are also forwarded
over nl80211.

Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rx.c

index f6b8d59..85dbaa8 100644 (file)
@@ -926,6 +926,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
         */
        sdata->control_port_protocol = params->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+       sdata->control_port_over_nl80211 =
+                               params->crypto.control_port_over_nl80211;
        sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
                                                        &params->crypto,
                                                        sdata->vif.type);
@@ -935,6 +937,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                        params->crypto.control_port_ethertype;
                vlan->control_port_no_encrypt =
                        params->crypto.control_port_no_encrypt;
+               vlan->control_port_over_nl80211 =
+                       params->crypto.control_port_over_nl80211;
                vlan->encrypt_headroom =
                        ieee80211_cs_headroom(sdata->local,
                                              &params->crypto,
@@ -2020,6 +2024,8 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        if (err)
                return err;
 
+       sdata->control_port_over_nl80211 = setup->control_port_over_nl80211;
+
        /* can mesh use other SMPS modes? */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
index dc582aa..6449a1c 100644 (file)
@@ -1844,6 +1844,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = local->rx_chains;
+       sdata->control_port_over_nl80211 = params->control_port_over_nl80211;
 
        ieee80211_queue_work(&local->hw, &sdata->work);
 
index 275d626..6372dbd 100644 (file)
@@ -900,6 +900,7 @@ struct ieee80211_sub_if_data {
        u16 sequence_number;
        __be16 control_port_protocol;
        bool control_port_no_encrypt;
+       bool control_port_over_nl80211;
        int encrypt_headroom;
 
        atomic_t num_tx_queued;
index d13ba06..555e389 100644 (file)
@@ -519,6 +519,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                        master->control_port_protocol;
                sdata->control_port_no_encrypt =
                        master->control_port_no_encrypt;
+               sdata->control_port_over_nl80211 =
+                       master->control_port_over_nl80211;
                sdata->vif.cab_queue = master->vif.cab_queue;
                memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
                       sizeof(sdata->vif.hw_queue));
index 8d0333b..9ea17af 100644 (file)
@@ -554,6 +554,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                           NL80211_FEATURE_USERSPACE_MPM |
                           NL80211_FEATURE_FULL_AP_CLIENT_STATE;
        wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA);
+       wiphy_ext_feature_set(wiphy,
+                             NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211);
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
index d2bc520..20d2b18 100644 (file)
@@ -4855,6 +4855,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->control_port_protocol = req->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
+       sdata->control_port_over_nl80211 =
+                                       req->crypto.control_port_over_nl80211;
        sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
                                                        sdata->vif.type);
 
index 3a9f0c0..03102af 100644 (file)
@@ -2245,6 +2245,32 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
        return true;
 }
 
+static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
+                                                struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct net_device *dev = sdata->dev;
+
+       if (unlikely((skb->protocol == sdata->control_port_protocol ||
+                     skb->protocol == cpu_to_be16(ETH_P_PREAUTH)) &&
+                    sdata->control_port_over_nl80211)) {
+               struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+               bool noencrypt = status->flag & RX_FLAG_DECRYPTED;
+               struct ethhdr *ehdr = eth_hdr(skb);
+
+               cfg80211_rx_control_port(dev, skb->data, skb->len,
+                                        ehdr->h_source,
+                                        be16_to_cpu(skb->protocol), noencrypt);
+               dev_kfree_skb(skb);
+       } else {
+               /* deliver to local stack */
+               if (rx->napi)
+                       napi_gro_receive(rx->napi, skb);
+               else
+                       netif_receive_skb(skb);
+       }
+}
+
 /*
  * requires that rx->skb is a frame with ethernet header
  */
@@ -2329,13 +2355,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 #endif
 
        if (skb) {
-               /* deliver to local stack */
                skb->protocol = eth_type_trans(skb, dev);
                memset(skb->cb, 0, sizeof(skb->cb));
-               if (rx->napi)
-                       napi_gro_receive(rx->napi, skb);
-               else
-                       netif_receive_skb(skb);
+
+               ieee80211_deliver_skb_to_local_stack(skb, rx);
        }
 
        if (xmit_skb) {