iwmc3200wifi: mark some pmksa functions static
[safe/jmp/linux-2.6] / drivers / net / wireless / iwmc3200wifi / cfg80211.c
index 0372658..fc239a3 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/sched.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/ieee80211.h>
@@ -158,34 +159,6 @@ static int iwm_key_init(struct iwm_key *key, u8 key_index,
        return 0;
 }
 
-static int iwm_reset_profile(struct iwm_priv *iwm)
-{
-       int ret;
-
-       if (!iwm->umac_profile_active)
-               return 0;
-
-       /*
-        * If there is a current active profile, but no
-        * default key, it's not worth trying to associate again.
-        */
-       if (iwm->default_key < 0)
-               return 0;
-
-       /*
-        * Here we have an active profile, but a key setting changed.
-        * We thus have to invalidate the current profile, and push the
-        * new one. Keys will be pushed when association takes place.
-        */
-       ret = iwm_invalidate_mlme_profile(iwm);
-       if (ret < 0) {
-               IWM_ERR(iwm, "Couldn't invalidate profile\n");
-               return ret;
-       }
-
-       return iwm_send_mlme_profile(iwm);
-}
-
 static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                u8 key_index, const u8 *mac_addr,
                                struct key_params *params)
@@ -245,10 +218,6 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        if (key_index == iwm->default_key)
                iwm->default_key = -1;
 
-       /* If the interface is down, we just cache this */
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return 0;
-
        return iwm_set_key(iwm, 1, key);
 }
 
@@ -257,7 +226,6 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
                                        u8 key_index)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       int ret;
 
        IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
@@ -268,19 +236,12 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
        iwm->default_key = key_index;
 
-       /* If the interface is down, we just cache this */
-       if (!test_bit(IWM_STATUS_READY, &iwm->status))
-               return 0;
-
-       ret = iwm_set_tx_key(iwm, key_index);
-       if (ret < 0)
-               return ret;
-
-       return iwm_reset_profile(iwm);
+       return iwm_set_tx_key(iwm, key_index);
 }
 
-int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
-                            u8 *mac, struct station_info *sinfo)
+static int iwm_cfg80211_get_station(struct wiphy *wiphy,
+                                   struct net_device *ndev,
+                                   u8 *mac, struct station_info *sinfo)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
 
@@ -302,7 +263,7 @@ int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
 {
        struct wiphy *wiphy = iwm_to_wiphy(iwm);
-       struct iwm_bss_info *bss, *next;
+       struct iwm_bss_info *bss;
        struct iwm_umac_notif_bss_info *umac_bss;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_channel *channel;
@@ -310,7 +271,7 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
        s32 signal;
        int freq;
 
-       list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
+       list_for_each_entry(bss, &iwm->bss_list, node) {
                umac_bss = bss->bss;
                mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
 
@@ -367,11 +328,8 @@ static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
 
        iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
 
-       if (iwm->umac_profile_active) {
-               int ret = iwm_invalidate_mlme_profile(iwm);
-               if (ret < 0)
-                       IWM_ERR(iwm, "Couldn't invalidate profile\n");
-       }
+       if (iwm->umac_profile_active)
+               iwm_invalidate_mlme_profile(iwm);
 
        return 0;
 }
@@ -447,39 +405,21 @@ static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
        struct ieee80211_channel *chan = params->channel;
-       struct cfg80211_bss *bss;
 
        if (!test_bit(IWM_STATUS_READY, &iwm->status))
                return -EIO;
 
-       /* UMAC doesn't support creating IBSS network with specified bssid.
-        * This should be removed after we have join only mode supported. */
+       /* UMAC doesn't support creating or joining an IBSS network
+        * with specified bssid. */
        if (params->bssid)
                return -EOPNOTSUPP;
 
-       bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
-                               params->ssid, params->ssid_len);
-       if (!bss) {
-               iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
-               schedule_timeout_interruptible(2 * HZ);
-               bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
-                                       params->ssid, params->ssid_len);
-       }
-       /* IBSS join only mode is not supported by UMAC ATM */
-       if (bss) {
-               cfg80211_put_bss(bss);
-               return -EOPNOTSUPP;
-       }
-
        iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
        iwm->umac_profile->ibss.band = chan->band;
        iwm->umac_profile->ibss.channel = iwm->channel;
        iwm->umac_profile->ssid.ssid_len = params->ssid_len;
        memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
 
-       if (params->bssid)
-               memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
-
        return iwm_send_mlme_profile(iwm);
 }
 
@@ -525,17 +465,19 @@ static int iwm_set_auth_type(struct iwm_priv *iwm,
 
 static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
 {
+       IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
+
        if (!wpa_version) {
                iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
                return 0;
        }
 
+       if (wpa_version & NL80211_WPA_VERSION_1)
+               iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
+
        if (wpa_version & NL80211_WPA_VERSION_2)
                iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
 
-       if (wpa_version & NL80211_WPA_VERSION_1)
-               iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
-
        return 0;
 }
 
@@ -549,6 +491,9 @@ static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
                return 0;
        }
 
