wl_cfg80211.c 152.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Copyright (c) 2010 Broadcom Corporation
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */

#include <linux/kernel.h>
#include <linux/etherdevice.h>
21
#include <linux/module.h>
22
#include <linux/vmalloc.h>
23
#include <net/cfg80211.h>
24
#include <net/netlink.h>
25 26 27 28 29

#include <brcmu_utils.h>
#include <defs.h>
#include <brcmu_wifi.h>
#include "dhd.h"
30
#include "dhd_dbg.h"
31
#include "tracepoint.h"
32
#include "fwil_types.h"
33
#include "p2p.h"
34
#include "btcoex.h"
35
#include "wl_cfg80211.h"
36
#include "feature.h"
37
#include "fwil.h"
38
#include "proto.h"
39
#include "vendor.h"
40

41 42 43 44 45 46 47 48 49 50 51 52
#define BRCMF_SCAN_IE_LEN_MAX		2048
#define BRCMF_PNO_VERSION		2
#define BRCMF_PNO_TIME			30
#define BRCMF_PNO_REPEAT		4
#define BRCMF_PNO_FREQ_EXPO_MAX		3
#define BRCMF_PNO_MAX_PFN_COUNT		16
#define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT	6
#define BRCMF_PNO_HIDDEN_BIT		2
#define BRCMF_PNO_WPA_AUTH_ANY		0xFFFFFFFF
#define BRCMF_PNO_SCAN_COMPLETE		1
#define BRCMF_PNO_SCAN_INCOMPLETE	0

53
#define BRCMF_IFACE_MAX_CNT		3
54

H
Hante Meuleman 已提交
55 56 57 58
#define WPA_OUI				"\x00\x50\xF2"	/* WPA OUI */
#define WPA_OUI_TYPE			1
#define RSN_OUI				"\x00\x0F\xAC"	/* RSN OUI */
#define	WME_OUI_TYPE			2
59
#define WPS_OUI_TYPE			4
H
Hante Meuleman 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

#define VS_IE_FIXED_HDR_LEN		6
#define WPA_IE_VERSION_LEN		2
#define WPA_IE_MIN_OUI_LEN		4
#define WPA_IE_SUITE_COUNT_LEN		2

#define WPA_CIPHER_NONE			0	/* None */
#define WPA_CIPHER_WEP_40		1	/* WEP (40-bit) */
#define WPA_CIPHER_TKIP			2	/* TKIP: default for WPA */
#define WPA_CIPHER_AES_CCM		4	/* AES (CCM) */
#define WPA_CIPHER_WEP_104		5	/* WEP (104-bit) */

#define RSN_AKM_NONE			0	/* None (IBSS) */
#define RSN_AKM_UNSPECIFIED		1	/* Over 802.1x */
#define RSN_AKM_PSK			2	/* Pre-shared Key */
#define RSN_CAP_LEN			2	/* Length of RSN capabilities */
#define RSN_CAP_PTK_REPLAY_CNTR_MASK	0x000C

#define VNDR_IE_CMD_LEN			4	/* length of the set command
						 * string :"add", "del" (+ NUL)
						 */
#define VNDR_IE_COUNT_OFFSET		4
#define VNDR_IE_PKTFLAG_OFFSET		8
#define VNDR_IE_VSIE_OFFSET		12
#define VNDR_IE_HDR_SIZE		12
85
#define VNDR_IE_PARSE_LIMIT		5
H
Hante Meuleman 已提交
86 87 88

#define	DOT11_MGMT_HDR_LEN		24	/* d11 management header len */
#define	DOT11_BCN_PRB_FIXED_LEN		12	/* beacon/probe fixed length */
89

90 91 92 93
#define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS	320
#define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS	400
#define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS	20

94 95 96
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))

97
static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
98
{
99
	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
100 101
		brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
			  vif->sme_state);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
		return false;
	}
	return true;
}

#define RATE_TO_BASE100KBPS(rate)   (((rate) * 10) / 2)
#define RATETAB_ENT(_rateid, _flags) \
	{                                                               \
		.bitrate        = RATE_TO_BASE100KBPS(_rateid),     \
		.hw_value       = (_rateid),                            \
		.flags          = (_flags),                             \
	}

static struct ieee80211_rate __wl_rates[] = {
	RATETAB_ENT(BRCM_RATE_1M, 0),
	RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
	RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
	RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
	RATETAB_ENT(BRCM_RATE_6M, 0),
	RATETAB_ENT(BRCM_RATE_9M, 0),
	RATETAB_ENT(BRCM_RATE_12M, 0),
	RATETAB_ENT(BRCM_RATE_18M, 0),
	RATETAB_ENT(BRCM_RATE_24M, 0),
	RATETAB_ENT(BRCM_RATE_36M, 0),
	RATETAB_ENT(BRCM_RATE_48M, 0),
	RATETAB_ENT(BRCM_RATE_54M, 0),
};

#define wl_a_rates		(__wl_rates + 4)
#define wl_a_rates_size	8
#define wl_g_rates		(__wl_rates + 0)
#define wl_g_rates_size	12

135 136 137 138
/* Band templates duplicated per wiphy. The channel info
 * is filled in after querying the device.
 */
static const struct ieee80211_supported_band __wl_band_2ghz = {
139 140 141 142 143
	.band = IEEE80211_BAND_2GHZ,
	.bitrates = wl_g_rates,
	.n_bitrates = wl_g_rates_size,
};

144
static const struct ieee80211_supported_band __wl_band_5ghz_a = {
145 146 147 148 149
	.band = IEEE80211_BAND_5GHZ,
	.bitrates = wl_a_rates,
	.n_bitrates = wl_a_rates_size,
};

150 151
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
 * By default world regulatory domain defined in reg.c puts the flags
152 153 154
 * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
 * With respect to these flags, wpa_supplicant doesn't * start p2p
 * operations on 5GHz channels. All the changes in world regulatory
155 156 157 158 159 160 161 162 163 164 165 166 167 168
 * domain are to be done here.
 */
static const struct ieee80211_regdomain brcmf_regdom = {
	.n_reg_rules = 4,
	.alpha2 =  "99",
	.reg_rules = {
		/* IEEE 802.11b/g, channels 1..11 */
		REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
		/* If any */
		/* IEEE 802.11 channel 14 - Only JP enables
		 * this and for 802.11b only
		 */
		REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
		/* IEEE 802.11a, channel 36..64 */
169
		REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
170
		/* IEEE 802.11a, channel 100..165 */
171
		REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
172 173 174 175 176 177 178 179 180 181
};

static const u32 __wl_cipher_suites[] = {
	WLAN_CIPHER_SUITE_WEP40,
	WLAN_CIPHER_SUITE_WEP104,
	WLAN_CIPHER_SUITE_TKIP,
	WLAN_CIPHER_SUITE_CCMP,
	WLAN_CIPHER_SUITE_AES_CMAC,
};

H
Hante Meuleman 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
/* Vendor specific ie. id = 221, oui and type defines exact ie */
struct brcmf_vs_tlv {
	u8 id;
	u8 len;
	u8 oui[3];
	u8 oui_type;
};

struct parsed_vndr_ie_info {
	u8 *ie_ptr;
	u32 ie_len;	/* total length including id & length field */
	struct brcmf_vs_tlv vndrie;
};

struct parsed_vndr_ies {
	u32 count;
198
	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
H
Hante Meuleman 已提交
199 200
};

201 202 203 204
static int brcmf_roamoff;
module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
MODULE_PARM_DESC(roamoff, "do not use internal roaming engine");

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
/* Quarter dBm units to mW
 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
 * Table is offset so the last entry is largest mW value that fits in
 * a u16.
 */

#define QDBM_OFFSET 153		/* Offset for first entry */
#define QDBM_TABLE_LEN 40	/* Table size */

/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
 */
#define QDBM_TABLE_LOW_BOUND 6493	/* Low bound */

/* Largest mW value that will round down to the last table entry,
 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
 * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
 */
#define QDBM_TABLE_HIGH_BOUND 64938	/* High bound */

static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
/* qdBm:	+0	+1	+2	+3	+4	+5	+6	+7 */
/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
};

static u16 brcmf_qdbm_to_mw(u8 qdbm)
{
	uint factor = 1;
	int idx = qdbm - QDBM_OFFSET;

	if (idx >= QDBM_TABLE_LEN)
		/* clamp to max u16 mW value */
		return 0xFFFF;

	/* scale the qdBm index up to the range of the table 0-40
	 * where an offset of 40 qdBm equals a factor of 10 mW.
	 */
	while (idx < 0) {
		idx += 40;
		factor *= 10;
	}

	/* return the mW value scaled down to the correct factor of 10,
	 * adding in factor/2 to get proper rounding.
	 */
	return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
}

static u8 brcmf_mw_to_qdbm(u16 mw)
{
	u8 qdbm;
	int offset;
	uint mw_uint = mw;
	uint boundary;

	/* handle boundary case */
	if (mw_uint <= 1)
		return 0;

	offset = QDBM_OFFSET;

	/* move mw into the range of the table */
	while (mw_uint < QDBM_TABLE_LOW_BOUND) {
		mw_uint *= 10;
		offset -= 40;
	}

	for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
		boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
						    nqdBm_to_mW_map[qdbm]) / 2;
		if (mw_uint < boundary)
			break;
	}

	qdbm += (u8) offset;

	return qdbm;
}

289 290
static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
			       struct cfg80211_chan_def *ch)
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
{
	struct brcmu_chan ch_inf;
	s32 primary_offset;

	brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
		  ch->chan->center_freq, ch->center_freq1, ch->width);
	ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
	primary_offset = ch->center_freq1 - ch->chan->center_freq;
	switch (ch->width) {
	case NL80211_CHAN_WIDTH_20:
		ch_inf.bw = BRCMU_CHAN_BW_20;
		WARN_ON(primary_offset != 0);
		break;
	case NL80211_CHAN_WIDTH_40:
		ch_inf.bw = BRCMU_CHAN_BW_40;
		if (primary_offset < 0)
			ch_inf.sb = BRCMU_CHAN_SB_U;
		else
			ch_inf.sb = BRCMU_CHAN_SB_L;
		break;
	case NL80211_CHAN_WIDTH_80:
		ch_inf.bw = BRCMU_CHAN_BW_80;
		if (primary_offset < 0) {
			if (primary_offset < -CH_10MHZ_APART)
				ch_inf.sb = BRCMU_CHAN_SB_UU;
			else
				ch_inf.sb = BRCMU_CHAN_SB_UL;
		} else {
			if (primary_offset > CH_10MHZ_APART)
				ch_inf.sb = BRCMU_CHAN_SB_LL;
			else
				ch_inf.sb = BRCMU_CHAN_SB_LU;
		}
		break;
	default:
		WARN_ON_ONCE(1);
	}
	switch (ch->chan->band) {
	case IEEE80211_BAND_2GHZ:
		ch_inf.band = BRCMU_CHAN_BAND_2G;
		break;
	case IEEE80211_BAND_5GHZ:
		ch_inf.band = BRCMU_CHAN_BAND_5G;
		break;
	default:
		WARN_ON_ONCE(1);
	}
	d11inf->encchspec(&ch_inf);

	return ch_inf.chspec;
}

F
Franky Lin 已提交
343 344
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
			struct ieee80211_channel *ch)
345
{
F
Franky Lin 已提交
346
	struct brcmu_chan ch_inf;
347

F
Franky Lin 已提交
348 349 350
	ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
	ch_inf.bw = BRCMU_CHAN_BW_20;
	d11inf->encchspec(&ch_inf);
351

F
Franky Lin 已提交
352
	return ch_inf.chspec;
353 354
}

355 356 357 358
/* Traverse a string of 1-byte tag/1-byte length/variable-length value
 * triples, returning a pointer to the substring whose first element
 * matches tag
 */
359 360
const struct brcmf_tlv *
brcmf_parse_tlvs(const void *buf, int buflen, uint key)
361
{
362 363
	const struct brcmf_tlv *elt = buf;
	int totlen = buflen;
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383

	/* find tagged parameter */
	while (totlen >= TLV_HDR_LEN) {
		int len = elt->len;

		/* validate remaining totlen */
		if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN)))
			return elt;

		elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN));
		totlen -= (len + TLV_HDR_LEN);
	}

	return NULL;
}

/* Is any of the tlvs the expected entry? If
 * not update the tlvs buffer pointer/length.
 */
static bool
384 385
brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
		 const u8 *oui, u32 oui_len, u8 type)
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
{
	/* If the contents match the OUI and the type */
	if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
	    !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
	    type == ie[TLV_BODY_OFF + oui_len]) {
		return true;
	}

	if (tlvs == NULL)
		return false;
	/* point to the next ie */
	ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
	/* calculate the length of the rest of the buffer */
	*tlvs_len -= (int)(ie - *tlvs);
	/* update the pointer to the start of the buffer */
	*tlvs = ie;

	return false;
}

static struct brcmf_vs_tlv *
407
brcmf_find_wpaie(const u8 *parse, u32 len)
408
{
409
	const struct brcmf_tlv *ie;
410 411

	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
412
		if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,
413 414 415 416 417 418 419
				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
			return (struct brcmf_vs_tlv *)ie;
	}
	return NULL;
}

static struct brcmf_vs_tlv *
420
brcmf_find_wpsie(const u8 *parse, u32 len)
421
{
422
	const struct brcmf_tlv *ie;
423 424 425 426 427 428 429 430 431 432

	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
				     WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE))
			return (struct brcmf_vs_tlv *)ie;
	}
	return NULL;
}


433 434 435 436 437 438 439 440 441 442 443 444 445 446
static void convert_key_from_CPU(struct brcmf_wsec_key *key,
				 struct brcmf_wsec_key_le *key_le)
{
	key_le->index = cpu_to_le32(key->index);
	key_le->len = cpu_to_le32(key->len);
	key_le->algo = cpu_to_le32(key->algo);
	key_le->flags = cpu_to_le32(key->flags);
	key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
	key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
	key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
	memcpy(key_le->data, key->data, sizeof(key->data));
	memcpy(key_le->ea, key->ea, sizeof(key->ea));
}

447
static int
448
send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
449 450 451 452 453
{
	int err;
	struct brcmf_wsec_key_le key_le;

	convert_key_from_CPU(key, &key_le);
454

455 456
	brcmf_netdev_wait_pend8021x(ndev);

457
	err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
458
					sizeof(key_le));
459

460
	if (err)
461
		brcmf_err("wsec_key error (%d)\n", err);
462 463 464
	return err;
}

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
static s32
brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
{
	s32 err;
	u32 mode;

	if (enable)
		mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
	else
		mode = 0;

	/* Try to set and enable ARP offload feature, this may fail, then it  */
	/* is simply not supported and err 0 will be returned                 */
	err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
	if (err) {
		brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
			  mode, err);
		err = 0;
	} else {
		err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
		if (err) {
			brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
				  enable, err);
			err = 0;
		} else
			brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
				  enable, mode);
	}

	return err;
}

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
static void
brcmf_cfg80211_update_proto_addr_mode(struct wireless_dev *wdev)
{
	struct net_device *ndev = wdev->netdev;
	struct brcmf_if *ifp = netdev_priv(ndev);

	if ((wdev->iftype == NL80211_IFTYPE_ADHOC) ||
	    (wdev->iftype == NL80211_IFTYPE_AP) ||
	    (wdev->iftype == NL80211_IFTYPE_P2P_GO))
		brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
						ADDR_DIRECT);
	else
		brcmf_proto_configure_addr_mode(ifp->drvr, ifp->ifidx,
						ADDR_INDIRECT);
}

513 514 515 516 517 518 519 520 521 522 523 524 525
static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif)
{
	enum nl80211_iftype iftype;

	iftype = vif->wdev.iftype;
	return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO;
}

static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
{
	return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
}

526 527 528 529 530 531
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
						     const char *name,
						     enum nl80211_iftype type,
						     u32 *flags,
						     struct vif_params *params)
{
532 533
	struct wireless_dev *wdev;

534 535 536 537 538 539 540 541 542 543 544 545
	brcmf_dbg(TRACE, "enter: %s type %d\n", name, type);
	switch (type) {
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_WDS:
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_MESH_POINT:
		return ERR_PTR(-EOPNOTSUPP);
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_P2P_GO:
546
	case NL80211_IFTYPE_P2P_DEVICE:
547 548 549 550
		wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params);
		if (!IS_ERR(wdev))
			brcmf_cfg80211_update_proto_addr_mode(wdev);
		return wdev;
551 552 553 554 555 556
	case NL80211_IFTYPE_UNSPECIFIED:
	default:
		return ERR_PTR(-EINVAL);
	}
}

557 558
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
{
559
	if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
560 561 562
		brcmf_set_mpc(ifp, mpc);
}

563
void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
564 565 566 567 568 569 570 571 572 573 574 575 576
{
	s32 err = 0;

	if (check_vif_up(ifp->vif)) {
		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
		if (err) {
			brcmf_err("fail to set mpc\n");
			return;
		}
		brcmf_dbg(INFO, "MPC : %d\n", mpc);
	}
}

577 578 579
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
				struct brcmf_if *ifp, bool aborted,
				bool fw_abort)
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
{
	struct brcmf_scan_params_le params_le;
	struct cfg80211_scan_request *scan_request;
	s32 err = 0;

	brcmf_dbg(SCAN, "Enter\n");

	/* clear scan request, because the FW abort can cause a second call */
	/* to this functon and might cause a double cfg80211_scan_done      */
	scan_request = cfg->scan_request;
	cfg->scan_request = NULL;

	if (timer_pending(&cfg->escan_timeout))
		del_timer_sync(&cfg->escan_timeout);

	if (fw_abort) {
		/* Do a scan abort to stop the driver's scan engine */
		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
		memset(&params_le, 0, sizeof(params_le));
		memset(params_le.bssid, 0xFF, ETH_ALEN);
		params_le.bss_type = DOT11_BSSTYPE_ANY;
		params_le.scan_type = 0;
		params_le.channel_num = cpu_to_le32(1);
		params_le.nprobes = cpu_to_le32(1);
		params_le.active_time = cpu_to_le32(-1);
		params_le.passive_time = cpu_to_le32(-1);
		params_le.home_time = cpu_to_le32(-1);
		/* Scan is aborted by setting channel_list[0] to -1 */
		params_le.channel_list[0] = cpu_to_le16(-1);
		/* E-Scan (or anyother type) can be aborted by SCAN */
610
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
611 612 613 614
					     &params_le, sizeof(params_le));
		if (err)
			brcmf_err("Scan abort  failed\n");
	}
615

616
	brcmf_scan_config_mpc(ifp, 1);
617

618 619 620 621 622 623 624 625 626 627 628 629 630 631
	/*
	 * e-scan can be initiated by scheduled scan
	 * which takes precedence.
	 */
	if (cfg->sched_escan) {
		brcmf_dbg(SCAN, "scheduled scan completed\n");
		cfg->sched_escan = false;
		if (!aborted)
			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
	} else if (scan_request) {
		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
			  aborted ? "Aborted" : "Done");
		cfg80211_scan_done(scan_request, aborted);
	}
632 633
	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
		brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
634 635 636 637

	return err;
}

638 639 640
static
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
{
641 642 643 644 645 646 647 648 649
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
	struct net_device *ndev = wdev->netdev;

	/* vif event pending in firmware */
	if (brcmf_cfg80211_vif_event_armed(cfg))
		return -EBUSY;

	if (ndev) {
		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
650 651 652
		    cfg->escan_info.ifp == netdev_priv(ndev))
			brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
						    true, true);
653 654 655 656

		brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
	}

657 658 659 660 661 662 663 664 665 666 667
	switch (wdev->iftype) {
	case NL80211_IFTYPE_ADHOC:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_WDS:
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_MESH_POINT:
		return -EOPNOTSUPP;
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_P2P_GO:
668
	case NL80211_IFTYPE_P2P_DEVICE:
669 670 671 672 673 674 675 676
		return brcmf_p2p_del_vif(wiphy, wdev);
	case NL80211_IFTYPE_UNSPECIFIED:
	default:
		return -EINVAL;
	}
	return -EOPNOTSUPP;
}

677 678 679 680 681
static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
			 enum nl80211_iftype type, u32 *flags,
			 struct vif_params *params)
{
682
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
683
	struct brcmf_if *ifp = netdev_priv(ndev);
684
	struct brcmf_cfg80211_vif *vif = ifp->vif;
685
	s32 infra = 0;
H
Hante Meuleman 已提交
686
	s32 ap = 0;
687 688
	s32 err = 0;

689
	brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
690 691 692 693

	switch (type) {
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_WDS:
694 695
		brcmf_err("type (%d) : currently we do not support this type\n",
			  type);
696 697 698 699 700
		return -EOPNOTSUPP;
	case NL80211_IFTYPE_ADHOC:
		infra = 0;
		break;
	case NL80211_IFTYPE_STATION:
701 702 703 704 705 706 707 708 709 710 711 712
		/* Ignore change for p2p IF. Unclear why supplicant does this */
		if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ||
		    (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) {
			brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n");
			/* WAR: It is unexpected to get a change of VIF for P2P
			 * IF, but it happens. The request can not be handled
			 * but returning EPERM causes a crash. Returning 0
			 * without setting ieee80211_ptr->iftype causes trace
			 * (WARN_ON) but it works with wpa_supplicant
			 */
			return 0;
		}
713 714
		infra = 1;
		break;
H
Hante Meuleman 已提交
715
	case NL80211_IFTYPE_AP:
716
	case NL80211_IFTYPE_P2P_GO:
H
Hante Meuleman 已提交
717 718
		ap = 1;
		break;
719 720 721 722 723
	default:
		err = -EINVAL;
		goto done;
	}

H
Hante Meuleman 已提交
724
	if (ap) {
725 726 727 728 729 730 731 732
		if (type == NL80211_IFTYPE_P2P_GO) {
			brcmf_dbg(INFO, "IF Type = P2P GO\n");
			err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO);
		}
		if (!err) {
			set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
			brcmf_dbg(INFO, "IF Type = AP\n");
		}
733
	} else {
734
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
H
Hante Meuleman 已提交
735
		if (err) {
736
			brcmf_err("WLC_SET_INFRA error (%d)\n", err);
H
Hante Meuleman 已提交
737 738 739
			err = -EAGAIN;
			goto done;
		}
740
		brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
741
			  "Adhoc" : "Infra");
742
	}
H
Hante Meuleman 已提交
743
	ndev->ieee80211_ptr->iftype = type;
744

745 746
	brcmf_cfg80211_update_proto_addr_mode(&vif->wdev);

747
done:
748
	brcmf_dbg(TRACE, "Exit\n");
749 750 751 752

	return err;
}

F
Franky Lin 已提交
753 754
static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
			     struct brcmf_scan_params_le *params_le,
