X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fiwlwifi%2Fiwl-sta.c;h=60a6e010603608eeca8550b5b928f3c3dcaf75e8;hb=2e4f40d2eb763a17c75c07fff605402737260c59;hp=b3caed487f03b1a910f953acc114c6c68f7c6061;hpb=4f85f5b39208e755a93f63296ec1224d14121b6c;p=linux-2.6 diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b3caed487f..60a6e01060 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -30,16 +30,14 @@ #include #include -#include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" -#include "iwl-io.h" #include "iwl-helpers.h" -#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */ -#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */ +#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ +#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) { @@ -74,10 +72,39 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) } EXPORT_SYMBOL(iwl_find_station); +int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +{ + if (priv->iw_mode == IEEE80211_IF_TYPE_STA) { + return IWL_AP_ID; + } else { + u8 *da = ieee80211_get_DA(hdr); + return iwl_find_station(priv, da); + } +} +EXPORT_SYMBOL(iwl_get_ra_sta_id); + +static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) +{ + unsigned long flags; + DECLARE_MAC_BUF(mac); + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); + + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", + print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} + static int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; + u8 sta_id = cmd->cmd.addsta.sta.sta_id; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); @@ -93,8 +120,8 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: - /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */ - /* fail through */ + iwl_sta_ucode_activate(priv, sta_id); + /* fall through */ default: IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", res->u.add_sta.status); @@ -105,8 +132,6 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, return 1; } - - int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { @@ -140,6 +165,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret == 0) { switch (res->u.add_sta.status) { case ADD_STA_SUCCESS_MSK: + iwl_sta_ucode_activate(priv, sta->sta.sta_id); IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); break; default: @@ -208,89 +234,92 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_ht_info *ht_info) { int i; - int index = IWL_INVALID_STATION; + int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) - index = IWL_AP_ID; + sta_id = IWL_AP_ID; else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; + sta_id = priv->hw_params.bcast_sta_id; else for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { if (!compare_ether_addr(priv->stations[i].sta.sta.addr, addr)) { - index = i; + sta_id = i; break; } if (!priv->stations[i].used && - index == IWL_INVALID_STATION) - index = i; + sta_id == IWL_INVALID_STATION) + sta_id = i; } - /* These two conditions have the same outcome, but keep them separate - since they have different meanings */ - if (unlikely(index == IWL_INVALID_STATION)) { + since they have different meanings */ + if (unlikely(sta_id == IWL_INVALID_STATION)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; + return sta_id; } - if (priv->stations[index].used && - !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { + if (priv->stations[sta_id].used && + !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return index; + return sta_id; } - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); - station = &priv->stations[index]; - station->used = 1; + station = &priv->stations[sta_id]; + station->used = IWL_STA_DRIVER_ACTIVE; + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", + sta_id, print_mac(mac, addr)); priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; - station->sta.sta.sta_id = index; + station->sta.sta.sta_id = sta_id; station->sta.station_flags = 0; /* BCAST station and IBSS stations do not work in HT mode */ - if (index != priv->hw_params.bcast_sta_id && + if (sta_id != priv->hw_params.bcast_sta_id && priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl_set_ht_add_station(priv, index, ht_info); + iwl_set_ht_add_station(priv, sta_id, ht_info); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); /* Add station to device's station table */ iwl_send_add_sta(priv, &station->sta, flags); - return index; + return sta_id; } EXPORT_SYMBOL(iwl_add_station_flags); - -static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) +static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - u8 sta_id; DECLARE_MAC_BUF(mac); - sta_id = iwl_find_station(priv, addr); - if (sta_id != IWL_INVALID_STATION) { - IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", - print_mac(mac, addr)); - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; - memset(&priv->stations[sta_id], 0, - sizeof(struct iwl_station_entry)); - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; - } - return -EINVAL; + u8 sta_id = iwl_find_station(priv, addr); + + BUG_ON(sta_id == IWL_INVALID_STATION); + + IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", + print_mac(mac, addr)); + + spin_lock_irqsave(&priv->sta_lock, flags); + + /* Ucode must be active and driver must be non active */ + if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) + IWL_ERROR("removed non active STA %d\n", sta_id); + + priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; + + memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); + spin_unlock_irqrestore(&priv->sta_lock, flags); } static int iwl_remove_sta_callback(struct iwl_priv *priv, @@ -316,6 +345,7 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, iwl_sta_ucode_deactivate(priv, addr); break; default: + IWL_ERROR("REPLY_REMOVE_STA failed\n"); break; } @@ -376,49 +406,68 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, return ret; } + /** * iwl_remove_station - Remove driver's knowledge of station. - * */ -u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { - int index = IWL_INVALID_STATION; - int i; + int sta_id = IWL_INVALID_STATION; + int i, ret = -EINVAL; unsigned long flags; + DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); if (is_ap) - index = IWL_AP_ID; + sta_id = IWL_AP_ID; else if (is_broadcast_ether_addr(addr)) - index = priv->hw_params.bcast_sta_id; + sta_id = priv->hw_params.bcast_sta_id; else for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) if (priv->stations[i].used && !compare_ether_addr(priv->stations[i].sta.sta.addr, addr)) { - index = i; + sta_id = i; break; } - if (unlikely(index == IWL_INVALID_STATION)) + if (unlikely(sta_id == IWL_INVALID_STATION)) + goto out; + + IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", + sta_id, print_mac(mac, addr)); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + IWL_ERROR("Removing %s but non DRIVER active\n", + print_mac(mac, addr)); goto out; + } - if (priv->stations[index].used) { - priv->stations[index].used = 0; - priv->num_stations--; + if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { + IWL_ERROR("Removing %s but non UCODE active\n", + print_mac(mac, addr)); + goto out; } + + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + + priv->num_stations--; + BUG_ON(priv->num_stations < 0); + spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_remove_station(priv, addr, CMD_ASYNC); - return index; + + ret = iwl_send_remove_station(priv, addr, CMD_ASYNC); + return ret; out: spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; + return ret; } EXPORT_SYMBOL(iwl_remove_station); -int iwl_get_free_ucode_key_index(struct iwl_priv *priv) + +static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -488,6 +537,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, priv->default_wep_key--; memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); ret = iwl_send_static_wepkey_cmd(priv, 1); + IWL_DEBUG_WEP("Remove default WEP key: idx=%d ret=%d\n", + keyconf->keyidx, ret); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; @@ -500,6 +551,12 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, int ret; unsigned long flags; + if (keyconf->keylen != WEP_KEY_LEN_128 && + keyconf->keylen != WEP_KEY_LEN_64) { + IWL_DEBUG_WEP("Bad WEP key length %d\n", keyconf->keylen); + return -EINVAL; + } + keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; keyconf->hw_key_idx = HW_KEY_DEFAULT; priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; @@ -516,6 +573,8 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, keyconf->keylen); ret = iwl_send_static_wepkey_cmd(priv, 0); + IWL_DEBUG_WEP("Set default WEP key: len=%d idx=%d ret=%d\n", + keyconf->keylen, keyconf->keyidx, ret); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; @@ -662,6 +721,9 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3; + IWL_DEBUG_WEP("Remove dynamic key: idx=%d sta=%d\n", + keyconf->keyidx, sta_id); + if (keyconf->keyidx != keyidx) { /* We need to remove a key with index different that the one * in the uCode. This means that the key we need to remove has @@ -686,7 +748,6 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; @@ -716,6 +777,10 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, ret = -EINVAL; } + IWL_DEBUG_WEP("Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n", + keyconf->alg, keyconf->keylen, keyconf->keyidx, + sta_id, ret); + return ret; } EXPORT_SYMBOL(iwl_set_dynamic_key); @@ -758,10 +823,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, if (lq->sta_id == 0xFF) lq->sta_id = IWL_AP_ID; - iwl_dump_lq_cmd(priv,lq); + iwl_dump_lq_cmd(priv, lq); - if (iwl_is_associated(priv) && priv->assoc_station_added && - priv->lq_mngr.lq_ready) + if (iwl_is_associated(priv) && priv->assoc_station_added) return iwl_send_cmd(priv, &cmd); return 0; @@ -775,7 +839,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd); * for automatic fallback during transmission. * * NOTE: This sets up a default set of values. These will be replaced later - * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of + * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of * rc80211_simple. * * NOTE: Run REPLY_ADD_STA command to set up station table entry, before @@ -808,7 +872,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ link_cmd.rs_table[i].rate_n_flags = - iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); + iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); r = iwl4965_get_prev_ieee_rate(r); } @@ -823,6 +887,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), &link_cmd, NULL); } + /** * iwl_rxon_add_station - add station into station table. * @@ -853,7 +918,6 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) } EXPORT_SYMBOL(iwl_rxon_add_station); - /** * iwl_get_sta_id - Find station's index within station table * @@ -911,7 +975,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) } EXPORT_SYMBOL(iwl_get_sta_id); - /** * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table */ @@ -930,4 +993,3 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) } EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); -