iwl-sta.c 31.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/******************************************************************************
 *
 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
 *
 * Portions of this file are derived from the ipw3945 project, as well
 * as portions of the ieee80211 subsystem header files.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
 *
 * The full GNU General Public License is included in this distribution in the
 * file called LICENSE.
 *
 * Contact Information:
 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *
 *****************************************************************************/

#include <net/mac80211.h>
31
#include <linux/etherdevice.h>
32

33
#include "iwl-dev.h"
34 35 36
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"
37

38

39 40
#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
41

42 43 44 45 46 47 48
u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
{
	int i;
	int start = 0;
	int ret = IWL_INVALID_STATION;
	unsigned long flags;

49 50
	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
	    (priv->iw_mode == NL80211_IFTYPE_AP))
51 52 53 54 55 56 57 58 59 60 61 62 63 64
		start = IWL_STA_ID;

	if (is_broadcast_ether_addr(addr))
		return priv->hw_params.bcast_sta_id;

	spin_lock_irqsave(&priv->sta_lock, flags);
	for (i = start; i < priv->hw_params.max_stations; i++)
		if (priv->stations[i].used &&
		    (!compare_ether_addr(priv->stations[i].sta.sta.addr,
					 addr))) {
			ret = i;
			goto out;
		}

J
Johannes Berg 已提交
65 66
	IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n",
			      addr, priv->num_stations);
67 68 69 70 71 72 73

 out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return ret;
}
EXPORT_SYMBOL(iwl_find_station);

74 75
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
76
	if (priv->iw_mode == NL80211_IFTYPE_STATION) {
77 78 79 80 81 82 83 84
		return IWL_AP_ID;
	} else {
		u8 *da = ieee80211_get_DA(hdr);
		return iwl_find_station(priv, da);
	}
}
EXPORT_SYMBOL(iwl_get_ra_sta_id);

85 86 87 88 89 90 91 92 93 94
static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
{
	unsigned long flags;

	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;
J
Johannes Berg 已提交
95 96
	IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n",
			priv->stations[sta_id].sta.sta.addr);
97 98 99 100

	spin_unlock_irqrestore(&priv->sta_lock, flags);
}

101 102 103 104
static int iwl_add_sta_callback(struct iwl_priv *priv,
				   struct iwl_cmd *cmd, struct sk_buff *skb)
{
	struct iwl_rx_packet *res = NULL;
105 106 107
	struct iwl_addsta_cmd *addsta =
		(struct iwl_addsta_cmd *)cmd->cmd.payload;
	u8 sta_id = addsta->sta.sta_id;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

	if (!skb) {
		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
		return 1;
	}

	res = (struct iwl_rx_packet *)skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
			  res->hdr.flags);
		return 1;
	}

	switch (res->u.add_sta.status) {
	case ADD_STA_SUCCESS_MSK:
123 124
		iwl_sta_ucode_activate(priv, sta_id);
		 /* fall through */
125 126 127 128 129 130 131 132 133 134
	default:
		IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
			     res->u.add_sta.status);
		break;
	}

	/* We didn't cache the SKB; let the caller free it */
	return 1;
}

135
static int iwl_send_add_sta(struct iwl_priv *priv,
136 137 138 139 140 141 142 143 144 145 146
		     struct iwl_addsta_cmd *sta, u8 flags)
{
	struct iwl_rx_packet *res = NULL;
	int ret = 0;
	u8 data[sizeof(*sta)];
	struct iwl_host_cmd cmd = {
		.id = REPLY_ADD_STA,
		.meta.flags = flags,
		.data = data,
	};

147 148 149
	if (flags & CMD_ASYNC)
		cmd.meta.u.callback = iwl_add_sta_callback;
	else
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
		cmd.meta.flags |= CMD_WANT_SKB;

	cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
	ret = iwl_send_cmd(priv, &cmd);

	if (ret || (flags & CMD_ASYNC))
		return ret;

	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
			  res->hdr.flags);
		ret = -EIO;
	}

	if (ret == 0) {
		switch (res->u.add_sta.status) {
		case ADD_STA_SUCCESS_MSK:
168
			iwl_sta_ucode_activate(priv, sta->sta.sta_id);
169 170 171 172 173 174 175 176 177 178 179 180 181 182
			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
			break;
		default:
			ret = -EIO;
			IWL_WARNING("REPLY_ADD_STA failed\n");
			break;
		}
	}

	priv->alloc_rxb_skb--;
	dev_kfree_skb_any(cmd.meta.u.skb);

	return ret;
}
183