H
Hante Meuleman 已提交
755 756 757 758 759 760
			     struct cfg80211_scan_request *request)
{
	u32 n_ssids;
	u32 n_channels;
	s32 i;
	s32 offset;
761
	u16 chanspec;
H
Hante Meuleman 已提交
762
	char *ptr;
763
	struct brcmf_ssid_le ssid_le;
H
Hante Meuleman 已提交
764

765
	memset(params_le->bssid, 0xFF, ETH_ALEN);
H
Hante Meuleman 已提交
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
	params_le->bss_type = DOT11_BSSTYPE_ANY;
	params_le->scan_type = 0;
	params_le->channel_num = 0;
	params_le->nprobes = cpu_to_le32(-1);
	params_le->active_time = cpu_to_le32(-1);
	params_le->passive_time = cpu_to_le32(-1);
	params_le->home_time = cpu_to_le32(-1);
	memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));

	/* if request is null exit so it will be all channel broadcast scan */
	if (!request)
		return;

	n_ssids = request->n_ssids;
	n_channels = request->n_channels;
	/* Copy channel array if applicable */
782 783
	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
		  n_channels);
H
Hante Meuleman 已提交
784 785
	if (n_channels > 0) {
		for (i = 0; i < n_channels; i++) {
F
Franky Lin 已提交
786 787
			chanspec = channel_to_chanspec(&cfg->d11inf,
						       request->channels[i]);
788 789
			brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
				  request->channels[i]->hw_value, chanspec);
790
			params_le->channel_list[i] = cpu_to_le16(chanspec);
H
Hante Meuleman 已提交
791 792
		}
	} else {
793
		brcmf_dbg(SCAN, "Scanning all channels\n");
H
Hante Meuleman 已提交
794 795
	}
	/* Copy ssid array if applicable */
796
	brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
H
Hante Meuleman 已提交
797 798 799 800 801 802
	if (n_ssids > 0) {
		offset = offsetof(struct brcmf_scan_params_le, channel_list) +
				n_channels * sizeof(u16);
		offset = roundup(offset, sizeof(u32));
		ptr = (char *)params_le + offset;
		for (i = 0; i < n_ssids; i++) {
803 804 805 806 807 808
			memset(&ssid_le, 0, sizeof(ssid_le));
			ssid_le.SSID_len =
					cpu_to_le32(request->ssids[i].ssid_len);
			memcpy(ssid_le.SSID, request->ssids[i].ssid,
			       request->ssids[i].ssid_len);
			if (!ssid_le.SSID_len)
809
				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
H
Hante Meuleman 已提交
810
			else
811 812
				brcmf_dbg(SCAN, "%d: scan for  %s size =%d\n",
					  i, ssid_le.SSID, ssid_le.SSID_len);
813 814
			memcpy(ptr, &ssid_le, sizeof(ssid_le));
			ptr += sizeof(ssid_le);
H
Hante Meuleman 已提交
815 816
		}
	} else {
817
		brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
H
Hante Meuleman 已提交
818
		if ((request->ssids) && request->ssids->ssid_len) {
819 820 821
			brcmf_dbg(SCAN, "SSID %s len=%d\n",
				  params_le->ssid_le.SSID,
				  request->ssids->ssid_len);
H
Hante Meuleman 已提交
822 823 824 825 826 827 828 829 830 831 832 833 834
			params_le->ssid_le.SSID_len =
				cpu_to_le32(request->ssids->ssid_len);
			memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
				request->ssids->ssid_len);
		}
	}
	/* Adding mask to channel numbers */
	params_le->channel_num =
		cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
			(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
}

static s32
835
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
H
Hante Meuleman 已提交
836 837 838 839 840 841 842
		struct cfg80211_scan_request *request, u16 action)
{
	s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
			  offsetof(struct brcmf_escan_params_le, params_le);
	struct brcmf_escan_params_le *params;
	s32 err = 0;

843
	brcmf_dbg(SCAN, "E-SCAN START\n");
H
Hante Meuleman 已提交
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858

	if (request != NULL) {
		/* Allocate space for populating ssids in struct */
		params_size += sizeof(u32) * ((request->n_channels + 1) / 2);

		/* Allocate space for populating ssids in struct */
		params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
	}

	params = kzalloc(params_size, GFP_KERNEL);
	if (!params) {
		err = -ENOMEM;
		goto exit;
	}
	BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
F
Franky Lin 已提交
859
	brcmf_escan_prep(cfg, &params->params_le, request);
H
Hante Meuleman 已提交
860 861 862 863
	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
	params->action = cpu_to_le16(action);
	params->sync_id = cpu_to_le16(0x1234);

864
	err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
H
Hante Meuleman 已提交
865 866
	if (err) {
		if (err == -EBUSY)
867
			brcmf_dbg(INFO, "system busy : escan canceled\n");
H
Hante Meuleman 已提交
868
		else
869
			brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
870 871 872 873 874 875 876 877
	}

	kfree(params);
exit:
	return err;
}

static s32
878
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
879
	       struct brcmf_if *ifp, struct cfg80211_scan_request *request)
H
Hante Meuleman 已提交
880 881
{
	s32 err;
882
	u32 passive_scan;
H
Hante Meuleman 已提交
883
	struct brcmf_scan_results *results;
884
	struct escan_info *escan = &cfg->escan_info;
H
Hante Meuleman 已提交
885

886
	brcmf_dbg(SCAN, "Enter\n");
887
	escan->ifp = ifp;
888 889
	escan->wiphy = wiphy;
	escan->escan_state = WL_ESCAN_STATE_SCANNING;
890
	passive_scan = cfg->active_scan ? 0 : 1;
891
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
892
				    passive_scan);
H
Hante Meuleman 已提交
893
	if (err) {
894
		brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
895 896
		return err;
	}
897
	brcmf_scan_config_mpc(ifp, 0);
898
	results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
899 900 901 902
	results->version = 0;
	results->count = 0;
	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;

903
	err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
H
Hante Meuleman 已提交
904
	if (err)
905
		brcmf_scan_config_mpc(ifp, 1);
H
Hante Meuleman 已提交
906 907 908 909
	return err;
}

static s32
910
brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
H
Hante Meuleman 已提交
911 912 913
		     struct cfg80211_scan_request *request,
		     struct cfg80211_ssid *this_ssid)
{
914 915
	struct brcmf_if *ifp = vif->ifp;
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
H
Hante Meuleman 已提交
916
	struct cfg80211_ssid *ssids;
917
	struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
918
	u32 passive_scan;
H
Hante Meuleman 已提交
919 920 921 922 923
	bool escan_req;
	bool spec_scan;
	s32 err;
	u32 SSID_len;

924
	brcmf_dbg(SCAN, "START ESCAN\n");
H
Hante Meuleman 已提交
925

926
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
927
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
H
Hante Meuleman 已提交
928 929
		return -EAGAIN;
	}
930
	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
931 932
		brcmf_err("Scanning being aborted: status (%lu)\n",
			  cfg->scan_status);
H
Hante Meuleman 已提交
933 934
		return -EAGAIN;
	}
935 936 937 938 939
	if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
		brcmf_err("Scanning suppressed: status (%lu)\n",
			  cfg->scan_status);
		return -EAGAIN;
	}
940
	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
941
		brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
H
Hante Meuleman 已提交
942 943 944
		return -EAGAIN;
	}

945
	/* If scan req comes for p2p0, send it over primary I/F */
946 947
	if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
		vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
948

H
Hante Meuleman 已提交
949
	/* Arm scan timeout timer */
950
	mod_timer(&cfg->escan_timeout, jiffies +
H
Hante Meuleman 已提交
951 952 953 954 955 956 957 958 959 960 961 962 963
			WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);

	escan_req = false;
	if (request) {
		/* scan bss */
		ssids = request->ssids;
		escan_req = true;
	} else {
		/* scan in ibss */
		/* we don't do escan in ibss */
		ssids = this_ssid;
	}

964
	cfg->scan_request = request;
965
	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
H
Hante Meuleman 已提交
966
	if (escan_req) {
967
		cfg->escan_info.run = brcmf_run_escan;
968
		err = brcmf_p2p_scan_prep(wiphy, request, vif);
969 970 971
		if (err)
			goto scan_out;

972
		err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
973
		if (err)
H
Hante Meuleman 已提交
974 975
			goto scan_out;
	} else {
976 977
		brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
			  ssids->ssid, ssids->ssid_len);
H
Hante Meuleman 已提交
978 979 980 981 982 983 984 985 986
		memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
		SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
		sr->ssid_le.SSID_len = cpu_to_le32(0);
		spec_scan = false;
		if (SSID_len) {
			memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
			sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
			spec_scan = true;
		} else
987
			brcmf_dbg(SCAN, "Broadcast scan\n");
H
Hante Meuleman 已提交
988

989
		passive_scan = cfg->active_scan ? 0 : 1;
990
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
991
					    passive_scan);
H
Hante Meuleman 已提交
992
		if (err) {
993
			brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
994 995
			goto scan_out;
		}
996
		brcmf_scan_config_mpc(ifp, 0);
997
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
998
					     &sr->ssid_le, sizeof(sr->ssid_le));
H
Hante Meuleman 已提交
999 1000
		if (err) {
			if (err == -EBUSY)
1001 1002
				brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
					  sr->ssid_le.SSID);
H
Hante Meuleman 已提交
1003
			else
1004
				brcmf_err("WLC_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
1005

1006
			brcmf_scan_config_mpc(ifp, 1);
H
Hante Meuleman 已提交
1007 1008 1009 1010 1011 1012 1013
			goto scan_out;
		}
	}

	return 0;

scan_out:
1014
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
1015 1016 1017
	if (timer_pending(&cfg->escan_timeout))
		del_timer_sync(&cfg->escan_timeout);
	cfg->scan_request = NULL;
H
Hante Meuleman 已提交
1018 1019 1020
	return err;
}

1021
static s32
1022
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
1023
{
1024
	struct brcmf_cfg80211_vif *vif;
1025 1026
	s32 err = 0;

1027
	brcmf_dbg(TRACE, "Enter\n");
1028 1029
	vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
	if (!check_vif_up(vif))
1030 1031
		return -EIO;

1032
	err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
H
Hante Meuleman 已提交
1033

1034
	if (err)
1035
		brcmf_err("scan error (%d)\n", err);
1036

1037
	brcmf_dbg(TRACE, "Exit\n");
1038 1039 1040 1041 1042 1043 1044
	return err;
}

static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
{
	s32 err = 0;

1045 1046
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
				      rts_threshold);
1047
	if (err)
1048
		brcmf_err("Error (%d)\n", err);
1049 1050 1051 1052 1053 1054 1055 1056

	return err;
}

static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
{
	s32 err = 0;

1057 1058
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
				      frag_threshold);
1059
	if (err)
1060
		brcmf_err("Error (%d)\n", err);
1061 1062 1063 1064 1065 1066 1067

	return err;
}

static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
{
	s32 err = 0;
H
Hante Meuleman 已提交
1068
	u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
1069

1070
	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
1071
	if (err) {
1072
		brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
1073 1074 1075 1076 1077 1078 1079
		return err;
	}
	return err;
}

static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
1080 1081
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
1082
	struct brcmf_if *ifp = netdev_priv(ndev);
1083 1084
	s32 err = 0;

1085
	brcmf_dbg(TRACE, "Enter\n");
1086
	if (!check_vif_up(ifp->vif))
1087 1088 1089
		return -EIO;

	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
1090 1091 1092
	    (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
		cfg->conf->rts_threshold = wiphy->rts_threshold;
		err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
1093 1094 1095 1096
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
1097 1098 1099
	    (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
		cfg->conf->frag_threshold = wiphy->frag_threshold;
		err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
1100 1101 1102 1103
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_LONG
1104 1105 1106
	    && (cfg->conf->retry_long != wiphy->retry_long)) {
		cfg->conf->retry_long = wiphy->retry_long;
		err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
1107 1108 1109 1110
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_SHORT
1111 1112 1113
	    && (cfg->conf->retry_short != wiphy->retry_short)) {
		cfg->conf->retry_short = wiphy->retry_short;
		err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
1114 1115 1116 1117 1118
		if (!err)
			goto done;
	}

done:
1119
	brcmf_dbg(TRACE, "Exit\n");
1120 1121 1122 1123 1124 1125 1126 1127
	return err;
}

static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
{
	memset(prof, 0, sizeof(*prof));
}

1128
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
1129
{
1130
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
1131 1132
	s32 err = 0;

1133
	brcmf_dbg(TRACE, "Enter\n");
1134

1135
	if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
1136
		brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
1137
		err = brcmf_fil_cmd_data_set(vif->ifp,
1138
					     BRCMF_C_DISASSOC, NULL, 0);
1139
		if (err) {
1140
			brcmf_err("WLC_DISASSOC failed (%d)\n", err);
1141
		}
1142
		clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
1143 1144
		cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);

1145
	}
1146
	clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
1147 1148
	clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
	brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
1149
	brcmf_dbg(TRACE, "Exit\n");
1150 1151 1152 1153 1154 1155
}

static s32
brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_ibss_params *params)
{
1156
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1157 1158
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1159 1160 1161 1162 1163
	struct brcmf_join_params join_params;
	size_t join_params_size = 0;
	s32 err = 0;
	s32 wsec = 0;
	s32 bcnprd;
1164
	u16 chanspec;
1165

1166
	brcmf_dbg(TRACE, "Enter\n");
1167
	if (!check_vif_up(ifp->vif))
1168 1169 1170
		return -EIO;

	if (params->ssid)
1171
		brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
1172
	else {
1173
		brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
1174 1175 1176
		return -EOPNOTSUPP;
	}

1177
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1178 1179

	if (params->bssid)
1180
		brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
1181
	else
1182
		brcmf_dbg(CONN, "No BSSID specified\n");
1183

1184
	if (params->chandef.chan)
1185 1186
		brcmf_dbg(CONN, "channel: %d\n",
			  params->chandef.chan->center_freq);
1187
	else
1188
		brcmf_dbg(CONN, "no channel specified\n");
1189 1190

	if (params->channel_fixed)
1191
		brcmf_dbg(CONN, "fixed channel required\n");
1192
	else
1193
		brcmf_dbg(CONN, "no fixed channel required\n");
1194 1195

	if (params->ie && params->ie_len)
1196
		brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
1197
	else
1198
		brcmf_dbg(CONN, "no ie specified\n");
1199 1200

	if (params->beacon_interval)
1201 1202
		brcmf_dbg(CONN, "beacon interval: %d\n",
			  params->beacon_interval);
1203
	else
1204
		brcmf_dbg(CONN, "no beacon interval specified\n");
1205 1206

	if (params->basic_rates)
1207
		brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
1208
	else
1209
		brcmf_dbg(CONN, "no basic rates specified\n");
1210 1211

	if (params->privacy)
1212
		brcmf_dbg(CONN, "privacy required\n");
1213
	else
1214
		brcmf_dbg(CONN, "no privacy required\n");
1215 1216 1217 1218 1219

	/* Configure Privacy for starter */
	if (params->privacy)
		wsec |= WEP_ENABLED;

1220
	err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
1221
	if (err) {
1222
		brcmf_err("wsec failed (%d)\n", err);
1223 1224 1225 1226 1227 1228 1229 1230 1231
		goto done;
	}

	/* Configure Beacon Interval for starter */
	if (params->beacon_interval)
		bcnprd = params->beacon_interval;
	else
		bcnprd = 100;

H
Hante Meuleman 已提交
1232
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
1233
	if (err) {
1234
		brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
1235 1236 1237 1238 1239 1240 1241
		goto done;
	}

	/* Configure required join parameter */
	memset(&join_params, 0, sizeof(struct brcmf_join_params));

	/* SSID */
1242 1243 1244 1245
	profile->ssid.SSID_len = min_t(u32, params->ssid_len, 32);
	memcpy(profile->ssid.SSID, params->ssid, profile->ssid.SSID_len);
	memcpy(join_params.ssid_le.SSID, params->ssid, profile->ssid.SSID_len);
	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1246 1247 1248 1249 1250 1251 1252
	join_params_size = sizeof(join_params.ssid_le);

	/* BSSID */
	if (params->bssid) {
		memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
		join_params_size = sizeof(join_params.ssid_le) +
				   BRCMF_ASSOC_PARAMS_FIXED_SIZE;
1253
		memcpy(profile->bssid, params->bssid, ETH_ALEN);
1254
	} else {
1255
		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1256
		memset(profile->bssid, 0, ETH_ALEN);
1257 1258 1259
	}

	/* Channel */
1260
	if (params->chandef.chan) {
1261 1262
		u32 target_channel;

1263
		cfg->channel =
1264
			ieee80211_frequency_to_channel(
1265
				params->chandef.chan->center_freq);
1266 1267
		if (params->channel_fixed) {
			/* adding chanspec */
1268 1269
			chanspec = chandef_to_chanspec(&cfg->d11inf,
						       &params->chandef);
1270 1271 1272 1273
			join_params.params_le.chanspec_list[0] =
				cpu_to_le16(chanspec);
			join_params.params_le.chanspec_num = cpu_to_le32(1);
			join_params_size += sizeof(join_params.params_le);
1274 1275 1276
		}

		/* set channel for starter */
1277
		target_channel = cfg->channel;
H
Hante Meuleman 已提交
1278
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
1279
					    target_channel);
1280
		if (err) {
1281
			brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
1282 1283 1284
			goto done;
		}
	} else
1285
		cfg->channel = 0;
1286

1287
	cfg->ibss_starter = false;
1288 1289


1290
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1291
				     &join_params, join_params_size);
1292
	if (err) {
1293
		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
1294 1295 1296 1297 1298
		goto done;
	}

done:
	if (err)
1299
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1300
	brcmf_dbg(TRACE, "Exit\n");
1301 1302 1303 1304 1305 1306
	return err;
}

static s32
brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
{
1307
	struct brcmf_if *ifp = netdev_priv(ndev);
1308

1309
	brcmf_dbg(TRACE, "Enter\n");
1310
	if (!check_vif_up(ifp->vif))
1311 1312
		return -EIO;

1313
	brcmf_link_down(ifp->vif);
1314

1315
	brcmf_dbg(TRACE, "Exit\n");
1316

1317
	return 0;
1318 1319 1320 1321 1322
}

static s32 brcmf_set_wpa_version(struct net_device *ndev,
				 struct cfg80211_connect_params *sme)
{
1323
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
		val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
	else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
		val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
	else
		val = WPA_AUTH_DISABLED;
1334
	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
1335
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1336
	if (err) {
1337
		brcmf_err("set wpa_auth failed (%d)\n", err);
1338 1339
		return err;
	}
1340
	sec = &profile->sec;
1341 1342 1343 1344 1345 1346 1347
	sec->wpa_versions = sme->crypto.wpa_versions;
	return err;
}

static s32 brcmf_set_auth_type(struct net_device *ndev,
			       struct cfg80211_connect_params *sme)
{
1348
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1349 1350 1351 1352 1353 1354 1355
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	switch (sme->auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		val = 0;
1356
		brcmf_dbg(CONN, "open system\n");
1357 1358 1359
		break;
	case NL80211_AUTHTYPE_SHARED_KEY:
		val = 1;
1360
		brcmf_dbg(CONN, "shared key\n");
1361 1362 1363
		break;
	case NL80211_AUTHTYPE_AUTOMATIC:
		val = 2;
1364
		brcmf_dbg(CONN, "automatic\n");
1365 1366
		break;
	case NL80211_AUTHTYPE_NETWORK_EAP:
1367
		brcmf_dbg(CONN, "network eap\n");
1368 1369
	default:
		val = 2;
1370
		brcmf_err("invalid auth type (%d)\n", sme->auth_type);
1371 1372 1373
		break;
	}

1374
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
1375
	if (err) {
1376
		brcmf_err("set auth failed (%d)\n", err);
1377 1378
		return err;
	}
1379
	sec = &profile->sec;
1380 1381 1382 1383 1384
	sec->auth_type = sme->auth_type;
	return err;
}

static s32
1385 1386
brcmf_set_wsec_mode(struct net_device *ndev,
		     struct cfg80211_connect_params *sme, bool mfp)
1387
{
1388
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1389 1390 1391
	struct brcmf_cfg80211_security *sec;
	s32 pval = 0;
	s32 gval = 0;
1392
	s32 wsec;
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
	s32 err = 0;

	if (sme->crypto.n_ciphers_pairwise) {
		switch (sme->crypto.ciphers_pairwise[0]) {
		case WLAN_CIPHER_SUITE_WEP40:
		case WLAN_CIPHER_SUITE_WEP104:
			pval = WEP_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			pval = TKIP_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			pval = AES_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_AES_CMAC:
			pval = AES_ENABLED;
			break;
		default:
1411 1412
			brcmf_err("invalid cipher pairwise (%d)\n",
				  sme->crypto.ciphers_pairwise[0]);
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
			return -EINVAL;
		}
	}
	if (sme->crypto.cipher_group) {
		switch (sme->crypto.cipher_group) {
		case WLAN_CIPHER_SUITE_WEP40:
		case WLAN_CIPHER_SUITE_WEP104:
			gval = WEP_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			gval = TKIP_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			gval = AES_ENABLED;
			break;
		case WLAN_CIPHER_SUITE_AES_CMAC:
			gval = AES_ENABLED;
			break;
		default:
1432 1433
			brcmf_err("invalid cipher group (%d)\n",
				  sme->crypto.cipher_group);
1434 1435 1436 1437
			return -EINVAL;
		}
	}

1438
	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
1439 1440 1441 1442 1443
	/* In case of privacy, but no security and WPS then simulate */
	/* setting AES. WPS-2.0 allows no security                   */
	if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&
	    sme->privacy)
		pval = AES_ENABLED;
1444 1445 1446 1447 1448 1449

	if (mfp)
		wsec = pval | gval | MFP_CAPABLE;
	else
		wsec = pval | gval;
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
1450
	if (err) {
1451
		brcmf_err("error (%d)\n", err);
1452 1453 1454
		return err;
	}

1455
	sec = &profile->sec;
1456 1457 1458 1459 1460 1461 1462 1463 1464
	sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
	sec->cipher_group = sme->crypto.cipher_group;

	return err;
}

static s32
brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
1465
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1466 1467 1468 1469 1470
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	if (sme->crypto.n_akm_suites) {
1471 1472
		err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
					       "wpa_auth", &val);
1473
		if (err) {
1474
			brcmf_err("could not get wpa_auth (%d)\n", err);
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
			return err;
		}
		if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
			switch (sme->crypto.akm_suites[0]) {
			case WLAN_AKM_SUITE_8021X:
				val = WPA_AUTH_UNSPECIFIED;
				break;
			case WLAN_AKM_SUITE_PSK:
				val = WPA_AUTH_PSK;
				break;
			default:
1486 1487
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
				return -EINVAL;
			}
		} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
			switch (sme->crypto.akm_suites[0]) {
			case WLAN_AKM_SUITE_8021X:
				val = WPA2_AUTH_UNSPECIFIED;
				break;
			case WLAN_AKM_SUITE_PSK:
				val = WPA2_AUTH_PSK;
				break;
			default:
1499 1500
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1501 1502 1503 1504
				return -EINVAL;
			}
		}

