OSDN Git Service

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[android-x86/kernel.git] / drivers / net / wireless / iwlwifi / iwl-sta.c
index 972b738..49493d1 100644 (file)
@@ -400,7 +400,8 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
 }
 
 static int iwl_send_remove_station(struct iwl_priv *priv,
-                                  const u8 *addr, int sta_id)
+                                  const u8 *addr, int sta_id,
+                                  bool temporary)
 {
        struct iwl_rx_packet *pkt;
        int ret;
@@ -436,9 +437,11 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
        if (!ret) {
                switch (pkt->u.rem_sta.status) {
                case REM_STA_SUCCESS_MSK:
-                       spin_lock_irqsave(&priv->sta_lock, flags_spin);
-                       iwl_sta_ucode_deactivate(priv, sta_id);
-                       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+                       if (!temporary) {
+                               spin_lock_irqsave(&priv->sta_lock, flags_spin);
+                               iwl_sta_ucode_deactivate(priv, sta_id);
+                               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+                       }
                        IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
                        break;
                default:
@@ -505,7 +508,7 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
 
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       return iwl_send_remove_station(priv, addr, sta_id);
+       return iwl_send_remove_station(priv, addr, sta_id, false);
 out_err:
        spin_unlock_irqrestore(&priv->sta_lock, flags);
        return -EINVAL;
@@ -624,6 +627,49 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 }
 EXPORT_SYMBOL(iwl_restore_stations);
 
+void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       unsigned long flags;
+       int sta_id = ctx->ap_sta_id;
+       int ret;
+       struct iwl_addsta_cmd sta_cmd;
+       struct iwl_link_quality_cmd lq;
+       bool active;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               return;
+       }
+
+       memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
+       sta_cmd.mode = 0;
+       memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+
+       active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
+       priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       if (active) {
+               ret = iwl_send_remove_station(
+                       priv, priv->stations[sta_id].sta.sta.addr,
+                       sta_id, true);
+               if (ret)
+                       IWL_ERR(priv, "failed to remove STA %pM (%d)\n",
+                               priv->stations[sta_id].sta.sta.addr, ret);
+       }
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
+       if (ret)
+               IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
+                       priv->stations[sta_id].sta.sta.addr, ret);
+       iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+}
+EXPORT_SYMBOL(iwl_reprogram_ap_sta);
+
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
        int i;
@@ -736,6 +782,14 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
                return -EINVAL;
 
+
+       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+       if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return -EINVAL;
+       }
+       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
        iwl_dump_lq_cmd(priv, lq);
        BUG_ON(init && (cmd.flags & CMD_ASYNC));