Merge tag 'v3.16-rc4' into drm-intel-next-queued
[deliverable/linux.git] / net / mac80211 / cfg.c
index 7b8d3cf8957407f2decb1c87a3307e45055b9213..d7513a503be11b180031342dcf316450fd6c69d3 100644 (file)
@@ -472,8 +472,10 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
+       struct rate_control_ref *ref = local->rate_ctrl;
        struct timespec uptime;
        u64 packets = 0;
+       u32 thr = 0;
        int i, ac;
 
        sinfo->generation = sdata->local->sta_generation;
@@ -587,6 +589,17 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+       /* check if the driver has a SW RC implementation */
+       if (ref && ref->ops->get_expected_throughput)
+               thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv);
+       else
+               thr = drv_get_expected_throughput(local, &sta->sta);
+
+       if (thr != 0) {
+               sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+               sinfo->expected_throughput = thr;
+       }
 }
 
 static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
@@ -777,7 +790,7 @@ static void ieee80211_get_et_strings(struct wiphy *wiphy,
 }
 
 static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
-                                int idx, u8 *mac, struct station_info *sinfo)
+                                 int idx, u8 *mac, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -807,7 +820,7 @@ static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
-                                u8 *mac, struct station_info *sinfo)
+                                const u8 *mac, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1084,6 +1097,31 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+bool ieee80211_csa_needs_block_tx(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       lockdep_assert_held(&local->mtx);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (!sdata->vif.csa_active)
+                       continue;
+
+               if (!sdata->csa_block_tx)
+                       continue;
+
+               rcu_read_unlock();
+               return true;
+       }
+       rcu_read_unlock();
+
+       return false;
+}
+
 static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1101,7 +1139,14 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
 
        /* abort any running channel switch */
+       mutex_lock(&local->mtx);
        sdata->vif.csa_active = false;
+       if (!ieee80211_csa_needs_block_tx(local))
+               ieee80211_wake_queues_by_reason(&local->hw,
+                                       IEEE80211_MAX_QUEUE_MAP,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+       mutex_unlock(&local->mtx);
+
        kfree(sdata->u.ap.next_beacon);
        sdata->u.ap.next_beacon = NULL;
 
@@ -1425,7 +1470,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
 }
 
 static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
-                                u8 *mac, struct station_parameters *params)
+                                const u8 *mac,
+                                struct station_parameters *params)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
@@ -1459,6 +1505,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
                sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
                sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       } else {
+               sta->sta.tdls = true;
        }
 
        err = sta_apply_parameters(local, sta, params);