1505
		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1506 1507
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
					       "wpa_auth", val);
1508
		if (err) {
1509
			brcmf_err("could not set wpa_auth (%d)\n", err);
1510 1511 1512
			return err;
		}
	}
1513
	sec = &profile->sec;
1514 1515 1516 1517 1518 1519
	sec->wpa_auth = sme->crypto.akm_suites[0];

	return err;
}

static s32
1520 1521
brcmf_set_sharedkey(struct net_device *ndev,
		    struct cfg80211_connect_params *sme)
1522
{
1523
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1524 1525 1526 1527 1528
	struct brcmf_cfg80211_security *sec;
	struct brcmf_wsec_key key;
	s32 val;
	s32 err = 0;

1529
	brcmf_dbg(CONN, "key len (%d)\n", sme->key_len);
1530

1531 1532 1533
	if (sme->key_len == 0)
		return 0;

1534
	sec = &profile->sec;
1535 1536
	brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
		  sec->wpa_versions, sec->cipher_pairwise);
1537 1538 1539 1540

	if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
		return 0;

1541 1542 1543
	if (!(sec->cipher_pairwise &
	    (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
		return 0;
1544

1545 1546 1547 1548
	memset(&key, 0, sizeof(key));
	key.len = (u32) sme->key_len;
	key.index = (u32) sme->key_idx;
	if (key.len > sizeof(key.data)) {
1549
		brcmf_err("Too long key length (%u)\n", key.len);
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
		return -EINVAL;
	}
	memcpy(key.data, sme->key, key.len);
	key.flags = BRCMF_PRIMARY_KEY;
	switch (sec->cipher_pairwise) {
	case WLAN_CIPHER_SUITE_WEP40:
		key.algo = CRYPTO_ALGO_WEP1;
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		key.algo = CRYPTO_ALGO_WEP128;
		break;
	default:
1562 1563
		brcmf_err("Invalid algorithm (%d)\n",
			  sme->crypto.ciphers_pairwise[0]);
1564 1565 1566
		return -EINVAL;
	}
	/* Set the new key/index */
1567 1568 1569
	brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
		  key.len, key.index, key.algo);
	brcmf_dbg(CONN, "key \"%s\"\n", key.data);
1570
	err = send_key_to_dongle(ndev, &key);
1571 1572 1573 1574
	if (err)
		return err;

	if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
1575
		brcmf_dbg(CONN, "set auth_type to shared key\n");
1576
		val = WL_AUTH_SHARED_KEY;	/* shared key */
1577
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
1578
		if (err)
1579
			brcmf_err("set auth failed (%d)\n", err);
1580 1581 1582 1583
	}
	return err;
}

1584 1585 1586 1587
static
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
					   enum nl80211_auth_type type)
{
1588 1589 1590 1591
	if (type == NL80211_AUTHTYPE_AUTOMATIC &&
	    brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_AUTO_AUTH)) {
		brcmf_dbg(CONN, "WAR: use OPEN instead of AUTO\n");
		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
1592 1593 1594 1595
	}
	return type;
}

1596 1597
static s32
brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1598
		       struct cfg80211_connect_params *sme)
1599
{
1600
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1601 1602
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1603 1604 1605
	struct ieee80211_channel *chan = sme->channel;
	struct brcmf_join_params join_params;
	size_t join_params_size;
1606 1607 1608
	const struct brcmf_tlv *rsn_ie;
	const struct brcmf_vs_tlv *wpa_ie;
	const void *ie;
1609 1610
	u32 ie_len;
	struct brcmf_ext_join_params_le *ext_join_params;
1611
	u16 chanspec;
1612 1613
	s32 err = 0;

1614
	brcmf_dbg(TRACE, "Enter\n");
1615
	if (!check_vif_up(ifp->vif))
1616 1617 1618
		return -EIO;

	if (!sme->ssid) {
1619
		brcmf_err("Invalid ssid\n");
1620 1621 1622
		return -EOPNOTSUPP;
	}

1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) {
		/* A normal (non P2P) connection request setup. */
		ie = NULL;
		ie_len = 0;
		/* find the WPA_IE */
		wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len);
		if (wpa_ie) {
			ie = wpa_ie;
			ie_len = wpa_ie->len + TLV_HDR_LEN;
		} else {
			/* find the RSN_IE */
1634 1635
			rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
						  sme->ie_len,
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651
						  WLAN_EID_RSN);
			if (rsn_ie) {
				ie = rsn_ie;
				ie_len = rsn_ie->len + TLV_HDR_LEN;
			}
		}
		brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len);
	}

	err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG,
				    sme->ie, sme->ie_len);
	if (err)
		brcmf_err("Set Assoc REQ IE Failed\n");
	else
		brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n");

1652
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1653 1654

	if (chan) {
1655
		cfg->channel =
1656
			ieee80211_frequency_to_channel(chan->center_freq);
F
Franky Lin 已提交
1657
		chanspec = channel_to_chanspec(&cfg->d11inf, chan);
1658 1659 1660
		brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
			  cfg->channel, chan->center_freq, chanspec);
	} else {
1661
		cfg->channel = 0;
1662 1663
		chanspec = 0;
	}
1664

1665
	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1666 1667 1668

	err = brcmf_set_wpa_version(ndev, sme);
	if (err) {
1669
		brcmf_err("wl_set_wpa_version failed (%d)\n", err);
1670 1671 1672
		goto done;
	}

1673
	sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
1674 1675
	err = brcmf_set_auth_type(ndev, sme);
	if (err) {
1676
		brcmf_err("wl_set_auth_type failed (%d)\n", err);
1677 1678 1679
		goto done;
	}

1680
	err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
1681
	if (err) {
1682
		brcmf_err("wl_set_set_cipher failed (%d)\n", err);
1683 1684 1685 1686 1687
		goto done;
	}

	err = brcmf_set_key_mgmt(ndev, sme);
	if (err) {
1688
		brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
1689 1690 1691
		goto done;
	}

1692
	err = brcmf_set_sharedkey(ndev, sme);
1693
	if (err) {
1694
		brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
1695 1696 1697
		goto done;
	}

1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
	profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID),
				       (u32)sme->ssid_len);
	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
	if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
		profile->ssid.SSID[profile->ssid.SSID_len] = 0;
		brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID,
			  profile->ssid.SSID_len);
	}

	/* Join with specific BSSID and cached SSID
	 * If SSID is zero join based on BSSID only
	 */
	join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) +
		offsetof(struct brcmf_assoc_params_le, chanspec_list);
	if (cfg->channel)
		join_params_size += sizeof(u16);
	ext_join_params = kzalloc(join_params_size, GFP_KERNEL);
	if (ext_join_params == NULL) {
		err = -ENOMEM;
		goto done;
	}
	ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
	memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,
	       profile->ssid.SSID_len);
1722

1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
	/* Set up join scan parameters */
	ext_join_params->scan_le.scan_type = -1;
	ext_join_params->scan_le.home_time = cpu_to_le32(-1);

	if (sme->bssid)
		memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
	else
		memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);

	if (cfg->channel) {
		ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);

		ext_join_params->assoc_le.chanspec_list[0] =
			cpu_to_le16(chanspec);
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
		/* Increase dwell time to receive probe response or detect
		 * beacon from target AP at a noisy air only during connect
		 * command.
		 */
		ext_join_params->scan_le.active_time =
			cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS);
		ext_join_params->scan_le.passive_time =
			cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS);
		/* To sync with presence period of VSDB GO send probe request
		 * more frequently. Probe request will be stopped when it gets
		 * probe response from target AP/GO.
		 */
		ext_join_params->scan_le.nprobes =
			cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS /
				    BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);
	} else {
		ext_join_params->scan_le.active_time = cpu_to_le32(-1);
		ext_join_params->scan_le.passive_time = cpu_to_le32(-1);
		ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
	}

	err  = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
					 join_params_size);
	kfree(ext_join_params);
	if (!err)
		/* This is it. join command worked, we are done */
		goto done;

	/* join command failed, fallback to set ssid */
1766 1767 1768
	memset(&join_params, 0, sizeof(join_params));
	join_params_size = sizeof(join_params.ssid_le);

1769 1770
	memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1771

1772 1773 1774 1775
	if (sme->bssid)
		memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
	else
		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1776

1777 1778 1779 1780 1781
	if (cfg->channel) {
		join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
		join_params.params_le.chanspec_num = cpu_to_le32(1);
		join_params_size += sizeof(join_params.params_le);
	}
1782
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1783
				     &join_params, join_params_size);
1784
	if (err)
1785
		brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
1786 1787 1788

done:
	if (err)
1789
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1790
	brcmf_dbg(TRACE, "Exit\n");
1791 1792 1793 1794 1795 1796 1797
	return err;
}

static s32
brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
		       u16 reason_code)
{
1798 1799
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1800 1801 1802
	struct brcmf_scb_val_le scbval;
	s32 err = 0;

1803
	brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
1804
	if (!check_vif_up(ifp->vif))
1805 1806
		return -EIO;

1807
	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
1808
	cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
1809

1810
	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
1811
	scbval.val = cpu_to_le32(reason_code);
1812
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
1813
				     &scbval, sizeof(scbval));
1814
	if (err)
1815
		brcmf_err("error (%d)\n", err);
1816

1817
	brcmf_dbg(TRACE, "Exit\n");
1818 1819 1820 1821
	return err;
}

static s32
1822
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
1823
			    enum nl80211_tx_power_setting type, s32 mbm)
1824 1825
{

1826
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1827 1828
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct brcmf_if *ifp = netdev_priv(ndev);
1829 1830 1831
	u16 txpwrmw;
	s32 err = 0;
	s32 disable = 0;
1832
	s32 dbm = MBM_TO_DBM(mbm);
1833

1834
	brcmf_dbg(TRACE, "Enter\n");
1835
	if (!check_vif_up(ifp->vif))
1836 1837 1838 1839 1840 1841 1842 1843
		return -EIO;

	switch (type) {
	case NL80211_TX_POWER_AUTOMATIC:
		break;
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_FIXED:
		if (dbm < 0) {
1844
			brcmf_err("TX_POWER_FIXED - dbm is negative\n");
1845 1846 1847 1848 1849 1850 1851
			err = -EINVAL;
			goto done;
		}
		break;
	}
	/* Make sure radio is off or on as far as software is concerned */
	disable = WL_RADIO_SW_DISABLE << 16;
1852
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
1853
	if (err)
1854
		brcmf_err("WLC_SET_RADIO error (%d)\n", err);
1855 1856 1857 1858 1859

	if (dbm > 0xffff)
		txpwrmw = 0xffff;
	else
		txpwrmw = (u16) dbm;
1860 1861
	err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
				      (s32)brcmf_mw_to_qdbm(txpwrmw));
1862
	if (err)
1863
		brcmf_err("qtxpower error (%d)\n", err);
1864
	cfg->conf->tx_power = dbm;
1865 1866

done:
1867
	brcmf_dbg(TRACE, "Exit\n");
1868 1869 1870
	return err;
}

1871 1872 1873
static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
				       struct wireless_dev *wdev,
				       s32 *dbm)
1874
{
1875
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1876
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
1877 1878 1879 1880
	s32 txpwrdbm;
	u8 result;
	s32 err = 0;

1881
	brcmf_dbg(TRACE, "Enter\n");
1882
	if (!check_vif_up(ifp->vif))
1883 1884
		return -EIO;

1885
	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
1886
	if (err) {
1887
		brcmf_err("error (%d)\n", err);
1888 1889 1890 1891
		goto done;
	}

	result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
1892
	*dbm = (s32) brcmf_qdbm_to_mw(result);
1893 1894

done:
1895
	brcmf_dbg(TRACE, "Exit\n");
1896 1897 1898 1899 1900 1901 1902
	return err;
}

static s32
brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
			       u8 key_idx, bool unicast, bool multicast)
{
1903
	struct brcmf_if *ifp = netdev_priv(ndev);
1904 1905 1906 1907
	u32 index;
	u32 wsec;
	s32 err = 0;

1908
	brcmf_dbg(TRACE, "Enter\n");
1909
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1910
	if (!check_vif_up(ifp->vif))
1911 1912
		return -EIO;

1913
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
1914
	if (err) {
1915
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
1916 1917 1918 1919 1920 1921
		goto done;
	}

	if (wsec & WEP_ENABLED) {
		/* Just select a new current key */
		index = key_idx;
1922
		err = brcmf_fil_cmd_int_set(ifp,
1923
					    BRCMF_C_SET_KEY_PRIMARY, index);
1924
		if (err)
1925
			brcmf_err("error (%d)\n", err);
1926 1927
	}
done:
1928
	brcmf_dbg(TRACE, "Exit\n");
1929 1930 1931 1932 1933 1934 1935
	return err;
}

static s32
brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
	      u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
1936
	struct brcmf_if *ifp = netdev_priv(ndev);
1937 1938
	struct brcmf_wsec_key key;
	s32 err = 0;
1939
	u8 keybuf[8];
1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950

	memset(&key, 0, sizeof(key));
	key.index = (u32) key_idx;
	/* Instead of bcast for ea address for default wep keys,
		 driver needs it to be Null */
	if (!is_multicast_ether_addr(mac_addr))
		memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
	key.len = (u32) params->key_len;
	/* check for key index change */
	if (key.len == 0) {
		/* key delete */
1951
		err = send_key_to_dongle(ndev, &key);
1952
		if (err)
1953
			brcmf_err("key delete error (%d)\n", err);
1954 1955
	} else {
		if (key.len > sizeof(key.data)) {
1956
			brcmf_err("Invalid key length (%d)\n", key.len);
1957 1958 1959
			return -EINVAL;
		}

1960
		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
1961 1962
		memcpy(key.data, params->key, key.len);

1963
		if (!brcmf_is_apmode(ifp->vif) &&
1964 1965
		    (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
			memcpy(keybuf, &key.data[24], sizeof(keybuf));
			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
			memcpy(&key.data[16], keybuf, sizeof(keybuf));
		}

		/* if IW_ENCODE_EXT_RX_SEQ_VALID set */
		if (params->seq && params->seq_len == 6) {
			/* rx iv */
			u8 *ivptr;
			ivptr = (u8 *) params->seq;
			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
			    (ivptr[3] << 8) | ivptr[2];
			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
			key.iv_initialized = true;
		}

		switch (params->cipher) {
		case WLAN_CIPHER_SUITE_WEP40:
			key.algo = CRYPTO_ALGO_WEP1;
1985
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
1986 1987 1988
			break;
		case WLAN_CIPHER_SUITE_WEP104:
			key.algo = CRYPTO_ALGO_WEP128;
1989
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
1990 1991 1992
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			key.algo = CRYPTO_ALGO_TKIP;
1993
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
1994 1995 1996
			break;
		case WLAN_CIPHER_SUITE_AES_CMAC:
			key.algo = CRYPTO_ALGO_AES_CCM;
1997
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
1998 1999 2000
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			key.algo = CRYPTO_ALGO_AES_CCM;
2001
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
2002 2003
			break;
		default:
2004
			brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
2005 2006
			return -EINVAL;
		}
2007
		err = send_key_to_dongle(ndev, &key);
2008
		if (err)
2009
			brcmf_err("wsec_key error (%d)\n", err);
2010 2011 2012 2013 2014 2015 2016 2017 2018
	}
	return err;
}

static s32
brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr,
		    struct key_params *params)
{
2019
	struct brcmf_if *ifp = netdev_priv(ndev);
2020 2021 2022 2023 2024 2025
	struct brcmf_wsec_key key;
	s32 val;
	s32 wsec;
	s32 err = 0;
	u8 keybuf[8];

2026
	brcmf_dbg(TRACE, "Enter\n");
2027
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2028
	if (!check_vif_up(ifp->vif))
2029 2030
		return -EIO;

2031 2032 2033
	if (mac_addr &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2034
		brcmf_dbg(TRACE, "Exit");
2035 2036 2037 2038 2039 2040 2041 2042
		return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
	}
	memset(&key, 0, sizeof(key));

	key.len = (u32) params->key_len;
	key.index = (u32) key_idx;

	if (key.len > sizeof(key.data)) {
2043
		brcmf_err("Too long key length (%u)\n", key.len);
2044 2045 2046 2047 2048 2049 2050 2051 2052
		err = -EINVAL;
		goto done;
	}
	memcpy(key.data, params->key, key.len);

	key.flags = BRCMF_PRIMARY_KEY;
	switch (params->cipher) {
	case WLAN_CIPHER_SUITE_WEP40:
		key.algo = CRYPTO_ALGO_WEP1;
2053
		val = WEP_ENABLED;
2054
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
2055 2056 2057
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		key.algo = CRYPTO_ALGO_WEP128;
2058
		val = WEP_ENABLED;
2059
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
2060 2061
		break;
	case WLAN_CIPHER_SUITE_TKIP:
2062
		if (!brcmf_is_apmode(ifp->vif)) {
2063
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
H
Hante Meuleman 已提交
2064 2065 2066 2067
			memcpy(keybuf, &key.data[24], sizeof(keybuf));
			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
			memcpy(&key.data[16], keybuf, sizeof(keybuf));
		}
2068
		key.algo = CRYPTO_ALGO_TKIP;
2069
		val = TKIP_ENABLED;
2070
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
2071 2072 2073
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
		key.algo = CRYPTO_ALGO_AES_CCM;
2074
		val = AES_ENABLED;
2075
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
2076 2077 2078
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		key.algo = CRYPTO_ALGO_AES_CCM;
2079
		val = AES_ENABLED;
2080
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
2081 2082
		break;
	default:
2083
		brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
2084 2085 2086 2087
		err = -EINVAL;
		goto done;
	}

2088
	err = send_key_to_dongle(ndev, &key);
2089 2090 2091
	if (err)
		goto done;

2092
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2093
	if (err) {
2094
		brcmf_err("get wsec error (%d)\n", err);
2095 2096 2097
		goto done;
	}
	wsec |= val;
2098
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2099
	if (err) {
2100
		brcmf_err("set wsec error (%d)\n", err);
2101 2102 2103 2104
		goto done;
	}

done:
2105
	brcmf_dbg(TRACE, "Exit\n");
2106 2107 2108 2109 2110 2111 2112
	return err;
}

static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr)
{
2113
	struct brcmf_if *ifp = netdev_priv(ndev);
2114 2115 2116
	struct brcmf_wsec_key key;
	s32 err = 0;

2117
	brcmf_dbg(TRACE, "Enter\n");
2118
	if (!check_vif_up(ifp->vif))
2119 2120
		return -EIO;

2121 2122
	if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
		/* we ignore this key index in this case */
2123
		brcmf_err("invalid key index (%d)\n", key_idx);
2124 2125 2126
		return -EINVAL;
	}

2127 2128 2129 2130 2131 2132
	memset(&key, 0, sizeof(key));

	key.index = (u32) key_idx;
	key.flags = BRCMF_PRIMARY_KEY;
	key.algo = CRYPTO_ALGO_OFF;

2133
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2134 2135

	/* Set the new key/index */
2136
	err = send_key_to_dongle(ndev, &key);
2137

2138
	brcmf_dbg(TRACE, "Exit\n");
2139 2140 2141 2142 2143 2144 2145 2146 2147
	return err;
}

static s32
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
		    void (*callback) (void *cookie, struct key_params * params))
{
	struct key_params params;
2148 2149
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
2150 2151 2152 2153
	struct brcmf_cfg80211_security *sec;
	s32 wsec;
	s32 err = 0;

2154
	brcmf_dbg(TRACE, "Enter\n");
2155
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2156
	if (!check_vif_up(ifp->vif))
2157 2158 2159 2160
		return -EIO;

	memset(&params, 0, sizeof(params));

2161
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2162
	if (err) {
2163
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
2164 2165 2166 2167
		/* Ignore this error, may happen during DISASSOC */
		err = -EAGAIN;
		goto done;
	}
2168
	if (wsec & WEP_ENABLED) {
2169
		sec = &profile->sec;
2170 2171
		if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
			params.cipher = WLAN_CIPHER_SUITE_WEP40;
2172
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
2173 2174
		} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
			params.cipher = WLAN_CIPHER_SUITE_WEP104;
2175
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
2176
		}
2177
	} else if (wsec & TKIP_ENABLED) {
2178
		params.cipher = WLAN_CIPHER_SUITE_TKIP;
2179
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
2180
	} else if (wsec & AES_ENABLED) {
2181
		params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
2182
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
2183
	} else  {
2184
		brcmf_err("Invalid algo (0x%x)\n", wsec);
2185 2186 2187 2188 2189 2190
		err = -EINVAL;
		goto done;
	}
	callback(cookie, &params);

done:
2191
	brcmf_dbg(TRACE, "Exit\n");
2192 2193 2194 2195 2196 2197 2198
	return err;
}

static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
				    struct net_device *ndev, u8 key_idx)
{
2199
	brcmf_dbg(INFO, "Not supported\n");
2200 2201 2202 2203 2204 2205

	return -EOPNOTSUPP;
}

static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
2206
			   const u8 *mac, struct station_info *sinfo)
2207
{
2208 2209
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
2210 2211 2212 2213
	struct brcmf_scb_val_le scb_val;
	int rssi;
	s32 rate;
	s32 err = 0;
2214
	u8 *bssid = profile->bssid;
2215
	struct brcmf_sta_info_le sta_info_le;
2216 2217
	u32 beacon_period;
	u32 dtim_period;
2218

2219
	brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
2220
	if (!check_vif_up(ifp->vif))
2221 2222
		return -EIO;

2223
	if (brcmf_is_apmode(ifp->vif)) {
2224
		memcpy(&sta_info_le, mac, ETH_ALEN);
2225
		err = brcmf_fil_iovar_data_get(ifp, "sta_info",
2226
					       &sta_info_le,
2227
					       sizeof(sta_info_le));
H
Hante Meuleman 已提交
2228
		if (err < 0) {
2229
			brcmf_err("GET STA INFO failed, %d\n", err);
H
Hante Meuleman 已提交
2230 2231 2232
			goto done;
		}
		sinfo->filled = STATION_INFO_INACTIVE_TIME;
2233 2234
		sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
		if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
H
Hante Meuleman 已提交
2235
			sinfo->filled |= STATION_INFO_CONNECTED_TIME;
2236
			sinfo->connected_time = le32_to_cpu(sta_info_le.in);
H
Hante Meuleman 已提交
2237
		}
2238 2239
		brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
			  sinfo->inactive_time, sinfo->connected_time);
