Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / cfg.c
index a6893602f87a753ebafeae0d0b8f449bdc7251f7..c50c19402588807482ef7d7aad715818eed4bb90 100644 (file)
@@ -175,7 +175,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                 *       add it to the device after the station.
                 */
                if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
-                       ieee80211_key_free(sdata->local, key);
+                       ieee80211_key_free_unused(key);
                        err = -ENOENT;
                        goto out_unlock;
                }
@@ -214,8 +214,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        }
 
        err = ieee80211_key_link(key, sdata, sta);
-       if (err)
-               ieee80211_key_free(sdata->local, key);
 
  out_unlock:
        mutex_unlock(&sdata->local->sta_mtx);
@@ -254,7 +252,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                goto out_unlock;
        }
 
-       __ieee80211_key_free(key);
+       ieee80211_key_free(key, true);
 
        ret = 0;
  out_unlock:
@@ -445,12 +443,14 @@ 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 timespec uptime;
+       u64 packets = 0;
+       int ac;
 
        sinfo->generation = sdata->local->sta_generation;
 
        sinfo->filled = STATION_INFO_INACTIVE_TIME |
-                       STATION_INFO_RX_BYTES |
-                       STATION_INFO_TX_BYTES |
+                       STATION_INFO_RX_BYTES64 |
+                       STATION_INFO_TX_BYTES64 |
                        STATION_INFO_RX_PACKETS |
                        STATION_INFO_TX_PACKETS |
                        STATION_INFO_TX_RETRIES |
@@ -467,10 +467,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        sinfo->connected_time = uptime.tv_sec - sta->last_connected;
 
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+       sinfo->tx_bytes = 0;
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               sinfo->tx_bytes += sta->tx_bytes[ac];
+               packets += sta->tx_packets[ac];
+       }
+       sinfo->tx_packets = packets;
        sinfo->rx_bytes = sta->rx_bytes;
-       sinfo->tx_bytes = sta->tx_bytes;
        sinfo->rx_packets = sta->rx_packets;
-       sinfo->tx_packets = sta->tx_packets;
        sinfo->tx_retries = sta->tx_retry_count;
        sinfo->tx_failed = sta->tx_retry_failed;
        sinfo->rx_dropped_misc = sta->rx_dropped;
@@ -598,8 +602,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                data[i++] += sta->rx_fragments;         \
                data[i++] += sta->rx_dropped;           \
                                                        \
-               data[i++] += sta->tx_packets;           \
-               data[i++] += sta->tx_bytes;             \
+               data[i++] += sinfo.tx_packets;          \
+               data[i++] += sinfo.tx_bytes;            \
                data[i++] += sta->tx_fragments;         \
                data[i++] += sta->tx_filtered_count;    \
                data[i++] += sta->tx_retry_failed;      \
@@ -621,13 +625,14 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
                        goto do_survey;
 
+               sinfo.filled = 0;
+               sta_set_sinfo(sta, &sinfo);
+
                i = 0;
                ADD_STA_STATS(sta);
 
                data[i++] = sta->sta_state;
 
-               sinfo.filled = 0;
-               sta_set_sinfo(sta, &sinfo);
 
                if (sinfo.filled & STATION_INFO_TX_BITRATE)
                        data[i] = 100000 *
@@ -1035,9 +1040,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
                sta_info_flush_defer(vlan);
        sta_info_flush_defer(sdata);
        rcu_barrier();
-       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
                sta_info_flush_cleanup(vlan);
+               ieee80211_free_keys(vlan);
+       }
        sta_info_flush_cleanup(sdata);
+       ieee80211_free_keys(sdata);
 
        sdata->vif.bss_conf.enable_beacon = false;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
@@ -1177,6 +1185,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                        mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
                if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
                        set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+       } else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+               /*
+                * TDLS -- everything follows authorized, but
+                * only becoming authorized is possible, not
+                * going back
+                */
+               if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+                       set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                              BIT(NL80211_STA_FLAG_ASSOCIATED);
+                       mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_ASSOCIATED);
+               }
        }
 
        ret = sta_apply_auth_flags(local, sta, mask, set);
@@ -1261,7 +1281,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
                u32 changed = 0;