@@ -1492,7 +1540,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                                u8 *mac)
+                                const u8 *mac)
 {
        struct ieee80211_sub_if_data *sdata;
 
@@ -1506,7 +1554,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_change_station(struct wiphy *wiphy,
-                                   struct net_device *dev, u8 *mac,
+                                   struct net_device *dev, const u8 *mac,
                                    struct station_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1631,7 +1679,7 @@ out_err:
 
 #ifdef CONFIG_MAC80211_MESH
 static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
-                                u8 *dst, u8 *next_hop)
+                              const u8 *dst, const u8 *next_hop)
 {
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
@@ -1659,7 +1707,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
-                              u8 *dst)
+                              const u8 *dst)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -1670,9 +1718,8 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
-static int ieee80211_change_mpath(struct wiphy *wiphy,
-                                   struct net_device *dev,
-                                   u8 *dst, u8 *next_hop)
+static int ieee80211_change_mpath(struct wiphy *wiphy, struct net_device *dev,
+                                 const u8 *dst, const u8 *next_hop)
 {
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
@@ -1764,8 +1811,8 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
-                                int idx, u8 *dst, u8 *next_hop,
-                                struct mpath_info *pinfo)
+                               int idx, u8 *dst, u8 *next_hop,
+                               struct mpath_info *pinfo)
 {
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
@@ -3019,26 +3066,11 @@ void ieee80211_csa_finish(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_csa_finish);
 
-static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
+                                         u32 *changed)
 {
-       struct ieee80211_local *local = sdata->local;
-       int err, changed = 0;
-
-       sdata_assert_lock(sdata);
-
-       mutex_lock(&local->mtx);
-       sdata->radar_required = sdata->csa_radar_required;
-       err = ieee80211_vif_change_channel(sdata, &changed);
-       mutex_unlock(&local->mtx);
-       if (WARN_ON(err < 0))
-               return;
-
-       if (!local->use_chanctx) {
-               local->_oper_chandef = sdata->csa_chandef;
-               ieee80211_hw_config(local, 0);
-       }
+       int err;
 
-       sdata->vif.csa_active = false;
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
                err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
@@ -3046,35 +3078,74 @@ static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                sdata->u.ap.next_beacon = NULL;
 
                if (err < 0)
-                       return;
-               changed |= err;
+                       return err;
+               *changed |= err;
                break;
        case NL80211_IFTYPE_ADHOC:
                err = ieee80211_ibss_finish_csa(sdata);
                if (err < 0)
-                       return;
-               changed |= err;
+                       return err;
+               *changed |= err;
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
                err = ieee80211_mesh_finish_csa(sdata);
                if (err < 0)
-                       return;
-               changed |= err;
+                       return err;
+               *changed |= err;
                break;
 #endif
        default:
                WARN_ON(1);
-               return;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       u32 changed = 0;
+       int err;
+
+       sdata_assert_lock(sdata);
+       lockdep_assert_held(&local->mtx);
+
+       sdata->radar_required = sdata->csa_radar_required;
+       err = ieee80211_vif_change_channel(sdata, &changed);
+       if (err < 0)
+               return err;
+
+       if (!local->use_chanctx) {
+               local->_oper_chandef = sdata->csa_chandef;
+               ieee80211_hw_config(local, 0);
        }
 
+       sdata->vif.csa_active = false;
+
+       err = ieee80211_set_after_csa_beacon(sdata, &changed);
+       if (err)
+               return err;
+
        ieee80211_bss_info_change_notify(sdata, changed);
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
-       ieee80211_wake_queues_by_reason(&sdata->local->hw,
+       if (!ieee80211_csa_needs_block_tx(local))
+               ieee80211_wake_queues_by_reason(&local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+       return 0;
+}
+
+static void ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
+{
+       if (__ieee80211_csa_finalize(sdata)) {
+               sdata_info(sdata, "failed to finalize CSA, disconnecting\n");
+               cfg80211_stop_iface(sdata->local->hw.wiphy, &sdata->wdev,
+                                   GFP_KERNEL);
+       }
 }
 
 void ieee80211_csa_finalize_work(struct work_struct *work)
@@ -3082,8 +3153,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        struct ieee80211_sub_if_data *sdata =
                container_of(work, struct ieee80211_sub_if_data,
                             csa_finalize_work);
+       struct ieee80211_local *local = sdata->local;
 
        sdata_lock(sdata);
+       mutex_lock(&local->mtx);
+
        /* AP might have been stopped while waiting for the lock. */
        if (!sdata->vif.csa_active)
                goto unlock;
@@ -3094,6 +3168,7 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        ieee80211_csa_finalize(sdata);
 
 unlock:
+       mutex_unlock(&local->mtx);
        sdata_unlock(sdata);
 }
 
@@ -3129,9 +3204,25 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
                if (params->count <= 1)
                        break;
 
-               sdata->csa_counter_offset_beacon =
-                       params->counter_offset_beacon;
-               sdata->csa_counter_offset_presp = params->counter_offset_presp;
+               if ((params->n_counter_offsets_beacon >
+                    IEEE80211_MAX_CSA_COUNTERS_NUM) ||
+                   (params->n_counter_offsets_presp >
+                    IEEE80211_MAX_CSA_COUNTERS_NUM))
+                       return -EINVAL;
+
+               /* make sure we don't have garbage in other counters */
+               memset(sdata->csa_counter_offset_beacon, 0,
+                      sizeof(sdata->csa_counter_offset_beacon));
+               memset(sdata->csa_counter_offset_presp, 0,
+                      sizeof(sdata->csa_counter_offset_presp));
+
+               memcpy(sdata->csa_counter_offset_beacon,
+                      params->counter_offsets_beacon,
+                      params->n_counter_offsets_beacon * sizeof(u16));
+               memcpy(sdata->csa_counter_offset_presp,
+                      params->counter_offsets_presp,
+                      params->n_counter_offsets_presp * sizeof(u16));
+
                err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
                if (err < 0) {
                        kfree(sdata->u.ap.next_beacon);
@@ -3220,8 +3311,9 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
-                            struct cfg80211_csa_settings *params)
+static int
+__ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+                          struct cfg80211_csa_settings *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -3230,6 +3322,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        int err, num_chanctx, changed = 0;
 
        sdata_assert_lock(sdata);
+       lockdep_assert_held(&local->mtx);
 
        if (!list_empty(&local->roc_list) || local->scanning)
                return -EBUSY;
@@ -3272,15 +3365,16 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                return err;
 
        sdata->csa_radar_required = params->radar_required;
-
-       if (params->block_tx)
-               ieee80211_stop_queues_by_reason(&local->hw,
-                               IEEE80211_MAX_QUEUE_MAP,
-                               IEEE80211_QUEUE_STOP_REASON_CSA);
-
        sdata->csa_chandef = params->chandef;
+       sdata->csa_block_tx = params->block_tx;
+       sdata->csa_current_counter = params->count;
        sdata->vif.csa_active = true;
 
+       if (sdata->csa_block_tx)
+               ieee80211_stop_queues_by_reason(&local->hw,
+                                       IEEE80211_MAX_QUEUE_MAP,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+
        if (changed) {
                ieee80211_bss_info_change_notify(sdata, changed);
                drv_channel_switch_beacon(sdata, &params->chandef);
@@ -3292,6 +3386,20 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+                            struct cfg80211_csa_settings *params)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       int err;
+
+       mutex_lock(&local->mtx);
+       err = __ieee80211_channel_switch(wiphy, dev, params);
+       mutex_unlock(&local->mtx);
+
+       return err;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                             struct cfg80211_mgmt_tx_params *params,
                             u64 *cookie)
@@ -3304,6 +3412,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        bool need_offchan = false;
        u32 flags;
        int ret;
+       u8 *data;
 
        if (params->dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
@@ -3397,7 +3506,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
 
-       memcpy(skb_put(skb, params->len), params->buf, params->len);
+       data = skb_put(skb, params->len);
+       memcpy(data, params->buf, params->len);
+
+       /* Update CSA counters */
+       if (sdata->vif.csa_active &&
+           (sdata->vif.type == NL80211_IFTYPE_AP ||
+            sdata->vif.type == NL80211_IFTYPE_ADHOC) &&
+           params->n_csa_offsets) {
+               int i;
+               u8 c = sdata->csa_current_counter;
+
+               for (i = 0; i < params->n_csa_offsets; i++)
+                       data[params->csa_offsets[i]] = c;
+       }
 
        IEEE80211_SKB_CB(skb)->flags = flags;
 
@@ -3506,320 +3628,6 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
        return 0;
 }
 
-static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
-{
-       u8 *pos = (void *)skb_put(skb, 7);
-
-       *pos++ = WLAN_EID_EXT_CAPABILITY;
-       *pos++ = 5; /* len */
-       *pos++ = 0x0;
-       *pos++ = 0x0;
-       *pos++ = 0x0;
-       *pos++ = 0x0;
-       *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
-}
-
-static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       u16 capab;
-
-       capab = 0;
-       if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
-               return capab;
-
-       if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
-               capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
-       if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
-               capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
-
-       return capab;
-}
-
-static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
-                                      u8 *peer, u8 *bssid)
-{
-       struct ieee80211_tdls_lnkie *lnkid;
-
-       lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
-
-       lnkid->ie_type = WLAN_EID_LINK_ID;
-       lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
-
-       memcpy(lnkid->bssid, bssid, ETH_ALEN);
-       memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
-       memcpy(lnkid->resp_sta, peer, ETH_ALEN);
-}
-
-static int
-ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
-                              u8 *peer, u8 action_code, u8 dialog_token,
-                              u16 status_code, struct sk_buff *skb)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-       struct ieee80211_tdls_data *tf;
-
-       tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
-
-       memcpy(tf->da, peer, ETH_ALEN);
-       memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
-       tf->ether_type = cpu_to_be16(ETH_P_TDLS);
-       tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
-
-       switch (action_code) {
-       case WLAN_TDLS_SETUP_REQUEST:
-               tf->category = WLAN_CATEGORY_TDLS;
-               tf->action_code = WLAN_TDLS_SETUP_REQUEST;
-
-               skb_put(skb, sizeof(tf->u.setup_req));
-               tf->u.setup_req.dialog_token = dialog_token;
-               tf->u.setup_req.capability =
-                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
-
-               ieee80211_add_srates_ie(sdata, skb, false, band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-               ieee80211_tdls_add_ext_capab(skb);
-               break;
-       case WLAN_TDLS_SETUP_RESPONSE:
-               tf->category = WLAN_CATEGORY_TDLS;
-               tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
-
-               skb_put(skb, sizeof(tf->u.setup_resp));
-               tf->u.setup_resp.status_code = cpu_to_le16(status_code);
-               tf->u.setup_resp.dialog_token = dialog_token;
-               tf->u.setup_resp.capability =
-                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
-
-               ieee80211_add_srates_ie(sdata, skb, false, band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-               ieee80211_tdls_add_ext_capab(skb);
-               break;
-       case WLAN_TDLS_SETUP_CONFIRM:
-               tf->category = WLAN_CATEGORY_TDLS;
-               tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
-
-               skb_put(skb, sizeof(tf->u.setup_cfm));
-               tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
-               tf->u.setup_cfm.dialog_token = dialog_token;
-               break;
-       case WLAN_TDLS_TEARDOWN:
-               tf->category = WLAN_CATEGORY_TDLS;
-               tf->action_code = WLAN_TDLS_TEARDOWN;
-
-               skb_put(skb, sizeof(tf->u.teardown));
-               tf->u.teardown.reason_code = cpu_to_le16(status_code);
-               break;
-       case WLAN_TDLS_DISCOVERY_REQUEST:
-               tf->category = WLAN_CATEGORY_TDLS;
-               tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
-
-               skb_put(skb, sizeof(tf->u.discover_req));
-               tf->u.discover_req.dialog_token = dialog_token;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int
-ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
-                          u8 *peer, u8 action_code, u8 dialog_token,
-                          u16 status_code, struct sk_buff *skb)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-       struct ieee80211_mgmt *mgmt;
-
-       mgmt = (void *)skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       memcpy(mgmt->da, peer, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
-       memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                         IEEE80211_STYPE_ACTION);
-
-       switch (action_code) {
-       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-               skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
-               mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
-               mgmt->u.action.u.tdls_discover_resp.action_code =
-                       WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
-               mgmt->u.action.u.tdls_discover_resp.dialog_token =
-                       dialog_token;
-               mgmt->u.action.u.tdls_discover_resp.capability =
-                       cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
-
-               ieee80211_add_srates_ie(sdata, skb, false, band);
-               ieee80211_add_ext_srates_ie(sdata, skb, false, band);
-               ieee80211_tdls_add_ext_capab(skb);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
-                              u8 *peer, u8 action_code, u8 dialog_token,
-                              u16 status_code, u32 peer_capability,
-                              const u8 *extra_ies, size_t extra_ies_len)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = NULL;
-       bool send_direct;
-       int ret;
-
-       if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
-               return -ENOTSUPP;
-
-       /* make sure we are in managed mode, and associated */
-       if (sdata->vif.type != NL80211_IFTYPE_STATION ||
-           !sdata->u.mgd.associated)
-               return -EINVAL;
-
-       tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
-                action_code, peer);
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           max(sizeof(struct ieee80211_mgmt),
-                               sizeof(struct ieee80211_tdls_data)) +
-                           50 + /* supported rates */
-                           7 + /* ext capab */
-                           extra_ies_len +
-                           sizeof(struct ieee80211_tdls_lnkie));
-       if (!skb)
-               return -ENOMEM;
-
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       switch (action_code) {
-       case WLAN_TDLS_SETUP_REQUEST:
-       case WLAN_TDLS_SETUP_RESPONSE:
-       case WLAN_TDLS_SETUP_CONFIRM:
-       case WLAN_TDLS_TEARDOWN:
-       case WLAN_TDLS_DISCOVERY_REQUEST:
-               ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
-                                                    action_code, dialog_token,
-                                                    status_code, skb);
-               send_direct = false;
-               break;
-       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-               ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
-                                                dialog_token, status_code,
-                                                skb);
-               send_direct = true;
-               break;
-       default:
-               ret = -ENOTSUPP;
-               break;
-       }
-
-       if (ret < 0)
-               goto fail;
-
-       if (extra_ies_len)
-               memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
-
-       /* the TDLS link IE is always added last */
-       switch (action_code) {
-       case WLAN_TDLS_SETUP_REQUEST:
-       case WLAN_TDLS_SETUP_CONFIRM:
-       case WLAN_TDLS_TEARDOWN:
-       case WLAN_TDLS_DISCOVERY_REQUEST:
-               /* we are the initiator */
-               ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
-                                          sdata->u.mgd.bssid);
-               break;
-       case WLAN_TDLS_SETUP_RESPONSE:
-       case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
-               /* we are the responder */
-               ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
-                                          sdata->u.mgd.bssid);
-               break;
-       default:
-               ret = -ENOTSUPP;
-               goto fail;
-       }
-
-       if (send_direct) {
-               ieee80211_tx_skb(sdata, skb);
-               return 0;
-       }
-
-       /*
-        * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
-        * we should default to AC_VI.
-        */
-       switch (action_code) {
-       case WLAN_TDLS_SETUP_REQUEST:
-       case WLAN_TDLS_SETUP_RESPONSE:
-               skb_set_queue_mapping(skb, IEEE80211_AC_BK);
-               skb->priority = 2;
-               break;
-       default:
-               skb_set_queue_mapping(skb, IEEE80211_AC_VI);
-               skb->priority = 5;
-               break;
-       }
-
-       /* disable bottom halves when entering the Tx path */
-       local_bh_disable();
-       ret = ieee80211_subif_start_xmit(skb, dev);
-       local_bh_enable();
-
-       return ret;
-
-fail:
-       dev_kfree_skb(skb);
-       return ret;
-}
-
-static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
-                              u8 *peer, enum nl80211_tdls_operation oper)
-{
-       struct sta_info *sta;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
-               return -ENOTSUPP;
-
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
-               return -EINVAL;
-
-       tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
-
-       switch (oper) {
-       case NL80211_TDLS_ENABLE_LINK:
-               rcu_read_lock();
-               sta = sta_info_get(sdata, peer);
-               if (!sta) {
-                       rcu_read_unlock();
-                       return -ENOLINK;
-               }
-
-               set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
-               rcu_read_unlock();
-               break;
-       case NL80211_TDLS_DISABLE_LINK:
-               return sta_info_destroy_addr(sdata, peer);
-       case NL80211_TDLS_TEARDOWN:
-       case NL80211_TDLS_SETUP:
-       case NL80211_TDLS_DISCOVERY_REQ:
-               /* We don't support in-driver setup/teardown/discovery */
-               return -ENOTSUPP;
-       default:
-               return -ENOTSUPP;
-       }
-
-       return 0;
-}
-
 static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
                                  const u8 *peer, u64 *cookie)
 {
This page took 0.034005 seconds and 5 git commands to generate.