2240
	} else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
H
Hante Meuleman 已提交
2241
		if (memcmp(mac, bssid, ETH_ALEN)) {
2242 2243
			brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
				  mac, bssid);
H
Hante Meuleman 已提交
2244 2245 2246 2247
			err = -ENOENT;
			goto done;
		}
		/* Report the current tx rate */
2248
		err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2249
		if (err) {
2250
			brcmf_err("Could not get rate (%d)\n", err);
H
Hante Meuleman 已提交
2251
			goto done;
2252
		} else {
H
Hante Meuleman 已提交
2253 2254
			sinfo->filled |= STATION_INFO_TX_BITRATE;
			sinfo->txrate.legacy = rate * 5;
2255
			brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
2256
		}
2257

2258 2259
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
			     &ifp->vif->sme_state)) {
H
Hante Meuleman 已提交
2260
			memset(&scb_val, 0, sizeof(scb_val));
2261 2262
			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
						     &scb_val, sizeof(scb_val));
H
Hante Meuleman 已提交
2263
			if (err) {
2264
				brcmf_err("Could not get rssi (%d)\n", err);
H
Hante Meuleman 已提交
2265 2266 2267 2268 2269
				goto done;
			} else {
				rssi = le32_to_cpu(scb_val.val);
				sinfo->filled |= STATION_INFO_SIGNAL;
				sinfo->signal = rssi;
2270
				brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
H
Hante Meuleman 已提交
2271
			}
2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295
			err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD,
						    &beacon_period);
			if (err) {
				brcmf_err("Could not get beacon period (%d)\n",
					  err);
				goto done;
			} else {
				sinfo->bss_param.beacon_interval =
					beacon_period;
				brcmf_dbg(CONN, "Beacon peroid %d\n",
					  beacon_period);
			}
			err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD,
						    &dtim_period);
			if (err) {
				brcmf_err("Could not get DTIM period (%d)\n",
					  err);
				goto done;
			} else {
				sinfo->bss_param.dtim_period = dtim_period;
				brcmf_dbg(CONN, "DTIM peroid %d\n",
					  dtim_period);
			}
			sinfo->filled |= STATION_INFO_BSS_PARAM;
H
Hante Meuleman 已提交
2296 2297 2298
		}
	} else
		err = -EPERM;
2299
done:
2300
	brcmf_dbg(TRACE, "Exit\n");
2301 2302 2303 2304 2305 2306 2307 2308 2309
	return err;
}

static s32
brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
			   bool enabled, s32 timeout)
{
	s32 pm;
	s32 err = 0;
2310
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2311
	struct brcmf_if *ifp = netdev_priv(ndev);
2312

2313
	brcmf_dbg(TRACE, "Enter\n");
2314 2315 2316 2317 2318

	/*
	 * Powersave enable/disable request is coming from the
	 * cfg80211 even before the interface is up. In that
	 * scenario, driver will be storing the power save
2319
	 * preference in cfg struct to apply this to
2320 2321
	 * FW later while initializing the dongle
	 */
2322
	cfg->pwr_save = enabled;
2323
	if (!check_vif_up(ifp->vif)) {
2324

2325
		brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
2326 2327 2328 2329
		goto done;
	}

	pm = enabled ? PM_FAST : PM_OFF;
2330 2331 2332 2333 2334
	/* Do not enable the power save after assoc if it is a p2p interface */
	if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
		brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
		pm = PM_OFF;
	}
2335
	brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
2336

2337
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
2338 2339
	if (err) {
		if (err == -ENODEV)
2340
			brcmf_err("net_device is not ready yet\n");
2341
		else
2342
			brcmf_err("error (%d)\n", err);
2343 2344
	}
done:
2345
	brcmf_dbg(TRACE, "Exit\n");
2346 2347 2348
	return err;
}

2349
static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
2350
				   struct brcmf_bss_info_le *bi)
2351
{
2352
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2353 2354 2355
	struct ieee80211_channel *notify_channel;
	struct cfg80211_bss *bss;
	struct ieee80211_supported_band *band;
F
Franky Lin 已提交
2356
	struct brcmu_chan ch;
2357 2358 2359 2360 2361 2362 2363 2364 2365
	u16 channel;
	u32 freq;
	u16 notify_capability;
	u16 notify_interval;
	u8 *notify_ie;
	size_t notify_ielen;
	s32 notify_signal;

	if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
2366
		brcmf_err("Bss info is larger than buffer. Discarding\n");
2367 2368 2369
		return 0;
	}

F
Franky Lin 已提交
2370 2371 2372 2373 2374 2375
	if (!bi->ctl_ch) {
		ch.chspec = le16_to_cpu(bi->chanspec);
		cfg->d11inf.decchspec(&ch);
		bi->ctl_ch = ch.chnum;
	}
	channel = bi->ctl_ch;
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390

	if (channel <= CH_MAX_2G_CHANNEL)
		band = wiphy->bands[IEEE80211_BAND_2GHZ];
	else
		band = wiphy->bands[IEEE80211_BAND_5GHZ];

	freq = ieee80211_channel_to_frequency(channel, band->band);
	notify_channel = ieee80211_get_channel(wiphy, freq);

	notify_capability = le16_to_cpu(bi->capability);
	notify_interval = le16_to_cpu(bi->beacon_period);
	notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
	notify_ielen = le32_to_cpu(bi->ie_length);
	notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;

2391 2392 2393 2394 2395
	brcmf_dbg(CONN, "bssid: %pM\n", bi->BSSID);
	brcmf_dbg(CONN, "Channel: %d(%d)\n", channel, freq);
	brcmf_dbg(CONN, "Capability: %X\n", notify_capability);
	brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
	brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
2396 2397

	bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
2398
		0, notify_capability, notify_interval, notify_ie,
2399 2400
		notify_ielen, notify_signal, GFP_KERNEL);

2401 2402 2403
	if (!bss)
		return -ENOMEM;

2404
	cfg80211_put_bss(wiphy, bss);
2405

2406
	return 0;
2407 2408
}

2409 2410 2411 2412 2413 2414 2415 2416 2417
static struct brcmf_bss_info_le *
next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
{
	if (bss == NULL)
		return list->bss_info_le;
	return (struct brcmf_bss_info_le *)((unsigned long)bss +
					    le32_to_cpu(bss->length));
}

2418
static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
2419 2420
{
	struct brcmf_scan_results *bss_list;
2421
	struct brcmf_bss_info_le *bi = NULL;	/* must be initialized */
2422 2423 2424
	s32 err = 0;
	int i;

2425
	bss_list = cfg->bss_list;
2426 2427
	if (bss_list->count != 0 &&
	    bss_list->version != BRCMF_BSS_INFO_VERSION) {
2428 2429
		brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
			  bss_list->version);
2430 2431
		return -EOPNOTSUPP;
	}
2432
	brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
2433
	for (i = 0; i < bss_list->count; i++) {
2434
		bi = next_bss_le(bss_list, bi);
2435
		err = brcmf_inform_single_bss(cfg, bi);
2436 2437 2438 2439 2440 2441
		if (err)
			break;
	}
	return err;
}

2442
static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
2443 2444
			  struct net_device *ndev, const u8 *bssid)
{
2445
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2446
	struct ieee80211_channel *notify_channel;
2447
	struct brcmf_bss_info_le *bi = NULL;
2448
	struct ieee80211_supported_band *band;
2449
	struct cfg80211_bss *bss;
F
Franky Lin 已提交
2450
	struct brcmu_chan ch;
2451 2452 2453 2454 2455 2456 2457 2458 2459
	u8 *buf = NULL;
	s32 err = 0;
	u32 freq;
	u16 notify_capability;
	u16 notify_interval;
	u8 *notify_ie;
	size_t notify_ielen;
	s32 notify_signal;

2460
	brcmf_dbg(TRACE, "Enter\n");
2461 2462 2463 2464 2465 2466 2467 2468 2469

	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
	if (buf == NULL) {
		err = -ENOMEM;
		goto CleanUp;
	}

	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);

2470 2471
	err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
				     buf, WL_BSS_INFO_MAX);
2472
	if (err) {
2473
		brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
2474 2475 2476
		goto CleanUp;
	}

2477
	bi = (struct brcmf_bss_info_le *)(buf + 4);
2478

F
Franky Lin 已提交
2479 2480
	ch.chspec = le16_to_cpu(bi->chanspec);
	cfg->d11inf.decchspec(&ch);
2481

F
Franky Lin 已提交
2482
	if (ch.band == BRCMU_CHAN_BAND_2G)
2483 2484 2485 2486
		band = wiphy->bands[IEEE80211_BAND_2GHZ];
	else
		band = wiphy->bands[IEEE80211_BAND_5GHZ];

F
Franky Lin 已提交
2487
	freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
2488 2489 2490 2491 2492 2493 2494 2495
	notify_channel = ieee80211_get_channel(wiphy, freq);

	notify_capability = le16_to_cpu(bi->capability);
	notify_interval = le16_to_cpu(bi->beacon_period);
	notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
	notify_ielen = le32_to_cpu(bi->ie_length);
	notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;

F
Franky Lin 已提交
2496
	brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
2497 2498 2499
	brcmf_dbg(CONN, "capability: %X\n", notify_capability);
	brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
	brcmf_dbg(CONN, "signal: %d\n", notify_signal);
2500

2501
	bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
2502
		0, notify_capability, notify_interval,
2503 2504
		notify_ie, notify_ielen, notify_signal, GFP_KERNEL);

2505 2506 2507 2508 2509
	if (!bss) {
		err = -ENOMEM;
		goto CleanUp;
	}

2510
	cfg80211_put_bss(wiphy, bss);
2511

2512 2513 2514 2515
CleanUp:

	kfree(buf);

2516
	brcmf_dbg(TRACE, "Exit\n");
2517 2518 2519 2520

	return err;
}

2521 2522
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
				 struct brcmf_if *ifp)
H
Hante Meuleman 已提交
2523
{
2524
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
2525
	struct brcmf_bss_info_le *bi;
2526
	struct brcmf_ssid *ssid;
2527
	const struct brcmf_tlv *tim;
2528 2529 2530 2531 2532 2533
	u16 beacon_interval;
	u8 dtim_period;
	size_t ie_len;
	u8 *ie;
	s32 err = 0;

2534
	brcmf_dbg(TRACE, "Enter\n");
2535
	if (brcmf_is_ibssmode(ifp->vif))
2536 2537
		return err;

2538
	ssid = &profile->ssid;
2539

2540
	*(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
2541
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
2542
				     cfg->extra_buf, WL_EXTRA_BUF_MAX);
2543
	if (err) {
2544
		brcmf_err("Could not get bss info %d\n", err);
2545 2546 2547
		goto update_bss_info_out;
	}

2548 2549
	bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
	err = brcmf_inform_single_bss(cfg, bi);
2550 2551 2552 2553 2554 2555 2556
	if (err)
		goto update_bss_info_out;

	ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
	ie_len = le32_to_cpu(bi->ie_length);
	beacon_interval = le16_to_cpu(bi->beacon_period);

2557
	tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
2558 2559 2560 2561 2562 2563 2564 2565 2566
	if (tim)
		dtim_period = tim->data[1];
	else {
		/*
		* active scan was done so we could not get dtim
		* information out of probe response.
		* so we speficially query dtim information to dongle.
		*/
		u32 var;
2567
		err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
2568
		if (err) {
2569
			brcmf_err("wl dtim_assoc failed (%d)\n", err);
2570 2571 2572 2573 2574 2575
			goto update_bss_info_out;
		}
		dtim_period = (u8)var;
	}

update_bss_info_out:
2576
	brcmf_dbg(TRACE, "Exit");
2577 2578 2579
	return err;
}

H
Hante Meuleman 已提交
2580
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
2581
{
2582
	struct escan_info *escan = &cfg->escan_info;
2583

2584
	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2585
	if (cfg->scan_request) {
2586
		escan->escan_state = WL_ESCAN_STATE_IDLE;
2587
		brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
2588
	}
2589 2590
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2591 2592
}

H
Hante Meuleman 已提交
2593 2594
static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
{
2595 2596
	struct brcmf_cfg80211_info *cfg =
			container_of(work, struct brcmf_cfg80211_info,
H
Hante Meuleman 已提交
2597 2598
				     escan_timeout_work);

2599
	brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
H
Hante Meuleman 已提交
2600 2601 2602 2603
}

static void brcmf_escan_timeout(unsigned long data)
{
2604 2605
	struct brcmf_cfg80211_info *cfg =
			(struct brcmf_cfg80211_info *)data;
H
Hante Meuleman 已提交
2606

2607
	if (cfg->scan_request) {
2608
		brcmf_err("timer expired\n");
2609
		schedule_work(&cfg->escan_timeout_work);
H
Hante Meuleman 已提交
2610 2611 2612 2613
	}
}

static s32
F
Franky Lin 已提交
2614 2615
brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
			      struct brcmf_bss_info_le *bss,
H
Hante Meuleman 已提交
2616 2617
			      struct brcmf_bss_info_le *bss_info_le)
{
F
Franky Lin 已提交
2618 2619 2620 2621 2622 2623 2624
	struct brcmu_chan ch_bss, ch_bss_info_le;

	ch_bss.chspec = le16_to_cpu(bss->chanspec);
	cfg->d11inf.decchspec(&ch_bss);
	ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
	cfg->d11inf.decchspec(&ch_bss_info_le);

H
Hante Meuleman 已提交
2625
	if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
F
Franky Lin 已提交
2626
		ch_bss.band == ch_bss_info_le.band &&
H
Hante Meuleman 已提交
2627 2628
		bss_info_le->SSID_len == bss->SSID_len &&
		!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2629 2630
		if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
2631 2632 2633
			s16 bss_rssi = le16_to_cpu(bss->RSSI);
			s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);

H
Hante Meuleman 已提交
2634 2635 2636
			/* preserve max RSSI if the measurements are
			* both on-channel or both off-channel
			*/
2637
			if (bss_info_rssi > bss_rssi)
H
Hante Meuleman 已提交
2638
				bss->RSSI = bss_info_le->RSSI;
2639 2640
		} else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
H
Hante Meuleman 已提交
2641 2642 2643 2644
			/* preserve the on-channel rssi measurement
			* if the new measurement is off channel
			*/
			bss->RSSI = bss_info_le->RSSI;
2645
			bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
H
Hante Meuleman 已提交
2646 2647 2648 2649 2650 2651 2652
		}
		return 1;
	}
	return 0;
}

static s32
2653
brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
H
Hante Meuleman 已提交
2654 2655
			     const struct brcmf_event_msg *e, void *data)
{
2656
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
H
Hante Meuleman 已提交
2657 2658 2659 2660 2661 2662 2663
	s32 status;
	struct brcmf_escan_result_le *escan_result_le;
	struct brcmf_bss_info_le *bss_info_le;
	struct brcmf_bss_info_le *bss = NULL;
	u32 bi_length;
	struct brcmf_scan_results *list;
	u32 i;
2664
	bool aborted;
H
Hante Meuleman 已提交
2665

2666
	status = e->status;
H
Hante Meuleman 已提交
2667

2668 2669
	if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
		brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
H
Hante Meuleman 已提交
2670 2671 2672 2673
		return -EPERM;
	}

	if (status == BRCMF_E_STATUS_PARTIAL) {
2674
		brcmf_dbg(SCAN, "ESCAN Partial result\n");
H
Hante Meuleman 已提交
2675 2676
		escan_result_le = (struct brcmf_escan_result_le *) data;
		if (!escan_result_le) {
2677
			brcmf_err("Invalid escan result (NULL pointer)\n");
H
Hante Meuleman 已提交
2678 2679 2680
			goto exit;
		}
		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2681 2682
			brcmf_err("Invalid bss_count %d: ignoring\n",
				  escan_result_le->bss_count);
H
Hante Meuleman 已提交
2683 2684 2685 2686
			goto exit;
		}
		bss_info_le = &escan_result_le->bss_info_le;

2687 2688 2689 2690 2691 2692 2693 2694
		if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
			goto exit;

		if (!cfg->scan_request) {
			brcmf_dbg(SCAN, "result without cfg80211 request\n");
			goto exit;
		}

H
Hante Meuleman 已提交
2695 2696 2697
		bi_length = le32_to_cpu(bss_info_le->length);
		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
					WL_ESCAN_RESULTS_FIXED_SIZE)) {
2698 2699
			brcmf_err("Invalid bss_info length %d: ignoring\n",
				  bi_length);
H
Hante Meuleman 已提交
2700 2701 2702
			goto exit;
		}

2703
		if (!(cfg_to_wiphy(cfg)->interface_modes &
H
Hante Meuleman 已提交
2704 2705 2706
					BIT(NL80211_IFTYPE_ADHOC))) {
			if (le16_to_cpu(bss_info_le->capability) &
						WLAN_CAPABILITY_IBSS) {
2707
				brcmf_err("Ignoring IBSS result\n");
H
Hante Meuleman 已提交
2708 2709 2710 2711 2712
				goto exit;
			}
		}

		list = (struct brcmf_scan_results *)
2713
				cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
2714
		if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2715
			brcmf_err("Buffer is too small: ignoring\n");
H
Hante Meuleman 已提交
2716 2717 2718 2719 2720 2721 2722
			goto exit;
		}

		for (i = 0; i < list->count; i++) {
			bss = bss ? (struct brcmf_bss_info_le *)
				((unsigned char *)bss +
				le32_to_cpu(bss->length)) : list->bss_info_le;
F
Franky Lin 已提交
2723 2724
			if (brcmf_compare_update_same_bss(cfg, bss,
							  bss_info_le))
H
Hante Meuleman 已提交
2725 2726
				goto exit;
		}
2727
		memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
H
Hante Meuleman 已提交
2728 2729 2730 2731 2732
			bss_info_le, bi_length);
		list->version = le32_to_cpu(bss_info_le->version);
		list->buflen += bi_length;
		list->count++;
	} else {
2733
		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2734 2735
		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
			goto exit;
2736 2737 2738 2739
		if (cfg->scan_request) {
			cfg->bss_list = (struct brcmf_scan_results *)
				cfg->escan_info.escan_buf;
			brcmf_inform_bss(cfg);
2740
			aborted = status != BRCMF_E_STATUS_SUCCESS;
2741
			brcmf_notify_escan_complete(cfg, ifp, aborted,
2742
						    false);
H
Hante Meuleman 已提交
2743
		} else
2744 2745
			brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
				  status);
H
Hante Meuleman 已提交
2746 2747
	}
exit:
2748
	return 0;
H
Hante Meuleman 已提交
2749 2750
}

2751
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
H
Hante Meuleman 已提交
2752
{
2753 2754
	brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
			    brcmf_cfg80211_escan_handler);
2755 2756 2757 2758 2759 2760 2761
	cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
	/* Init scan_timeout timer */
	init_timer(&cfg->escan_timeout);
	cfg->escan_timeout.data = (unsigned long) cfg;
	cfg->escan_timeout.function = brcmf_escan_timeout;
	INIT_WORK(&cfg->escan_timeout_work,
		  brcmf_cfg80211_escan_timeout_worker);
H
Hante Meuleman 已提交
2762 2763
}

2764
static __always_inline void brcmf_delay(u32 ms)
2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775
{
	if (ms < 1000 / HZ) {
		cond_resched();
		mdelay(ms);
	} else {
		msleep(ms);
	}
}

static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
2776
	brcmf_dbg(TRACE, "Enter\n");
2777 2778 2779 2780 2781 2782 2783

	return 0;
}

static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
				  struct cfg80211_wowlan *wow)
{
2784 2785
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
2786
	struct brcmf_cfg80211_vif *vif;
2787

2788
	brcmf_dbg(TRACE, "Enter\n");
2789 2790

	/*
2791 2792
	 * if the primary net_device is not READY there is nothing
	 * we can do but pray resume goes smoothly.
2793
	 */
2794 2795 2796
	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
	if (!check_vif_up(vif))
		goto exit;
2797

2798 2799 2800
	list_for_each_entry(vif, &cfg->vif_list, list) {
		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
			continue;
2801
		/*
2802 2803
		 * While going to suspend if associated with AP disassociate
		 * from AP to save power while system is in suspended state
2804
		 */
2805 2806 2807 2808 2809 2810 2811
		brcmf_link_down(vif);

		/* Make sure WPA_Supplicant receives all the event
		 * generated due to DISASSOC call to the fw to keep
		 * the state fw and WPA_Supplicant state consistent
		 */
		brcmf_delay(500);
2812 2813
	}

2814 2815
	/* end any scanning */
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
2816
		brcmf_abort_scanning(cfg);
2817 2818

	/* Turn off watchdog timer */
2819
	brcmf_set_mpc(netdev_priv(ndev), 1);
2820

2821
exit:
2822
	brcmf_dbg(TRACE, "Exit\n");
2823 2824
	/* clear any scanning activity */
	cfg->scan_status = 0;
2825 2826 2827 2828 2829 2830 2831 2832
	return 0;
}

static __used s32
brcmf_update_pmklist(struct net_device *ndev,
		     struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
{
	int i, j;
2833
	int pmkid_len;
2834

2835 2836
	pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);

2837
	brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
2838
	for (i = 0; i < pmkid_len; i++) {
2839 2840
		brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
			  &pmk_list->pmkids.pmkid[i].BSSID);
2841
		for (j = 0; j < WLAN_PMKID_LEN; j++)
2842 2843
			brcmf_dbg(CONN, "%02x\n",
				  pmk_list->pmkids.pmkid[i].PMKID[j]);
2844 2845 2846
	}

	if (!err)
2847 2848
		brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
					 (char *)pmk_list, sizeof(*pmk_list));
2849 2850 2851 2852 2853 2854 2855 2856

	return err;
}

static s32
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
			 struct cfg80211_pmksa *pmksa)
{
2857
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2858
	struct brcmf_if *ifp = netdev_priv(ndev);
2859
	struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
2860 2861
	s32 err = 0;
	int i;
2862
	int pmkid_len;
2863

2864
	brcmf_dbg(TRACE, "Enter\n");
2865
	if (!check_vif_up(ifp->vif))
2866 2867
		return -EIO;

2868 2869
	pmkid_len = le32_to_cpu(pmkids->npmkid);
	for (i = 0; i < pmkid_len; i++)
2870 2871 2872 2873 2874
		if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
			break;
	if (i < WL_NUM_PMKIDS_MAX) {
		memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
		memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
2875 2876 2877 2878
		if (i == pmkid_len) {
			pmkid_len++;
			pmkids->npmkid = cpu_to_le32(pmkid_len);
		}
2879 2880 2881
	} else
		err = -EINVAL;

2882 2883
	brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
		  pmkids->pmkid[pmkid_len].BSSID);
2884
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2885
		brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
2886

2887
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2888

2889
	brcmf_dbg(TRACE, "Exit\n");