184
static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
J
Johannes Berg 已提交
185
				   struct ieee80211_sta_ht_cap *sta_ht_inf)
186 187 188 189 190 191 192
{
	__le32 sta_flags;
	u8 mimo_ps_mode;

	if (!sta_ht_inf || !sta_ht_inf->ht_supported)
		goto done;

193
	mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2;
194 195 196 197 198 199

	sta_flags = priv->stations[index].sta.station_flags;

	sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);

	switch (mimo_ps_mode) {
200
	case WLAN_HT_CAP_SM_PS_STATIC:
201 202
		sta_flags |= STA_FLG_MIMO_DIS_MSK;
		break;
203
	case WLAN_HT_CAP_SM_PS_DYNAMIC:
204 205
		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
		break;
206
	case WLAN_HT_CAP_SM_PS_DISABLED:
207 208
		break;
	default:
J
Jiri Slaby 已提交
209
		IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode);
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		break;
	}

	sta_flags |= cpu_to_le32(
	      (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);

	sta_flags |= cpu_to_le32(
	      (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);

	if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
		sta_flags |= STA_FLG_FAT_EN_MSK;
	else
		sta_flags &= ~STA_FLG_FAT_EN_MSK;

	priv->stations[index].sta.station_flags = sta_flags;
 done:
	return;
}

/**
 * iwl_add_station_flags - Add station to tables in driver and device
 */
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
J
Johannes Berg 已提交
233
			 u8 flags, struct ieee80211_sta_ht_cap *ht_info)
234 235
{
	int i;
236
	int sta_id = IWL_INVALID_STATION;
237 238 239 240 241
	struct iwl_station_entry *station;
	unsigned long flags_spin;

	spin_lock_irqsave(&priv->sta_lock, flags_spin);
	if (is_ap)
242
		sta_id = IWL_AP_ID;
243
	else if (is_broadcast_ether_addr(addr))
244
		sta_id = priv->hw_params.bcast_sta_id;
245 246 247 248
	else
		for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
						addr)) {
249
				sta_id = i;
250 251 252 253
				break;
			}

			if (!priv->stations[i].used &&
254 255
			    sta_id == IWL_INVALID_STATION)
				sta_id = i;
256 257 258
		}

	/* These two conditions have the same outcome, but keep them separate
259 260
	   since they have different meanings */
	if (unlikely(sta_id == IWL_INVALID_STATION)) {
261
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
262
		return sta_id;
263 264
	}

265 266
	if (priv->stations[sta_id].used &&
	    !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
267
		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
268
		return sta_id;
269 270 271
	}


272 273
	station = &priv->stations[sta_id];
	station->used = IWL_STA_DRIVER_ACTIVE;
J
Johannes Berg 已提交
274 275
	IWL_DEBUG_ASSOC("Add STA to driver ID %d: %pM\n",
			sta_id, addr);
276 277 278 279 280 281
	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;
282
	station->sta.sta.sta_id = sta_id;
283 284 285
	station->sta.station_flags = 0;

	/* BCAST station and IBSS stations do not work in HT mode */
286
	if (sta_id != priv->hw_params.bcast_sta_id &&
287
	    priv->iw_mode != NL80211_IFTYPE_ADHOC)
288
		iwl_set_ht_add_station(priv, sta_id, ht_info);
289 290 291 292 293

	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);

	/* Add station to device's station table */
	iwl_send_add_sta(priv, &station->sta, flags);
294
	return sta_id;
295 296 297 298

}
EXPORT_SYMBOL(iwl_add_station_flags);

299
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
300 301
{
	unsigned long flags;
302 303 304 305
	u8 sta_id = iwl_find_station(priv, addr);

	BUG_ON(sta_id == IWL_INVALID_STATION);

J
Johannes Berg 已提交
306
	IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr);
307 308 309 310 311 312 313 314 315 316 317

	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);
318 319 320 321 322 323
}

static int iwl_remove_sta_callback(struct iwl_priv *priv,
				   struct iwl_cmd *cmd, struct sk_buff *skb)
{
	struct iwl_rx_packet *res = NULL;
324 325 326
	struct iwl_rem_sta_cmd *rm_sta =
		 (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
	const char *addr = rm_sta->addr;
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

	if (!skb) {
		IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
		return 1;
	}

	res = (struct iwl_rx_packet *)skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
		res->hdr.flags);
		return 1;
	}

	switch (res->u.rem_sta.status) {
	case REM_STA_SUCCESS_MSK:
		iwl_sta_ucode_deactivate(priv, addr);
		break;
	default:
345
		IWL_ERROR("REPLY_REMOVE_STA failed\n");
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
		break;
	}

	/* We didn't cache the SKB; let the caller free it */
	return 1;
}

static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
				   u8 flags)
{
	struct iwl_rx_packet *res = NULL;
	int ret;

	struct iwl_rem_sta_cmd rm_sta_cmd;

	struct iwl_host_cmd cmd = {
		.id = REPLY_REMOVE_STA,
		.len = sizeof(struct iwl_rem_sta_cmd),
		.meta.flags = flags,
		.data = &rm_sta_cmd,
	};

	memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
	rm_sta_cmd.num_sta = 1;
	memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);

	if (flags & CMD_ASYNC)
		cmd.meta.u.callback = iwl_remove_sta_callback;
	else
		cmd.meta.flags |= CMD_WANT_SKB;
	ret = iwl_send_cmd(priv, &cmd);

	if (ret || (flags & CMD_ASYNC))
		return ret;

	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
		IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
			  res->hdr.flags);
		ret = -EIO;
	}

	if (!ret) {
		switch (res->u.rem_sta.status) {
		case REM_STA_SUCCESS_MSK:
			iwl_sta_ucode_deactivate(priv, addr);
			IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n");
			break;
		default:
			ret = -EIO;
			IWL_ERROR("REPLY_REMOVE_STA failed\n");
			break;
		}
	}

	priv->alloc_rxb_skb--;
	dev_kfree_skb_any(cmd.meta.u.skb);

	return ret;
}
406

407 408 409
/**
 * iwl_remove_station - Remove driver's knowledge of station.
 */
410
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
411
{
412 413
	int sta_id = IWL_INVALID_STATION;
	int i, ret = -EINVAL;
414 415 416 417 418
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

	if (is_ap)
419
		sta_id = IWL_AP_ID;
420
	else if (is_broadcast_ether_addr(addr))
421
		sta_id = priv->hw_params.bcast_sta_id;
422 423 424 425 426
	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)) {
427
				sta_id = i;
428 429 430
				break;
			}

431
	if (unlikely(sta_id == IWL_INVALID_STATION))
432 433
		goto out;

J
Johannes Berg 已提交
434 435
	IWL_DEBUG_ASSOC("Removing STA from driver:%d  %pM\n",
		sta_id, addr);
436 437

	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
J
Johannes Berg 已提交
438 439
		IWL_ERROR("Removing %pM but non DRIVER active\n",
				addr);
440 441 442 443
		goto out;
	}

	if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
J
Johannes Berg 已提交
444 445
		IWL_ERROR("Removing %pM but non UCODE active\n",
				addr);
446
		goto out;
447 448
	}

449 450 451 452 453

	priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;

	priv->num_stations--;

454
	BUG_ON(priv->num_stations < 0);
455

456
	spin_unlock_irqrestore(&priv->sta_lock, flags);
457 458 459

	ret = iwl_send_remove_station(priv, addr, CMD_ASYNC);
	return ret;
460 461
out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
462
	return ret;
463 464
}
EXPORT_SYMBOL(iwl_remove_station);
465

466
static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
467 468 469 470
{
	int i;

	for (i = 0; i < STA_KEY_MAX_NUM; i++)
471
		if (!test_and_set_bit(i, &priv->ucode_key_table))
472 473 474 475
			return i;

	return -1;
}
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
{
	int i, not_empty = 0;
	u8 buff[sizeof(struct iwl_wep_cmd) +
		sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
	struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
	size_t cmd_size  = sizeof(struct iwl_wep_cmd);
	struct iwl_host_cmd cmd = {
		.id = REPLY_WEPKEY,
		.data = wep_cmd,
		.meta.flags = CMD_ASYNC,
	};

	memset(wep_cmd, 0, cmd_size +
			(sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));

	for (i = 0; i < WEP_KEYS_MAX ; i++) {
		wep_cmd->key[i].key_index = i;
		if (priv->wep_keys[i].key_size) {
			wep_cmd->key[i].key_offset = i;
			not_empty = 1;
		} else {
			wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
		}

		wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
		memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
				priv->wep_keys[i].key_size);
	}

	wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
	wep_cmd->num_keys = WEP_KEYS_MAX;

	cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;

	cmd.len = cmd_size;

	if (not_empty || send_if_empty)
		return iwl_send_cmd(priv, &cmd);
	else
		return 0;
}
519
EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
520 521

int iwl_remove_default_wep_key(struct iwl_priv *priv,
522
			       struct ieee80211_key_conf *keyconf)
523 524 525 526 527
{
	int ret;
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
528 529 530 531 532

	if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
		IWL_ERROR("index %d not used in uCode key table.\n",
			  keyconf->keyidx);

533
	priv->default_wep_key--;
534
	memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
535
	ret = iwl_send_static_wepkey_cmd(priv, 1);
536 537
	IWL_DEBUG_WEP("Remove default WEP key: idx=%d ret=%d\n",
		      keyconf->keyidx, ret);
538 539 540 541
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
542
EXPORT_SYMBOL(iwl_remove_default_wep_key);
543 544 545 546 547 548 549

int iwl_set_default_wep_key(struct iwl_priv *priv,
			    struct ieee80211_key_conf *keyconf)
{
	int ret;
	unsigned long flags;

550 551 552 553 554 555
	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;
	}

556
	keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
557
	keyconf->hw_key_idx = HW_KEY_DEFAULT;
558 559 560 561 562
	priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->default_wep_key++;

563 564 565 566
	if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
		IWL_ERROR("index %d already used in uCode key table.\n",
			keyconf->keyidx);

567 568 569 570 571
	priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
	memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
							keyconf->keylen);

	ret = iwl_send_static_wepkey_cmd(priv, 0);
572 573
	IWL_DEBUG_WEP("Set default WEP key: len=%d idx=%d ret=%d\n",
		keyconf->keylen, keyconf->keyidx, ret);
574 575 576 577
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
578
EXPORT_SYMBOL(iwl_set_default_wep_key);
579

580
static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
				struct ieee80211_key_conf *keyconf,
				u8 sta_id)
{
	unsigned long flags;
	__le16 key_flags = 0;
	int ret;

	keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;

	key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
	key_flags &= ~STA_KEY_FLG_INVALID;

	if (keyconf->keylen == WEP_KEY_LEN_128)
		key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;

T
Tomas Winkler 已提交
597
	if (sta_id == priv->hw_params.bcast_sta_id)
598 599 600 601 602 603 604 605 606 607 608 609 610 611
		key_flags |= STA_KEY_MULTICAST_MSK;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
	priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;

	memcpy(priv->stations[sta_id].keyinfo.key,
				keyconf->key, keyconf->keylen);

	memcpy(&priv->stations[sta_id].sta.key.key[3],
				keyconf->key, keyconf->keylen);

612 613 614
	if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
			== STA_KEY_FLG_NO_ENC)
		priv->stations[sta_id].sta.key.key_offset =
615
				 iwl_get_free_ucode_key_index(priv);
616 617
	/* else, we are overriding an existing key => no need to allocated room
	 * in uCode. */
618

619
	priv->stations[sta_id].sta.key.key_flags = key_flags;
620 621 622
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

623
	ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
624 625 626 627 628

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
629 630 631 632 633 634 635 636 637 638 639 640

static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
				   struct ieee80211_key_conf *keyconf,
				   u8 sta_id)
{
	unsigned long flags;
	__le16 key_flags = 0;

	key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
	key_flags &= ~STA_KEY_FLG_INVALID;

T
Tomas Winkler 已提交
641
	if (sta_id == priv->hw_params.bcast_sta_id)
642 643 644 645 646 647 648 649 650 651 652 653 654 655
		key_flags |= STA_KEY_MULTICAST_MSK;

	keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;

	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
	       keyconf->keylen);

	memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
	       keyconf->keylen);

656 657 658 659 660 661 662
	if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
			== STA_KEY_FLG_NO_ENC)
		priv->stations[sta_id].sta.key.key_offset =
				 iwl_get_free_ucode_key_index(priv);
	/* else, we are overriding an existing key => no need to allocated room
	 * in uCode. */

663 664 665 666 667 668 669
	priv->stations[sta_id].sta.key.key_flags = key_flags;
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
670
	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
}

static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
				   struct ieee80211_key_conf *keyconf,
				   u8 sta_id)
{
	unsigned long flags;
	int ret = 0;

	keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
	keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
	priv->stations[sta_id].keyinfo.keylen = 16;
687 688 689 690

	if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
			== STA_KEY_FLG_NO_ENC)
		priv->stations[sta_id].sta.key.key_offset =
691
				 iwl_get_free_ucode_key_index(priv);
692 693
	/* else, we are overriding an existing key => no need to allocated room
	 * in uCode. */
694

T
Tomas Winkler 已提交
695
	/* This copy is actually not needed: we get the key with each TX */
696 697 698 699 700 701 702 703 704
	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);

	memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}

705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
void iwl_update_tkip_key(struct iwl_priv *priv,
			struct ieee80211_key_conf *keyconf,
			const u8 *addr, u32 iv32, u16 *phase1key)
{
	u8 sta_id = IWL_INVALID_STATION;
	unsigned long flags;
	__le16 key_flags = 0;
	int i;
	DECLARE_MAC_BUF(mac);

	sta_id = iwl_find_station(priv, addr);
	if (sta_id == IWL_INVALID_STATION) {
		IWL_DEBUG_MAC80211("leave - %pM not in station map.\n",
				   addr);
		return;
	}

	if (iwl_scan_cancel(priv)) {
		/* cancel scan failed, just live w/ bad key and rely
		   briefly on SW decryption */
		return;
	}

	key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
	key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
	key_flags &= ~STA_KEY_FLG_INVALID;

	if (sta_id == priv->hw_params.bcast_sta_id)
		key_flags |= STA_KEY_MULTICAST_MSK;

	spin_lock_irqsave(&priv->sta_lock, flags);

	priv->stations[sta_id].sta.key.key_flags = key_flags;
	priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;

	for (i = 0; i < 5; i++)
		priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
			cpu_to_le16(phase1key[i]);

	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);

	spin_unlock_irqrestore(&priv->sta_lock, flags);

}
EXPORT_SYMBOL(iwl_update_tkip_key);

754 755 756
int iwl_remove_dynamic_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *keyconf,
				u8 sta_id)
757 758
{
	unsigned long flags;
759 760 761
	int ret = 0;
	u16 key_flags;
	u8 keyidx;
762

763
	priv->key_mapping_key--;
764 765

	spin_lock_irqsave(&priv->sta_lock, flags);
766 767 768
	key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
	keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;

769 770 771
	IWL_DEBUG_WEP("Remove dynamic key: idx=%d sta=%d\n",
		      keyconf->keyidx, sta_id);

772 773 774 775 776 777 778 779 780 781
	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
		 * been replaced by another one with different index.
		 * Don't do anything and return ok
		 */
		spin_unlock_irqrestore(&priv->sta_lock, flags);
		return 0;
	}

782 783 784 785 786
	if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
		&priv->ucode_key_table))
		IWL_ERROR("index %d not used in uCode key table.\n",
			priv->stations[sta_id].sta.key.key_offset);
	memset(&priv->stations[sta_id].keyinfo, 0,
787
					sizeof(struct iwl_hw_key));
788 789
	memset(&priv->stations[sta_id].sta.key, 0,
					sizeof(struct iwl4965_keyinfo));
790 791 792
	priv->stations[sta_id].sta.key.key_flags =
			STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
	priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
793 794 795
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

796
	ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
797 798
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return ret;
799
}
800
EXPORT_SYMBOL(iwl_remove_dynamic_key);
801 802

int iwl_set_dynamic_key(struct iwl_priv *priv,
803
				struct ieee80211_key_conf *keyconf, u8 sta_id)
804 805 806
{
	int ret;

807 808
	priv->key_mapping_key++;
	keyconf->hw_key_idx = HW_KEY_DYNAMIC;
809

810
	switch (keyconf->alg) {
811
	case ALG_CCMP:
812
		ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
813 814
		break;
	case ALG_TKIP:
815
		ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
816 817
		break;
	case ALG_WEP:
818
		ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
819 820
		break;
	default:
821
		IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
822 823 824
		ret = -EINVAL;
	}

825 826 827 828
	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);

829 830
	return ret;
}
831
EXPORT_SYMBOL(iwl_set_dynamic_key);
832

833 834 835 836 837 838
#ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_dump_lq_cmd(struct iwl_priv *priv,
			   struct iwl_link_quality_cmd *lq)
{
	int i;
	IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
T
Tomas Winkler 已提交
839
	IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n",
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
		       lq->general_params.single_stream_ant_msk,
		       lq->general_params.dual_stream_ant_msk);

	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
		IWL_DEBUG_RATE("lq index %d 0x%X\n",
			       i, lq->rs_table[i].rate_n_flags);
}
#else
static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
				   struct iwl_link_quality_cmd *lq)
{
}
#endif

int iwl_send_lq_cmd(struct iwl_priv *priv,
		    struct iwl_link_quality_cmd *lq, u8 flags)
{
	struct iwl_host_cmd cmd = {
		.id = REPLY_TX_LINK_QUALITY_CMD,
		.len = sizeof(struct iwl_link_quality_cmd),
		.meta.flags = flags,
		.data = lq,
	};

	if ((lq->sta_id == 0xFF) &&
865
	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
866 867 868 869 870
		return -EINVAL;

	if (lq->sta_id == 0xFF)
		lq->sta_id = IWL_AP_ID;

871
	iwl_dump_lq_cmd(priv, lq);
872

873
	if (iwl_is_associated(priv) && priv->assoc_station_added)
874 875 876 877 878 879
		return  iwl_send_cmd(priv, &cmd);

	return 0;
}
EXPORT_SYMBOL(iwl_send_lq_cmd);

880 881 882 883 884 885 886
/**
 * iwl_sta_init_lq - Initialize a station's hardware rate table
 *
 * The uCode's station table contains a table of fallback rates
 * for automatic fallback during transmission.
 *
 * NOTE: This sets up a default set of values.  These will be replaced later
887
 *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
888 889 890 891 892 893 894 895 896 897 898 899
 *       rc80211_simple.
 *
 * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
 *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
 *       which requires station table entry to exist).
 */
static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
	int i, r;
	struct iwl_link_quality_cmd link_cmd = {
		.reserved1 = 0,
	};
900
	u32 rate_flags;
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915

	/* Set up the rate scaling to start at selected rate, fall back
	 * all the way down to 1M in IEEE order, and then spin on 1M */
	if (is_ap)
		r = IWL_RATE_54M_INDEX;
	else if (priv->band == IEEE80211_BAND_5GHZ)
		r = IWL_RATE_6M_INDEX;
	else
		r = IWL_RATE_1M_INDEX;

	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
		rate_flags = 0;
		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
			rate_flags |= RATE_MCS_CCK_MSK;

916 917
		rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
				RATE_MCS_ANT_POS;
918 919

		link_cmd.rs_table[i].rate_n_flags =
920
			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
921
		r = iwl_get_prev_ieee_rate(r);
922 923
	}

924 925
	link_cmd.general_params.single_stream_ant_msk =
				first_antenna(priv->hw_params.valid_tx_ant);
926 927 928 929 930 931 932 933 934 935
	link_cmd.general_params.dual_stream_ant_msk = 3;
	link_cmd.agg_params.agg_dis_start_th = 3;
	link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);

	/* Update the rate scaling for control frame Tx to AP */
	link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;

	iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
			       sizeof(link_cmd), &link_cmd, NULL);
}
936

