headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / net / wireless / iwmc3200wifi / cfg80211.c
index ee40317..f3c5565 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)
@@ -203,32 +176,6 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                return ret;
        }
 
-       /*
-        * The WEP keys can be set before or after setting the essid.
-        * We need to handle both cases by simply pushing the keys after
-        * we send the profile.
-        * If the profile is not set yet (i.e. we're pushing keys before
-        * the essid), we set the cipher appropriately.
-        * If the profile is set, we havent associated yet because our
-        * cipher was incorrectly set. So we invalidate and send the
-        * profile again.
-        */
-       if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-           key->cipher == WLAN_CIPHER_SUITE_WEP104) {
-               u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
-               u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
-
-               IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
-
-               if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
-                       *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
-               if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
-                       *ucast_cipher = *mcast_cipher =
-                               UMAC_CIPHER_TYPE_WEP_104;
-
-               return iwm_reset_profile(iwm);
-       }
-
        return iwm_set_key(iwm, 0, key);
 }
 
@@ -271,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);
 }
 
@@ -283,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);
 
@@ -294,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);
 
@@ -393,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;
 }
@@ -551,6 +483,8 @@ 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;
@@ -575,6 +509,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;
@@ -627,6 +564,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))
@@ -635,6 +573,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);
@@ -651,11 +597,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;
 
@@ -676,7 +622,48 @@ 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;
+       }
+
+       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,
@@ -687,7 +674,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;
 }