2890 2891 2892 2893 2894 2895 2896
	return err;
}

static s32
brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_pmksa *pmksa)
{
2897
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2898
	struct brcmf_if *ifp = netdev_priv(ndev);
2899 2900
	struct pmkid_list pmkid;
	s32 err = 0;
2901
	int i, pmkid_len;
2902

2903
	brcmf_dbg(TRACE, "Enter\n");
2904
	if (!check_vif_up(ifp->vif))
2905 2906 2907 2908 2909
		return -EIO;

	memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
	memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);

2910 2911
	brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
		  &pmkid.pmkid[0].BSSID);
2912
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2913
		brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
2914

2915
	pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
2916
	for (i = 0; i < pmkid_len; i++)
2917
		if (!memcmp
2918
		    (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
2919 2920 2921
		     ETH_ALEN))
			break;

2922 2923
	if ((pmkid_len > 0)
	    && (i < pmkid_len)) {
2924
		memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
2925
		       sizeof(struct pmkid));
2926
		for (; i < (pmkid_len - 1); i++) {
2927 2928
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
2929
			       ETH_ALEN);
2930 2931
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
2932 2933
			       WLAN_PMKID_LEN);
		}
2934
		cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
2935 2936 2937
	} else
		err = -EINVAL;

2938
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2939

2940
	brcmf_dbg(TRACE, "Exit\n");
2941 2942 2943 2944 2945 2946 2947
	return err;

}

static s32
brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
{
2948
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2949
	struct brcmf_if *ifp = netdev_priv(ndev);
2950 2951
	s32 err = 0;

2952
	brcmf_dbg(TRACE, "Enter\n");
2953
	if (!check_vif_up(ifp->vif))
2954 2955
		return -EIO;

2956 2957
	memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2958

2959
	brcmf_dbg(TRACE, "Exit\n");
2960 2961 2962 2963
	return err;

}

2964 2965 2966 2967 2968 2969 2970 2971 2972
/*
 * PFN result doesn't have all the info which are
 * required by the supplicant
 * (For e.g IEs) Do a target Escan so that sched scan results are reported
 * via wl_inform_single_bss in the required format. Escan does require the
 * scan request in the form of cfg80211_scan_request. For timebeing, create
 * cfg80211_scan_request one out of the received PNO event.
 */
static s32
2973
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
2974 2975
				const struct brcmf_event_msg *e, void *data)
{
2976
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2977 2978 2979 2980
	struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
	struct cfg80211_scan_request *request = NULL;
	struct cfg80211_ssid *ssid = NULL;
	struct ieee80211_channel *channel = NULL;
2981
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2982 2983 2984 2985 2986 2987 2988
	int err = 0;
	int channel_req = 0;
	int band = 0;
	struct brcmf_pno_scanresults_le *pfn_result;
	u32 result_count;
	u32 status;

2989
	brcmf_dbg(SCAN, "Enter\n");
2990

2991
	if (e->event_code == BRCMF_E_PFN_NET_LOST) {
2992
		brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004
		return 0;
	}

	pfn_result = (struct brcmf_pno_scanresults_le *)data;
	result_count = le32_to_cpu(pfn_result->count);
	status = le32_to_cpu(pfn_result->status);

	/*
	 * PFN event is limited to fit 512 bytes so we may get
	 * multiple NET_FOUND events. For now place a warning here.
	 */
	WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
3005
	brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
3006 3007 3008 3009
	if (result_count > 0) {
		int i;

		request = kzalloc(sizeof(*request), GFP_KERNEL);
3010 3011
		ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
		channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023
		if (!request || !ssid || !channel) {
			err = -ENOMEM;
			goto out_err;
		}

		request->wiphy = wiphy;
		data += sizeof(struct brcmf_pno_scanresults_le);
		netinfo_start = (struct brcmf_pno_net_info_le *)data;

		for (i = 0; i < result_count; i++) {
			netinfo = &netinfo_start[i];
			if (!netinfo) {
3024 3025
				brcmf_err("Invalid netinfo ptr. index: %d\n",
					  i);
3026 3027 3028 3029
				err = -EINVAL;
				goto out_err;
			}

3030 3031
			brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
				  netinfo->SSID, netinfo->channel);
3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053
			memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
			ssid[i].ssid_len = netinfo->SSID_len;
			request->n_ssids++;

			channel_req = netinfo->channel;
			if (channel_req <= CH_MAX_2G_CHANNEL)
				band = NL80211_BAND_2GHZ;
			else
				band = NL80211_BAND_5GHZ;
			channel[i].center_freq =
				ieee80211_channel_to_frequency(channel_req,
							       band);
			channel[i].band = band;
			channel[i].flags |= IEEE80211_CHAN_NO_HT40;
			request->channels[i] = &channel[i];
			request->n_channels++;
		}

		/* assign parsed ssid array */
		if (request->n_ssids)
			request->ssids = &ssid[0];

3054
		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3055
			/* Abort any on-going scan */
3056
			brcmf_abort_scanning(cfg);
3057 3058
		}

3059
		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3060
		cfg->escan_info.run = brcmf_run_escan;
3061
		err = brcmf_do_escan(cfg, wiphy, ifp, request);
3062
		if (err) {
3063
			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3064 3065
			goto out_err;
		}
3066 3067
		cfg->sched_escan = true;
		cfg->scan_request = request;
3068
	} else {
3069
		brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090
		goto out_err;
	}

	kfree(ssid);
	kfree(channel);
	kfree(request);
	return 0;

out_err:
	kfree(ssid);
	kfree(channel);
	kfree(request);
	cfg80211_sched_scan_stopped(wiphy);
	return err;
}

static int brcmf_dev_pno_clean(struct net_device *ndev)
{
	int ret;

	/* Disable pfn */
3091
	ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3092 3093
	if (ret == 0) {
		/* clear pfn */
3094 3095
		ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
					       NULL, 0);
3096 3097
	}
	if (ret < 0)
3098
		brcmf_err("failed code %d\n", ret);
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117

	return ret;
}

static int brcmf_dev_pno_config(struct net_device *ndev)
{
	struct brcmf_pno_param_le pfn_param;

	memset(&pfn_param, 0, sizeof(pfn_param));
	pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);

	/* set extra pno params */
	pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
	pfn_param.repeat = BRCMF_PNO_REPEAT;
	pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;

	/* set up pno scan fr */
	pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);

3118 3119
	return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
					&pfn_param, sizeof(pfn_param));
3120 3121 3122 3123 3124 3125 3126
}

static int
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
				struct net_device *ndev,
				struct cfg80211_sched_scan_request *request)
{
3127
	struct brcmf_if *ifp = netdev_priv(ndev);
3128
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3129 3130 3131 3132
	struct brcmf_pno_net_param_le pfn;
	int i;
	int ret = 0;

3133
	brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3134
		  request->n_match_sets, request->n_ssids);
3135
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3136
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3137 3138
		return -EAGAIN;
	}
3139 3140 3141 3142 3143
	if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
		brcmf_err("Scanning suppressed: status (%lu)\n",
			  cfg->scan_status);
		return -EAGAIN;
	}
3144

3145
	if (!request->n_ssids || !request->n_match_sets) {
3146
		brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3147
			  request->n_ssids);
3148 3149 3150 3151 3152 3153
		return -EINVAL;
	}

	if (request->n_ssids > 0) {
		for (i = 0; i < request->n_ssids; i++) {
			/* Active scan req for ssids */
3154 3155
			brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
				  request->ssids[i].ssid);
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167

			/*
			 * match_set ssids is a supert set of n_ssid list,
			 * so we need not add these set seperately.
			 */
		}
	}

	if (request->n_match_sets > 0) {
		/* clean up everything */
		ret = brcmf_dev_pno_clean(ndev);
		if  (ret < 0) {
3168
			brcmf_err("failed error=%d\n", ret);
3169 3170 3171 3172 3173 3174
			return ret;
		}

		/* configure pno */
		ret = brcmf_dev_pno_config(ndev);
		if (ret < 0) {
3175
			brcmf_err("PNO setup failed!! ret=%d\n", ret);
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187
			return -EINVAL;
		}

		/* configure each match set */
		for (i = 0; i < request->n_match_sets; i++) {
			struct cfg80211_ssid *ssid;
			u32 ssid_len;

			ssid = &request->match_sets[i].ssid;
			ssid_len = ssid->ssid_len;

			if (!ssid_len) {
3188
				brcmf_err("skip broadcast ssid\n");
3189 3190 3191 3192 3193 3194 3195 3196 3197
				continue;
			}
			pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
			pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
			pfn.wsec = cpu_to_le32(0);
			pfn.infra = cpu_to_le32(1);
			pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
			pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
			memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
3198
			ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3199
						       sizeof(pfn));
3200 3201
			brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
				  ret == 0 ? "set" : "failed", ssid->ssid);
3202 3203
		}
		/* Enable the PNO */
3204
		if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3205
			brcmf_err("PNO enable failed!! ret=%d\n", ret);
3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	return 0;
}

static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
					  struct net_device *ndev)
{
3218
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3219

3220
	brcmf_dbg(SCAN, "enter\n");
3221
	brcmf_dev_pno_clean(ndev);
3222
	if (cfg->sched_escan)
3223
		brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3224 3225 3226
	return 0;
}

3227
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
H
Hante Meuleman 已提交
3228 3229 3230 3231
{
	s32 err;

	/* set auth */
3232
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
H
Hante Meuleman 已提交
3233
	if (err < 0) {
3234
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
3235 3236 3237
		return err;
	}
	/* set wsec */
3238
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
H
Hante Meuleman 已提交
3239
	if (err < 0) {
3240
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
3241 3242 3243
		return err;
	}
	/* set upper-layer auth */
3244
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
H
Hante Meuleman 已提交
3245
	if (err < 0) {
3246
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
		return err;
	}

	return 0;
}

static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
{
	if (is_rsn_ie)
		return (memcmp(oui, RSN_OUI, TLV_OUI_LEN) == 0);

	return (memcmp(oui, WPA_OUI, TLV_OUI_LEN) == 0);
}

static s32
3262 3263 3264
brcmf_configure_wpaie(struct net_device *ndev,
		      const struct brcmf_vs_tlv *wpa_ie,
		      bool is_rsn_ie)
H
Hante Meuleman 已提交
3265
{
3266
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280
	u32 auth = 0; /* d11 open authentication */
	u16 count;
	s32 err = 0;
	s32 len = 0;
	u32 i;
	u32 wsec;
	u32 pval = 0;
	u32 gval = 0;
	u32 wpa_auth = 0;
	u32 offset;
	u8 *data;
	u16 rsn_cap;
	u32 wme_bss_disable;

3281
	brcmf_dbg(TRACE, "Enter\n");
H
Hante Meuleman 已提交
3282 3283 3284 3285 3286
	if (wpa_ie == NULL)
		goto exit;

	len = wpa_ie->len + TLV_HDR_LEN;
	data = (u8 *)wpa_ie;
3287
	offset = TLV_HDR_LEN;
H
Hante Meuleman 已提交
3288 3289
	if (!is_rsn_ie)
		offset += VS_IE_FIXED_HDR_LEN;
3290 3291
	else
		offset += WPA_IE_VERSION_LEN;
H
Hante Meuleman 已提交
3292 3293 3294 3295

	/* check for multicast cipher suite */
	if (offset + WPA_IE_MIN_OUI_LEN > len) {
		err = -EINVAL;
3296
		brcmf_err("no multicast cipher suite\n");
H
Hante Meuleman 已提交
3297 3298 3299 3300 3301
		goto exit;
	}

	if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
		err = -EINVAL;
3302
		brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323
		goto exit;
	}
	offset += TLV_OUI_LEN;

	/* pick up multicast cipher */
	switch (data[offset]) {
	case WPA_CIPHER_NONE:
		gval = 0;
		break;
	case WPA_CIPHER_WEP_40:
	case WPA_CIPHER_WEP_104:
		gval = WEP_ENABLED;
		break;
	case WPA_CIPHER_TKIP:
		gval = TKIP_ENABLED;
		break;
	case WPA_CIPHER_AES_CCM:
		gval = AES_ENABLED;
		break;
	default:
		err = -EINVAL;
3324
		brcmf_err("Invalid multi cast cipher info\n");
H
Hante Meuleman 已提交
3325 3326 3327 3328 3329 3330 3331 3332 3333 3334
		goto exit;
	}

	offset++;
	/* walk thru unicast cipher list and pick up what we recognize */
	count = data[offset] + (data[offset + 1] << 8);
	offset += WPA_IE_SUITE_COUNT_LEN;
	/* Check for unicast suite(s) */
	if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
		err = -EINVAL;
3335
		brcmf_err("no unicast cipher suite\n");
H
Hante Meuleman 已提交
3336 3337 3338 3339 3340
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3341
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
			goto exit;
		}
		offset += TLV_OUI_LEN;
		switch (data[offset]) {
		case WPA_CIPHER_NONE:
			break;
		case WPA_CIPHER_WEP_40:
		case WPA_CIPHER_WEP_104:
			pval |= WEP_ENABLED;
			break;
		case WPA_CIPHER_TKIP:
			pval |= TKIP_ENABLED;
			break;
		case WPA_CIPHER_AES_CCM:
			pval |= AES_ENABLED;
			break;
		default:
3359
			brcmf_err("Ivalid unicast security info\n");
H
Hante Meuleman 已提交
3360 3361 3362 3363 3364 3365 3366 3367 3368
		}
		offset++;
	}
	/* walk thru auth management suite list and pick up what we recognize */
	count = data[offset] + (data[offset + 1] << 8);
	offset += WPA_IE_SUITE_COUNT_LEN;
	/* Check for auth key management suite(s) */
	if (offset + (WPA_IE_MIN_OUI_LEN * count) > len) {
		err = -EINVAL;
3369
		brcmf_err("no auth key mgmt suite\n");
H
Hante Meuleman 已提交
3370 3371 3372 3373 3374
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3375
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3376 3377 3378 3379 3380
			goto exit;
		}
		offset += TLV_OUI_LEN;
		switch (data[offset]) {
		case RSN_AKM_NONE:
3381
			brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
H
Hante Meuleman 已提交
3382 3383 3384
			wpa_auth |= WPA_AUTH_NONE;
			break;
		case RSN_AKM_UNSPECIFIED:
3385
			brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
H
Hante Meuleman 已提交
3386 3387 3388 3389
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
				    (wpa_auth |= WPA_AUTH_UNSPECIFIED);
			break;
		case RSN_AKM_PSK:
3390
			brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
H
Hante Meuleman 已提交
3391 3392 3393 3394
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
				    (wpa_auth |= WPA_AUTH_PSK);
			break;
		default:
3395
			brcmf_err("Ivalid key mgmt info\n");
H
Hante Meuleman 已提交
3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407
		}
		offset++;
	}

	if (is_rsn_ie) {
		wme_bss_disable = 1;
		if ((offset + RSN_CAP_LEN) <= len) {
			rsn_cap = data[offset] + (data[offset + 1] << 8);
			if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
				wme_bss_disable = 0;
		}
		/* set wme_bss_disable to sync RSN Capabilities */
3408
		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
3409
					       wme_bss_disable);
H
Hante Meuleman 已提交
3410
		if (err < 0) {
3411
			brcmf_err("wme_bss_disable error %d\n", err);
H
Hante Meuleman 已提交
3412 3413 3414 3415 3416 3417 3418
			goto exit;
		}
	}
	/* FOR WPS , set SES_OW_ENABLED */
	wsec = (pval | gval | SES_OW_ENABLED);

	/* set auth */
3419
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
H
Hante Meuleman 已提交
3420
	if (err < 0) {
3421
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
3422 3423 3424
		goto exit;
	}
	/* set wsec */
3425
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
H
Hante Meuleman 已提交
3426
	if (err < 0) {
3427
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
3428 3429 3430
		goto exit;
	}
	/* set upper-layer auth */
3431
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
H
Hante Meuleman 已提交
3432
	if (err < 0) {
3433
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
3434 3435 3436 3437 3438 3439 3440 3441
		goto exit;
	}

exit:
	return err;
}

static s32
3442
brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
H
Hante Meuleman 已提交
3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459
		     struct parsed_vndr_ies *vndr_ies)
{
	struct brcmf_vs_tlv *vndrie;
	struct brcmf_tlv *ie;
	struct parsed_vndr_ie_info *parsed_info;
	s32 remaining_len;

	remaining_len = (s32)vndr_ie_len;
	memset(vndr_ies, 0, sizeof(*vndr_ies));

	ie = (struct brcmf_tlv *)vndr_ie_buf;
	while (ie) {
		if (ie->id != WLAN_EID_VENDOR_SPECIFIC)
			goto next;
		vndrie = (struct brcmf_vs_tlv *)ie;
		/* len should be bigger than OUI length + one */
		if (vndrie->len < (VS_IE_FIXED_HDR_LEN - TLV_HDR_LEN + 1)) {
3460 3461
			brcmf_err("invalid vndr ie. length is too small %d\n",
				  vndrie->len);
H
Hante Meuleman 已提交
3462 3463 3464 3465 3466 3467
			goto next;
		}
		/* if wpa or wme ie, do not add ie */
		if (!memcmp(vndrie->oui, (u8 *)WPA_OUI, TLV_OUI_LEN) &&
		    ((vndrie->oui_type == WPA_OUI_TYPE) ||
		    (vndrie->oui_type == WME_OUI_TYPE))) {
3468
			brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
H
Hante Meuleman 已提交
3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480
			goto next;
		}

		parsed_info = &vndr_ies->ie_info[vndr_ies->count];

		/* save vndr ie information */
		parsed_info->ie_ptr = (char *)vndrie;
		parsed_info->ie_len = vndrie->len + TLV_HDR_LEN;
		memcpy(&parsed_info->vndrie, vndrie, sizeof(*vndrie));

		vndr_ies->count++;

3481 3482 3483 3484 3485
		brcmf_dbg(TRACE, "** OUI %02x %02x %02x, type 0x%02x\n",
			  parsed_info->vndrie.oui[0],
			  parsed_info->vndrie.oui[1],
			  parsed_info->vndrie.oui[2],
			  parsed_info->vndrie.oui_type);
H
Hante Meuleman 已提交
3486

3487
		if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
H
Hante Meuleman 已提交
3488 3489
			break;
next:
3490 3491
		remaining_len -= (ie->len + TLV_HDR_LEN);
		if (remaining_len <= TLV_HDR_LEN)
H
Hante Meuleman 已提交
3492 3493
			ie = NULL;
		else
3494 3495
			ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
				TLV_HDR_LEN);
H
Hante Meuleman 已提交
3496
	}
3497
	return 0;
H
Hante Meuleman 已提交
3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520
}

static u32
brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
{

	__le32 iecount_le;
	__le32 pktflag_le;

	strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
	iebuf[VNDR_IE_CMD_LEN - 1] = '\0';

	iecount_le = cpu_to_le32(1);
	memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));

	pktflag_le = cpu_to_le32(pktflag);
	memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));

	memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);

	return ie_len + VNDR_IE_HDR_SIZE;
}

3521 3522
s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
			  const u8 *vndr_ie_buf, u32 vndr_ie_len)
H
Hante Meuleman 已提交
3523
{
3524 3525
	struct brcmf_if *ifp;
	struct vif_saved_ie *saved_ie;
H
Hante Meuleman 已提交
3526 3527 3528 3529
	s32 err = 0;
	u8  *iovar_ie_buf;
	u8  *curr_ie_buf;
	u8  *mgmt_ie_buf = NULL;
3530
	int mgmt_ie_buf_len;
3531
	u32 *mgmt_ie_len;
H
Hante Meuleman 已提交
3532 3533 3534 3535 3536 3537 3538 3539
	u32 del_add_ie_buf_len = 0;
	u32 total_ie_buf_len = 0;
	u32 parsed_ie_buf_len = 0;
	struct parsed_vndr_ies old_vndr_ies;
	struct parsed_vndr_ies new_vndr_ies;
	struct parsed_vndr_ie_info *vndrie_info;
	s32 i;
	u8 *ptr;
3540
	int remained_buf_len;
H
Hante Meuleman 已提交
3541

3542 3543 3544 3545 3546
	if (!vif)
		return -ENODEV;
	ifp = vif->ifp;
	saved_ie = &vif->saved_ie;

3547
	brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
H
Hante Meuleman 已提交
3548 3549 3550 3551
	iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!iovar_ie_buf)
		return -ENOMEM;
	curr_ie_buf = iovar_ie_buf;
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
	switch (pktflag) {
	case BRCMF_VNDR_IE_PRBREQ_FLAG:
		mgmt_ie_buf = saved_ie->probe_req_ie;
		mgmt_ie_len = &saved_ie->probe_req_ie_len;
		mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie);
		break;
	case BRCMF_VNDR_IE_PRBRSP_FLAG:
		mgmt_ie_buf = saved_ie->probe_res_ie;
		mgmt_ie_len = &saved_ie->probe_res_ie_len;
		mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie);
		break;
	case BRCMF_VNDR_IE_BEACON_FLAG:
		mgmt_ie_buf = saved_ie->beacon_ie;
		mgmt_ie_len = &saved_ie->beacon_ie_len;
		mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
		break;
	case BRCMF_VNDR_IE_ASSOCREQ_FLAG:
		mgmt_ie_buf = saved_ie->assoc_req_ie;
		mgmt_ie_len = &saved_ie->assoc_req_ie_len;
		mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie);
		break;
	default:
		err = -EPERM;
		brcmf_err("not suitable type\n");
		goto exit;
H
Hante Meuleman 已提交
3577 3578 3579 3580
	}

	if (vndr_ie_len > mgmt_ie_buf_len) {
		err = -ENOMEM;
3581
		brcmf_err("extra IE size too big\n");
H
Hante Meuleman 已提交
3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596
		goto exit;
	}

	/* parse and save new vndr_ie in curr_ie_buff before comparing it */
	if (vndr_ie_buf && vndr_ie_len && curr_ie_buf) {
		ptr = curr_ie_buf;
		brcmf_parse_vndr_ies(vndr_ie_buf, vndr_ie_len, &new_vndr_ies);
		for (i = 0; i < new_vndr_ies.count; i++) {
			vndrie_info = &new_vndr_ies.ie_info[i];
			memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
			       vndrie_info->ie_len);
			parsed_ie_buf_len += vndrie_info->ie_len;
		}
	}