-               if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
+
+               if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) {
                        switch (params->plink_state) {
                        case NL80211_PLINK_ESTAB:
                                if (sta->plink_state != NL80211_PLINK_ESTAB)
@@ -1292,15 +1313,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                                /*  nothing  */
                                break;
                        }
-               } else {
-                       switch (params->plink_action) {
-                       case PLINK_ACTION_OPEN:
-                               changed |= mesh_plink_open(sta);
-                               break;
-                       case PLINK_ACTION_BLOCK:
-                               changed |= mesh_plink_block(sta);
-                               break;
-                       }
+               }
+
+               switch (params->plink_action) {
+               case NL80211_PLINK_ACTION_NO_ACTION:
+                       /* nothing */
+                       break;
+               case NL80211_PLINK_ACTION_OPEN:
+                       changed |= mesh_plink_open(sta);
+                       break;
+               case NL80211_PLINK_ACTION_BLOCK:
+                       changed |= mesh_plink_block(sta);
+                       break;
                }
 
                if (params->local_pm)
@@ -1346,8 +1370,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
         * defaults -- if userspace wants something else we'll
         * change it accordingly in sta_apply_parameters()
         */
-       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       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);
+       }
 
        err = sta_apply_parameters(local, sta, params);
        if (err) {
@@ -1356,8 +1382,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        }
 
        /*
-        * for TDLS, rate control should be initialized only when supported
-        * rates are known.
+        * for TDLS, rate control should be initialized only when
+        * rates are known and station is marked authorized
         */
        if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
                rate_control_rate_init(sta);
@@ -1394,50 +1420,67 @@ 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, u8 *mac,
                                    struct station_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
+       enum cfg80211_station_type statype;
        int err;
 
        mutex_lock(&local->sta_mtx);
 
        sta = sta_info_get_bss(sdata, mac);
        if (!sta) {
-               mutex_unlock(&local->sta_mtx);
-               return -ENOENT;
+               err = -ENOENT;
+               goto out_err;
        }
 
-       /* in station mode, some updates are only valid with TDLS */
-       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-           (params->supported_rates || params->ht_capa || params->vht_capa ||
-            params->sta_modify_mask ||
-            (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) &&
-           !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
-               mutex_unlock(&local->sta_mtx);
-               return -EINVAL;
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_MESH_POINT:
+               if (sdata->u.mesh.user_mpm)
+                       statype = CFG80211_STA_MESH_PEER_USER;
+               else
+                       statype = CFG80211_STA_MESH_PEER_KERNEL;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               statype = CFG80211_STA_IBSS;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+                       statype = CFG80211_STA_AP_STA;
+                       break;
+               }
+               if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+                       statype = CFG80211_STA_TDLS_PEER_ACTIVE;
+               else
+                       statype = CFG80211_STA_TDLS_PEER_SETUP;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+               statype = CFG80211_STA_AP_CLIENT;
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               goto out_err;
        }
 
+       err = cfg80211_check_station_change(wiphy, params, statype);
+       if (err)
+               goto out_err;
+
        if (params->vlan && params->vlan != sta->sdata->dev) {
                bool prev_4addr = false;
                bool new_4addr = false;
 
                vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
-               if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-                   vlansdata->vif.type != NL80211_IFTYPE_AP) {
-                       mutex_unlock(&local->sta_mtx);
-                       return -EINVAL;
-               }
-
                if (params->vlan->ieee80211_ptr->use_4addr) {
                        if (vlansdata->u.vlan.sta) {
-                               mutex_unlock(&local->sta_mtx);
-                               return -EBUSY;
+                               err = -EBUSY;
+                               goto out_err;
                        }
 
                        rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
@@ -1464,12 +1507,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
        }
 
        err = sta_apply_parameters(local, sta, params);
-       if (err) {
-               mutex_unlock(&local->sta_mtx);
-               return err;
-       }
+       if (err)
+               goto out_err;
 
-       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+       /* When peer becomes authorized, init rate control as well */
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                rate_control_rate_init(sta);
 
        mutex_unlock(&local->sta_mtx);
@@ -1479,7 +1522,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                ieee80211_recalc_ps(local, -1);
                ieee80211_recalc_ps_vif(sdata);
        }
