|
@@ -36,8 +36,8 @@
|
|
#include "iwl-helpers.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)
|
|
u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
|
|
{
|
|
{
|
|
@@ -83,10 +83,28 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(iwl_get_ra_sta_id);
|
|
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,
|
|
static int iwl_add_sta_callback(struct iwl_priv *priv,
|
|
struct iwl_cmd *cmd, struct sk_buff *skb)
|
|
struct iwl_cmd *cmd, struct sk_buff *skb)
|
|
{
|
|
{
|
|
struct iwl_rx_packet *res = NULL;
|
|
struct iwl_rx_packet *res = NULL;
|
|
|
|
+ u8 sta_id = cmd->cmd.addsta.sta.sta_id;
|
|
|
|
|
|
if (!skb) {
|
|
if (!skb) {
|
|
IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
|
|
IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
|
|
@@ -102,8 +120,8 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
|
|
|
|
|
|
switch (res->u.add_sta.status) {
|
|
switch (res->u.add_sta.status) {
|
|
case ADD_STA_SUCCESS_MSK:
|
|
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:
|
|
default:
|
|
IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
|
|
IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
|
|
res->u.add_sta.status);
|
|
res->u.add_sta.status);
|
|
@@ -147,6 +165,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
|
|
if (ret == 0) {
|
|
if (ret == 0) {
|
|
switch (res->u.add_sta.status) {
|
|
switch (res->u.add_sta.status) {
|
|
case ADD_STA_SUCCESS_MSK:
|
|
case ADD_STA_SUCCESS_MSK:
|
|
|
|
+ iwl_sta_ucode_activate(priv, sta->sta.sta_id);
|
|
IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
|
|
IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
@@ -215,88 +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)
|
|
u8 flags, struct ieee80211_ht_info *ht_info)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
- int index = IWL_INVALID_STATION;
|
|
|
|
|
|
+ int sta_id = IWL_INVALID_STATION;
|
|
struct iwl_station_entry *station;
|
|
struct iwl_station_entry *station;
|
|
unsigned long flags_spin;
|
|
unsigned long flags_spin;
|
|
DECLARE_MAC_BUF(mac);
|
|
DECLARE_MAC_BUF(mac);
|
|
|
|
|
|
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
|
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
|
if (is_ap)
|
|
if (is_ap)
|
|
- index = IWL_AP_ID;
|
|
|
|
|
|
+ sta_id = IWL_AP_ID;
|
|
else if (is_broadcast_ether_addr(addr))
|
|
else if (is_broadcast_ether_addr(addr))
|
|
- index = priv->hw_params.bcast_sta_id;
|
|
|
|
|
|
+ sta_id = priv->hw_params.bcast_sta_id;
|
|
else
|
|
else
|
|
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
|
|
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
|
|
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
|
if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
|
addr)) {
|
|
addr)) {
|
|
- index = i;
|
|
|
|
|
|
+ sta_id = i;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (!priv->stations[i].used &&
|
|
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
|
|
/* 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);
|
|
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);
|
|
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++;
|
|
priv->num_stations++;
|
|
|
|
|
|
/* Set up the REPLY_ADD_STA command to send to device */
|
|
/* Set up the REPLY_ADD_STA command to send to device */
|
|
memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
|
|
memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
|
|
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
|
|
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
|
|
station->sta.mode = 0;
|
|
station->sta.mode = 0;
|
|
- station->sta.sta.sta_id = index;
|
|
|
|
|
|
+ station->sta.sta.sta_id = sta_id;
|
|
station->sta.station_flags = 0;
|
|
station->sta.station_flags = 0;
|
|
|
|
|
|
/* BCAST station and IBSS stations do not work in HT mode */
|
|
/* 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)
|
|
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);
|
|
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
|
|
|
|
|
/* Add station to device's station table */
|
|
/* Add station to device's station table */
|
|
iwl_send_add_sta(priv, &station->sta, flags);
|
|
iwl_send_add_sta(priv, &station->sta, flags);
|
|
- return index;
|
|
|
|
|
|
+ return sta_id;
|
|
|
|
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(iwl_add_station_flags);
|
|
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;
|
|
unsigned long flags;
|
|
- u8 sta_id;
|
|
|
|
DECLARE_MAC_BUF(mac);
|
|
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,
|
|
static int iwl_remove_sta_callback(struct iwl_priv *priv,
|
|
@@ -322,6 +345,7 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
|
|
iwl_sta_ucode_deactivate(priv, addr);
|
|
iwl_sta_ucode_deactivate(priv, addr);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
|
|
+ IWL_ERROR("REPLY_REMOVE_STA failed\n");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -386,44 +410,63 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
|
|
/**
|
|
/**
|
|
* iwl_remove_station - Remove driver's knowledge of station.
|
|
* 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;
|
|
unsigned long flags;
|
|
|
|
+ DECLARE_MAC_BUF(mac);
|
|
|
|
|
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
|
|
|
|
|
if (is_ap)
|
|
if (is_ap)
|
|
- index = IWL_AP_ID;
|
|
|
|
|
|
+ sta_id = IWL_AP_ID;
|
|
else if (is_broadcast_ether_addr(addr))
|
|
else if (is_broadcast_ether_addr(addr))
|
|
- index = priv->hw_params.bcast_sta_id;
|
|
|
|
|
|
+ sta_id = priv->hw_params.bcast_sta_id;
|
|
else
|
|
else
|
|
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
|
|
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
|
|
if (priv->stations[i].used &&
|
|
if (priv->stations[i].used &&
|
|
!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
|
!compare_ether_addr(priv->stations[i].sta.sta.addr,
|
|
addr)) {
|
|
addr)) {
|
|
- index = i;
|
|
|
|
|
|
+ sta_id = i;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- if (unlikely(index == IWL_INVALID_STATION))
|
|
|
|
|
|
+ if (unlikely(sta_id == IWL_INVALID_STATION))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- if (priv->stations[index].used) {
|
|
|
|
- priv->stations[index].used = 0;
|
|
|
|
- priv->num_stations--;
|
|
|
|
|
|
+ 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[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);
|
|
BUG_ON(priv->num_stations < 0);
|
|
|
|
+
|
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
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:
|
|
out:
|
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
- return 0;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(iwl_remove_station);
|
|
EXPORT_SYMBOL(iwl_remove_station);
|
|
|
|
+
|
|
static 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;
|
|
int i;
|
|
@@ -845,6 +888,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,
|
|
iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
|
|
sizeof(link_cmd), &link_cmd, NULL);
|
|
sizeof(link_cmd), &link_cmd, NULL);
|
|
}
|
|
}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* iwl_rxon_add_station - add station into station table.
|
|
* iwl_rxon_add_station - add station into station table.
|
|
*
|
|
*
|