3597
	if (mgmt_ie_buf && *mgmt_ie_len) {
H
Hante Meuleman 已提交
3598 3599 3600
		if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
		    (memcmp(mgmt_ie_buf, curr_ie_buf,
			    parsed_ie_buf_len) == 0)) {
3601
			brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
H
Hante Meuleman 已提交
3602 3603 3604 3605 3606 3607 3608 3609 3610 3611
			goto exit;
		}

		/* parse old vndr_ie */
		brcmf_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len, &old_vndr_ies);

		/* make a command to delete old ie */
		for (i = 0; i < old_vndr_ies.count; i++) {
			vndrie_info = &old_vndr_ies.ie_info[i];

3612 3613 3614 3615 3616 3617
			brcmf_dbg(TRACE, "DEL ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
				  vndrie_info->vndrie.id,
				  vndrie_info->vndrie.len,
				  vndrie_info->vndrie.oui[0],
				  vndrie_info->vndrie.oui[1],
				  vndrie_info->vndrie.oui[2]);
H
Hante Meuleman 已提交
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638

			del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
							   vndrie_info->ie_ptr,
							   vndrie_info->ie_len,
							   "del");
			curr_ie_buf += del_add_ie_buf_len;
			total_ie_buf_len += del_add_ie_buf_len;
		}
	}

	*mgmt_ie_len = 0;
	/* Add if there is any extra IE */
	if (mgmt_ie_buf && parsed_ie_buf_len) {
		ptr = mgmt_ie_buf;

		remained_buf_len = mgmt_ie_buf_len;

		/* make a command to add new ie */
		for (i = 0; i < new_vndr_ies.count; i++) {
			vndrie_info = &new_vndr_ies.ie_info[i];

3639 3640 3641
			/* verify remained buf size before copy data */
			if (remained_buf_len < (vndrie_info->vndrie.len +
							VNDR_IE_VSIE_OFFSET)) {
3642 3643
				brcmf_err("no space in mgmt_ie_buf: len left %d",
					  remained_buf_len);
3644 3645 3646 3647 3648
				break;
			}
			remained_buf_len -= (vndrie_info->ie_len +
					     VNDR_IE_VSIE_OFFSET);

3649 3650 3651 3652 3653 3654
			brcmf_dbg(TRACE, "ADDED ID : %d, Len: %d, OUI:%02x:%02x:%02x\n",
				  vndrie_info->vndrie.id,
				  vndrie_info->vndrie.len,
				  vndrie_info->vndrie.oui[0],
				  vndrie_info->vndrie.oui[1],
				  vndrie_info->vndrie.oui[2]);
H
Hante Meuleman 已提交
3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670

			del_add_ie_buf_len = brcmf_vndr_ie(curr_ie_buf, pktflag,
							   vndrie_info->ie_ptr,
							   vndrie_info->ie_len,
							   "add");

			/* save the parsed IE in wl struct */
			memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
			       vndrie_info->ie_len);
			*mgmt_ie_len += vndrie_info->ie_len;

			curr_ie_buf += del_add_ie_buf_len;
			total_ie_buf_len += del_add_ie_buf_len;
		}
	}
	if (total_ie_buf_len) {
3671
		err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
3672
						 total_ie_buf_len);
H
Hante Meuleman 已提交
3673
		if (err)
3674
			brcmf_err("vndr ie set error : %d\n", err);
H
Hante Meuleman 已提交
3675 3676 3677 3678 3679 3680 3681
	}

exit:
	kfree(iovar_ie_buf);
	return err;
}

3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
{
	s32 pktflags[] = {
		BRCMF_VNDR_IE_PRBREQ_FLAG,
		BRCMF_VNDR_IE_PRBRSP_FLAG,
		BRCMF_VNDR_IE_BEACON_FLAG
	};
	int i;

	for (i = 0; i < ARRAY_SIZE(pktflags); i++)
		brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);

	memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
	return 0;
}

3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724
static s32
brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
			struct cfg80211_beacon_data *beacon)
{
	s32 err;

	/* Set Beacon IEs to FW */
	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG,
				    beacon->tail, beacon->tail_len);
	if (err) {
		brcmf_err("Set Beacon IE Failed\n");
		return err;
	}
	brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");

	/* Set Probe Response IEs to FW */
	err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG,
				    beacon->proberesp_ies,
				    beacon->proberesp_ies_len);
	if (err)
		brcmf_err("Set Probe Resp IE Failed\n");
	else
		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");

	return err;
}

H
Hante Meuleman 已提交
3725 3726 3727 3728 3729
static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
			struct cfg80211_ap_settings *settings)
{
	s32 ie_offset;
3730
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3731
	struct brcmf_if *ifp = netdev_priv(ndev);
3732
	const struct brcmf_tlv *ssid_ie;
H
Hante Meuleman 已提交
3733 3734
	struct brcmf_ssid_le ssid_le;
	s32 err = -EPERM;
3735 3736
	const struct brcmf_tlv *rsn_ie;
	const struct brcmf_vs_tlv *wpa_ie;
H
Hante Meuleman 已提交
3737
	struct brcmf_join_params join_params;
3738 3739
	enum nl80211_iftype dev_role;
	struct brcmf_fil_bss_enable_le bss_enable;
3740
	u16 chanspec;
H
Hante Meuleman 已提交
3741

3742 3743 3744
	brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
		  settings->chandef.chan->hw_value,
		  settings->chandef.center_freq1, settings->chandef.width,
3745
		  settings->beacon_interval, settings->dtim_period);
3746 3747 3748
	brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
		  settings->ssid, settings->ssid_len, settings->auth_type,
		  settings->inactivity_timeout);
H
Hante Meuleman 已提交
3749

3750
	dev_role = ifp->vif->wdev.iftype;
H
Hante Meuleman 已提交
3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763

	memset(&ssid_le, 0, sizeof(ssid_le));
	if (settings->ssid == NULL || settings->ssid_len == 0) {
		ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
		ssid_ie = brcmf_parse_tlvs(
				(u8 *)&settings->beacon.head[ie_offset],
				settings->beacon.head_len - ie_offset,
				WLAN_EID_SSID);
		if (!ssid_ie)
			return -EINVAL;

		memcpy(ssid_le.SSID, ssid_ie->data, ssid_ie->len);
		ssid_le.SSID_len = cpu_to_le32(ssid_ie->len);
3764
		brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
H
Hante Meuleman 已提交
3765 3766 3767 3768 3769
	} else {
		memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
		ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
	}

3770
	brcmf_set_mpc(ifp, 0);
3771
	brcmf_configure_arp_offload(ifp, false);
H
Hante Meuleman 已提交
3772 3773 3774 3775 3776 3777 3778 3779 3780 3781

	/* find the RSN_IE */
	rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
				  settings->beacon.tail_len, WLAN_EID_RSN);

	/* find the WPA_IE */
	wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
				  settings->beacon.tail_len);

	if ((wpa_ie != NULL || rsn_ie != NULL)) {
3782
		brcmf_dbg(TRACE, "WPA(2) IE is found\n");
H
Hante Meuleman 已提交
3783 3784
		if (wpa_ie != NULL) {
			/* WPA IE */
3785
			err = brcmf_configure_wpaie(ndev, wpa_ie, false);
H
Hante Meuleman 已提交
3786 3787 3788 3789 3790
			if (err < 0)
				goto exit;
		} else {
			/* RSN IE */
			err = brcmf_configure_wpaie(ndev,
3791
				(struct brcmf_vs_tlv *)rsn_ie, true);
H
Hante Meuleman 已提交
3792 3793 3794 3795
			if (err < 0)
				goto exit;
		}
	} else {
3796
		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
3797
		brcmf_configure_opensecurity(ifp);
H
Hante Meuleman 已提交
3798 3799
	}

3800
	brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
H
Hante Meuleman 已提交
3801

3802
	chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
3803
	err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3804
	if (err < 0) {
3805
		brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err);
3806 3807 3808
		goto exit;
	}

H
Hante Meuleman 已提交
3809
	if (settings->beacon_interval) {
3810
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
3811
					    settings->beacon_interval);
H
Hante Meuleman 已提交
3812
		if (err < 0) {
3813
			brcmf_err("Beacon Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3814 3815 3816 3817
			goto exit;
		}
	}
	if (settings->dtim_period) {
3818
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
3819
					    settings->dtim_period);
H
Hante Meuleman 已提交
3820
		if (err < 0) {
3821
			brcmf_err("DTIM Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3822 3823 3824
			goto exit;
		}
	}
3825 3826 3827 3828 3829 3830 3831

	if (dev_role == NL80211_IFTYPE_AP) {
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
		if (err < 0) {
			brcmf_err("BRCMF_C_DOWN error %d\n", err);
			goto exit;
		}
3832
		brcmf_fil_iovar_int_set(ifp, "apsta", 0);
H
Hante Meuleman 已提交
3833 3834
	}

3835
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
H
Hante Meuleman 已提交
3836
	if (err < 0) {
3837
		brcmf_err("SET INFRA error %d\n", err);
H
Hante Meuleman 已提交
3838 3839
		goto exit;
	}
3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
	if (dev_role == NL80211_IFTYPE_AP) {
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
		if (err < 0) {
			brcmf_err("setting AP mode failed %d\n", err);
			goto exit;
		}
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
		if (err < 0) {
			brcmf_err("BRCMF_C_UP error (%d)\n", err);
			goto exit;
		}

		memset(&join_params, 0, sizeof(join_params));
		/* join parameters starts with ssid */
		memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le));
		/* create softap */
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
					     &join_params, sizeof(join_params));
		if (err < 0) {
			brcmf_err("SET SSID error (%d)\n", err);
			goto exit;
		}
		brcmf_dbg(TRACE, "AP mode configuration complete\n");
	} else {
		err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le,
						sizeof(ssid_le));
		if (err < 0) {
			brcmf_err("setting ssid failed %d\n", err);
			goto exit;
		}
		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
		bss_enable.enable = cpu_to_le32(1);
		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
					       sizeof(bss_enable));
		if (err < 0) {
			brcmf_err("bss_enable config failed %d\n", err);
			goto exit;
		}

		brcmf_dbg(TRACE, "GO mode configuration complete\n");
	}
3881 3882
	clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
	set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
H
Hante Meuleman 已提交
3883 3884

exit:
3885
	if (err) {
3886
		brcmf_set_mpc(ifp, 1);
3887 3888
		brcmf_configure_arp_offload(ifp, true);
	}
H
Hante Meuleman 已提交
3889 3890 3891 3892 3893
	return err;
}

static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
3894
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3895
	s32 err;
3896
	struct brcmf_fil_bss_enable_le bss_enable;
H
Hante Meuleman 已提交
3897
	struct brcmf_join_params join_params;
H
Hante Meuleman 已提交
3898

3899
	brcmf_dbg(TRACE, "Enter\n");
H
Hante Meuleman 已提交
3900

3901
	if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
H
Hante Meuleman 已提交
3902 3903 3904
		/* Due to most likely deauths outstanding we sleep */
		/* first to make sure they get processed by fw. */
		msleep(400);
H
Hante Meuleman 已提交
3905 3906 3907 3908 3909 3910

		memset(&join_params, 0, sizeof(join_params));
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
					     &join_params, sizeof(join_params));
		if (err < 0)
			brcmf_err("SET SSID error (%d)\n", err);
3911
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
H
Hante Meuleman 已提交
3912
		if (err < 0)
3913
			brcmf_err("BRCMF_C_UP error %d\n", err);
H
Hante Meuleman 已提交
3914 3915 3916 3917 3918 3919
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
		if (err < 0)
			brcmf_err("setting AP mode failed %d\n", err);
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
		if (err < 0)
			brcmf_err("setting INFRA mode failed %d\n", err);
3920 3921 3922 3923 3924 3925 3926
	} else {
		bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
		bss_enable.enable = cpu_to_le32(0);
		err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable,
					       sizeof(bss_enable));
		if (err < 0)
			brcmf_err("bss_enable config failed %d\n", err);
H
Hante Meuleman 已提交
3927
	}
3928
	brcmf_set_mpc(ifp, 1);
3929
	brcmf_configure_arp_offload(ifp, true);
3930 3931 3932
	set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
	clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);

H
Hante Meuleman 已提交
3933 3934 3935
	return err;
}

3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949
static s32
brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
			     struct cfg80211_beacon_data *info)
{
	struct brcmf_if *ifp = netdev_priv(ndev);
	s32 err;

	brcmf_dbg(TRACE, "Enter\n");

	err = brcmf_config_ap_mgmt_ie(ifp->vif, info);

	return err;
}

H
Hante Meuleman 已提交
3950 3951
static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3952
			   const u8 *mac)
H
Hante Meuleman 已提交
3953
{
3954
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
H
Hante Meuleman 已提交
3955
	struct brcmf_scb_val_le scbval;
3956
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3957 3958 3959 3960 3961
	s32 err;

	if (!mac)
		return -EFAULT;

3962
	brcmf_dbg(TRACE, "Enter %pM\n", mac);
H
Hante Meuleman 已提交
3963

3964 3965
	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
3966
	if (!check_vif_up(ifp->vif))
H
Hante Meuleman 已提交
3967 3968 3969 3970
		return -EIO;

	memcpy(&scbval.ea, mac, ETH_ALEN);
	scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
3971
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
3972
				     &scbval, sizeof(scbval));
H
Hante Meuleman 已提交
3973
	if (err)
3974
		brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
3975

3976
	brcmf_dbg(TRACE, "Exit\n");
H
Hante Meuleman 已提交
3977 3978 3979
	return err;
}

3980 3981 3982 3983 3984 3985

static void
brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
				   struct wireless_dev *wdev,
				   u16 frame_type, bool reg)
{
3986
	struct brcmf_cfg80211_vif *vif;
3987 3988 3989 3990 3991
	u16 mgmt_type;

	brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);

	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3992
	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
3993 3994 3995
	if (reg)
		vif->mgmt_rx_reg |= BIT(mgmt_type);
	else
3996
		vif->mgmt_rx_reg &= ~BIT(mgmt_type);
3997 3998 3999 4000 4001
}


static int
brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
4002
		       struct cfg80211_mgmt_tx_params *params, u64 *cookie)
4003 4004
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
4005 4006 4007
	struct ieee80211_channel *chan = params->chan;
	const u8 *buf = params->buf;
	size_t len = params->len;
4008 4009 4010 4011 4012
	const struct ieee80211_mgmt *mgmt;
	struct brcmf_cfg80211_vif *vif;
	s32 err = 0;
	s32 ie_offset;
	s32 ie_len;
H
Hante Meuleman 已提交
4013 4014 4015 4016
	struct brcmf_fil_action_frame_le *action_frame;
	struct brcmf_fil_af_params_le *af_params;
	bool ack;
	s32 chan_nr;
4017
	u32 freq;
4018 4019 4020 4021 4022 4023 4024

	brcmf_dbg(TRACE, "Enter\n");

	*cookie = 0;

	mgmt = (const struct ieee80211_mgmt *)buf;

4025 4026 4027 4028
	if (!ieee80211_is_mgmt(mgmt->frame_control)) {
		brcmf_err("Driver only allows MGMT packet type\n");
		return -EPERM;
	}
4029

4030 4031
	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);

4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047
	if (ieee80211_is_probe_resp(mgmt->frame_control)) {
		/* Right now the only reason to get a probe response */
		/* is for p2p listen response or for p2p GO from     */
		/* wpa_supplicant. Unfortunately the probe is send   */
		/* on primary ndev, while dongle wants it on the p2p */
		/* vif. Since this is only reason for a probe        */
		/* response to be sent, the vif is taken from cfg.   */
		/* If ever desired to send proberesp for non p2p     */
		/* response then data should be checked for          */
		/* "DIRECT-". Note in future supplicant will take    */
		/* dedicated p2p wdev to do this and then this 'hack'*/
		/* is not needed anymore.                            */
		ie_offset =  DOT11_MGMT_HDR_LEN +
			     DOT11_BCN_PRB_FIXED_LEN;
		ie_len = len - ie_offset;
		if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
4048
			vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4049 4050 4051 4052 4053 4054
		err = brcmf_vif_set_mgmt_ie(vif,
					    BRCMF_VNDR_IE_PRBRSP_FLAG,
					    &buf[ie_offset],
					    ie_len);
		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true,
					GFP_KERNEL);
H
Hante Meuleman 已提交
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069
	} else if (ieee80211_is_action(mgmt->frame_control)) {
		af_params = kzalloc(sizeof(*af_params), GFP_KERNEL);
		if (af_params == NULL) {
			brcmf_err("unable to allocate frame\n");
			err = -ENOMEM;
			goto exit;
		}
		action_frame = &af_params->action_frame;
		/* Add the packet Id */
		action_frame->packet_id = cpu_to_le32(*cookie);
		/* Add BSSID */
		memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN);
		memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
		/* Add the length exepted for 802.11 header  */
		action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
4070 4071 4072 4073 4074 4075 4076 4077 4078
		/* Add the channel. Use the one specified as parameter if any or
		 * the current one (got from the firmware) otherwise
		 */
		if (chan)
			freq = chan->center_freq;
		else
			brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
					      &freq);
		chan_nr = ieee80211_frequency_to_channel(freq);
H
Hante Meuleman 已提交
4079 4080 4081 4082 4083 4084
		af_params->channel = cpu_to_le32(chan_nr);

		memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
		       le16_to_cpu(action_frame->len));

		brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n",
4085
			  *cookie, le16_to_cpu(action_frame->len), freq);
H
Hante Meuleman 已提交
4086

4087
		ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
H
Hante Meuleman 已提交
4088 4089 4090 4091 4092
						  af_params);

		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
					GFP_KERNEL);
		kfree(af_params);
4093 4094 4095
	} else {
		brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
		brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4096
	}
4097

H
Hante Meuleman 已提交
4098
exit:
4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124
	return err;
}


static int
brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
					struct wireless_dev *wdev,
					u64 cookie)
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_cfg80211_vif *vif;
	int err = 0;

	brcmf_dbg(TRACE, "Enter p2p listen cancel\n");

	vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
	if (vif == NULL) {
		brcmf_err("No p2p device available for probe response\n");
		err = -ENODEV;
		goto exit;
	}
	brcmf_p2p_cancel_remain_on_channel(vif->ifp);
exit:
	return err;
}

4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157
static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
					   struct wireless_dev *wdev,
					   enum nl80211_crit_proto_id proto,
					   u16 duration)
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_cfg80211_vif *vif;

	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);

	/* only DHCP support for now */
	if (proto != NL80211_CRIT_PROTO_DHCP)
		return -EINVAL;

	/* suppress and abort scanning */
	set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
	brcmf_abort_scanning(cfg);

	return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
}

static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
					   struct wireless_dev *wdev)
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct brcmf_cfg80211_vif *vif;

	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);

	brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
	clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
}

4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178
static s32
brcmf_notify_tdls_peer_event(struct brcmf_if *ifp,
			     const struct brcmf_event_msg *e, void *data)
{
	switch (e->reason) {
	case BRCMF_E_REASON_TDLS_PEER_DISCOVERED:
		brcmf_dbg(TRACE, "TDLS Peer Discovered\n");
		break;
	case BRCMF_E_REASON_TDLS_PEER_CONNECTED:
		brcmf_dbg(TRACE, "TDLS Peer Connected\n");
		brcmf_proto_add_tdls_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
		break;
	case BRCMF_E_REASON_TDLS_PEER_DISCONNECTED:
		brcmf_dbg(TRACE, "TDLS Peer Disconnected\n");
		brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
		break;
	}

	return 0;
}

4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200
static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)
{
	int ret;

	switch (oper) {
	case NL80211_TDLS_DISCOVERY_REQ:
		ret = BRCMF_TDLS_MANUAL_EP_DISCOVERY;
		break;
	case NL80211_TDLS_SETUP:
		ret = BRCMF_TDLS_MANUAL_EP_CREATE;
		break;
	case NL80211_TDLS_TEARDOWN:
		ret = BRCMF_TDLS_MANUAL_EP_DELETE;
		break;
	default:
		brcmf_err("unsupported operation: %d\n", oper);
		ret = -EOPNOTSUPP;
	}
	return ret;
}

static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
4201
				    struct net_device *ndev, const u8 *peer,
4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225
				    enum nl80211_tdls_operation oper)
{
	struct brcmf_if *ifp;
	struct brcmf_tdls_iovar_le info;
	int ret = 0;

	ret = brcmf_convert_nl80211_tdls_oper(oper);
	if (ret < 0)
		return ret;

	ifp = netdev_priv(ndev);
	memset(&info, 0, sizeof(info));
	info.mode = (u8)ret;
	if (peer)
		memcpy(info.ea, peer, ETH_ALEN);

	ret = brcmf_fil_iovar_data_set(ifp, "tdls_endpoint",
				       &info, sizeof(info));
	if (ret < 0)
		brcmf_err("tdls_endpoint iovar failed: ret=%d\n", ret);

	return ret;
}

4226
static struct cfg80211_ops wl_cfg80211_ops = {
4227 4228
	.add_virtual_intf = brcmf_cfg80211_add_iface,
	.del_virtual_intf = brcmf_cfg80211_del_iface,
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248
	.change_virtual_intf = brcmf_cfg80211_change_iface,
	.scan = brcmf_cfg80211_scan,
	.set_wiphy_params = brcmf_cfg80211_set_wiphy_params,
	.join_ibss = brcmf_cfg80211_join_ibss,
	.leave_ibss = brcmf_cfg80211_leave_ibss,
	.get_station = brcmf_cfg80211_get_station,
	.set_tx_power = brcmf_cfg80211_set_tx_power,
	.get_tx_power = brcmf_cfg80211_get_tx_power,
	.add_key = brcmf_cfg80211_add_key,
	.del_key = brcmf_cfg80211_del_key,
	.get_key = brcmf_cfg80211_get_key,
	.set_default_key = brcmf_cfg80211_config_default_key,
	.set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key,
	.set_power_mgmt = brcmf_cfg80211_set_power_mgmt,
	.connect = brcmf_cfg80211_connect,
	.disconnect = brcmf_cfg80211_disconnect,
	.suspend = brcmf_cfg80211_suspend,
	.resume = brcmf_cfg80211_resume,
	.set_pmksa = brcmf_cfg80211_set_pmksa,
	.del_pmksa = brcmf_cfg80211_del_pmksa,
4249
	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
H
Hante Meuleman 已提交
4250 4251
	.start_ap = brcmf_cfg80211_start_ap,
	.stop_ap = brcmf_cfg80211_stop_ap,
4252
	.change_beacon = brcmf_cfg80211_change_beacon,
H
Hante Meuleman 已提交
4253
	.del_station = brcmf_cfg80211_del_station,
4254 4255
	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
4256 4257 4258 4259
	.mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
	.mgmt_tx = brcmf_cfg80211_mgmt_tx,
	.remain_on_channel = brcmf_p2p_remain_on_channel,
	.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
4260 4261
	.start_p2p_device = brcmf_p2p_start_device,
	.stop_p2p_device = brcmf_p2p_stop_device,
4262 4263
	.crit_proto_start = brcmf_cfg80211_crit_proto_start,
	.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
4264
	.tdls_oper = brcmf_cfg80211_tdls_oper,
4265 4266
};

4267
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
4268 4269
					   enum nl80211_iftype type,
					   bool pm_block)
4270 4271
{
	struct brcmf_cfg80211_vif *vif;
4272

4273
	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
4274
		  sizeof(*vif));
4275 4276 4277 4278 4279
	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
	if (!vif)
		return ERR_PTR(-ENOMEM);

	vif->wdev.wiphy = cfg->wiphy;
4280
	vif->wdev.iftype = type;
4281

4282 4283 4284
	vif->pm_block = pm_block;
	vif->roam_off = -1;

4285 4286
	brcmf_init_prof(&vif->profile);

4287 4288
	list_add_tail(&vif->list, &cfg->vif_list);
	return vif;
4289 4290
}

4291
void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
4292
{
4293 4294
	list_del(&vif->list);
	kfree(vif);
4295 4296
}

4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308
void brcmf_cfg80211_free_netdev(struct net_device *ndev)
{
	struct brcmf_cfg80211_vif *vif;
	struct brcmf_if *ifp;

	ifp = netdev_priv(ndev);
	vif = ifp->vif;

	brcmf_free_vif(vif);
	free_netdev(ndev);
}

4309
static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
4310
{
4311 4312
	u32 event = e->event_code;
	u32 status = e->status;
4313 4314

	if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
4315
		brcmf_dbg(CONN, "Processing set ssid\n");
4316 4317 4318 4319 4320 4321
		return true;
	}

	return false;
}

4322
static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
4323
{
4324 4325
	u32 event = e->event_code;
	u16 flags = e->flags;
4326

4327 4328 4329
	if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
	    (event == BRCMF_E_DISASSOC_IND) ||
	    ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
4330
		brcmf_dbg(CONN, "Processing link down\n");
4331 4332 4333 4334 4335
		return true;
	}
	return false;
}

4336
static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
4337 4338
			       const struct brcmf_event_msg *e)
{
4339 4340
	u32 event = e->event_code;
	u32 status = e->status;
4341 4342

	if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
4343 4344
		brcmf_dbg(CONN, "Processing Link %s & no network found\n",
			  e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
4345 4346 4347 4348
		return true;
	}

	if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
4349
		brcmf_dbg(CONN, "Processing connecting & no network found\n");
4350 4351 4352 4353 4354 4355
		return true;
	}

	return false;
}

4356
static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
4357
{
4358
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4359 4360 4361 4362 4363 4364 4365 4366 4367

	kfree(conn_info->req_ie);
	conn_info->req_ie = NULL;
	conn_info->req_ie_len = 0;
	kfree(conn_info->resp_ie);
	conn_info->resp_ie = NULL;
	conn_info->resp_ie_len = 0;
}

4368 4369
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
			       struct brcmf_if *ifp)
4370
{
4371
	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
4372
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4373 4374 4375 4376
	u32 req_len;
	u32 resp_len;
	s32 err = 0;

4377
	brcmf_clear_assoc_ies(cfg);
4378

4379 4380
	err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
				       cfg->extra_buf, WL_ASSOC_INFO_MAX);
4381
	if (err) {
4382
		brcmf_err("could not get assoc info (%d)\n", err);
4383 4384
		return err;
	}
4385
	assoc_info =
4386
		(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
4387 4388
	req_len = le32_to_cpu(assoc_info->req_len);
	resp_len = le32_to_cpu(assoc_info->resp_len);
4389
	if (req_len) {
4390
		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
4391 4392
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
4393
		if (err) {
4394
			brcmf_err("could not get assoc req (%d)\n", err);
4395 4396 4397 4398
			return err;
		}
		conn_info->req_ie_len = req_len;
		conn_info->req_ie =
4399
		    kmemdup(cfg->extra_buf, conn_info->req_ie_len,
4400 4401 4402 4403 4404 4405
			    GFP_KERNEL);
	} else {
		conn_info->req_ie_len = 0;
		conn_info->req_ie = NULL;
	}
	if (resp_len) {
4406
		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
4407 4408
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
4409
		if (err) {
4410
			brcmf_err("could not get assoc resp (%d)\n", err);
4411 4412 4413 4414
			return err;
		}
		conn_info->resp_ie_len = resp_len;
		conn_info->resp_ie =
4415
		    kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
4416 4417 4418 4419 4420
			    GFP_KERNEL);
	} else {
		conn_info->resp_ie_len = 0;
		conn_info->resp_ie = NULL;
	}
4421 4422
	brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
		  conn_info->req_ie_len, conn_info->resp_ie_len);
4423 4424 4425 4426 4427

	return err;
}

static s32
4428
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
4429 4430 4431
		       struct net_device *ndev,
		       const struct brcmf_event_msg *e)
{
4432 4433
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4434 4435
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
4436
	struct ieee80211_channel *notify_channel = NULL;
4437
	struct ieee80211_supported_band *band;
4438
	struct brcmf_bss_info_le *bi;
F
Franky Lin 已提交
4439
	struct brcmu_chan ch;
4440 4441
	u32 freq;
	s32 err = 0;
4442
	u8 *buf;
4443

4444
	brcmf_dbg(TRACE, "Enter\n");
4445

4446
	brcmf_get_assoc_ies(cfg, ifp);
4447
	memcpy(profile->bssid, e->addr, ETH_ALEN);
4448
	brcmf_update_bss_info(cfg, ifp);
4449

4450 4451 4452 4453 4454 4455 4456 4457
	buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
	if (buf == NULL) {
		err = -ENOMEM;
		goto done;
	}

	/* data sent to dongle has to be little endian */
	*(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
4458
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
4459
				     buf, WL_BSS_INFO_MAX);
4460 4461 4462

	if (err)
		goto done;
4463

4464
	bi = (struct brcmf_bss_info_le *)(buf + 4);
F
Franky Lin 已提交
4465 4466
	ch.chspec = le16_to_cpu(bi->chanspec);
	cfg->d11inf.decchspec(&ch);
4467

F
Franky Lin 已提交
4468
	if (ch.band == BRCMU_CHAN_BAND_2G)
4469 4470 4471 4472
		band = wiphy->bands[IEEE80211_BAND_2GHZ];
	else
		band = wiphy->bands[IEEE80211_BAND_5GHZ];

F
Franky Lin 已提交
4473
	freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
4474 4475
	notify_channel = ieee80211_get_channel(wiphy, freq);

4476 4477
done:
	kfree(buf);
4478
	cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
4479 4480
			conn_info->req_ie, conn_info->req_ie_len,
			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4481
	brcmf_dbg(CONN, "Report roaming result\n");
4482

4483
	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
4484
	brcmf_dbg(TRACE, "Exit\n");
4485 4486 4487 4488
	return err;
}

static s32
4489
brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
4490 4491 4492
		       struct net_device *ndev, const struct brcmf_event_msg *e,
		       bool completed)
{
4493 4494
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4495
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4496

4497
	brcmf_dbg(TRACE, "Enter\n");
4498

4499 4500
	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
			       &ifp->vif->sme_state)) {
4501
		if (completed) {
4502
			brcmf_get_assoc_ies(cfg, ifp);
4503
			memcpy(profile->bssid, e->addr, ETH_ALEN);
4504 4505 4506
			brcmf_update_bss_info(cfg, ifp);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
4507 4508
		}
		cfg80211_connect_result(ndev,
4509
					(u8 *)profile->bssid,
4510 4511 4512 4513 4514 4515 4516
					conn_info->req_ie,
					conn_info->req_ie_len,
					conn_info->resp_ie,
					conn_info->resp_ie_len,
					completed ? WLAN_STATUS_SUCCESS :
						    WLAN_STATUS_AUTH_TIMEOUT,
					GFP_KERNEL);
4517 4518
		brcmf_dbg(CONN, "Report connect result - connection %s\n",
			  completed ? "succeeded" : "failed");
4519
	}
4520
	brcmf_dbg(TRACE, "Exit\n");
4521
	return 0;
4522 4523 4524
}

static s32
4525
brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
H
Hante Meuleman 已提交
4526 4527 4528
			       struct net_device *ndev,
			       const struct brcmf_event_msg *e, void *data)
{
4529
	static int generation;
4530 4531
	u32 event = e->event_code;
	u32 reason = e->reason;
H
Hante Meuleman 已提交
4532 4533
	struct station_info sinfo;

4534
	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
4535 4536 4537 4538 4539 4540
	if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
	    ndev != cfg_to_ndev(cfg)) {
		brcmf_dbg(CONN, "AP mode link down\n");
		complete(&cfg->vif_disabled);
		return 0;
	}
H
Hante Meuleman 已提交
4541 4542

	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4543 4544
	    (reason == BRCMF_E_STATUS_SUCCESS)) {
		memset(&sinfo, 0, sizeof(sinfo));
H
Hante Meuleman 已提交
4545 4546
		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
		if (!data) {
4547
			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
H
Hante Meuleman 已提交
4548 4549 4550
			return -EINVAL;
		}
		sinfo.assoc_req_ies = data;
4551
		sinfo.assoc_req_ies_len = e->datalen;
H
Hante Meuleman 已提交
4552 4553
		generation++;
		sinfo.generation = generation;
4554
		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
H
Hante Meuleman 已提交
4555 4556 4557
	} else if ((event == BRCMF_E_DISASSOC_IND) ||
		   (event == BRCMF_E_DEAUTH_IND) ||
		   (event == BRCMF_E_DEAUTH)) {
4558
		cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
H
Hante Meuleman 已提交
4559
	}
4560
	return 0;
H
Hante Meuleman 已提交
4561 4562
}

4563
static s32
4564
brcmf_notify_connect_status(struct brcmf_if *ifp,
4565 4566
			    const struct brcmf_event_msg *e, void *data)
{
4567 4568
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct net_device *ndev = ifp->ndev;
4569
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4570
	struct ieee80211_channel *chan;
4571 4572
	s32 err = 0;

4573 4574 4575 4576 4577 4578 4579
	if ((e->event_code == BRCMF_E_DEAUTH) ||
	    (e->event_code == BRCMF_E_DEAUTH_IND) ||
	    (e->event_code == BRCMF_E_DISASSOC_IND) ||
	    ((e->event_code == BRCMF_E_LINK) && (!e->flags))) {
		brcmf_proto_delete_peer(ifp->drvr, ifp->ifidx, (u8 *)e->addr);
	}

4580
	if (brcmf_is_apmode(ifp->vif)) {
4581
		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4582
	} else if (brcmf_is_linkup(e)) {
4583
		brcmf_dbg(CONN, "Linkup\n");
4584
		if (brcmf_is_ibssmode(ifp->vif)) {
4585
			chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
4586
			memcpy(profile->bssid, e->addr, ETH_ALEN);
4587
			wl_inform_ibss(cfg, ndev, e->addr);
4588
			cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
4589 4590 4591 4592
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
4593
		} else
4594
			brcmf_bss_connect_done(cfg, ndev, e, true);
4595
	} else if (brcmf_is_linkdown(e)) {
4596
		brcmf_dbg(CONN, "Linkdown\n");
4597
		if (!brcmf_is_ibssmode(ifp->vif)) {
4598
			brcmf_bss_connect_done(cfg, ndev, e, false);
4599
		}
4600
		brcmf_link_down(ifp->vif);
4601
		brcmf_init_prof(ndev_to_prof(ndev));
4602 4603
		if (ndev != cfg_to_ndev(cfg))
			complete(&cfg->vif_disabled);
4604
	} else if (brcmf_is_nonetwork(cfg, e)) {
4605
		if (brcmf_is_ibssmode(ifp->vif))
4606 4607
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
4608
		else
4609
			brcmf_bss_connect_done(cfg, ndev, e, false);
4610 4611 4612 4613 4614 4615
	}

	return err;
}

static s32
4616
brcmf_notify_roaming_status(struct brcmf_if *ifp,
4617 4618
			    const struct brcmf_event_msg *e, void *data)
{
4619
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4620 4621
	u32 event = e->event_code;
	u32 status = e->status;
4622 4623

	if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
4624
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
4625
			brcmf_bss_roaming_done(cfg, ifp->ndev, e);
4626
		else
4627
			brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
4628 4629
	}

4630
	return 0;
4631 4632 4633
}

static s32
4634
brcmf_notify_mic_status(struct brcmf_if *ifp,
4635 4636
			const struct brcmf_event_msg *e, void *data)
{
4637
	u16 flags = e->flags;
4638 4639 4640 4641 4642 4643 4644
	enum nl80211_key_type key_type;

	if (flags & BRCMF_EVENT_MSG_GROUP)
		key_type = NL80211_KEYTYPE_GROUP;
	else
		key_type = NL80211_KEYTYPE_PAIRWISE;

4645
	cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
4646 4647 4648 4649 4650
				     NULL, GFP_KERNEL);

	return 0;
}

4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669
static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
				  const struct brcmf_event_msg *e, void *data)
{
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data;
	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
	struct brcmf_cfg80211_vif *vif;

	brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n",
		  ifevent->action, ifevent->flags, ifevent->ifidx,
		  ifevent->bssidx);

	mutex_lock(&event->vif_event_lock);
	event->action = ifevent->action;
	vif = event->vif;

	switch (ifevent->action) {
	case BRCMF_E_IF_ADD:
		/* waiting process may have timed out */
4670 4671
		if (!cfg->vif_event.vif) {
			mutex_unlock(&event->vif_event_lock);
4672
			return -EBADF;
4673
		}
4674 4675 4676

		ifp->vif = vif;
		vif->ifp = ifp;
4677 4678 4679 4680 4681
		if (ifp->ndev) {
			vif->wdev.netdev = ifp->ndev;
			ifp->ndev->ieee80211_ptr = &vif->wdev;
			SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
		}
4682 4683
		mutex_unlock(&event->vif_event_lock);
		wake_up(&event->vif_wq);
4684
		return 0;
4685 4686 4687 4688 4689 4690 4691 4692

	case BRCMF_E_IF_DEL:
		mutex_unlock(&event->vif_event_lock);
		/* event may not be upon user request */
		if (brcmf_cfg80211_vif_event_armed(cfg))
			wake_up(&event->vif_wq);
		return 0;

4693 4694 4695 4696 4697
	case BRCMF_E_IF_CHANGE:
		mutex_unlock(&event->vif_event_lock);
		wake_up(&event->vif_wq);
		return 0;

4698 4699 4700 4701 4702 4703 4704
	default:
		mutex_unlock(&event->vif_event_lock);
		break;
	}
	return -EINVAL;
}

4705 4706 4707 4708 4709 4710 4711 4712 4713
static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
{
	conf->frag_threshold = (u32)-1;
	conf->rts_threshold = (u32)-1;
	conf->retry_short = (u32)-1;
	conf->retry_long = (u32)-1;
	conf->tx_power = -1;
}

4714
static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
4715
{
4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735
	brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
			    brcmf_notify_roaming_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
			    brcmf_notify_mic_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
			    brcmf_notify_connect_status);
	brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
			    brcmf_notify_sched_scan_results);
4736 4737
	brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
			    brcmf_notify_vif_event);
4738
	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
4739
			    brcmf_p2p_notify_rx_mgmt_p2p_probereq);
4740 4741
	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
			    brcmf_p2p_notify_listen_complete);
4742 4743
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
			    brcmf_p2p_notify_action_frame_rx);
H
Hante Meuleman 已提交
4744 4745
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
			    brcmf_p2p_notify_action_tx_complete);
4746 4747
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
			    brcmf_p2p_notify_action_tx_complete);
4748 4749
}

4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
{
	kfree(cfg->conf);
	cfg->conf = NULL;
	kfree(cfg->escan_ioctl_buf);
	cfg->escan_ioctl_buf = NULL;
	kfree(cfg->extra_buf);
	cfg->extra_buf = NULL;
	kfree(cfg->pmk_list);
	cfg->pmk_list = NULL;
}

static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
{
	cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
	if (!cfg->conf)
4766
		goto init_priv_mem_out;
4767 4768
	cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
	if (!cfg->escan_ioctl_buf)
H
Hante Meuleman 已提交
4769
		goto init_priv_mem_out;
4770 4771
	cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!cfg->extra_buf)
4772
		goto init_priv_mem_out;
4773 4774
	cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
	if (!cfg->pmk_list)
4775 4776 4777 4778 4779
		goto init_priv_mem_out;

	return 0;

init_priv_mem_out:
4780
	brcmf_deinit_priv_mem(cfg);
4781 4782 4783 4784

	return -ENOMEM;
}

4785
static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4786 4787 4788
{
	s32 err = 0;

4789 4790
	cfg->scan_request = NULL;
	cfg->pwr_save = true;
4791 4792
	cfg->active_scan = true;	/* we do active scan per default */
	cfg->dongle_up = false;		/* dongle is not up yet */
4793
	err = brcmf_init_priv_mem(cfg);
4794 4795
	if (err)
		return err;
4796
	brcmf_register_event_handlers(cfg);
4797 4798 4799
	mutex_init(&cfg->usr_sync);
	brcmf_init_escan(cfg);
	brcmf_init_conf(cfg->conf);
4800
	init_completion(&cfg->vif_disabled);
4801 4802 4803
	return err;
}

4804
static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
4805
{
4806 4807 4808
	cfg->dongle_up = false;	/* dongle down */
	brcmf_abort_scanning(cfg);
	brcmf_deinit_priv_mem(cfg);
4809 4810
}

4811 4812 4813 4814 4815 4816
static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
{
	init_waitqueue_head(&event->vif_wq);
	mutex_init(&event->vif_event_lock);
}

4817
static s32
4818
brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
4819 4820
{
	s32 err = 0;
4821 4822
	__le32 roamtrigger[2];
	__le32 roam_delta[2];
4823 4824 4825 4826 4827

	/*
	 * Setup timeout if Beacons are lost and roam is
	 * off to report link down
	 */
4828
	if (brcmf_roamoff) {
4829
		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
4830
		if (err) {
4831
			brcmf_err("bcn_timeout error (%d)\n", err);
4832 4833 4834 4835 4836 4837 4838 4839
			goto dongle_rom_out;
		}
	}

	/*
	 * Enable/Disable built-in roaming to allow supplicant
	 * to take care of roaming
	 */
4840 4841 4842
	brcmf_dbg(INFO, "Internal Roaming = %s\n",
		  brcmf_roamoff ? "Off" : "On");
	err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
4843
	if (err) {
4844
		brcmf_err("roam_off error (%d)\n", err);
4845 4846 4847
		goto dongle_rom_out;
	}

4848 4849
	roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
	roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
4850
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
4851
				     (void *)roamtrigger, sizeof(roamtrigger));
4852
	if (err) {
4853
		brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
4854 4855 4856
		goto dongle_rom_out;
	}

4857 4858
	roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
	roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
4859
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
4860
				     (void *)roam_delta, sizeof(roam_delta));
4861
	if (err) {
4862
		brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
4863 4864 4865 4866 4867 4868 4869 4870
		goto dongle_rom_out;
	}

dongle_rom_out:
	return err;
}

static s32
4871
brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
4872
		      s32 scan_unassoc_time, s32 scan_passive_time)
4873 4874 4875
{
	s32 err = 0;

4876
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
4877
				    scan_assoc_time);
4878 4879
	if (err) {
		if (err == -EOPNOTSUPP)
4880
			brcmf_dbg(INFO, "Scan assoc time is not supported\n");
4881
		else
4882
			brcmf_err("Scan assoc time error (%d)\n", err);
4883 4884
		goto dongle_scantime_out;
	}
4885
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
4886
				    scan_unassoc_time);
4887 4888
	if (err) {
		if (err == -EOPNOTSUPP)
4889
			brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
4890
		else
4891
			brcmf_err("Scan unassoc time error (%d)\n", err);
4892 4893 4894
		goto dongle_scantime_out;
	}

4895
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
4896
				    scan_passive_time);
4897 4898
	if (err) {
		if (err == -EOPNOTSUPP)
4899
			brcmf_dbg(INFO, "Scan passive time is not supported\n");
4900
		else
4901
			brcmf_err("Scan passive time error (%d)\n", err);
4902 4903 4904 4905 4906 4907 4908
		goto dongle_scantime_out;
	}

dongle_scantime_out:
	return err;
}

4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946
/* Filter the list of channels received from firmware counting only
 * the 20MHz channels. The wiphy band data only needs those which get
 * flagged to indicate if they can take part in higher bandwidth.
 */
static void brcmf_count_20mhz_channels(struct brcmf_cfg80211_info *cfg,
				       struct brcmf_chanspec_list *chlist,
				       u32 chcnt[])
{
	u32 total = le32_to_cpu(chlist->count);
	struct brcmu_chan ch;
	int i;

	for (i = 0; i <= total; i++) {
		ch.chspec = (u16)le32_to_cpu(chlist->element[i]);
		cfg->d11inf.decchspec(&ch);

		/* Firmware gives a ordered list. We skip non-20MHz
		 * channels is 2G. For 5G we can abort upon reaching
		 * a non-20MHz channel in the list.
		 */
		if (ch.bw != BRCMU_CHAN_BW_20) {
			if (ch.band == BRCMU_CHAN_BAND_5G)
				break;
			else
				continue;
		}

		if (ch.band == BRCMU_CHAN_BAND_2G)
			chcnt[0] += 1;
		else if (ch.band == BRCMU_CHAN_BAND_5G)
			chcnt[1] += 1;
	}
}

static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel,
					   struct brcmu_chan *ch)
{
	u32 ht40_flag;
4947

4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965
	ht40_flag = channel->flags & IEEE80211_CHAN_NO_HT40;
	if (ch->sb == BRCMU_CHAN_SB_U) {
		if (ht40_flag == IEEE80211_CHAN_NO_HT40)
			channel->flags &= ~IEEE80211_CHAN_NO_HT40;
		channel->flags |= IEEE80211_CHAN_NO_HT40PLUS;
	} else {
		/* It should be one of
		 * IEEE80211_CHAN_NO_HT40 or
		 * IEEE80211_CHAN_NO_HT40PLUS
		 */
		channel->flags &= ~IEEE80211_CHAN_NO_HT40;
		if (ht40_flag == IEEE80211_CHAN_NO_HT40)
			channel->flags |= IEEE80211_CHAN_NO_HT40MINUS;
	}
}

static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
				    u32 bw_cap[])
4966 4967
{
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
4968 4969 4970
	struct ieee80211_supported_band *band;
	struct ieee80211_channel *channel;
	struct wiphy *wiphy;
4971
	struct brcmf_chanspec_list *list;
F
Franky Lin 已提交
4972
	struct brcmu_chan ch;
4973
	int err;
4974 4975 4976
	u8 *pbuf;
	u32 i, j;
	u32 total;
4977 4978
	u32 chaninfo;
	u32 chcnt[2] = { 0, 0 };
4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991
	u32 index;

	pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);

	if (pbuf == NULL)
		return -ENOMEM;

	list = (struct brcmf_chanspec_list *)pbuf;

	err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
				       BRCMF_DCMD_MEDLEN);
	if (err) {
		brcmf_err("get chanspecs error (%d)\n", err);
4992
		goto fail_pbuf;
4993 4994
	}

