mac80211: Fix scan_ies_len to include DS Params
[cascardo/linux.git] / net / mac80211 / cfg.c
index 5de1ca3..18bd0e5 100644 (file)
@@ -68,14 +68,42 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
-               sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
+               struct ieee80211_local *local = sdata->local;
+
+               if (ieee80211_sdata_running(sdata)) {
+                       /*
+                        * Prohibit MONITOR_FLAG_COOK_FRAMES to be
+                        * changed while the interface is up.
+                        * Else we would need to add a lot of cruft
+                        * to update everything:
+                        *      cooked_mntrs, monitor and all fif_* counters
+                        *      reconfigure hardware
+                        */
+                       if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
+                           (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                               return -EBUSY;
+
+                       ieee80211_adjust_monitor_flags(sdata, -1);
+                       sdata->u.mntr_flags = *flags;
+                       ieee80211_adjust_monitor_flags(sdata, 1);
+
+                       ieee80211_configure_filter(local);
+               } else {
+                       /*
+                        * Because the interface is down, ieee80211_do_stop
+                        * and ieee80211_do_open take care of "everything"
+                        * mentioned in the comment above.
+                        */
+                       sdata->u.mntr_flags = *flags;
+               }
+       }
 
        return 0;
 }
 
 static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr,
+                            u8 key_idx, bool pairwise, const u8 *mac_addr,
                             struct key_params *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -103,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        if (IS_ERR(key))
                return PTR_ERR(key);
 
+       if (pairwise)
+               key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
+
        mutex_lock(&sdata->local->sta_mtx);
 
        if (mac_addr) {
@@ -125,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr)
+                            u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
@@ -142,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                if (!sta)
                        goto out_unlock;
 
-               if (sta->key) {
-                       ieee80211_key_free(sdata->local, sta->key);
-                       WARN_ON(sta->key);
-                       ret = 0;
+               if (pairwise) {
+                       if (sta->ptk) {
+                               ieee80211_key_free(sdata->local, sta->ptk);
+                               ret = 0;
+                       }
+               } else {
+                       if (sta->gtk[key_idx]) {
+                               ieee80211_key_free(sdata->local,
+                                                  sta->gtk[key_idx]);
+                               ret = 0;
+                       }
                }
 
                goto out_unlock;
@@ -167,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
-                            u8 key_idx, const u8 *mac_addr, void *cookie,
+                            u8 key_idx, bool pairwise, const u8 *mac_addr,
+                            void *cookie,
                             void (*callback)(void *cookie,
                                              struct key_params *params))
 {
@@ -175,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta = NULL;
        u8 seq[6] = {0};
        struct key_params params;
-       struct ieee80211_key *key;
+       struct ieee80211_key *key = NULL;
        u32 iv32;
        u16 iv16;
        int err = -ENOENT;
@@ -189,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                if (!sta)
                        goto out;
 
-               key = sta->key;
+               if (pairwise)
+                       key = sta->ptk;
+               else if (key_idx < NUM_DEFAULT_KEYS)
+                       key = sta->gtk[key_idx];
        } else
                key = sdata->keys[key_idx];
 
@@ -285,13 +327,19 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                        STATION_INFO_TX_BYTES |
                        STATION_INFO_RX_PACKETS |
                        STATION_INFO_TX_PACKETS |
-                       STATION_INFO_TX_BITRATE;
+                       STATION_INFO_TX_RETRIES |
+                       STATION_INFO_TX_FAILED |
+                       STATION_INFO_TX_BITRATE |
+                       STATION_INFO_RX_DROP_MISC;
 
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
        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;
 
        if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
            (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
@@ -577,6 +625,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
                                 struct sta_info *sta,
                                 struct station_parameters *params)
 {
+       unsigned long flags;
        u32 rates;
        int i, j;
        struct ieee80211_supported_band *sband;
@@ -585,7 +634,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 
        sband = local->hw.wiphy->bands[local->oper_channel->band];
 
-       spin_lock_bh(&sta->lock);
+       spin_lock_irqsave(&sta->flaglock, flags);
        mask = params->sta_flags_mask;
        set = params->sta_flags_set;
 
@@ -612,7 +661,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
                if (set & BIT(NL80211_STA_FLAG_MFP))
                        sta->flags |= WLAN_STA_MFP;
        }
-       spin_unlock_bh(&sta->lock);
+       spin_unlock_irqrestore(&sta->flaglock, flags);
 
        /*
         * cfg80211 validates this (1-2007) and allows setting the AID
@@ -1150,15 +1199,26 @@ static int ieee80211_scan(struct wiphy *wiphy,
                          struct net_device *dev,
                          struct cfg80211_scan_request *req)
 {
-       struct ieee80211_sub_if_data *sdata;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-           sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
-           (sdata->vif.type != NL80211_IFTYPE_AP || sdata->u.ap.beacon))
+       switch (ieee80211_vif_type_p2p(&sdata->vif)) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+               if (sdata->local->ops->hw_scan)
+                       break;
+               /* FIXME: implement NoA while scanning in software */
+               return -EOPNOTSUPP;
+       case NL80211_IFTYPE_AP:
+               if (sdata->u.ap.beacon)
+                       return -EOPNOTSUPP;
+               break;
+       default:
                return -EOPNOTSUPP;
+       }
 
        return ieee80211_request_scan(sdata, req);
 }
@@ -1305,7 +1365,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
 }
 
 static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
-                                 u8 *addr)
+                                 const u8 *addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -1354,7 +1414,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
        if (!sdata->u.mgd.associated ||
            sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
                mutex_lock(&sdata->local->iflist_mtx);
-               ieee80211_recalc_smps(sdata->local, sdata);
+               ieee80211_recalc_smps(sdata->local);
                mutex_unlock(&sdata->local->iflist_mtx);
                return 0;
        }
@@ -1509,7 +1569,11 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_ADHOC:
-               if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
+               if (!ieee80211_is_action(mgmt->frame_control) ||
+                   mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
                        break;
                rcu_read_lock();
                sta = sta_info_get(sdata, mgmt->da);
@@ -1518,6 +1582,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
                break;
        default:
                return -EOPNOTSUPP;
@@ -1539,6 +1604,23 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
+                                         struct net_device *dev,
+                                         u16 frame_type, bool reg)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
+               return;
+
+       if (reg)
+               local->probe_req_reg++;
+       else
+               local->probe_req_reg--;
+
+       ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -1590,4 +1672,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
        .mgmt_tx = ieee80211_mgmt_tx,
        .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+       .mgmt_frame_register = ieee80211_mgmt_frame_register,
 };