]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/mac80211/cfg.c
mac80211: fix rx monitor filter refcounters
[net-next-2.6.git] / net / mac80211 / cfg.c
index 9eb02a34088989d68ff9ec499b0541ed3c962c85..9e63fc28f8599e0d3e2359e914958570dcdc8e89 100644 (file)
 #include "rate.h"
 #include "mesh.h"
 
-static bool nl80211_type_check(enum nl80211_iftype type)
-{
-       switch (type) {
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_MONITOR:
-#ifdef CONFIG_MAC80211_MESH
-       case NL80211_IFTYPE_MESH_POINT:
-#endif
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_AP_VLAN:
-       case NL80211_IFTYPE_WDS:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool nl80211_params_check(enum nl80211_iftype type,
-                                struct vif_params *params)
-{
-       if (!nl80211_type_check(type))
-               return false;
-
-       return true;
-}
-
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
                               enum nl80211_iftype type, u32 *flags,
                               struct vif_params *params)
@@ -55,9 +28,6 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
        struct ieee80211_sub_if_data *sdata;
        int err;
 
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        err = ieee80211_if_add(local, name, &dev, type, params);
        if (err || type != NL80211_IFTYPE_MONITOR || !flags)
                return err;
@@ -82,12 +52,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret;
 
-       if (ieee80211_sdata_running(sdata))
-               return -EBUSY;
-
-       if (!nl80211_params_check(type, params))
-               return -EINVAL;
-
        ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
@@ -104,8 +68,36 @@ 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;
 }
@@ -114,54 +106,46 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, const u8 *mac_addr,
                             struct key_params *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta = NULL;
-       enum ieee80211_key_alg alg;
        struct ieee80211_key *key;
        int err;
 
-       if (!netif_running(dev))
+       if (!ieee80211_sdata_running(sdata))
                return -ENETDOWN;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
+       /* reject WEP and TKIP keys if WEP failed to initialize */
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               alg = ALG_WEP;
-               break;
        case WLAN_CIPHER_SUITE_TKIP:
-               alg = ALG_TKIP;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               alg = ALG_CCMP;
-               break;
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-               alg = ALG_AES_CMAC;
+       case WLAN_CIPHER_SUITE_WEP104:
+               if (IS_ERR(sdata->local->wep_tx_tfm))
+                       return -EINVAL;
                break;
        default:
-               return -EINVAL;
+               break;
        }
 
-       key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
-                                 params->seq_len, params->seq);
-       if (!key)
-               return -ENOMEM;
+       key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
+                                 params->key, params->seq_len, params->seq);
+       if (IS_ERR(key))
+               return PTR_ERR(key);
 
        mutex_lock(&sdata->local->sta_mtx);
 
        if (mac_addr) {
                sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta) {
-                       ieee80211_key_free(key);
+                       ieee80211_key_free(sdata->local, key);
                        err = -ENOENT;
                        goto out_unlock;
                }
        }
 
-       ieee80211_key_link(key, sdata, sta);
+       err = ieee80211_key_link(key, sdata, sta);
+       if (err)
+               ieee80211_key_free(sdata->local, key);
 
-       err = 0;
  out_unlock:
        mutex_unlock(&sdata->local->sta_mtx);
 
@@ -187,7 +171,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                        goto out_unlock;
 
                if (sta->key) {
-                       ieee80211_key_free(sta->key);
+                       ieee80211_key_free(sdata->local, sta->key);
                        WARN_ON(sta->key);
                        ret = 0;
                }
@@ -200,7 +184,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                goto out_unlock;
        }
 
-       ieee80211_key_free(sdata->keys[key_idx]);
+       ieee80211_key_free(sdata->local, sdata->keys[key_idx]);
        WARN_ON(sdata->keys[key_idx]);
 
        ret = 0;
@@ -242,10 +226,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
        memset(&params, 0, sizeof(params));
 
-       switch (key->conf.alg) {
-       case ALG_TKIP:
-               params.cipher = WLAN_CIPHER_SUITE_TKIP;
+       params.cipher = key->conf.cipher;
 
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
                iv32 = key->u.tkip.tx.iv32;
                iv16 = key->u.tkip.tx.iv16;
 
@@ -263,8 +247,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                params.seq = seq;
                params.seq_len = 6;
                break;
-       case ALG_CCMP:
-               params.cipher = WLAN_CIPHER_SUITE_CCMP;
+       case WLAN_CIPHER_SUITE_CCMP:
                seq[0] = key->u.ccmp.tx_pn[5];
                seq[1] = key->u.ccmp.tx_pn[4];
                seq[2] = key->u.ccmp.tx_pn[3];
@@ -274,14 +257,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                params.seq = seq;
                params.seq_len = 6;
                break;
-       case ALG_WEP:
-               if (key->conf.keylen == 5)
-                       params.cipher = WLAN_CIPHER_SUITE_WEP40;
-               else
-                       params.cipher = WLAN_CIPHER_SUITE_WEP104;
-               break;
-       case ALG_AES_CMAC:
-               params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
                seq[0] = key->u.aes_cmac.tx_pn[5];
                seq[1] = key->u.aes_cmac.tx_pn[4];
                seq[2] = key->u.aes_cmac.tx_pn[3];
@@ -319,15 +295,10 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
                                             struct net_device *dev,
                                             u8 key_idx)
 {
-       struct ieee80211_sub_if_data *sdata;
-
-       rcu_read_lock();
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        ieee80211_set_default_mgmt_key(sdata, key_idx);
 
-       rcu_read_unlock();
-
        return 0;
 }
 
@@ -627,13 +598,14 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
        skb->dev = sta->sdata->dev;
        skb->protocol = eth_type_trans(skb, sta->sdata->dev);
        memset(skb->cb, 0, sizeof(skb->cb));
-       netif_rx(skb);
+       netif_rx_ni(skb);
 }
 
 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;
@@ -642,7 +614,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;
 
@@ -669,7 +641,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
@@ -1143,16 +1115,12 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.uapsd = false;
 
        if (drv_conf_tx(local, params->queue, &p)) {
-               printk(KERN_DEBUG "%s: failed to set TX queue "
-                      "parameters for queue %d\n",
-                      wiphy_name(local->hw.wiphy), params->queue);
+               wiphy_debug(local->hw.wiphy,
+                           "failed to set TX queue parameters for queue %d\n",
+                           params->queue);
                return -EINVAL;
        }
 
-       /* enable WMM or activate new settings */
-       local->hw.conf.flags |= IEEE80211_CONF_QOS;
-       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
-
        return 0;
 }
 
@@ -1211,15 +1179,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);
 }
@@ -1545,11 +1524,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
        return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
 
-static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
-                           struct ieee80211_channel *chan,
-                           enum nl80211_channel_type channel_type,
-                           bool channel_type_valid,
-                           const u8 *buf, size_t len, u64 *cookie)
+static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
+                            struct ieee80211_channel *chan,
+                            enum nl80211_channel_type channel_type,
+                            bool channel_type_valid,
+                            const u8 *buf, size_t len, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1579,8 +1558,6 @@ static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_STATION:
-               if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
-                       flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                break;
        default:
                return -EOPNOTSUPP;
@@ -1651,6 +1628,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_bitrate_mask = ieee80211_set_bitrate_mask,
        .remain_on_channel = ieee80211_remain_on_channel,
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
-       .action = ieee80211_action,
+       .mgmt_tx = ieee80211_mgmt_tx,
        .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
 };