4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030
	brcmf_count_20mhz_channels(cfg, list, chcnt);
	wiphy = cfg_to_wiphy(cfg);
	if (chcnt[0]) {
		band = kmemdup(&__wl_band_2ghz, sizeof(__wl_band_2ghz),
			       GFP_KERNEL);
		if (band == NULL) {
			err = -ENOMEM;
			goto fail_pbuf;
		}
		band->channels = kcalloc(chcnt[0], sizeof(*channel),
					 GFP_KERNEL);
		if (band->channels == NULL) {
			kfree(band);
			err = -ENOMEM;
			goto fail_pbuf;
		}
		band->n_channels = 0;
		wiphy->bands[IEEE80211_BAND_2GHZ] = band;
	}
	if (chcnt[1]) {
		band = kmemdup(&__wl_band_5ghz_a, sizeof(__wl_band_5ghz_a),
			       GFP_KERNEL);
		if (band == NULL) {
			err = -ENOMEM;
			goto fail_band2g;
		}
		band->channels = kcalloc(chcnt[1], sizeof(*channel),
					 GFP_KERNEL);
		if (band->channels == NULL) {
			kfree(band);
			err = -ENOMEM;
			goto fail_band2g;
		}
		band->n_channels = 0;
		wiphy->bands[IEEE80211_BAND_5GHZ] = band;
	}
5031 5032 5033

	total = le32_to_cpu(list->count);
	for (i = 0; i < total; i++) {
F
Franky Lin 已提交
5034 5035
		ch.chspec = (u16)le32_to_cpu(list->element[i]);
		cfg->d11inf.decchspec(&ch);
5036

F
Franky Lin 已提交
5037
		if (ch.band == BRCMU_CHAN_BAND_2G) {
5038
			band = wiphy->bands[IEEE80211_BAND_2GHZ];
F
Franky Lin 已提交
5039
		} else if (ch.band == BRCMU_CHAN_BAND_5G) {
5040
			band = wiphy->bands[IEEE80211_BAND_5GHZ];
5041
		} else {
5042
			brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
5043 5044
			continue;
		}
5045
		if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
5046
		    ch.bw == BRCMU_CHAN_BW_40)
5047
			continue;
5048
		if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
5049 5050
		    ch.bw == BRCMU_CHAN_BW_80)
			continue;
5051 5052 5053 5054 5055 5056

		channel = band->channels;
		index = band->n_channels;
		for (j = 0; j < band->n_channels; j++) {
			if (channel[j].hw_value == ch.chnum) {
				index = j;
5057 5058 5059
				break;
			}
		}
5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074
		channel[index].center_freq =
			ieee80211_channel_to_frequency(ch.chnum, band->band);
		channel[index].hw_value = ch.chnum;

		/* assuming the chanspecs order is HT20,
		 * HT40 upper, HT40 lower, and VHT80.
		 */
		if (ch.bw == BRCMU_CHAN_BW_80) {
			channel[index].flags &= ~IEEE80211_CHAN_NO_80MHZ;
		} else if (ch.bw == BRCMU_CHAN_BW_40) {
			brcmf_update_bw40_channel_flag(&channel[index], &ch);
		} else {
			/* disable other bandwidths for now as mentioned
			 * order assure they are enabled for subsequent
			 * chanspecs.
5075
			 */
5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090
			channel[index].flags = IEEE80211_CHAN_NO_HT40 |
					       IEEE80211_CHAN_NO_80MHZ;
			ch.bw = BRCMU_CHAN_BW_20;
			cfg->d11inf.encchspec(&ch);
			chaninfo = ch.chspec;
			err = brcmf_fil_bsscfg_int_get(ifp, "per_chan_info",
						       &chaninfo);
			if (!err) {
				if (chaninfo & WL_CHAN_RADAR)
					channel[index].flags |=
						(IEEE80211_CHAN_RADAR |
						 IEEE80211_CHAN_NO_IR);
				if (chaninfo & WL_CHAN_PASSIVE)
					channel[index].flags |=
						IEEE80211_CHAN_NO_IR;
5091 5092
			}
		}
5093 5094
		if (index == band->n_channels)
			band->n_channels++;
5095
	}
5096 5097 5098 5099 5100 5101 5102 5103
	kfree(pbuf);
	return 0;

fail_band2g:
	kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
	kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
	wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
fail_pbuf:
5104 5105 5106 5107
	kfree(pbuf);
	return err;
}

5108
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
5109
{
5110 5111
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
	struct ieee80211_supported_band *band;
5112
	struct brcmf_fil_bwcap_le band_bwcap;
5113 5114
	struct brcmf_chanspec_list *list;
	u8 *pbuf;
5115 5116
	u32 val;
	int err;
5117 5118 5119
	struct brcmu_chan ch;
	u32 num_chan;
	int i, j;
5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135

	/* verify support for bw_cap command */
	val = WLC_BAND_5G;
	err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val);

	if (!err) {
		/* only set 2G bandwidth using bw_cap command */
		band_bwcap.band = cpu_to_le32(WLC_BAND_2G);
		band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ);
		err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap,
					       sizeof(band_bwcap));
	} else {
		brcmf_dbg(INFO, "fallback to mimo_bw_cap\n");
		val = WLC_N_BW_40ALL;
		err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val);
	}
5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179

	if (!err) {
		/* update channel info in 2G band */
		pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);

		if (pbuf == NULL)
			return -ENOMEM;

		ch.band = BRCMU_CHAN_BAND_2G;
		ch.bw = BRCMU_CHAN_BW_40;
		ch.chnum = 0;
		cfg->d11inf.encchspec(&ch);

		/* pass encoded chanspec in query */
		*(__le16 *)pbuf = cpu_to_le16(ch.chspec);

		err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
					       BRCMF_DCMD_MEDLEN);
		if (err) {
			brcmf_err("get chanspecs error (%d)\n", err);
			kfree(pbuf);
			return err;
		}

		band = cfg_to_wiphy(cfg)->bands[IEEE80211_BAND_2GHZ];
		list = (struct brcmf_chanspec_list *)pbuf;
		num_chan = le32_to_cpu(list->count);
		for (i = 0; i < num_chan; i++) {
			ch.chspec = (u16)le32_to_cpu(list->element[i]);
			cfg->d11inf.decchspec(&ch);
			if (WARN_ON(ch.band != BRCMU_CHAN_BAND_2G))
				continue;
			if (WARN_ON(ch.bw != BRCMU_CHAN_BW_40))
				continue;
			for (j = 0; j < band->n_channels; j++) {
				if (band->channels[j].hw_value == ch.chnum)
					break;
			}
			if (WARN_ON(j == band->n_channels))
				continue;

			brcmf_update_bw40_channel_flag(&band->channels[j], &ch);
		}
	}
5180 5181 5182
	return err;
}

5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222
static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
{
	u32 band, mimo_bwcap;
	int err;

	band = WLC_BAND_2G;
	err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
	if (!err) {
		bw_cap[IEEE80211_BAND_2GHZ] = band;
		band = WLC_BAND_5G;
		err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
		if (!err) {
			bw_cap[IEEE80211_BAND_5GHZ] = band;
			return;
		}
		WARN_ON(1);
		return;
	}
	brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
	mimo_bwcap = 0;
	err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
	if (err)
		/* assume 20MHz if firmware does not give a clue */
		mimo_bwcap = WLC_N_BW_20ALL;

	switch (mimo_bwcap) {
	case WLC_N_BW_40ALL:
		bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
		/* fall-thru */
	case WLC_N_BW_20IN2G_40IN5G:
		bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
		/* fall-thru */
	case WLC_N_BW_20ALL:
		bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
		bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
		break;
	default:
		brcmf_err("invalid mimo_bw_cap value\n");
	}
}
5223

5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272
static void brcmf_update_ht_cap(struct ieee80211_supported_band *band,
				u32 bw_cap[2], u32 nchain)
{
	band->ht_cap.ht_supported = true;
	if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
		band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
		band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
	}
	band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
	band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
	band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
	band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
	memset(band->ht_cap.mcs.rx_mask, 0xff, nchain);
	band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}

static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp)
{
	u16 mcs_map;
	int i;

	for (i = 0, mcs_map = 0xFFFF; i < nchain; i++)
		mcs_map = (mcs_map << 2) | supp;

	return cpu_to_le16(mcs_map);
}

static void brcmf_update_vht_cap(struct ieee80211_supported_band *band,
				 u32 bw_cap[2], u32 nchain)
{
	__le16 mcs_map;

	/* not allowed in 2.4G band */
	if (band->band == IEEE80211_BAND_2GHZ)
		return;

	band->vht_cap.vht_supported = true;
	/* 80MHz is mandatory */
	band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
	if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) {
		band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
		band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
	}
	/* all support 256-QAM */
	mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9);
	band->vht_cap.vht_mcs.rx_mcs_map = mcs_map;
	band->vht_cap.vht_mcs.tx_mcs_map = mcs_map;
}

5273
static int brcmf_setup_wiphybands(struct wiphy *wiphy)
5274
{
5275
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
5276
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5277 5278
	u32 nmode = 0;
	u32 vhtmode = 0;
5279
	u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
D
Daniel Kim 已提交
5280 5281
	u32 rxchain;
	u32 nchain;
5282
	int err;
5283
	s32 i;
5284
	struct ieee80211_supported_band *band;
5285

5286
	(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
5287 5288 5289 5290
	err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
	if (err) {
		brcmf_err("nmode error (%d)\n", err);
	} else {
5291
		brcmf_get_bwcap(ifp, bw_cap);
5292
	}
5293 5294 5295
	brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
		  nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
		  bw_cap[IEEE80211_BAND_5GHZ]);
5296

D
Daniel Kim 已提交
5297 5298 5299 5300 5301 5302 5303 5304 5305 5306
	err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain);
	if (err) {
		brcmf_err("rxchain error (%d)\n", err);
		nchain = 1;
	} else {
		for (nchain = 0; rxchain; nchain++)
			rxchain = rxchain & (rxchain - 1);
	}
	brcmf_dbg(INFO, "nchain=%d\n", nchain);

5307
	err = brcmf_construct_chaninfo(cfg, bw_cap);
5308
	if (err) {
5309
		brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
5310 5311 5312
		return err;
	}

5313 5314 5315 5316
	wiphy = cfg_to_wiphy(cfg);
	for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
		band = wiphy->bands[i];
		if (band == NULL)
5317
			continue;
5318

5319 5320 5321 5322
		if (nmode)
			brcmf_update_ht_cap(band, bw_cap, nchain);
		if (vhtmode)
			brcmf_update_vht_cap(band, bw_cap, nchain);
5323 5324
	}

5325
	return 0;
5326 5327
}

5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391
static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
	{
		.max = 2,
		.types = BIT(NL80211_IFTYPE_STATION) |
			 BIT(NL80211_IFTYPE_ADHOC) |
			 BIT(NL80211_IFTYPE_AP)
	},
	{
		.max = 1,
		.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
			 BIT(NL80211_IFTYPE_P2P_GO)
	},
	{
		.max = 1,
		.types = BIT(NL80211_IFTYPE_P2P_DEVICE)
	}
};
static struct ieee80211_iface_combination brcmf_iface_combos[] = {
	{
		 .max_interfaces = BRCMF_IFACE_MAX_CNT,
		 .num_different_channels = 1,
		 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
		 .limits = brcmf_iface_limits
	}
};

static const struct ieee80211_txrx_stypes
brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
	[NL80211_IFTYPE_STATION] = {
		.tx = 0xffff,
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
	},
	[NL80211_IFTYPE_P2P_CLIENT] = {
		.tx = 0xffff,
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
	},
	[NL80211_IFTYPE_P2P_GO] = {
		.tx = 0xffff,
		.rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
		      BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
		      BIT(IEEE80211_STYPE_DISASSOC >> 4) |
		      BIT(IEEE80211_STYPE_AUTH >> 4) |
		      BIT(IEEE80211_STYPE_DEAUTH >> 4) |
		      BIT(IEEE80211_STYPE_ACTION >> 4)
	},
	[NL80211_IFTYPE_P2P_DEVICE] = {
		.tx = 0xffff,
		.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
		      BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
	}
};

static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
	/* scheduled scan settings */
	wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
	wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
	wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
}

5392
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
5393
{
5394
	struct ieee80211_iface_combination ifc_combo;
5395 5396 5397 5398 5399 5400 5401 5402 5403 5404
	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
	wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
				 BIT(NL80211_IFTYPE_ADHOC) |
				 BIT(NL80211_IFTYPE_AP) |
				 BIT(NL80211_IFTYPE_P2P_CLIENT) |
				 BIT(NL80211_IFTYPE_P2P_GO) |
				 BIT(NL80211_IFTYPE_P2P_DEVICE);
	/* need VSDB firmware feature for concurrent channels */
5405
	ifc_combo = brcmf_iface_combos[0];
5406
	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
5407 5408 5409 5410
		ifc_combo.num_different_channels = 2;
	wiphy->iface_combinations = kmemdup(&ifc_combo,
					    sizeof(ifc_combo),
					    GFP_KERNEL);
5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428
	wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
	wiphy->cipher_suites = __wl_cipher_suites;
	wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
			WIPHY_FLAG_OFFCHAN_TX |
			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
			WIPHY_FLAG_SUPPORTS_TDLS;
	if (!brcmf_roamoff)
		wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
	wiphy->mgmt_stypes = brcmf_txrx_stypes;
	wiphy->max_remain_on_channel_duration = 5000;
	brcmf_wiphy_pno_params(wiphy);

	/* vendor commands/events support */
	wiphy->vendor_commands = brcmf_vendor_cmds;
	wiphy->n_vendor_commands = BRCMF_VNDR_CMDS_LAST - 1;

5429
	return brcmf_setup_wiphybands(wiphy);
5430 5431
}

5432
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5433 5434 5435
{
	struct net_device *ndev;
	struct wireless_dev *wdev;
5436
	struct brcmf_if *ifp;
5437 5438 5439
	s32 power_mode;
	s32 err = 0;

5440
	if (cfg->dongle_up)
5441 5442
		return err;

5443
	ndev = cfg_to_ndev(cfg);
5444
	wdev = ndev->ieee80211_ptr;
5445 5446 5447 5448
	ifp = netdev_priv(ndev);

	/* make sure RF is ready for work */
	brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
5449

5450 5451
	brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
			      WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5452

5453
	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
5454
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5455 5456
	if (err)
		goto default_conf_out;
5457 5458
	brcmf_dbg(INFO, "power save set to %s\n",
		  (power_mode ? "enabled" : "disabled"));
5459

5460
	err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
5461 5462
	if (err)
		goto default_conf_out;
5463 5464
	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
					  NULL, NULL);
5465
	if (err)
5466 5467
		goto default_conf_out;

5468 5469
	brcmf_configure_arp_offload(ifp, true);

5470
	cfg->dongle_up = true;
5471
default_conf_out:
5472 5473 5474 5475 5476

	return err;

}

5477
static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5478
{
5479
	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5480

5481
	return brcmf_config_dongle(ifp->drvr->config);
5482 5483
}

5484
static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5485
{
5486
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5487

5488 5489 5490 5491
	/*
	 * While going down, if associated with AP disassociate
	 * from AP to save power
	 */
5492 5493
	if (check_vif_up(ifp->vif)) {
		brcmf_link_down(ifp->vif);
5494 5495 5496 5497 5498 5499 5500 5501

		/* Make sure WPA_Supplicant receives all the event
		   generated due to DISASSOC call to the fw to keep
		   the state fw and WPA_Supplicant state consistent
		 */
		brcmf_delay(500);
	}

5502
	brcmf_abort_scanning(cfg);
5503
	clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5504 5505 5506 5507

	return 0;
}

5508
s32 brcmf_cfg80211_up(struct net_device *ndev)
5509
{
5510 5511
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5512 5513
	s32 err = 0;

5514
	mutex_lock(&cfg->usr_sync);
5515
	err = __brcmf_cfg80211_up(ifp);
5516
	mutex_unlock(&cfg->usr_sync);
5517 5518 5519 5520

	return err;
}

5521
s32 brcmf_cfg80211_down(struct net_device *ndev)
5522
{
5523 5524
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5525 5526
	s32 err = 0;

5527
	mutex_lock(&cfg->usr_sync);
5528
	err = __brcmf_cfg80211_down(ifp);
5529
	mutex_unlock(&cfg->usr_sync);
5530 5531 5532 5533

	return err;
}

5534 5535 5536 5537 5538 5539 5540
enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
{
	struct wireless_dev *wdev = &ifp->vif->wdev;

	return wdev->iftype;
}

5541
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
5542 5543 5544 5545 5546
{
	struct brcmf_cfg80211_vif *vif;

	list_for_each_entry(vif, &cfg->vif_list, list) {
		if (test_bit(state, &vif->sme_state))
5547
			return true;
5548
	}
5549
	return false;
5550
}
5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593

static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event,
				    u8 action)
{
	u8 evt_action;

	mutex_lock(&event->vif_event_lock);
	evt_action = event->action;
	mutex_unlock(&event->vif_event_lock);
	return evt_action == action;
}

void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
				  struct brcmf_cfg80211_vif *vif)
{
	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;

	mutex_lock(&event->vif_event_lock);
	event->vif = vif;
	event->action = 0;
	mutex_unlock(&event->vif_event_lock);
}

bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
{
	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
	bool armed;

	mutex_lock(&event->vif_event_lock);
	armed = event->vif != NULL;
	mutex_unlock(&event->vif_event_lock);

	return armed;
}
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
					  u8 action, ulong timeout)
{
	struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;

	return wait_event_timeout(event->vif_wq,
				  vif_event_equals(event, action), timeout);
}

5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607
static void brcmf_free_wiphy(struct wiphy *wiphy)
{
	kfree(wiphy->iface_combinations);
	if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
		kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels);
		kfree(wiphy->bands[IEEE80211_BAND_2GHZ]);
	}
	if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
		kfree(wiphy->bands[IEEE80211_BAND_5GHZ]->channels);
		kfree(wiphy->bands[IEEE80211_BAND_5GHZ]);
	}
	wiphy_free(wiphy);
}

5608 5609 5610 5611 5612 5613 5614 5615 5616 5617
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
						  struct device *busdev)
{
	struct net_device *ndev = drvr->iflist[0]->ndev;
	struct brcmf_cfg80211_info *cfg;
	struct wiphy *wiphy;
	struct brcmf_cfg80211_vif *vif;
	struct brcmf_if *ifp;
	s32 err = 0;
	s32 io_type;
5618
	u16 *cap = NULL;
5619 5620 5621 5622 5623 5624 5625

	if (!ndev) {
		brcmf_err("ndev is invalid\n");
		return NULL;
	}

	ifp = netdev_priv(ndev);
5626 5627 5628
	wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
	if (!wiphy) {
		brcmf_err("Could not allocate wiphy device\n");
5629
		return NULL;
5630 5631
	}
	set_wiphy_dev(wiphy, busdev);
5632 5633 5634 5635 5636 5637 5638 5639

	cfg = wiphy_priv(wiphy);
	cfg->wiphy = wiphy;
	cfg->pub = drvr;
	init_vif_event(&cfg->vif_event);
	INIT_LIST_HEAD(&cfg->vif_list);

	vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false);
5640 5641
	if (IS_ERR(vif))
		goto wiphy_out;
5642 5643 5644 5645 5646 5647 5648 5649 5650

	vif->ifp = ifp;
	vif->wdev.netdev = ndev;
	ndev->ieee80211_ptr = &vif->wdev;
	SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));

	err = wl_init_priv(cfg);
	if (err) {
		brcmf_err("Failed to init iwm_priv (%d)\n", err);
5651 5652
		brcmf_free_vif(vif);
		goto wiphy_out;
5653 5654 5655
	}
	ifp->vif = vif;

5656 5657
	/* determine d11 io type before wiphy setup */
	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
5658
	if (err) {
5659 5660
		brcmf_err("Failed to get D11 version (%d)\n", err);
		goto priv_out;
5661
	}
5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684
	cfg->d11inf.io_type = (u8)io_type;
	brcmu_d11_attach(&cfg->d11inf);

	err = brcmf_setup_wiphy(wiphy, ifp);
	if (err < 0)
		goto priv_out;

	brcmf_dbg(INFO, "Registering custom regulatory\n");
	wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
	wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);

	/* firmware defaults to 40MHz disabled in 2G band. We signal
	 * cfg80211 here that we do and have it decide we can enable
	 * it. But first check if device does support 2G operation.
	 */
	if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
		cap = &wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap;
		*cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
	}
	err = wiphy_register(wiphy);
	if (err < 0) {
		brcmf_err("Could not register wiphy device (%d)\n", err);
		goto priv_out;
5685 5686 5687 5688 5689
	}

	/* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
	 * setup 40MHz in 2GHz band and enable OBSS scanning.
	 */
5690 5691
	if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
		err = brcmf_enable_bw40_2g(cfg);
5692 5693 5694
		if (!err)
			err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
						      BRCMF_OBSS_COEX_AUTO);
5695 5696
		else
			*cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5697 5698
	}

5699
	err = brcmf_p2p_attach(cfg);
5700
	if (err) {
5701 5702 5703 5704 5705 5706 5707 5708
		brcmf_err("P2P initilisation failed (%d)\n", err);
		goto wiphy_unreg_out;
	}
	err = brcmf_btcoex_attach(cfg);
	if (err) {
		brcmf_err("BT-coex initialisation failed (%d)\n", err);
		brcmf_p2p_detach(&cfg->p2p);
		goto wiphy_unreg_out;
5709 5710
	}

5711
	err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
5712
	if (err) {
5713 5714
		brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
		wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
5715 5716 5717
	} else {
		brcmf_fweh_register(cfg->pub, BRCMF_E_TDLS_PEER_EVENT,
				    brcmf_notify_tdls_peer_event);
5718 5719 5720 5721
	}

	return cfg;

5722 5723 5724
wiphy_unreg_out:
	wiphy_unregister(cfg->wiphy);
priv_out:
5725 5726
	wl_deinit_priv(cfg);
	brcmf_free_vif(vif);
5727 5728
wiphy_out:
	brcmf_free_wiphy(wiphy);
5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739
	return NULL;
}

void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
{
	if (!cfg)
		return;

	WARN_ON(!list_empty(&cfg->vif_list));
	wiphy_unregister(cfg->wiphy);
	brcmf_btcoex_detach(cfg);
5740
	brcmf_p2p_detach(&cfg->p2p);
5741
	wl_deinit_priv(cfg);
5742
	brcmf_free_wiphy(cfg->wiphy);
5743
}