+
        return 0;
+out_err:
+       mutex_unlock(&local->sta_mtx);
+       return err;
 }
 
 #ifdef CONFIG_MAC80211_MESH
@@ -1687,6 +1734,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        ifmsh->mesh_sp_id = setup->sync_method;
        ifmsh->mesh_pp_id = setup->path_sel_proto;
        ifmsh->mesh_pm_id = setup->path_metric;
+       ifmsh->user_mpm = setup->user_mpm;
        ifmsh->security = IEEE80211_MESH_SEC_NONE;
        if (setup->is_authenticated)
                ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
@@ -1730,8 +1778,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
                conf->dot11MeshTTL = nconf->dot11MeshTTL;
        if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
                conf->element_ttl = nconf->element_ttl;
-       if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
+       if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) {
+               if (ifmsh->user_mpm)
+                       return -EBUSY;
                conf->auto_open_plinks = nconf->auto_open_plinks;
+       }
        if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
                conf->dot11MeshNbrOffsetMaxNeighbor =
                        nconf->dot11MeshNbrOffsetMaxNeighbor;
@@ -2371,7 +2422,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_channel *channel,
                                    unsigned int duration, u64 *cookie,
-                                   struct sk_buff *txskb)
+                                   struct sk_buff *txskb,
+                                   enum ieee80211_roc_type type)
 {
        struct ieee80211_roc_work *roc, *tmp;
        bool queued = false;
@@ -2390,6 +2442,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        roc->duration = duration;
        roc->req_duration = duration;
        roc->frame = txskb;
+       roc->type = type;
        roc->mgmt_tx_cookie = (unsigned long)txskb;
        roc->sdata = sdata;
        INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
@@ -2420,7 +2473,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        if (!duration)
                duration = 10;
 
-       ret = drv_remain_on_channel(local, sdata, channel, duration);
+       ret = drv_remain_on_channel(local, sdata, channel, duration, type);
        if (ret) {
                kfree(roc);
                return ret;
@@ -2439,10 +2492,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                 *
                 * If it hasn't started yet, just increase the duration
                 * and add the new one to the list of dependents.
+                * If the type of the new ROC has higher priority, modify the
+                * type of the previous one to match that of the new one.
                 */
                if (!tmp->started) {
                        list_add_tail(&roc->list, &tmp->dependents);
                        tmp->duration = max(tmp->duration, roc->duration);
+                       tmp->type = max(tmp->type, roc->type);
                        queued = true;
                        break;
                }
@@ -2454,16 +2510,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                        /*
                         * In the offloaded ROC case, if it hasn't begun, add
                         * this new one to the dependent list to be handled
-                        * when the the master one begins. If it has begun,
+                        * when the master one begins. If it has begun,
                         * check that there's still a minimum time left and
                         * if so, start this one, transmitting the frame, but
-                        * add it to the list directly after this one with a
+                        * add it to the list directly after this one with
                         * a reduced time so we'll ask the driver to execute
                         * it right after finishing the previous one, in the
                         * hope that it'll also be executed right afterwards,
                         * effectively extending the old one.
                         * If there's no minimum time left, just add it to the
                         * normal list.
+                        * TODO: the ROC type is ignored here, assuming that it
+                        * is better to immediately use the current ROC.
                         */
                        if (!tmp->hw_begun) {
                                list_add_tail(&roc->list, &tmp->dependents);
@@ -2557,7 +2615,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
 
        mutex_lock(&local->mtx);
        ret = ieee80211_start_roc_work(local, sdata, chan,
-                                      duration, cookie, NULL);
+                                      duration, cookie, NULL,
+                                      IEEE80211_ROC_TYPE_NORMAL);
        mutex_unlock(&local->mtx);
 
        return ret;
@@ -2792,7 +2851,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 
        /* This will handle all kinds of coalescing and immediate TX */
        ret = ieee80211_start_roc_work(local, sdata, chan,
-                                      wait, cookie, skb);
+                                      wait, cookie, skb,
+                                      IEEE80211_ROC_TYPE_MGMT_TX);
        if (ret)
                kfree_skb(skb);
  out_unlock: