iwl-sta.c 32.9 KB
Newer Older
1 2
/******************************************************************************
 *
3
 * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
26 27 28 29 30
 * 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
#include "iwl-core.h"
#include "iwl-sta.h"
36

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

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

47 48
	if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
	    (priv->iw_mode == NL80211_IFTYPE_AP))
49 50 51 52 53 54 55 56 57 58 59 60 61 62
		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;
		}

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

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

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

83 84 85 86 87 88
static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
{
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);

89
	if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
90 91
		IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
			sta_id);
92 93

	priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
94
	IWL_DEBUG_ASSOC(priv, "Added STA to Ucode: %pM\n",
J
Johannes Berg 已提交
95
			priv->stations[sta_id].sta.sta.addr);
96 97 98 99

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

100 101 102
static void iwl_add_sta_callback(struct iwl_priv *priv,
				 struct iwl_device_cmd *cmd,
				 struct sk_buff *skb)
103 104
{
	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

	if (!skb) {
110
		IWL_ERR(priv, "Error: Response NULL in REPLY_ADD_STA.\n");
111
		return;
112 113 114 115
	}

	res = (struct iwl_rx_packet *)skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
116
		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
117
			  res->hdr.flags);
118
		return;
119 120 121 122
	}

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

132
int iwl_send_add_sta(struct iwl_priv *priv,
133 134 135 136 137 138 139
		     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,
J
Johannes Berg 已提交
140
		.flags = flags,
141 142 143
		.data = data,
	};

144
	if (flags & CMD_ASYNC)
J
Johannes Berg 已提交
145
		cmd.callback = iwl_add_sta_callback;
146
	else
J
Johannes Berg 已提交
147
		cmd.flags |= CMD_WANT_SKB;
148 149 150 151 152 153 154

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

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

J
Johannes Berg 已提交
155
	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
156
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
157
		IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",
158 159 160 161 162 163 164
			  res->hdr.flags);
		ret = -EIO;
	}

	if (ret == 0) {
		switch (res->u.add_sta.status) {
		case ADD_STA_SUCCESS_MSK:
165
			iwl_sta_ucode_activate(priv, sta->sta.sta_id);
166
			IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");
167 168 169
			break;
		default:
			ret = -EIO;
170
			IWL_WARN(priv, "REPLY_ADD_STA failed\n");
171 172 173 174 175
			break;
		}
	}

	priv->alloc_rxb_skb--;
J
Johannes Berg 已提交
176
	dev_kfree_skb_any(cmd.reply_skb);
177 178 179

	return ret;
}
180
EXPORT_SYMBOL(iwl_send_add_sta);
181

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

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

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

	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) {
198
	case WLAN_HT_CAP_SM_PS_STATIC:
199 200
		sta_flags |= STA_FLG_MIMO_DIS_MSK;
		break;
201
	case WLAN_HT_CAP_SM_PS_DYNAMIC:
202 203
		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
		break;
204
	case WLAN_HT_CAP_SM_PS_DISABLED:
205 206
		break;
	default:
207
		IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode);
208 209 210 211 212 213 214 215 216
		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);

217 218
	if (iwl_is_ht40_tx_allowed(priv, sta_ht_inf))
		sta_flags |= STA_FLG_HT40_EN_MSK;
219
	else
220
		sta_flags &= ~STA_FLG_HT40_EN_MSK;
221 222 223 224 225 226 227

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

/**
228
 * iwl_add_station - Add station to tables in driver and device
229
 */
230 231
u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
		struct ieee80211_sta_ht_cap *ht_info)
232 233 234
{
	struct iwl_station_entry *station;
	unsigned long flags_spin;
235 236 237
	int i;
	int sta_id = IWL_INVALID_STATION;
	u16 rate;
238 239 240

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

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

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

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


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

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

289 290 291 292 293 294
	/* 3945 only */
	rate = (priv->band == IEEE80211_BAND_5GHZ) ?
		IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
	/* Turn on both antennas for the station... */
	station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);

295 296 297 298
	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);

	/* Add station to device's station table */
	iwl_send_add_sta(priv, &station->sta, flags);
299
	return sta_id;
300 301

}
302
EXPORT_SYMBOL(iwl_add_station);
303

304
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
305 306
{
	unsigned long flags;
307
	u8 sta_id = iwl_find_station(priv, addr);
308 309 310

	BUG_ON(sta_id == IWL_INVALID_STATION);

311
	IWL_DEBUG_ASSOC(priv, "Removed STA from Ucode: %pM\n", addr);
312 313 314 315 316

	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)
317
		IWL_ERR(priv, "removed non active STA %d\n", sta_id);
318 319 320 321 322

	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);
323 324
}

325 326 327
static void iwl_remove_sta_callback(struct iwl_priv *priv,
				    struct iwl_device_cmd *cmd,
				    struct sk_buff *skb)
328 329
{
	struct iwl_rx_packet *res = NULL;
330 331 332
	struct iwl_rem_sta_cmd *rm_sta =
		 (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
	const char *addr = rm_sta->addr;
333 334

	if (!skb) {
335
		IWL_ERR(priv, "Error: Response NULL in REPLY_REMOVE_STA.\n");
336
		return;
337 338 339 340
	}

	res = (struct iwl_rx_packet *)skb->data;
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
341
		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
342
		res->hdr.flags);
343
		return;
344 345 346 347 348 349 350
	}

	switch (res->u.rem_sta.status) {
	case REM_STA_SUCCESS_MSK:
		iwl_sta_ucode_deactivate(priv, addr);
		break;
	default:
351
		IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
		break;
	}
}

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),
J
Johannes Berg 已提交
367
		.flags = flags,
368 369 370 371 372 373 374 375
		.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)
J
Johannes Berg 已提交
376
		cmd.callback = iwl_remove_sta_callback;
377
	else
J
Johannes Berg 已提交
378
		cmd.flags |= CMD_WANT_SKB;
379 380 381 382 383
	ret = iwl_send_cmd(priv, &cmd);

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

J
Johannes Berg 已提交
384
	res = (struct iwl_rx_packet *)cmd.reply_skb->data;
385
	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
386
		IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
387 388 389 390 391 392 393 394
			  res->hdr.flags);
		ret = -EIO;
	}

	if (!ret) {
		switch (res->u.rem_sta.status) {
		case REM_STA_SUCCESS_MSK:
			iwl_sta_ucode_deactivate(priv, addr);
395
			IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
396 397 398
			break;
		default:
			ret = -EIO;
399
			IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
400 401 402 403 404
			break;
		}
	}

	priv->alloc_rxb_skb--;
J
Johannes Berg 已提交
405
	dev_kfree_skb_any(cmd.reply_skb);
406 407 408

	return ret;
}
409

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

	spin_lock_irqsave(&priv->sta_lock, flags);

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

434
	if (unlikely(sta_id == IWL_INVALID_STATION))
435 436
		goto out;

437
	IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
J
Johannes Berg 已提交
438
		sta_id, addr);
439 440

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

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

452 453 454 455 456

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

	priv->num_stations--;

457
	BUG_ON(priv->num_stations < 0);
458

459
	spin_unlock_irqrestore(&priv->sta_lock, flags);
460 461 462

	ret = iwl_send_remove_station(priv, addr, CMD_ASYNC);
	return ret;
463 464
out:
	spin_unlock_irqrestore(&priv->sta_lock, flags);
465
	return ret;
466
}
467

468 469 470 471 472 473 474 475
/**
 * iwl_clear_stations_table - Clear the driver's station table
 *
 * NOTE:  This does not clear or otherwise alter the device's station table.
 */
void iwl_clear_stations_table(struct iwl_priv *priv)
{
	unsigned long flags;
476
	int i;
477 478 479 480 481 482

	spin_lock_irqsave(&priv->sta_lock, flags);

	if (iwl_is_alive(priv) &&
	   !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
	   iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
483
		IWL_ERR(priv, "Couldn't clear the station table\n");
484 485 486 487

	priv->num_stations = 0;
	memset(priv->stations, 0, sizeof(priv->stations));

488 489 490
	/* clean ucode key table bit map */
	priv->ucode_key_table = 0;

491 492 493
	/* keep track of static keys */
	for (i = 0; i < WEP_KEYS_MAX ; i++) {
		if (priv->wep_keys[i].key_size)
494
			set_bit(i, &priv->ucode_key_table);
495 496
	}

497 498 499 500
	spin_unlock_irqrestore(&priv->sta_lock, flags);
}
EXPORT_SYMBOL(iwl_clear_stations_table);

501
int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
502 503 504 505
{
	int i;

	for (i = 0; i < STA_KEY_MAX_NUM; i++)
506
		if (!test_and_set_bit(i, &priv->ucode_key_table))
507 508
			return i;

509
	return WEP_INVALID_OFFSET;
510
}
511
EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
512 513 514 515 516 517 518 519 520 521 522

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,
J
Johannes Berg 已提交
523
		.flags = CMD_ASYNC,
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
	};

	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;
}
555
EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
556 557

int iwl_remove_default_wep_key(struct iwl_priv *priv,
558
			       struct ieee80211_key_conf *keyconf)
559 560 561 562 563
{
	int ret;
	unsigned long flags;

	spin_lock_irqsave(&priv->sta_lock, flags);
564 565
	IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
		      keyconf->keyidx);
566 567

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

571
	priv->default_wep_key--;
572
	memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
573 574 575 576 577
	if (iwl_is_rfkill(priv)) {
		IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
		spin_unlock_irqrestore(&priv->sta_lock, flags);
		return 0;
	}
578
	ret = iwl_send_static_wepkey_cmd(priv, 1);
579
	IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
580
		      keyconf->keyidx, ret);
581 582 583 584
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
585
EXPORT_SYMBOL(iwl_remove_default_wep_key);
586 587 588 589 590 591 592

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

593 594
	if (keyconf->keylen != WEP_KEY_LEN_128 &&
	    keyconf->keylen != WEP_KEY_LEN_64) {
595
		IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen);
596 597 598
		return -EINVAL;
	}

599
	keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
600
	keyconf->hw_key_idx = HW_KEY_DEFAULT;
601 602 603 604 605
	priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;

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

606
	if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
607
		IWL_ERR(priv, "index %d already used in uCode key table.\n",
608 609
			keyconf->keyidx);

610 611 612 613 614
	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);
615
	IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
616
		keyconf->keylen, keyconf->keyidx, ret);
617 618 619 620
	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
621
EXPORT_SYMBOL(iwl_set_default_wep_key);
622

623
static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
				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 已提交
640
	if (sta_id == priv->hw_params.bcast_sta_id)
641 642 643 644 645 646 647 648 649 650 651 652 653 654
		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);

655 656 657
	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 =
658
				 iwl_get_free_ucode_key_index(priv);
659 660
	/* else, we are overriding an existing key => no need to allocated room
	 * in uCode. */
661

662
	WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
J
Jiri Slaby 已提交
663
		"no space for a new key");
664

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

669
	ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
670 671 672 673 674

	spin_unlock_irqrestore(&priv->sta_lock, flags);

	return ret;
}
675 676 677 678 679 680 681

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;
682
	int ret;
683 684 685 686 687

	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 已提交
688
	if (sta_id == priv->hw_params.bcast_sta_id)
689 690 691 692 693 694 695 696 697 698 699 700 701 702
		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);

703 704 705 706 707 708 709
	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. */

710
	WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
J
Jiri Slaby 已提交
711
		"no space for a new key");
712

713 714 715 716
	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;

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

719 720
	spin_unlock_irqrestore(&priv->sta_lock, flags);

721
	return ret;
722 723 724 725 726 727 728 729
}

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;
730 731 732 733 734 735 736 737
	__le16 key_flags = 0;

	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;
738 739 740 741 742 743 744 745

	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;
746 747 748 749

	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 =
750
				 iwl_get_free_ucode_key_index(priv);
751 752
	/* else, we are overriding an existing key => no need to allocated room
	 * in uCode. */
753

754
	WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
J
Jiri Slaby 已提交
755
		"no space for a new key");
756

757 758 759
	priv->stations[sta_id].sta.key.key_flags = key_flags;


760 761 762 763 764 765 766 767 768 769
	/* This copy is acutally not needed: we get the key with each TX */
	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;
}

770 771 772 773 774 775 776 777
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;
	int i;

778
	sta_id = iwl_find_station(priv, addr);
779
	if (sta_id == IWL_INVALID_STATION) {
780
		IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
				   addr);
		return;
	}

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

	spin_lock_irqsave(&priv->sta_lock, 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);

809 810 811
int iwl_remove_dynamic_key(struct iwl_priv *priv,
				struct ieee80211_key_conf *keyconf,
				u8 sta_id)
812 813
{
	unsigned long flags;
814 815 816
	int ret = 0;
	u16 key_flags;
	u8 keyidx;
817

818
	priv->key_mapping_key--;
819 820

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

824
	IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n",
825 826
		      keyconf->keyidx, sta_id);

827 828 829 830 831 832 833 834 835 836
	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;
	}

837
	if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
838
		IWL_WARN(priv, "Removing wrong key %d 0x%x\n",
839 840 841 842 843
			    keyconf->keyidx, key_flags);
		spin_unlock_irqrestore(&priv->sta_lock, flags);
		return 0;
	}

844 845
	if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
		&priv->ucode_key_table))
846
		IWL_ERR(priv, "index %d not used in uCode key table.\n",
847 848
			priv->stations[sta_id].sta.key.key_offset);
	memset(&priv->stations[sta_id].keyinfo, 0,
849
					sizeof(struct iwl_hw_key));
850 851
	memset(&priv->stations[sta_id].sta.key, 0,
					sizeof(struct iwl4965_keyinfo));
852 853 854
	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;
855 856 857
	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;

858 859 860 861 862
	if (iwl_is_rfkill(priv)) {
		IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
		spin_unlock_irqrestore(&priv->sta_lock, flags);
		return 0;
	}
863
	ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
864 865
	spin_unlock_irqrestore(&priv->sta_lock, flags);
	return ret;
866
}
867
EXPORT_SYMBOL(iwl_remove_dynamic_key);
868 869

int iwl_set_dynamic_key(struct iwl_priv *priv,
870
				struct ieee80211_key_conf *keyconf, u8 sta_id)
871 872 873
{
	int ret;

874 875
	priv->key_mapping_key++;
	keyconf->hw_key_idx = HW_KEY_DYNAMIC;
876

877
	switch (keyconf->alg) {
878
	case ALG_CCMP:
879
		ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
880 881
		break;
	case ALG_TKIP:
882
		ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
883 884
		break;
	case ALG_WEP:
885
		ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
886 887
		break;
	default:
888 889
		IWL_ERR(priv,
			"Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
890 891 892
		ret = -EINVAL;
	}

893
	IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
894 895 896
		      keyconf->alg, keyconf->keylen, keyconf->keyidx,
		      sta_id, ret);

897 898
	return ret;
}
899
EXPORT_SYMBOL(iwl_set_dynamic_key);
900

901 902 903 904 905
#ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_dump_lq_cmd(struct iwl_priv *priv,
			   struct iwl_link_quality_cmd *lq)
{
	int i;
906 907
	IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id);
	IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n",
908 909 910 911
		       lq->general_params.single_stream_ant_msk,
		       lq->general_params.dual_stream_ant_msk);

	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
912
		IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n",
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
			       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),
J
Johannes Berg 已提交
928
		.flags = flags,
929 930 931 932
		.data = lq,
	};

	if ((lq->sta_id == 0xFF) &&
933
	    (priv->iw_mode == NL80211_IFTYPE_ADHOC))
934 935 936 937 938
		return -EINVAL;

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

939
	iwl_dump_lq_cmd(priv, lq);
940

941
	if (iwl_is_associated(priv) && priv->assoc_station_added)
942 943 944 945 946 947
		return  iwl_send_cmd(priv, &cmd);

	return 0;
}
EXPORT_SYMBOL(iwl_send_lq_cmd);

948 949 950 951 952 953 954
/**
 * 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
955
 *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
956 957 958 959 960 961
 *       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).
 */
962
static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
963 964 965 966 967
{
	int i, r;
	struct iwl_link_quality_cmd link_cmd = {
		.reserved1 = 0,
	};
968
	u32 rate_flags;
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983

	/* 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;

984 985
		rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
				RATE_MCS_ANT_POS;
986 987

		link_cmd.rs_table[i].rate_n_flags =
988
			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
989
		r = iwl_get_prev_ieee_rate(r);
990 991
	}

992 993
	link_cmd.general_params.single_stream_ant_msk =
				first_antenna(priv->hw_params.valid_tx_ant);
994
	link_cmd.general_params.dual_stream_ant_msk = 3;
995 996 997
	link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
	link_cmd.agg_params.agg_time_limit =
		cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
998 999 1000 1001 1002 1003 1004

	/* 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);
}
1005

1006 1007 1008 1009
/**
 * iwl_rxon_add_station - add station into station table.
 *
 * there is only one AP station with id= IWL_AP_ID
T
Tomas Winkler 已提交
1010
 * NOTE: mutex must be held before calling this function
1011
 */
1012
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
1013
{
J
Johannes Berg 已提交
1014 1015 1016
	struct ieee80211_sta *sta;
	struct ieee80211_sta_ht_cap ht_config;
	struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
1017 1018 1019
	u8 sta_id;

	/* Add station to device's station table */
J
Johannes Berg 已提交
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

	/*
	 * 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();
	}

1037
	sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053

	/* 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;
1054
	__le16 fc = hdr->frame_control;
1055 1056

	/* If this frame is broadcast or management, use broadcast station id */
1057
	if (!ieee80211_is_data(fc) ||  is_multicast_ether_addr(hdr->addr1))
1058 1059 1060 1061 1062 1063
		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) */
1064
	case NL80211_IFTYPE_STATION:
1065 1066 1067
		return IWL_AP_ID;

	/* If we are an AP, then find the station, or use BCAST */
1068
	case NL80211_IFTYPE_AP:
1069
		sta_id = iwl_find_station(priv, hdr->addr1);
1070 1071 1072 1073 1074 1075
		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 */
1076
	case NL80211_IFTYPE_ADHOC:
1077
		sta_id = iwl_find_station(priv, hdr->addr1);
1078 1079 1080 1081
		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

		/* Create new station table entry */
1082 1083
		sta_id = iwl_add_station(priv, hdr->addr1, false,
					CMD_ASYNC, NULL);
1084 1085 1086 1087

		if (sta_id != IWL_INVALID_STATION)
			return sta_id;

1088
		IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
1089
			       "Defaulting to broadcast...\n",
J
Johannes Berg 已提交
1090
			       hdr->addr1);
1091
		iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
1092 1093 1094
		return priv->hw_params.bcast_sta_id;

	default:
1095 1096
		IWL_WARN(priv, "Unknown mode of operation: %d\n",
			priv->iw_mode);
1097 1098 1099 1100 1101
		return priv->hw_params.bcast_sta_id;
	}
}
EXPORT_SYMBOL(iwl_get_sta_id);

1102
/**
1103
 * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
1104
 */
1105
void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
{
	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);
}
1118 1119 1120 1121 1122 1123 1124 1125
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;

1126
	sta_id = iwl_find_station(priv, addr);
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
	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;

1148
	sta_id = iwl_find_station(priv, addr);
1149 1150
	if (sta_id == IWL_INVALID_STATION) {
		IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
1151
		return -ENXIO;
1152
	}
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182

	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 ??? */
1183
	u8 sta_id = iwl_find_station(priv, addr);
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196

	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;
		}
	}
}
1197