937 938 939 940
/**
 * iwl_rxon_add_station - add station into station table.
 *
 * there is only one AP station with id= IWL_AP_ID
T
Tomas Winkler 已提交
941
 * NOTE: mutex must be held before calling this function
942 943 944
 */
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
{
J
Johannes Berg 已提交
945 946 947
	struct ieee80211_sta *sta;
	struct ieee80211_sta_ht_cap ht_config;
	struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
948 949 950
	u8 sta_id;

	/* Add station to device's station table */
J
Johannes Berg 已提交
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969

	/*
	 * XXX: This check is definitely not correct, if we're an AP
	 *	it'll always be false which is not what we want, but
	 *	it doesn't look like iwlagn is prepared to be an HT
	 *	AP anyway.
	 */
	if (priv->current_ht_config.is_ht) {
		rcu_read_lock();
		sta = ieee80211_find_sta(priv->hw, addr);
		if (sta) {
			memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
			cur_ht_config = &ht_config;
		}
		rcu_read_unlock();
	}

	sta_id = iwl_add_station_flags(priv, addr, is_ap,
				       0, cur_ht_config);
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996

	/* Set up default rate scaling table in device's station table */
	iwl_sta_init_lq(priv, addr, is_ap);

	return sta_id;
}
EXPORT_SYMBOL(iwl_rxon_add_station);

/**
 * iwl_get_sta_id - Find station's index within station table
 *
 * If new IBSS station, create new entry in station table
 */
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
	int sta_id;
	u16 fc = le16_to_cpu(hdr->frame_control);

	/* If this frame is broadcast or management, use broadcast station id */
	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
	    is_multicast_ether_addr(hdr->addr1))
		return priv->hw_params.bcast_sta_id;

	switch (priv->iw_mode) {

	/* If we are a client station in a BSS network, use the special
	 * AP station entry (that's the only station we communicate with) */
997
	case NL80211_IFTYPE_STATION:
998 999 1000
		return IWL_AP_ID;

	/* If we are an AP, then find the station, or use BCAST */
1001
	case NL80211_IFTYPE_AP:
1002 1003 1004 1005 1006 1007 1008
		sta_id = iwl_find_station(priv, hdr->addr1);
		if (sta_id != IWL_INVALID_STATION)
			return sta_id;
		return priv->hw_params.bcast_sta_id;

	/* If this frame is going out to an IBSS network, find the station,
	 * or create a new station table entry */
1009
	case NL80211_IFTYPE_ADHOC:
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
		sta_id = iwl_find_station(priv, hdr->addr1);
		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

		/* Create new station table entry */
		sta_id = iwl_add_station_flags(priv, hdr->addr1,
						   0, CMD_ASYNC, NULL);

		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

J
Johannes Berg 已提交
1021
		IWL_DEBUG_DROP("Station %pM not in station map. "
1022
			       "Defaulting to broadcast...\n",
J
Johannes Berg 已提交
1023
			       hdr->addr1);
1024 1025 1026
		iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
		return priv->hw_params.bcast_sta_id;

1027 1028
	/* If we are in monitor mode, use BCAST. This is required for
	 * packet injection. */
1029
	case NL80211_IFTYPE_MONITOR:
1030 1031
		return priv->hw_params.bcast_sta_id;

1032
	default:
J
Jiri Slaby 已提交
1033
		IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode);
1034 1035 1036 1037 1038
		return priv->hw_params.bcast_sta_id;
	}
}
EXPORT_SYMBOL(iwl_get_sta_id);

1039
/**
1040
 * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
1041
 */
1042
void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
{
	unsigned long flags;

	/* Remove "disable" flag, to enable Tx for this TID */
	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
	priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);

int iwl_sta_rx_agg_start(struct iwl_priv *priv,
			 const u8 *addr, int tid, u16 ssn)
{
	unsigned long flags;
	int sta_id;

	sta_id = iwl_find_station(priv, addr);
	if (sta_id == IWL_INVALID_STATION)
		return -ENXIO;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].sta.station_flags_msk = 0;
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
					CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_rx_agg_start);

int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
{
	unsigned long flags;
	int sta_id;

	sta_id = iwl_find_station(priv, addr);
	if (sta_id == IWL_INVALID_STATION)
		return -ENXIO;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].sta.station_flags_msk = 0;
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
					CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);

static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
	priv->stations[sta_id].sta.sta.modify_mask = 0;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}

void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
{
	/* FIXME: need locking over ps_status ??? */
	u8 sta_id = iwl_find_station(priv, addr);

	if (sta_id != IWL_INVALID_STATION) {
		u8 sta_awake = priv->stations[sta_id].
				ps_status == STA_PS_STATUS_WAKE;

		if (sta_awake && ps_bit)
			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
		else if (!sta_awake && !ps_bit) {
			iwl_sta_modify_ps_wake(priv, sta_id);
			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
		}
	}
}
1132