+       IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
+                    cipher);
+
        switch (cipher) {
        case IW_AUTH_CIPHER_NONE:
                *profile_cipher = UMAC_CIPHER_TYPE_NONE;
@@ -601,6 +546,7 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
        struct ieee80211_channel *chan = sme->channel;
+       struct key_params key_param;
        int ret;
 
        if (!test_bit(IWM_STATUS_READY, &iwm->status))
@@ -609,6 +555,14 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        if (!sme->ssid)
                return -EINVAL;
 
+       if (iwm->umac_profile_active) {
+               ret = iwm_invalidate_mlme_profile(iwm);
+               if (ret) {
+                       IWM_ERR(iwm, "Couldn't invalidate profile\n");
+                       return ret;
+               }
+       }
+
        if (chan)
                iwm->channel =
                        ieee80211_frequency_to_channel(chan->center_freq);
@@ -625,11 +579,11 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                iwm->umac_profile->bss_num = 0;
        }
 
-       ret = iwm_set_auth_type(iwm, sme->auth_type);
+       ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
        if (ret < 0)
                return ret;
 
-       ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+       ret = iwm_set_auth_type(iwm, sme->auth_type);
        if (ret < 0)
                return ret;
 
@@ -650,7 +604,55 @@ static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                        return ret;
        }
 
-       return iwm_send_mlme_profile(iwm);
+       /*
+        * We save the WEP key in case we want to do shared authentication.
+        * We have to do it so because UMAC will assert whenever it gets a
+        * key before a profile.
+        */
+       if (sme->key) {
+               key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL);
+               if (key_param.key == NULL)
+                       return -ENOMEM;
+               key_param.key_len = sme->key_len;
+               key_param.seq_len = 0;
+               key_param.cipher = sme->crypto.ciphers_pairwise[0];
+
+               ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx,
+                                  NULL, &key_param);
+               kfree(key_param.key);
+               if (ret < 0) {
+                       IWM_ERR(iwm, "Invalid key_params\n");
+                       return ret;
+               }
+
+               iwm->default_key = sme->key_idx;
+       }
+
+       /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */
+       if ((iwm->umac_profile->sec.flags &
+            (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) &&
+           iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) {
+                       iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK;
+       }
+
+       ret = iwm_send_mlme_profile(iwm);
+
+       if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK ||
+           sme->key == NULL)
+               return ret;
+
+       /*
+        * We want to do shared auth.
+        * We need to actually set the key we previously cached,
+        * and then tell the UMAC it's the default one.
+        * That will trigger the auth+assoc UMAC machinery, and again,
+        * this must be done after setting the profile.
+        */
+       ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]);
+       if (ret < 0)
+               return ret;
+
+       return iwm_set_tx_key(iwm, iwm->default_key);
 }
 
 static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
@@ -661,7 +663,7 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
        IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
 
        if (iwm->umac_profile_active)
-               return iwm_invalidate_mlme_profile(iwm);
+               iwm_invalidate_mlme_profile(iwm);
 
        return 0;
 }
@@ -669,10 +671,24 @@ static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
                                    enum tx_power_setting type, int dbm)
 {
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+       int ret;
+
        switch (type) {
        case TX_POWER_AUTOMATIC:
                return 0;
+       case TX_POWER_FIXED:
+               if (!test_bit(IWM_STATUS_READY, &iwm->status))
+                       return 0;
+
+               ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+                                             CFG_TX_PWR_LIMIT_USR, dbm * 2);
+               if (ret < 0)
+                       return ret;
+
+               return iwm_tx_power_trigger(iwm);
        default:
+               IWM_ERR(iwm, "Unsupported power type: %d\n", type);
                return -EOPNOTSUPP;
        }
 
@@ -683,7 +699,7 @@ static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
 
-       *dbm = iwm->txpower;
+       *dbm = iwm->txpower >> 1;
 
        return 0;
 }
@@ -709,6 +725,36 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
                                       CFG_POWER_INDEX, iwm->conf.power_index);
 }
 
+static int iwm_cfg80211_set_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+       return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
+}
+
+static int iwm_cfg80211_del_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+       return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
+}
+
+static int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy,
+                                   struct net_device *netdev)
+{
+       struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+       struct cfg80211_pmksa pmksa;
+
+       memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
+
+       return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH);
+}
+
+
 static struct cfg80211_ops iwm_cfg80211_ops = {
        .change_virtual_intf = iwm_cfg80211_change_iface,
        .add_key = iwm_cfg80211_add_key,
@@ -725,6 +771,9 @@ static struct cfg80211_ops iwm_cfg80211_ops = {
        .set_tx_power = iwm_cfg80211_set_txpower,
        .get_tx_power = iwm_cfg80211_get_txpower,
        .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+       .set_pmksa = iwm_cfg80211_set_pmksa,
+       .del_pmksa = iwm_cfg80211_del_pmksa,
+       .flush_pmksa = iwm_cfg80211_flush_pmksa,
 };
 
 static const u32 cipher_suites[] = {
@@ -770,6 +819,7 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
 
        set_wiphy_dev(wdev->wiphy, dev);
        wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
+       wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS;
        wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                       BIT(NL80211_IFTYPE_ADHOC);
        wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;