wl_cfg80211.c 150.5 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 "vendor.h"
39

40 41 42 43 44 45 46 47 48 49 50 51
#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

52
#define BRCMF_IFACE_MAX_CNT		3
53

H
Hante Meuleman 已提交
54 55 56 57
#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
58
#define WPS_OUI_TYPE			4
H
Hante Meuleman 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

#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
84
#define VNDR_IE_PARSE_LIMIT		5
H
Hante Meuleman 已提交
85 86 87

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

89 90 91 92
#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

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

96
static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
97
{
98
	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
99 100
		brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
			  vif->sme_state);
101 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
		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

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

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

149 150
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
 * By default world regulatory domain defined in reg.c puts the flags
151 152 153
 * 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
154 155 156 157 158 159 160 161 162 163 164 165 166 167
 * 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 */
168
		REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),
169
		/* IEEE 802.11a, channel 100..165 */
170
		REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
171 172 173 174 175 176 177 178 179 180
};

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 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
/* 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;
197
	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
H
Hante Meuleman 已提交
198 199
};

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

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

288 289
static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
			       struct cfg80211_chan_def *ch)
290 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
{
	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 已提交
342 343
u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
			struct ieee80211_channel *ch)
344
{
F
Franky Lin 已提交
345
	struct brcmu_chan ch_inf;
346

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

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

354 355 356 357
/* 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
 */
358 359
const struct brcmf_tlv *
brcmf_parse_tlvs(const void *buf, int buflen, uint key)
360
{
361 362
	const struct brcmf_tlv *elt = buf;
	int totlen = buflen;
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

	/* 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
383 384
brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len,
		 const u8 *oui, u32 oui_len, u8 type)
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
{
	/* 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 *
406
brcmf_find_wpaie(const u8 *parse, u32 len)
407
{
408
	const struct brcmf_tlv *ie;
409 410

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

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

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


432 433 434 435 436 437 438 439 440 441 442 443 444 445
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));
}

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

	convert_key_from_CPU(key, &key_le);
453

454 455
	brcmf_netdev_wait_pend8021x(ndev);

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

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

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

496 497 498 499 500 501 502 503 504 505 506 507 508
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;
}

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
						     const char *name,
						     enum nl80211_iftype type,
						     u32 *flags,
						     struct vif_params *params)
{
	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:
527
	case NL80211_IFTYPE_P2P_DEVICE:
528 529 530 531 532 533 534
		return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
	case NL80211_IFTYPE_UNSPECIFIED:
	default:
		return ERR_PTR(-EINVAL);
	}
}

535 536
static void brcmf_scan_config_mpc(struct brcmf_if *ifp, int mpc)
{
537
	if (brcmf_feat_is_quirk_enabled(ifp, BRCMF_FEAT_QUIRK_NEED_MPC))
538 539 540
		brcmf_set_mpc(ifp, mpc);
}

541
void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
542 543 544 545 546 547 548 549 550 551 552 553 554
{
	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);
	}
}

555 556 557
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
				struct brcmf_if *ifp, bool aborted,
				bool fw_abort)
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
{
	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 */
588
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
589 590 591 592
					     &params_le, sizeof(params_le));
		if (err)
			brcmf_err("Scan abort  failed\n");
	}
593

594
	brcmf_scan_config_mpc(ifp, 1);
595

596 597 598 599 600 601 602 603 604 605 606 607 608 609
	/*
	 * 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);
	}
610 611
	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
		brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
612 613 614 615

	return err;
}

616 617 618
static
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
{
619 620 621 622 623 624 625 626 627
	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) &&
628 629 630
		    cfg->escan_info.ifp == netdev_priv(ndev))
			brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
						    true, true);
631 632 633 634

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

635 636 637 638 639 640 641 642 643 644 645
	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:
646
	case NL80211_IFTYPE_P2P_DEVICE:
647 648 649 650 651 652 653 654
		return brcmf_p2p_del_vif(wiphy, wdev);
	case NL80211_IFTYPE_UNSPECIFIED:
	default:
		return -EINVAL;
	}
	return -EOPNOTSUPP;
}

655 656 657 658 659
static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
			 enum nl80211_iftype type, u32 *flags,
			 struct vif_params *params)
{
660
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
661
	struct brcmf_if *ifp = netdev_priv(ndev);
662
	struct brcmf_cfg80211_vif *vif = ifp->vif;
663
	s32 infra = 0;
H
Hante Meuleman 已提交
664
	s32 ap = 0;
665 666
	s32 err = 0;

667
	brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
668 669 670 671

	switch (type) {
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_WDS:
672 673
		brcmf_err("type (%d) : currently we do not support this type\n",
			  type);
674 675 676 677 678
		return -EOPNOTSUPP;
	case NL80211_IFTYPE_ADHOC:
		infra = 0;
		break;
	case NL80211_IFTYPE_STATION:
679 680 681 682 683 684 685 686 687 688 689 690
		/* 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;
		}
691 692
		infra = 1;
		break;
H
Hante Meuleman 已提交
693
	case NL80211_IFTYPE_AP:
694
	case NL80211_IFTYPE_P2P_GO:
H
Hante Meuleman 已提交
695 696
		ap = 1;
		break;
697 698 699 700 701
	default:
		err = -EINVAL;
		goto done;
	}

H
Hante Meuleman 已提交
702
	if (ap) {
703 704 705 706 707 708 709 710
		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");
		}
711
	} else {
712
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
H
Hante Meuleman 已提交
713
		if (err) {
714
			brcmf_err("WLC_SET_INFRA error (%d)\n", err);
H
Hante Meuleman 已提交
715 716 717
			err = -EAGAIN;
			goto done;
		}
718
		brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?
719
			  "Adhoc" : "Infra");
720
	}
H
Hante Meuleman 已提交
721
	ndev->ieee80211_ptr->iftype = type;
722 723

done:
724
	brcmf_dbg(TRACE, "Exit\n");
725 726 727 728

	return err;
}

F
Franky Lin 已提交
729 730
static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
			     struct brcmf_scan_params_le *params_le,
H
Hante Meuleman 已提交
731 732 733 734 735 736
			     struct cfg80211_scan_request *request)
{
	u32 n_ssids;
	u32 n_channels;
	s32 i;
	s32 offset;
737
	u16 chanspec;
H
Hante Meuleman 已提交
738
	char *ptr;
739
	struct brcmf_ssid_le ssid_le;
H
Hante Meuleman 已提交
740

741
	memset(params_le->bssid, 0xFF, ETH_ALEN);
H
Hante Meuleman 已提交
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
	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 */
758 759
	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
		  n_channels);
H
Hante Meuleman 已提交
760 761
	if (n_channels > 0) {
		for (i = 0; i < n_channels; i++) {
F
Franky Lin 已提交
762 763
			chanspec = channel_to_chanspec(&cfg->d11inf,
						       request->channels[i]);
764 765
			brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
				  request->channels[i]->hw_value, chanspec);
766
			params_le->channel_list[i] = cpu_to_le16(chanspec);
H
Hante Meuleman 已提交
767 768
		}
	} else {
769
		brcmf_dbg(SCAN, "Scanning all channels\n");
H
Hante Meuleman 已提交
770 771
	}
	/* Copy ssid array if applicable */
772
	brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
H
Hante Meuleman 已提交
773 774 775 776 777 778
	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++) {
779 780 781 782 783 784
			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)
785
				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
H
Hante Meuleman 已提交
786
			else
787 788
				brcmf_dbg(SCAN, "%d: scan for  %s size =%d\n",
					  i, ssid_le.SSID, ssid_le.SSID_len);
789 790
			memcpy(ptr, &ssid_le, sizeof(ssid_le));
			ptr += sizeof(ssid_le);
H
Hante Meuleman 已提交
791 792
		}
	} else {
793
		brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
H
Hante Meuleman 已提交
794
		if ((request->ssids) && request->ssids->ssid_len) {
795 796 797
			brcmf_dbg(SCAN, "SSID %s len=%d\n",
				  params_le->ssid_le.SSID,
				  request->ssids->ssid_len);
H
Hante Meuleman 已提交
798 799 800 801 802 803 804 805 806 807 808 809 810
			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
811
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
H
Hante Meuleman 已提交
812 813 814 815 816 817 818
		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;

819
	brcmf_dbg(SCAN, "E-SCAN START\n");
H
Hante Meuleman 已提交
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

	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 已提交
835
	brcmf_escan_prep(cfg, &params->params_le, request);
H
Hante Meuleman 已提交
836 837 838 839
	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
	params->action = cpu_to_le16(action);
	params->sync_id = cpu_to_le16(0x1234);

840
	err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
H
Hante Meuleman 已提交
841 842
	if (err) {
		if (err == -EBUSY)
843
			brcmf_dbg(INFO, "system busy : escan canceled\n");
H
Hante Meuleman 已提交
844
		else
845
			brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
846 847 848 849 850 851 852 853
	}

	kfree(params);
exit:
	return err;
}

static s32
854
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
855
	       struct brcmf_if *ifp, struct cfg80211_scan_request *request)
H
Hante Meuleman 已提交
856 857
{
	s32 err;
858
	u32 passive_scan;
H
Hante Meuleman 已提交
859
	struct brcmf_scan_results *results;
860
	struct escan_info *escan = &cfg->escan_info;
H
Hante Meuleman 已提交
861

862
	brcmf_dbg(SCAN, "Enter\n");
863
	escan->ifp = ifp;
864 865
	escan->wiphy = wiphy;
	escan->escan_state = WL_ESCAN_STATE_SCANNING;
866
	passive_scan = cfg->active_scan ? 0 : 1;
867
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
868
				    passive_scan);
H
Hante Meuleman 已提交
869
	if (err) {
870
		brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
871 872
		return err;
	}
873
	brcmf_scan_config_mpc(ifp, 0);
874
	results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
875 876 877 878
	results->version = 0;
	results->count = 0;
	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;

879
	err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
H
Hante Meuleman 已提交
880
	if (err)
881
		brcmf_scan_config_mpc(ifp, 1);
H
Hante Meuleman 已提交
882 883 884 885
	return err;
}

static s32
886
brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
H
Hante Meuleman 已提交
887 888 889
		     struct cfg80211_scan_request *request,
		     struct cfg80211_ssid *this_ssid)
{
890 891
	struct brcmf_if *ifp = vif->ifp;
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
H
Hante Meuleman 已提交
892
	struct cfg80211_ssid *ssids;
893
	struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
894
	u32 passive_scan;
H
Hante Meuleman 已提交
895 896 897 898 899
	bool escan_req;
	bool spec_scan;
	s32 err;
	u32 SSID_len;

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

902
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
903
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
H
Hante Meuleman 已提交
904 905
		return -EAGAIN;
	}
906
	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
907 908
		brcmf_err("Scanning being aborted: status (%lu)\n",
			  cfg->scan_status);
H
Hante Meuleman 已提交
909 910
		return -EAGAIN;
	}
911 912 913 914 915
	if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
		brcmf_err("Scanning suppressed: status (%lu)\n",
			  cfg->scan_status);
		return -EAGAIN;
	}
916
	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
917
		brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
H
Hante Meuleman 已提交
918 919 920
		return -EAGAIN;
	}

921
	/* If scan req comes for p2p0, send it over primary I/F */
922 923
	if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
		vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
924

H
Hante Meuleman 已提交
925
	/* Arm scan timeout timer */
926
	mod_timer(&cfg->escan_timeout, jiffies +
H
Hante Meuleman 已提交
927 928 929 930 931 932 933 934 935 936 937 938 939
			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;
	}

940
	cfg->scan_request = request;
941
	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
H
Hante Meuleman 已提交
942
	if (escan_req) {
943
		cfg->escan_info.run = brcmf_run_escan;
944
		err = brcmf_p2p_scan_prep(wiphy, request, vif);
945 946 947
		if (err)
			goto scan_out;

948
		err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
949
		if (err)
H
Hante Meuleman 已提交
950 951
			goto scan_out;
	} else {
952 953
		brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
			  ssids->ssid, ssids->ssid_len);
H
Hante Meuleman 已提交
954 955 956 957 958 959 960 961 962
		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
963
			brcmf_dbg(SCAN, "Broadcast scan\n");
H
Hante Meuleman 已提交
964

965
		passive_scan = cfg->active_scan ? 0 : 1;
966
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
967
					    passive_scan);
H
Hante Meuleman 已提交
968
		if (err) {
969
			brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
970 971
			goto scan_out;
		}
972
		brcmf_scan_config_mpc(ifp, 0);
973
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
974
					     &sr->ssid_le, sizeof(sr->ssid_le));
H
Hante Meuleman 已提交
975 976
		if (err) {
			if (err == -EBUSY)
977 978
				brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
					  sr->ssid_le.SSID);
H
Hante Meuleman 已提交
979
			else
980
				brcmf_err("WLC_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
981

982
			brcmf_scan_config_mpc(ifp, 1);
H
Hante Meuleman 已提交
983 984 985 986 987 988 989
			goto scan_out;
		}
	}

	return 0;

scan_out:
990
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
991 992 993
	if (timer_pending(&cfg->escan_timeout))
		del_timer_sync(&cfg->escan_timeout);
	cfg->scan_request = NULL;
H
Hante Meuleman 已提交
994 995 996
	return err;
}

997
static s32
998
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
999
{
1000
	struct brcmf_cfg80211_vif *vif;
1001 1002
	s32 err = 0;

1003
	brcmf_dbg(TRACE, "Enter\n");
1004 1005
	vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
	if (!check_vif_up(vif))
1006 1007
		return -EIO;

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

1010
	if (err)
1011
		brcmf_err("scan error (%d)\n", err);
1012

1013
	brcmf_dbg(TRACE, "Exit\n");
1014 1015 1016 1017 1018 1019 1020
	return err;
}

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

1021 1022
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
				      rts_threshold);
1023
	if (err)
1024
		brcmf_err("Error (%d)\n", err);
1025 1026 1027 1028 1029 1030 1031 1032

	return err;
}

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

1033 1034
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
				      frag_threshold);
1035
	if (err)
1036
		brcmf_err("Error (%d)\n", err);
1037 1038 1039 1040 1041 1042 1043

	return err;
}

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

1046
	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
1047
	if (err) {
1048
		brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
1049 1050 1051 1052 1053 1054 1055
		return err;
	}
	return err;
}

static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
1056 1057
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
1058
	struct brcmf_if *ifp = netdev_priv(ndev);
1059 1060
	s32 err = 0;

1061
	brcmf_dbg(TRACE, "Enter\n");
1062
	if (!check_vif_up(ifp->vif))
1063 1064 1065
		return -EIO;

	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
1066 1067 1068
	    (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
		cfg->conf->rts_threshold = wiphy->rts_threshold;
		err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
1069 1070 1071 1072
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
1073 1074 1075
	    (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
		cfg->conf->frag_threshold = wiphy->frag_threshold;
		err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
1076 1077 1078 1079
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_LONG
1080 1081 1082
	    && (cfg->conf->retry_long != wiphy->retry_long)) {
		cfg->conf->retry_long = wiphy->retry_long;
		err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
1083 1084 1085 1086
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_SHORT
1087 1088 1089
	    && (cfg->conf->retry_short != wiphy->retry_short)) {
		cfg->conf->retry_short = wiphy->retry_short;
		err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
1090 1091 1092 1093 1094
		if (!err)
			goto done;
	}

done:
1095
	brcmf_dbg(TRACE, "Exit\n");
1096 1097 1098 1099 1100 1101 1102 1103
	return err;
}

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

1104
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
1105
{
1106
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
1107 1108
	s32 err = 0;

1109
	brcmf_dbg(TRACE, "Enter\n");
1110

1111
	if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
1112
		brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
1113
		err = brcmf_fil_cmd_data_set(vif->ifp,
1114
					     BRCMF_C_DISASSOC, NULL, 0);
1115
		if (err) {
1116
			brcmf_err("WLC_DISASSOC failed (%d)\n", err);
1117
		}
1118
		clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
1119 1120
		cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);

1121
	}
1122
	clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
1123 1124
	clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
	brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
1125
	brcmf_dbg(TRACE, "Exit\n");
1126 1127 1128 1129 1130 1131
}

static s32
brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_ibss_params *params)
{
1132
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1133 1134
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1135 1136 1137 1138 1139
	struct brcmf_join_params join_params;
	size_t join_params_size = 0;
	s32 err = 0;
	s32 wsec = 0;
	s32 bcnprd;
1140
	u16 chanspec;
1141

1142
	brcmf_dbg(TRACE, "Enter\n");
1143
	if (!check_vif_up(ifp->vif))
1144 1145 1146
		return -EIO;

	if (params->ssid)
1147
		brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
1148
	else {
1149
		brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
1150 1151 1152
		return -EOPNOTSUPP;
	}

1153
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1154 1155

	if (params->bssid)
1156
		brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
1157
	else
1158
		brcmf_dbg(CONN, "No BSSID specified\n");
1159

1160
	if (params->chandef.chan)
1161 1162
		brcmf_dbg(CONN, "channel: %d\n",
			  params->chandef.chan->center_freq);
1163
	else
1164
		brcmf_dbg(CONN, "no channel specified\n");
1165 1166

	if (params->channel_fixed)
1167
		brcmf_dbg(CONN, "fixed channel required\n");
1168
	else
1169
		brcmf_dbg(CONN, "no fixed channel required\n");
1170 1171

	if (params->ie && params->ie_len)
1172
		brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
1173
	else
1174
		brcmf_dbg(CONN, "no ie specified\n");
1175 1176

	if (params->beacon_interval)
1177 1178
		brcmf_dbg(CONN, "beacon interval: %d\n",
			  params->beacon_interval);
1179
	else
1180
		brcmf_dbg(CONN, "no beacon interval specified\n");
1181 1182

	if (params->basic_rates)
1183
		brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
1184
	else
1185
		brcmf_dbg(CONN, "no basic rates specified\n");
1186 1187

	if (params->privacy)
1188
		brcmf_dbg(CONN, "privacy required\n");
1189
	else
1190
		brcmf_dbg(CONN, "no privacy required\n");
1191 1192 1193 1194 1195

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

1196
	err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
1197
	if (err) {
1198
		brcmf_err("wsec failed (%d)\n", err);
1199 1200 1201 1202 1203 1204 1205 1206 1207
		goto done;
	}

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

H
Hante Meuleman 已提交
1208
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
1209
	if (err) {
1210
		brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
1211 1212 1213 1214 1215 1216 1217
		goto done;
	}

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

	/* SSID */
1218 1219 1220 1221
	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);
1222 1223 1224 1225 1226 1227 1228
	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;
1229
		memcpy(profile->bssid, params->bssid, ETH_ALEN);
1230
	} else {
1231
		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1232
		memset(profile->bssid, 0, ETH_ALEN);
1233 1234 1235
	}

	/* Channel */
1236
	if (params->chandef.chan) {
1237 1238
		u32 target_channel;

1239
		cfg->channel =
1240
			ieee80211_frequency_to_channel(
1241
				params->chandef.chan->center_freq);
1242 1243
		if (params->channel_fixed) {
			/* adding chanspec */
1244 1245
			chanspec = chandef_to_chanspec(&cfg->d11inf,
						       &params->chandef);
1246 1247 1248 1249
			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);
1250 1251 1252
		}

		/* set channel for starter */
1253
		target_channel = cfg->channel;
H
Hante Meuleman 已提交
1254
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
1255
					    target_channel);
1256
		if (err) {
1257
			brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
1258 1259 1260
			goto done;
		}
	} else
1261
		cfg->channel = 0;
1262

1263
	cfg->ibss_starter = false;
1264 1265


1266
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1267
				     &join_params, join_params_size);
1268
	if (err) {
1269
		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
1270 1271 1272 1273 1274
		goto done;
	}

done:
	if (err)
1275
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1276
	brcmf_dbg(TRACE, "Exit\n");
1277 1278 1279 1280 1281 1282
	return err;
}

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

1285
	brcmf_dbg(TRACE, "Enter\n");
1286
	if (!check_vif_up(ifp->vif))
1287 1288
		return -EIO;

1289
	brcmf_link_down(ifp->vif);
1290

1291
	brcmf_dbg(TRACE, "Exit\n");
1292

1293
	return 0;
1294 1295 1296 1297 1298
}

static s32 brcmf_set_wpa_version(struct net_device *ndev,
				 struct cfg80211_connect_params *sme)
{
1299
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
	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;
1310
	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
1311
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
1312
	if (err) {
1313
		brcmf_err("set wpa_auth failed (%d)\n", err);
1314 1315
		return err;
	}
1316
	sec = &profile->sec;
1317 1318 1319 1320 1321 1322 1323
	sec->wpa_versions = sme->crypto.wpa_versions;
	return err;
}

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

	switch (sme->auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		val = 0;
1332
		brcmf_dbg(CONN, "open system\n");
1333 1334 1335
		break;
	case NL80211_AUTHTYPE_SHARED_KEY:
		val = 1;
1336
		brcmf_dbg(CONN, "shared key\n");
1337 1338 1339
		break;
	case NL80211_AUTHTYPE_AUTOMATIC:
		val = 2;
1340
		brcmf_dbg(CONN, "automatic\n");
1341 1342
		break;
	case NL80211_AUTHTYPE_NETWORK_EAP:
1343
		brcmf_dbg(CONN, "network eap\n");
1344 1345
	default:
		val = 2;
1346
		brcmf_err("invalid auth type (%d)\n", sme->auth_type);
1347 1348 1349
		break;
	}

1350
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
1351
	if (err) {
1352
		brcmf_err("set auth failed (%d)\n", err);
1353 1354
		return err;
	}
1355
	sec = &profile->sec;
1356 1357 1358 1359 1360
	sec->auth_type = sme->auth_type;
	return err;
}

static s32
1361 1362
brcmf_set_wsec_mode(struct net_device *ndev,
		     struct cfg80211_connect_params *sme, bool mfp)
1363
{
1364
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1365 1366 1367
	struct brcmf_cfg80211_security *sec;
	s32 pval = 0;
	s32 gval = 0;
1368
	s32 wsec;
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
	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:
1387 1388
			brcmf_err("invalid cipher pairwise (%d)\n",
				  sme->crypto.ciphers_pairwise[0]);
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
			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:
1408 1409
			brcmf_err("invalid cipher group (%d)\n",
				  sme->crypto.cipher_group);
1410 1411 1412 1413
			return -EINVAL;
		}
	}

1414
	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
1415 1416 1417 1418 1419
	/* 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;
1420 1421 1422 1423 1424 1425

	if (mfp)
		wsec = pval | gval | MFP_CAPABLE;
	else
		wsec = pval | gval;
	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
1426
	if (err) {
1427
		brcmf_err("error (%d)\n", err);
1428 1429 1430
		return err;
	}

1431
	sec = &profile->sec;
1432 1433 1434 1435 1436 1437 1438 1439 1440
	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)
{
1441
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1442 1443 1444 1445 1446
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	if (sme->crypto.n_akm_suites) {
1447 1448
		err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
					       "wpa_auth", &val);
1449
		if (err) {
1450
			brcmf_err("could not get wpa_auth (%d)\n", err);
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
			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:
1462 1463
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
				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:
1475 1476
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1477 1478 1479 1480
				return -EINVAL;
			}
		}

1481
		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1482 1483
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
					       "wpa_auth", val);
1484
		if (err) {
1485
			brcmf_err("could not set wpa_auth (%d)\n", err);
1486 1487 1488
			return err;
		}
	}
1489
	sec = &profile->sec;
1490 1491 1492 1493 1494 1495
	sec->wpa_auth = sme->crypto.akm_suites[0];

	return err;
}

static s32
1496 1497
brcmf_set_sharedkey(struct net_device *ndev,
		    struct cfg80211_connect_params *sme)
1498
{
1499
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1500 1501 1502 1503 1504
	struct brcmf_cfg80211_security *sec;
	struct brcmf_wsec_key key;
	s32 val;
	s32 err = 0;

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

1507 1508 1509
	if (sme->key_len == 0)
		return 0;

1510
	sec = &profile->sec;
1511 1512
	brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
		  sec->wpa_versions, sec->cipher_pairwise);
1513 1514 1515 1516

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

1517 1518 1519
	if (!(sec->cipher_pairwise &
	    (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
		return 0;
1520

1521 1522 1523 1524
	memset(&key, 0, sizeof(key));
	key.len = (u32) sme->key_len;
	key.index = (u32) sme->key_idx;
	if (key.len > sizeof(key.data)) {
1525
		brcmf_err("Too long key length (%u)\n", key.len);
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
		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:
1538 1539
		brcmf_err("Invalid algorithm (%d)\n",
			  sme->crypto.ciphers_pairwise[0]);
1540 1541 1542
		return -EINVAL;
	}
	/* Set the new key/index */
1543 1544 1545
	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);
1546
	err = send_key_to_dongle(ndev, &key);
1547 1548 1549 1550
	if (err)
		return err;

	if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
1551
		brcmf_dbg(CONN, "set auth_type to shared key\n");
1552
		val = WL_AUTH_SHARED_KEY;	/* shared key */
1553
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
1554
		if (err)
1555
			brcmf_err("set auth failed (%d)\n", err);
1556 1557 1558 1559
	}
	return err;
}

1560 1561 1562 1563
static
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
					   enum nl80211_auth_type type)
{
1564 1565 1566 1567
	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;
1568 1569 1570 1571
	}
	return type;
}

1572 1573
static s32
brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1574
		       struct cfg80211_connect_params *sme)
1575
{
1576
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1577 1578
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1579 1580 1581
	struct ieee80211_channel *chan = sme->channel;
	struct brcmf_join_params join_params;
	size_t join_params_size;
1582 1583 1584
	const struct brcmf_tlv *rsn_ie;
	const struct brcmf_vs_tlv *wpa_ie;
	const void *ie;
1585 1586
	u32 ie_len;
	struct brcmf_ext_join_params_le *ext_join_params;
1587
	u16 chanspec;
1588 1589
	s32 err = 0;

1590
	brcmf_dbg(TRACE, "Enter\n");
1591
	if (!check_vif_up(ifp->vif))
1592 1593 1594
		return -EIO;

	if (!sme->ssid) {
1595
		brcmf_err("Invalid ssid\n");
1596 1597 1598
		return -EOPNOTSUPP;
	}

1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
	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 */
1610 1611
			rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie,
						  sme->ie_len,
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
						  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");

1628
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1629 1630

	if (chan) {
1631
		cfg->channel =
1632
			ieee80211_frequency_to_channel(chan->center_freq);
F
Franky Lin 已提交
1633
		chanspec = channel_to_chanspec(&cfg->d11inf, chan);
1634 1635 1636
		brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
			  cfg->channel, chan->center_freq, chanspec);
	} else {
1637
		cfg->channel = 0;
1638 1639
		chanspec = 0;
	}
1640

1641
	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1642 1643 1644

	err = brcmf_set_wpa_version(ndev, sme);
	if (err) {
1645
		brcmf_err("wl_set_wpa_version failed (%d)\n", err);
1646 1647 1648
		goto done;
	}

1649
	sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
1650 1651
	err = brcmf_set_auth_type(ndev, sme);
	if (err) {
1652
		brcmf_err("wl_set_auth_type failed (%d)\n", err);
1653 1654 1655
		goto done;
	}

1656
	err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
1657
	if (err) {
1658
		brcmf_err("wl_set_set_cipher failed (%d)\n", err);
1659 1660 1661 1662 1663
		goto done;
	}

	err = brcmf_set_key_mgmt(ndev, sme);
	if (err) {
1664
		brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
1665 1666 1667
		goto done;
	}

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

1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
	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);
1698

1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712
	/* 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);
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
		/* 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);
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
	}

	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 */
1742 1743 1744
	memset(&join_params, 0, sizeof(join_params));
	join_params_size = sizeof(join_params.ssid_le);

1745 1746
	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);
1747

1748 1749 1750 1751
	if (sme->bssid)
		memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
	else
		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1752

1753 1754 1755 1756 1757
	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);
	}
1758
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1759
				     &join_params, join_params_size);
1760
	if (err)
1761
		brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err);
1762 1763 1764

done:
	if (err)
1765
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1766
	brcmf_dbg(TRACE, "Exit\n");
1767 1768 1769 1770 1771 1772 1773
	return err;
}

static s32
brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
		       u16 reason_code)
{
1774 1775
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1776 1777 1778
	struct brcmf_scb_val_le scbval;
	s32 err = 0;

1779
	brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
1780
	if (!check_vif_up(ifp->vif))
1781 1782
		return -EIO;

1783
	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
1784
	cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
1785

1786
	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
1787
	scbval.val = cpu_to_le32(reason_code);
1788
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
1789
				     &scbval, sizeof(scbval));
1790
	if (err)
1791
		brcmf_err("error (%d)\n", err);
1792

1793
	brcmf_dbg(TRACE, "Exit\n");
1794 1795 1796 1797
	return err;
}

static s32
1798
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
1799
			    enum nl80211_tx_power_setting type, s32 mbm)
1800 1801
{

1802
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1803 1804
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct brcmf_if *ifp = netdev_priv(ndev);
1805 1806 1807
	u16 txpwrmw;
	s32 err = 0;
	s32 disable = 0;
1808
	s32 dbm = MBM_TO_DBM(mbm);
1809

1810
	brcmf_dbg(TRACE, "Enter\n");
1811
	if (!check_vif_up(ifp->vif))
1812 1813 1814 1815 1816 1817 1818 1819
		return -EIO;

	switch (type) {
	case NL80211_TX_POWER_AUTOMATIC:
		break;
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_FIXED:
		if (dbm < 0) {
1820
			brcmf_err("TX_POWER_FIXED - dbm is negative\n");
1821 1822 1823 1824 1825 1826 1827
			err = -EINVAL;
			goto done;
		}
		break;
	}
	/* Make sure radio is off or on as far as software is concerned */
	disable = WL_RADIO_SW_DISABLE << 16;
1828
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
1829
	if (err)
1830
		brcmf_err("WLC_SET_RADIO error (%d)\n", err);
1831 1832 1833 1834 1835

	if (dbm > 0xffff)
		txpwrmw = 0xffff;
	else
		txpwrmw = (u16) dbm;
1836 1837
	err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
				      (s32)brcmf_mw_to_qdbm(txpwrmw));
1838
	if (err)
1839
		brcmf_err("qtxpower error (%d)\n", err);
1840
	cfg->conf->tx_power = dbm;
1841 1842

done:
1843
	brcmf_dbg(TRACE, "Exit\n");
1844 1845 1846
	return err;
}

1847 1848 1849
static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
				       struct wireless_dev *wdev,
				       s32 *dbm)
1850
{
1851
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1852
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
1853 1854 1855 1856
	s32 txpwrdbm;
	u8 result;
	s32 err = 0;

1857
	brcmf_dbg(TRACE, "Enter\n");
1858
	if (!check_vif_up(ifp->vif))
1859 1860
		return -EIO;

1861
	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
1862
	if (err) {
1863
		brcmf_err("error (%d)\n", err);
1864 1865 1866 1867
		goto done;
	}

	result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
1868
	*dbm = (s32) brcmf_qdbm_to_mw(result);
1869 1870

done:
1871
	brcmf_dbg(TRACE, "Exit\n");
1872 1873 1874 1875 1876 1877 1878
	return err;
}

static s32
brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
			       u8 key_idx, bool unicast, bool multicast)
{
1879
	struct brcmf_if *ifp = netdev_priv(ndev);
1880 1881 1882 1883
	u32 index;
	u32 wsec;
	s32 err = 0;

1884
	brcmf_dbg(TRACE, "Enter\n");
1885
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1886
	if (!check_vif_up(ifp->vif))
1887 1888
		return -EIO;

1889
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
1890
	if (err) {
1891
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
1892 1893 1894 1895 1896 1897
		goto done;
	}

	if (wsec & WEP_ENABLED) {
		/* Just select a new current key */
		index = key_idx;
1898
		err = brcmf_fil_cmd_int_set(ifp,
1899
					    BRCMF_C_SET_KEY_PRIMARY, index);
1900
		if (err)
1901
			brcmf_err("error (%d)\n", err);
1902 1903
	}
done:
1904
	brcmf_dbg(TRACE, "Exit\n");
1905 1906 1907 1908 1909 1910 1911
	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)
{
1912
	struct brcmf_if *ifp = netdev_priv(ndev);
1913 1914
	struct brcmf_wsec_key key;
	s32 err = 0;
1915
	u8 keybuf[8];
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926

	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 */
1927
		err = send_key_to_dongle(ndev, &key);
1928
		if (err)
1929
			brcmf_err("key delete error (%d)\n", err);
1930 1931
	} else {
		if (key.len > sizeof(key.data)) {
1932
			brcmf_err("Invalid key length (%d)\n", key.len);
1933 1934 1935
			return -EINVAL;
		}

1936
		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
1937 1938
		memcpy(key.data, params->key, key.len);

1939
		if (!brcmf_is_apmode(ifp->vif) &&
1940 1941
		    (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
			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;
1961
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
1962 1963 1964
			break;
		case WLAN_CIPHER_SUITE_WEP104:
			key.algo = CRYPTO_ALGO_WEP128;
1965
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
1966 1967 1968
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			key.algo = CRYPTO_ALGO_TKIP;
1969
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
1970 1971 1972
			break;
		case WLAN_CIPHER_SUITE_AES_CMAC:
			key.algo = CRYPTO_ALGO_AES_CCM;
1973
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
1974 1975 1976
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			key.algo = CRYPTO_ALGO_AES_CCM;
1977
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
1978 1979
			break;
		default:
1980
			brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
1981 1982
			return -EINVAL;
		}
1983
		err = send_key_to_dongle(ndev, &key);
1984
		if (err)
1985
			brcmf_err("wsec_key error (%d)\n", err);
1986 1987 1988 1989 1990 1991 1992 1993 1994
	}
	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)
{
1995
	struct brcmf_if *ifp = netdev_priv(ndev);
1996 1997 1998 1999 2000 2001
	struct brcmf_wsec_key key;
	s32 val;
	s32 wsec;
	s32 err = 0;
	u8 keybuf[8];

2002
	brcmf_dbg(TRACE, "Enter\n");
2003
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2004
	if (!check_vif_up(ifp->vif))
2005 2006
		return -EIO;

2007 2008 2009
	if (mac_addr &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
		(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
2010
		brcmf_dbg(TRACE, "Exit");
2011 2012 2013 2014 2015 2016 2017 2018
		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)) {
2019
		brcmf_err("Too long key length (%u)\n", key.len);
2020 2021 2022 2023 2024 2025 2026 2027 2028
		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;
2029
		val = WEP_ENABLED;
2030
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
2031 2032 2033
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		key.algo = CRYPTO_ALGO_WEP128;
2034
		val = WEP_ENABLED;
2035
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
2036 2037
		break;
	case WLAN_CIPHER_SUITE_TKIP:
2038
		if (!brcmf_is_apmode(ifp->vif)) {
2039
			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
H
Hante Meuleman 已提交
2040 2041 2042 2043
			memcpy(keybuf, &key.data[24], sizeof(keybuf));
			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
			memcpy(&key.data[16], keybuf, sizeof(keybuf));
		}
2044
		key.algo = CRYPTO_ALGO_TKIP;
2045
		val = TKIP_ENABLED;
2046
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
2047 2048 2049
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
		key.algo = CRYPTO_ALGO_AES_CCM;
2050
		val = AES_ENABLED;
2051
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
2052 2053 2054
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		key.algo = CRYPTO_ALGO_AES_CCM;
2055
		val = AES_ENABLED;
2056
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
2057 2058
		break;
	default:
2059
		brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
2060 2061 2062 2063
		err = -EINVAL;
		goto done;
	}

2064
	err = send_key_to_dongle(ndev, &key);
2065 2066 2067
	if (err)
		goto done;

2068
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2069
	if (err) {
2070
		brcmf_err("get wsec error (%d)\n", err);
2071 2072 2073
		goto done;
	}
	wsec |= val;
2074
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
2075
	if (err) {
2076
		brcmf_err("set wsec error (%d)\n", err);
2077 2078 2079 2080
		goto done;
	}

done:
2081
	brcmf_dbg(TRACE, "Exit\n");
2082 2083 2084 2085 2086 2087 2088
	return err;
}

static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr)
{
2089
	struct brcmf_if *ifp = netdev_priv(ndev);
2090 2091 2092
	struct brcmf_wsec_key key;
	s32 err = 0;

2093
	brcmf_dbg(TRACE, "Enter\n");
2094
	if (!check_vif_up(ifp->vif))
2095 2096
		return -EIO;

2097 2098
	if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
		/* we ignore this key index in this case */
2099
		brcmf_err("invalid key index (%d)\n", key_idx);
2100 2101 2102
		return -EINVAL;
	}

2103 2104 2105 2106 2107 2108
	memset(&key, 0, sizeof(key));

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

2109
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2110 2111

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

2114
	brcmf_dbg(TRACE, "Exit\n");
2115 2116 2117 2118 2119 2120 2121 2122 2123
	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;
2124 2125
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
2126 2127 2128 2129
	struct brcmf_cfg80211_security *sec;
	s32 wsec;
	s32 err = 0;

2130
	brcmf_dbg(TRACE, "Enter\n");
2131
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
2132
	if (!check_vif_up(ifp->vif))
2133 2134 2135 2136
		return -EIO;

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

2137
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
2138
	if (err) {
2139
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
2140 2141 2142 2143
		/* Ignore this error, may happen during DISASSOC */
		err = -EAGAIN;
		goto done;
	}
2144
	if (wsec & WEP_ENABLED) {
2145
		sec = &profile->sec;
2146 2147
		if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
			params.cipher = WLAN_CIPHER_SUITE_WEP40;
2148
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
2149 2150
		} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
			params.cipher = WLAN_CIPHER_SUITE_WEP104;
2151
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
2152
		}
2153
	} else if (wsec & TKIP_ENABLED) {
2154
		params.cipher = WLAN_CIPHER_SUITE_TKIP;
2155
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
2156
	} else if (wsec & AES_ENABLED) {
2157
		params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
2158
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
2159
	} else  {
2160
		brcmf_err("Invalid algo (0x%x)\n", wsec);
2161 2162 2163 2164 2165 2166
		err = -EINVAL;
		goto done;
	}
	callback(cookie, &params);

done:
2167
	brcmf_dbg(TRACE, "Exit\n");
2168 2169 2170 2171 2172 2173 2174
	return err;
}

static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
				    struct net_device *ndev, u8 key_idx)
{
2175
	brcmf_dbg(INFO, "Not supported\n");
2176 2177 2178 2179 2180 2181

	return -EOPNOTSUPP;
}

static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
2182
			   const u8 *mac, struct station_info *sinfo)
2183
{
2184 2185
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
2186 2187 2188 2189
	struct brcmf_scb_val_le scb_val;
	int rssi;
	s32 rate;
	s32 err = 0;
2190
	u8 *bssid = profile->bssid;
2191
	struct brcmf_sta_info_le sta_info_le;
2192 2193
	u32 beacon_period;
	u32 dtim_period;
2194

2195
	brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
2196
	if (!check_vif_up(ifp->vif))
2197 2198
		return -EIO;

2199
	if (brcmf_is_apmode(ifp->vif)) {
2200
		memcpy(&sta_info_le, mac, ETH_ALEN);
2201
		err = brcmf_fil_iovar_data_get(ifp, "sta_info",
2202
					       &sta_info_le,
2203
					       sizeof(sta_info_le));
H
Hante Meuleman 已提交
2204
		if (err < 0) {
2205
			brcmf_err("GET STA INFO failed, %d\n", err);
H
Hante Meuleman 已提交
2206 2207 2208
			goto done;
		}
		sinfo->filled = STATION_INFO_INACTIVE_TIME;
2209 2210
		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 已提交
2211
			sinfo->filled |= STATION_INFO_CONNECTED_TIME;
2212
			sinfo->connected_time = le32_to_cpu(sta_info_le.in);
H
Hante Meuleman 已提交
2213
		}
2214 2215
		brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
			  sinfo->inactive_time, sinfo->connected_time);
2216
	} else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {
H
Hante Meuleman 已提交
2217
		if (memcmp(mac, bssid, ETH_ALEN)) {
2218 2219
			brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
				  mac, bssid);
H
Hante Meuleman 已提交
2220 2221 2222 2223
			err = -ENOENT;
			goto done;
		}
		/* Report the current tx rate */
2224
		err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
2225
		if (err) {
2226
			brcmf_err("Could not get rate (%d)\n", err);
H
Hante Meuleman 已提交
2227
			goto done;
2228
		} else {
H
Hante Meuleman 已提交
2229 2230
			sinfo->filled |= STATION_INFO_TX_BITRATE;
			sinfo->txrate.legacy = rate * 5;
2231
			brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
2232
		}
2233

2234 2235
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
			     &ifp->vif->sme_state)) {
H
Hante Meuleman 已提交
2236
			memset(&scb_val, 0, sizeof(scb_val));
2237 2238
			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
						     &scb_val, sizeof(scb_val));
H
Hante Meuleman 已提交
2239
			if (err) {
2240
				brcmf_err("Could not get rssi (%d)\n", err);
H
Hante Meuleman 已提交
2241 2242 2243 2244 2245
				goto done;
			} else {
				rssi = le32_to_cpu(scb_val.val);
				sinfo->filled |= STATION_INFO_SIGNAL;
				sinfo->signal = rssi;
2246
				brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
H
Hante Meuleman 已提交
2247
			}
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
			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 已提交
2272 2273 2274
		}
	} else
		err = -EPERM;
2275
done:
2276
	brcmf_dbg(TRACE, "Exit\n");
2277 2278 2279 2280 2281 2282 2283 2284 2285
	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;
2286
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2287
	struct brcmf_if *ifp = netdev_priv(ndev);
2288

2289
	brcmf_dbg(TRACE, "Enter\n");
2290 2291 2292 2293 2294

	/*
	 * 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
2295
	 * preference in cfg struct to apply this to
2296 2297
	 * FW later while initializing the dongle
	 */
2298
	cfg->pwr_save = enabled;
2299
	if (!check_vif_up(ifp->vif)) {
2300

2301
		brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
2302 2303 2304 2305
		goto done;
	}

	pm = enabled ? PM_FAST : PM_OFF;
2306 2307 2308 2309 2310
	/* 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;
	}
2311
	brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
2312

2313
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
2314 2315
	if (err) {
		if (err == -ENODEV)
2316
			brcmf_err("net_device is not ready yet\n");
2317
		else
2318
			brcmf_err("error (%d)\n", err);
2319 2320
	}
done:
2321
	brcmf_dbg(TRACE, "Exit\n");
2322 2323 2324
	return err;
}

2325
static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
2326
				   struct brcmf_bss_info_le *bi)
2327
{
2328
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2329 2330 2331
	struct ieee80211_channel *notify_channel;
	struct cfg80211_bss *bss;
	struct ieee80211_supported_band *band;
F
Franky Lin 已提交
2332
	struct brcmu_chan ch;
2333 2334 2335 2336 2337 2338 2339 2340 2341
	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) {
2342
		brcmf_err("Bss info is larger than buffer. Discarding\n");
2343 2344 2345
		return 0;
	}

F
Franky Lin 已提交
2346 2347 2348 2349 2350 2351
	if (!bi->ctl_ch) {
		ch.chspec = le16_to_cpu(bi->chanspec);
		cfg->d11inf.decchspec(&ch);
		bi->ctl_ch = ch.chnum;
	}
	channel = bi->ctl_ch;
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366

	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;

2367 2368 2369 2370 2371
	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);
2372 2373

	bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
2374
		0, notify_capability, notify_interval, notify_ie,
2375 2376
		notify_ielen, notify_signal, GFP_KERNEL);

2377 2378 2379
	if (!bss)
		return -ENOMEM;

2380
	cfg80211_put_bss(wiphy, bss);
2381

2382
	return 0;
2383 2384
}

2385 2386 2387 2388 2389 2390 2391 2392 2393
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));
}

2394
static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
2395 2396
{
	struct brcmf_scan_results *bss_list;
2397
	struct brcmf_bss_info_le *bi = NULL;	/* must be initialized */
2398 2399 2400
	s32 err = 0;
	int i;

2401
	bss_list = cfg->bss_list;
2402 2403
	if (bss_list->count != 0 &&
	    bss_list->version != BRCMF_BSS_INFO_VERSION) {
2404 2405
		brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
			  bss_list->version);
2406 2407
		return -EOPNOTSUPP;
	}
2408
	brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
2409
	for (i = 0; i < bss_list->count; i++) {
2410
		bi = next_bss_le(bss_list, bi);
2411
		err = brcmf_inform_single_bss(cfg, bi);
2412 2413 2414 2415 2416 2417
		if (err)
			break;
	}
	return err;
}

2418
static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
2419 2420
			  struct net_device *ndev, const u8 *bssid)
{
2421
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2422
	struct ieee80211_channel *notify_channel;
2423
	struct brcmf_bss_info_le *bi = NULL;
2424
	struct ieee80211_supported_band *band;
2425
	struct cfg80211_bss *bss;
F
Franky Lin 已提交
2426
	struct brcmu_chan ch;
2427 2428 2429 2430 2431 2432 2433 2434 2435
	u8 *buf = NULL;
	s32 err = 0;
	u32 freq;
	u16 notify_capability;
	u16 notify_interval;
	u8 *notify_ie;
	size_t notify_ielen;
	s32 notify_signal;

2436
	brcmf_dbg(TRACE, "Enter\n");
2437 2438 2439 2440 2441 2442 2443 2444 2445

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

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

2446 2447
	err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
				     buf, WL_BSS_INFO_MAX);
2448
	if (err) {
2449
		brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
2450 2451 2452
		goto CleanUp;
	}

2453
	bi = (struct brcmf_bss_info_le *)(buf + 4);
2454

F
Franky Lin 已提交
2455 2456
	ch.chspec = le16_to_cpu(bi->chanspec);
	cfg->d11inf.decchspec(&ch);
2457

F
Franky Lin 已提交
2458
	if (ch.band == BRCMU_CHAN_BAND_2G)
2459 2460 2461 2462
		band = wiphy->bands[IEEE80211_BAND_2GHZ];
	else
		band = wiphy->bands[IEEE80211_BAND_5GHZ];

F
Franky Lin 已提交
2463
	freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
2464 2465 2466 2467 2468 2469 2470 2471
	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 已提交
2472
	brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
2473 2474 2475
	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);
2476

2477
	bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
2478
		0, notify_capability, notify_interval,
2479 2480
		notify_ie, notify_ielen, notify_signal, GFP_KERNEL);

2481 2482 2483 2484 2485
	if (!bss) {
		err = -ENOMEM;
		goto CleanUp;
	}

2486
	cfg80211_put_bss(wiphy, bss);
2487

2488 2489 2490 2491
CleanUp:

	kfree(buf);

2492
	brcmf_dbg(TRACE, "Exit\n");
2493 2494 2495 2496

	return err;
}

2497 2498
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,
				 struct brcmf_if *ifp)
H
Hante Meuleman 已提交
2499
{
2500
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);
2501
	struct brcmf_bss_info_le *bi;
2502
	struct brcmf_ssid *ssid;
2503
	const struct brcmf_tlv *tim;
2504 2505 2506 2507 2508 2509
	u16 beacon_interval;
	u8 dtim_period;
	size_t ie_len;
	u8 *ie;
	s32 err = 0;

2510
	brcmf_dbg(TRACE, "Enter\n");
2511
	if (brcmf_is_ibssmode(ifp->vif))
2512 2513
		return err;

2514
	ssid = &profile->ssid;
2515

2516
	*(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
2517
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
2518
				     cfg->extra_buf, WL_EXTRA_BUF_MAX);
2519
	if (err) {
2520
		brcmf_err("Could not get bss info %d\n", err);
2521 2522 2523
		goto update_bss_info_out;
	}

2524 2525
	bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
	err = brcmf_inform_single_bss(cfg, bi);
2526 2527 2528 2529 2530 2531 2532
	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);

2533
	tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
2534 2535 2536 2537 2538 2539 2540 2541 2542
	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;
2543
		err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
2544
		if (err) {
2545
			brcmf_err("wl dtim_assoc failed (%d)\n", err);
2546 2547 2548 2549 2550 2551
			goto update_bss_info_out;
		}
		dtim_period = (u8)var;
	}

update_bss_info_out:
2552
	brcmf_dbg(TRACE, "Exit");
2553 2554 2555
	return err;
}

H
Hante Meuleman 已提交
2556
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
2557
{
2558
	struct escan_info *escan = &cfg->escan_info;
2559

2560
	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2561
	if (cfg->scan_request) {
2562
		escan->escan_state = WL_ESCAN_STATE_IDLE;
2563
		brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
2564
	}
2565 2566
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2567 2568
}

H
Hante Meuleman 已提交
2569 2570
static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
{
2571 2572
	struct brcmf_cfg80211_info *cfg =
			container_of(work, struct brcmf_cfg80211_info,
H
Hante Meuleman 已提交
2573 2574
				     escan_timeout_work);

2575
	brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
H
Hante Meuleman 已提交
2576 2577 2578 2579
}

static void brcmf_escan_timeout(unsigned long data)
{
2580 2581
	struct brcmf_cfg80211_info *cfg =
			(struct brcmf_cfg80211_info *)data;
H
Hante Meuleman 已提交
2582

2583
	if (cfg->scan_request) {
2584
		brcmf_err("timer expired\n");
2585
		schedule_work(&cfg->escan_timeout_work);
H
Hante Meuleman 已提交
2586 2587 2588 2589
	}
}

static s32
F
Franky Lin 已提交
2590 2591
brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
			      struct brcmf_bss_info_le *bss,
H
Hante Meuleman 已提交
2592 2593
			      struct brcmf_bss_info_le *bss_info_le)
{
F
Franky Lin 已提交
2594 2595 2596 2597 2598 2599 2600
	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 已提交
2601
	if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
F
Franky Lin 已提交
2602
		ch_bss.band == ch_bss_info_le.band &&
H
Hante Meuleman 已提交
2603 2604
		bss_info_le->SSID_len == bss->SSID_len &&
		!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2605 2606
		if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) ==
			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {
2607 2608 2609
			s16 bss_rssi = le16_to_cpu(bss->RSSI);
			s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);

H
Hante Meuleman 已提交
2610 2611 2612
			/* preserve max RSSI if the measurements are
			* both on-channel or both off-channel
			*/
2613
			if (bss_info_rssi > bss_rssi)
H
Hante Meuleman 已提交
2614
				bss->RSSI = bss_info_le->RSSI;
2615 2616
		} else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) &&
			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {
H
Hante Meuleman 已提交
2617 2618 2619 2620
			/* preserve the on-channel rssi measurement
			* if the new measurement is off channel
			*/
			bss->RSSI = bss_info_le->RSSI;
2621
			bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;
H
Hante Meuleman 已提交
2622 2623 2624 2625 2626 2627 2628
		}
		return 1;
	}
	return 0;
}

static s32
2629
brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
H
Hante Meuleman 已提交
2630 2631
			     const struct brcmf_event_msg *e, void *data)
{
2632
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
H
Hante Meuleman 已提交
2633 2634 2635 2636 2637 2638 2639
	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;
2640
	bool aborted;
H
Hante Meuleman 已提交
2641

2642
	status = e->status;
H
Hante Meuleman 已提交
2643

2644 2645
	if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
		brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
H
Hante Meuleman 已提交
2646 2647 2648 2649
		return -EPERM;
	}

	if (status == BRCMF_E_STATUS_PARTIAL) {
2650
		brcmf_dbg(SCAN, "ESCAN Partial result\n");
H
Hante Meuleman 已提交
2651 2652
		escan_result_le = (struct brcmf_escan_result_le *) data;
		if (!escan_result_le) {
2653
			brcmf_err("Invalid escan result (NULL pointer)\n");
H
Hante Meuleman 已提交
2654 2655 2656
			goto exit;
		}
		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2657 2658
			brcmf_err("Invalid bss_count %d: ignoring\n",
				  escan_result_le->bss_count);
H
Hante Meuleman 已提交
2659 2660 2661 2662
			goto exit;
		}
		bss_info_le = &escan_result_le->bss_info_le;

2663 2664 2665 2666 2667 2668 2669 2670
		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 已提交
2671 2672 2673
		bi_length = le32_to_cpu(bss_info_le->length);
		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
					WL_ESCAN_RESULTS_FIXED_SIZE)) {
2674 2675
			brcmf_err("Invalid bss_info length %d: ignoring\n",
				  bi_length);
H
Hante Meuleman 已提交
2676 2677 2678
			goto exit;
		}

2679
		if (!(cfg_to_wiphy(cfg)->interface_modes &
H
Hante Meuleman 已提交
2680 2681 2682
					BIT(NL80211_IFTYPE_ADHOC))) {
			if (le16_to_cpu(bss_info_le->capability) &
						WLAN_CAPABILITY_IBSS) {
2683
				brcmf_err("Ignoring IBSS result\n");
H
Hante Meuleman 已提交
2684 2685 2686 2687 2688
				goto exit;
			}
		}

		list = (struct brcmf_scan_results *)
2689
				cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
2690
		if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2691
			brcmf_err("Buffer is too small: ignoring\n");
H
Hante Meuleman 已提交
2692 2693 2694 2695 2696 2697 2698
			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 已提交
2699 2700
			if (brcmf_compare_update_same_bss(cfg, bss,
							  bss_info_le))
H
Hante Meuleman 已提交
2701 2702
				goto exit;
		}
2703
		memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
H
Hante Meuleman 已提交
2704 2705 2706 2707 2708
			bss_info_le, bi_length);
		list->version = le32_to_cpu(bss_info_le->version);
		list->buflen += bi_length;
		list->count++;
	} else {
2709
		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2710 2711
		if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
			goto exit;
2712 2713 2714 2715
		if (cfg->scan_request) {
			cfg->bss_list = (struct brcmf_scan_results *)
				cfg->escan_info.escan_buf;
			brcmf_inform_bss(cfg);
2716
			aborted = status != BRCMF_E_STATUS_SUCCESS;
2717
			brcmf_notify_escan_complete(cfg, ifp, aborted,
2718
						    false);
H
Hante Meuleman 已提交
2719
		} else
2720 2721
			brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
				  status);
H
Hante Meuleman 已提交
2722 2723
	}
exit:
2724
	return 0;
H
Hante Meuleman 已提交
2725 2726
}

2727
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
H
Hante Meuleman 已提交
2728
{
2729 2730
	brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
			    brcmf_cfg80211_escan_handler);
2731 2732 2733 2734 2735 2736 2737
	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 已提交
2738 2739
}

2740
static __always_inline void brcmf_delay(u32 ms)
2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751
{
	if (ms < 1000 / HZ) {
		cond_resched();
		mdelay(ms);
	} else {
		msleep(ms);
	}
}

static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
2752
	brcmf_dbg(TRACE, "Enter\n");
2753 2754 2755 2756 2757 2758 2759

	return 0;
}

static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
				  struct cfg80211_wowlan *wow)
{
2760 2761
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
2762
	struct brcmf_cfg80211_vif *vif;
2763

2764
	brcmf_dbg(TRACE, "Enter\n");
2765 2766

	/*
2767 2768
	 * if the primary net_device is not READY there is nothing
	 * we can do but pray resume goes smoothly.
2769
	 */
2770 2771 2772
	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
	if (!check_vif_up(vif))
		goto exit;
2773

2774 2775 2776
	list_for_each_entry(vif, &cfg->vif_list, list) {
		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
			continue;
2777
		/*
2778 2779
		 * While going to suspend if associated with AP disassociate
		 * from AP to save power while system is in suspended state
2780
		 */
2781 2782 2783 2784 2785 2786 2787
		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);
2788 2789
	}

2790 2791
	/* end any scanning */
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
2792
		brcmf_abort_scanning(cfg);
2793 2794

	/* Turn off watchdog timer */
2795
	brcmf_set_mpc(netdev_priv(ndev), 1);
2796

2797
exit:
2798
	brcmf_dbg(TRACE, "Exit\n");
2799 2800
	/* clear any scanning activity */
	cfg->scan_status = 0;
2801 2802 2803 2804 2805 2806 2807 2808
	return 0;
}

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

2811 2812
	pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);

2813
	brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
2814
	for (i = 0; i < pmkid_len; i++) {
2815 2816
		brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
			  &pmk_list->pmkids.pmkid[i].BSSID);
2817
		for (j = 0; j < WLAN_PMKID_LEN; j++)
2818 2819
			brcmf_dbg(CONN, "%02x\n",
				  pmk_list->pmkids.pmkid[i].PMKID[j]);
2820 2821 2822
	}

	if (!err)
2823 2824
		brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
					 (char *)pmk_list, sizeof(*pmk_list));
2825 2826 2827 2828 2829 2830 2831 2832

	return err;
}

static s32
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
			 struct cfg80211_pmksa *pmksa)
{
2833
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2834
	struct brcmf_if *ifp = netdev_priv(ndev);
2835
	struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
2836 2837
	s32 err = 0;
	int i;
2838
	int pmkid_len;
2839

2840
	brcmf_dbg(TRACE, "Enter\n");
2841
	if (!check_vif_up(ifp->vif))
2842 2843
		return -EIO;

2844 2845
	pmkid_len = le32_to_cpu(pmkids->npmkid);
	for (i = 0; i < pmkid_len; i++)
2846 2847 2848 2849 2850
		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);
2851 2852 2853 2854
		if (i == pmkid_len) {
			pmkid_len++;
			pmkids->npmkid = cpu_to_le32(pmkid_len);
		}
2855 2856 2857
	} else
		err = -EINVAL;

2858 2859
	brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
		  pmkids->pmkid[pmkid_len].BSSID);
2860
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2861
		brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
2862

2863
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2864

2865
	brcmf_dbg(TRACE, "Exit\n");
2866 2867 2868 2869 2870 2871 2872
	return err;
}

static s32
brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_pmksa *pmksa)
{
2873
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2874
	struct brcmf_if *ifp = netdev_priv(ndev);
2875 2876
	struct pmkid_list pmkid;
	s32 err = 0;
2877
	int i, pmkid_len;
2878

2879
	brcmf_dbg(TRACE, "Enter\n");
2880
	if (!check_vif_up(ifp->vif))
2881 2882 2883 2884 2885
		return -EIO;

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

2886 2887
	brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
		  &pmkid.pmkid[0].BSSID);
2888
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2889
		brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
2890

2891
	pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
2892
	for (i = 0; i < pmkid_len; i++)
2893
		if (!memcmp
2894
		    (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
2895 2896 2897
		     ETH_ALEN))
			break;

2898 2899
	if ((pmkid_len > 0)
	    && (i < pmkid_len)) {
2900
		memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
2901
		       sizeof(struct pmkid));
2902
		for (; i < (pmkid_len - 1); i++) {
2903 2904
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
2905
			       ETH_ALEN);
2906 2907
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
2908 2909
			       WLAN_PMKID_LEN);
		}
2910
		cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
2911 2912 2913
	} else
		err = -EINVAL;

2914
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2915

2916
	brcmf_dbg(TRACE, "Exit\n");
2917 2918 2919 2920 2921 2922 2923
	return err;

}

static s32
brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
{
2924
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2925
	struct brcmf_if *ifp = netdev_priv(ndev);
2926 2927
	s32 err = 0;

2928
	brcmf_dbg(TRACE, "Enter\n");
2929
	if (!check_vif_up(ifp->vif))
2930 2931
		return -EIO;

2932 2933
	memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2934

2935
	brcmf_dbg(TRACE, "Exit\n");
2936 2937 2938 2939
	return err;

}

2940 2941 2942 2943 2944 2945 2946 2947 2948
/*
 * 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
2949
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
2950 2951
				const struct brcmf_event_msg *e, void *data)
{
2952
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
2953 2954 2955 2956
	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;
2957
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2958 2959 2960 2961 2962 2963 2964
	int err = 0;
	int channel_req = 0;
	int band = 0;
	struct brcmf_pno_scanresults_le *pfn_result;
	u32 result_count;
	u32 status;

2965
	brcmf_dbg(SCAN, "Enter\n");
2966

2967
	if (e->event_code == BRCMF_E_PFN_NET_LOST) {
2968
		brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980
		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);
2981
	brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
2982 2983 2984 2985
	if (result_count > 0) {
		int i;

		request = kzalloc(sizeof(*request), GFP_KERNEL);
2986 2987
		ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
		channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999
		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) {
3000 3001
				brcmf_err("Invalid netinfo ptr. index: %d\n",
					  i);
3002 3003 3004 3005
				err = -EINVAL;
				goto out_err;
			}

3006 3007
			brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
				  netinfo->SSID, netinfo->channel);
3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029
			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];

3030
		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3031
			/* Abort any on-going scan */
3032
			brcmf_abort_scanning(cfg);
3033 3034
		}

3035
		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3036
		cfg->escan_info.run = brcmf_run_escan;
3037
		err = brcmf_do_escan(cfg, wiphy, ifp, request);
3038
		if (err) {
3039
			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
3040 3041
			goto out_err;
		}
3042 3043
		cfg->sched_escan = true;
		cfg->scan_request = request;
3044
	} else {
3045
		brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
		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 */
3067
	ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
3068 3069
	if (ret == 0) {
		/* clear pfn */
3070 3071
		ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
					       NULL, 0);
3072 3073
	}
	if (ret < 0)
3074
		brcmf_err("failed code %d\n", ret);
3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093

	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);

3094 3095
	return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
					&pfn_param, sizeof(pfn_param));
3096 3097 3098 3099 3100 3101 3102
}

static int
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
				struct net_device *ndev,
				struct cfg80211_sched_scan_request *request)
{
3103
	struct brcmf_if *ifp = netdev_priv(ndev);
3104
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
3105 3106 3107 3108
	struct brcmf_pno_net_param_le pfn;
	int i;
	int ret = 0;

3109
	brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
3110
		  request->n_match_sets, request->n_ssids);
3111
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
3112
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
3113 3114
		return -EAGAIN;
	}
3115 3116 3117 3118 3119
	if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
		brcmf_err("Scanning suppressed: status (%lu)\n",
			  cfg->scan_status);
		return -EAGAIN;
	}
3120

3121
	if (!request->n_ssids || !request->n_match_sets) {
3122
		brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
3123
			  request->n_ssids);
3124 3125 3126 3127 3128 3129
		return -EINVAL;
	}

	if (request->n_ssids > 0) {
		for (i = 0; i < request->n_ssids; i++) {
			/* Active scan req for ssids */
3130 3131
			brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
				  request->ssids[i].ssid);
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143

			/*
			 * 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) {
3144
			brcmf_err("failed error=%d\n", ret);
3145 3146 3147 3148 3149 3150
			return ret;
		}

		/* configure pno */
		ret = brcmf_dev_pno_config(ndev);
		if (ret < 0) {
3151
			brcmf_err("PNO setup failed!! ret=%d\n", ret);
3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163
			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) {
3164
				brcmf_err("skip broadcast ssid\n");
3165 3166 3167 3168 3169 3170 3171 3172 3173
				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);
3174
			ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
3175
						       sizeof(pfn));
3176 3177
			brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
				  ret == 0 ? "set" : "failed", ssid->ssid);
3178 3179
		}
		/* Enable the PNO */
3180
		if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
3181
			brcmf_err("PNO enable failed!! ret=%d\n", ret);
3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	return 0;
}

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

3196
	brcmf_dbg(SCAN, "enter\n");
3197
	brcmf_dev_pno_clean(ndev);
3198
	if (cfg->sched_escan)
3199
		brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
3200 3201 3202
	return 0;
}

3203
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
H
Hante Meuleman 已提交
3204 3205 3206 3207
{
	s32 err;

	/* set auth */
3208
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
H
Hante Meuleman 已提交
3209
	if (err < 0) {
3210
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
3211 3212 3213
		return err;
	}
	/* set wsec */
3214
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
H
Hante Meuleman 已提交
3215
	if (err < 0) {
3216
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
3217 3218 3219
		return err;
	}
	/* set upper-layer auth */
3220
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
H
Hante Meuleman 已提交
3221
	if (err < 0) {
3222
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237
		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
3238 3239 3240
brcmf_configure_wpaie(struct net_device *ndev,
		      const struct brcmf_vs_tlv *wpa_ie,
		      bool is_rsn_ie)
H
Hante Meuleman 已提交
3241
{
3242
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256
	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;

3257
	brcmf_dbg(TRACE, "Enter\n");
H
Hante Meuleman 已提交
3258 3259 3260 3261 3262
	if (wpa_ie == NULL)
		goto exit;

	len = wpa_ie->len + TLV_HDR_LEN;
	data = (u8 *)wpa_ie;
3263
	offset = TLV_HDR_LEN;
H
Hante Meuleman 已提交
3264 3265
	if (!is_rsn_ie)
		offset += VS_IE_FIXED_HDR_LEN;
3266 3267
	else
		offset += WPA_IE_VERSION_LEN;
H
Hante Meuleman 已提交
3268 3269 3270 3271

	/* check for multicast cipher suite */
	if (offset + WPA_IE_MIN_OUI_LEN > len) {
		err = -EINVAL;
3272
		brcmf_err("no multicast cipher suite\n");
H
Hante Meuleman 已提交
3273 3274 3275 3276 3277
		goto exit;
	}

	if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
		err = -EINVAL;
3278
		brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299
		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;
3300
		brcmf_err("Invalid multi cast cipher info\n");
H
Hante Meuleman 已提交
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310
		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;
3311
		brcmf_err("no unicast cipher suite\n");
H
Hante Meuleman 已提交
3312 3313 3314 3315 3316
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3317
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334
			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:
3335
			brcmf_err("Ivalid unicast security info\n");
H
Hante Meuleman 已提交
3336 3337 3338 3339 3340 3341 3342 3343 3344
		}
		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;
3345
		brcmf_err("no auth key mgmt suite\n");
H
Hante Meuleman 已提交
3346 3347 3348 3349 3350
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3351
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3352 3353 3354 3355 3356
			goto exit;
		}
		offset += TLV_OUI_LEN;
		switch (data[offset]) {
		case RSN_AKM_NONE:
3357
			brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
H
Hante Meuleman 已提交
3358 3359 3360
			wpa_auth |= WPA_AUTH_NONE;
			break;
		case RSN_AKM_UNSPECIFIED:
3361
			brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
H
Hante Meuleman 已提交
3362 3363 3364 3365
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
				    (wpa_auth |= WPA_AUTH_UNSPECIFIED);
			break;
		case RSN_AKM_PSK:
3366
			brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
H
Hante Meuleman 已提交
3367 3368 3369 3370
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
				    (wpa_auth |= WPA_AUTH_PSK);
			break;
		default:
3371
			brcmf_err("Ivalid key mgmt info\n");
H
Hante Meuleman 已提交
3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383
		}
		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 */
3384
		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
3385
					       wme_bss_disable);
H
Hante Meuleman 已提交
3386
		if (err < 0) {
3387
			brcmf_err("wme_bss_disable error %d\n", err);
H
Hante Meuleman 已提交
3388 3389 3390 3391 3392 3393 3394
			goto exit;
		}
	}
	/* FOR WPS , set SES_OW_ENABLED */
	wsec = (pval | gval | SES_OW_ENABLED);

	/* set auth */
3395
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
H
Hante Meuleman 已提交
3396
	if (err < 0) {
3397
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
3398 3399 3400
		goto exit;
	}
	/* set wsec */
3401
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
H
Hante Meuleman 已提交
3402
	if (err < 0) {
3403
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
3404 3405 3406
		goto exit;
	}
	/* set upper-layer auth */
3407
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
H
Hante Meuleman 已提交
3408
	if (err < 0) {
3409
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
3410 3411 3412 3413 3414 3415 3416 3417
		goto exit;
	}

exit:
	return err;
}

static s32
3418
brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
H
Hante Meuleman 已提交
3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
		     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)) {
3436 3437
			brcmf_err("invalid vndr ie. length is too small %d\n",
				  vndrie->len);
H
Hante Meuleman 已提交
3438 3439 3440 3441 3442 3443
			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))) {
3444
			brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
H
Hante Meuleman 已提交
3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456
			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++;

3457 3458 3459 3460 3461
		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 已提交
3462

3463
		if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT)
H
Hante Meuleman 已提交
3464 3465
			break;
next:
3466 3467
		remaining_len -= (ie->len + TLV_HDR_LEN);
		if (remaining_len <= TLV_HDR_LEN)
H
Hante Meuleman 已提交
3468 3469
			ie = NULL;
		else
3470 3471
			ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
				TLV_HDR_LEN);
H
Hante Meuleman 已提交
3472
	}
3473
	return 0;
H
Hante Meuleman 已提交
3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496
}

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

3497 3498
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 已提交
3499
{
3500 3501
	struct brcmf_if *ifp;
	struct vif_saved_ie *saved_ie;
H
Hante Meuleman 已提交
3502 3503 3504 3505
	s32 err = 0;
	u8  *iovar_ie_buf;
	u8  *curr_ie_buf;
	u8  *mgmt_ie_buf = NULL;
3506
	int mgmt_ie_buf_len;
3507
	u32 *mgmt_ie_len;
H
Hante Meuleman 已提交
3508 3509 3510 3511 3512 3513 3514 3515
	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;
3516
	int remained_buf_len;
H
Hante Meuleman 已提交
3517

3518 3519 3520 3521 3522
	if (!vif)
		return -ENODEV;
	ifp = vif->ifp;
	saved_ie = &vif->saved_ie;

3523
	brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
H
Hante Meuleman 已提交
3524 3525 3526 3527
	iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!iovar_ie_buf)
		return -ENOMEM;
	curr_ie_buf = iovar_ie_buf;
3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
	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 已提交
3553 3554 3555 3556
	}

	if (vndr_ie_len > mgmt_ie_buf_len) {
		err = -ENOMEM;
3557
		brcmf_err("extra IE size too big\n");
H
Hante Meuleman 已提交
3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572
		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;
		}
	}

3573
	if (mgmt_ie_buf && *mgmt_ie_len) {
H
Hante Meuleman 已提交
3574 3575 3576
		if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
		    (memcmp(mgmt_ie_buf, curr_ie_buf,
			    parsed_ie_buf_len) == 0)) {
3577
			brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
H
Hante Meuleman 已提交
3578 3579 3580 3581 3582 3583 3584 3585 3586 3587
			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];

3588 3589 3590 3591 3592 3593
			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 已提交
3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614

			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];

3615 3616 3617
			/* verify remained buf size before copy data */
			if (remained_buf_len < (vndrie_info->vndrie.len +
							VNDR_IE_VSIE_OFFSET)) {
3618 3619
				brcmf_err("no space in mgmt_ie_buf: len left %d",
					  remained_buf_len);
3620 3621 3622 3623 3624
				break;
			}
			remained_buf_len -= (vndrie_info->ie_len +
					     VNDR_IE_VSIE_OFFSET);

3625 3626 3627 3628 3629 3630
			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 已提交
3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646

			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) {
3647
		err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
3648
						 total_ie_buf_len);
H
Hante Meuleman 已提交
3649
		if (err)
3650
			brcmf_err("vndr ie set error : %d\n", err);
H
Hante Meuleman 已提交
3651 3652 3653 3654 3655 3656 3657
	}

exit:
	kfree(iovar_ie_buf);
	return err;
}

3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673
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;
}

3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700
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 已提交
3701 3702 3703 3704 3705
static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
			struct cfg80211_ap_settings *settings)
{
	s32 ie_offset;
3706
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3707
	struct brcmf_if *ifp = netdev_priv(ndev);
3708
	const struct brcmf_tlv *ssid_ie;
H
Hante Meuleman 已提交
3709 3710
	struct brcmf_ssid_le ssid_le;
	s32 err = -EPERM;
3711 3712
	const struct brcmf_tlv *rsn_ie;
	const struct brcmf_vs_tlv *wpa_ie;
H
Hante Meuleman 已提交
3713
	struct brcmf_join_params join_params;
3714 3715
	enum nl80211_iftype dev_role;
	struct brcmf_fil_bss_enable_le bss_enable;
3716
	u16 chanspec;
H
Hante Meuleman 已提交
3717

3718 3719 3720
	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,
3721
		  settings->beacon_interval, settings->dtim_period);
3722 3723 3724
	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 已提交
3725

3726
	dev_role = ifp->vif->wdev.iftype;
H
Hante Meuleman 已提交
3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739

	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);
3740
		brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
H
Hante Meuleman 已提交
3741 3742 3743 3744 3745
	} else {
		memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
		ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
	}

3746
	brcmf_set_mpc(ifp, 0);
3747
	brcmf_configure_arp_offload(ifp, false);
H
Hante Meuleman 已提交
3748 3749 3750 3751 3752 3753 3754 3755 3756 3757

	/* 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)) {
3758
		brcmf_dbg(TRACE, "WPA(2) IE is found\n");
H
Hante Meuleman 已提交
3759 3760
		if (wpa_ie != NULL) {
			/* WPA IE */
3761
			err = brcmf_configure_wpaie(ndev, wpa_ie, false);
H
Hante Meuleman 已提交
3762 3763 3764 3765 3766
			if (err < 0)
				goto exit;
		} else {
			/* RSN IE */
			err = brcmf_configure_wpaie(ndev,
3767
				(struct brcmf_vs_tlv *)rsn_ie, true);
H
Hante Meuleman 已提交
3768 3769 3770 3771
			if (err < 0)
				goto exit;
		}
	} else {
3772
		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
3773
		brcmf_configure_opensecurity(ifp);
H
Hante Meuleman 已提交
3774 3775
	}

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

3778
	chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef);
3779
	err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
3780
	if (err < 0) {
3781
		brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err);
3782 3783 3784
		goto exit;
	}

H
Hante Meuleman 已提交
3785
	if (settings->beacon_interval) {
3786
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
3787
					    settings->beacon_interval);
H
Hante Meuleman 已提交
3788
		if (err < 0) {
3789
			brcmf_err("Beacon Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3790 3791 3792 3793
			goto exit;
		}
	}
	if (settings->dtim_period) {
3794
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
3795
					    settings->dtim_period);
H
Hante Meuleman 已提交
3796
		if (err < 0) {
3797
			brcmf_err("DTIM Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3798 3799 3800
			goto exit;
		}
	}
3801 3802 3803 3804 3805 3806 3807

	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;
		}
3808
		brcmf_fil_iovar_int_set(ifp, "apsta", 0);
H
Hante Meuleman 已提交
3809 3810
	}

3811
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
H
Hante Meuleman 已提交
3812
	if (err < 0) {
3813
		brcmf_err("SET INFRA error %d\n", err);
H
Hante Meuleman 已提交
3814 3815
		goto exit;
	}
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856
	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");
	}
3857 3858
	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 已提交
3859 3860

exit:
3861
	if (err) {
3862
		brcmf_set_mpc(ifp, 1);
3863 3864
		brcmf_configure_arp_offload(ifp, true);
	}
H
Hante Meuleman 已提交
3865 3866 3867 3868 3869
	return err;
}

static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
3870
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3871
	s32 err;
3872
	struct brcmf_fil_bss_enable_le bss_enable;
H
Hante Meuleman 已提交
3873
	struct brcmf_join_params join_params;
H
Hante Meuleman 已提交
3874

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

3877
	if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) {
H
Hante Meuleman 已提交
3878 3879 3880
		/* Due to most likely deauths outstanding we sleep */
		/* first to make sure they get processed by fw. */
		msleep(400);
H
Hante Meuleman 已提交
3881 3882 3883 3884 3885 3886

		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);
3887
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
H
Hante Meuleman 已提交
3888
		if (err < 0)
3889
			brcmf_err("BRCMF_C_UP error %d\n", err);
H
Hante Meuleman 已提交
3890 3891 3892 3893 3894 3895
		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);
3896 3897 3898 3899 3900 3901 3902
	} 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 已提交
3903
	}
3904
	brcmf_set_mpc(ifp, 1);
3905
	brcmf_configure_arp_offload(ifp, true);
3906 3907 3908
	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 已提交
3909 3910 3911
	return err;
}

3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925
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 已提交
3926 3927
static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
3928
			   const u8 *mac)
H
Hante Meuleman 已提交
3929
{
3930
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
H
Hante Meuleman 已提交
3931
	struct brcmf_scb_val_le scbval;
3932
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3933 3934 3935 3936 3937
	s32 err;

	if (!mac)
		return -EFAULT;

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

3940 3941
	if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
		ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
3942
	if (!check_vif_up(ifp->vif))
H
Hante Meuleman 已提交
3943 3944 3945 3946
		return -EIO;

	memcpy(&scbval.ea, mac, ETH_ALEN);
	scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
3947
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
3948
				     &scbval, sizeof(scbval));
H
Hante Meuleman 已提交
3949
	if (err)
3950
		brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
3951

3952
	brcmf_dbg(TRACE, "Exit\n");
H
Hante Meuleman 已提交
3953 3954 3955
	return err;
}

3956 3957 3958 3959 3960 3961

static void
brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
				   struct wireless_dev *wdev,
				   u16 frame_type, bool reg)
{
3962
	struct brcmf_cfg80211_vif *vif;
3963 3964 3965 3966 3967
	u16 mgmt_type;

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

	mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
3968
	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
3969 3970 3971
	if (reg)
		vif->mgmt_rx_reg |= BIT(mgmt_type);
	else
3972
		vif->mgmt_rx_reg &= ~BIT(mgmt_type);
3973 3974 3975 3976 3977
}


static int
brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
3978
		       struct cfg80211_mgmt_tx_params *params, u64 *cookie)
3979 3980
{
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
3981 3982 3983
	struct ieee80211_channel *chan = params->chan;
	const u8 *buf = params->buf;
	size_t len = params->len;
3984 3985 3986 3987 3988
	const struct ieee80211_mgmt *mgmt;
	struct brcmf_cfg80211_vif *vif;
	s32 err = 0;
	s32 ie_offset;
	s32 ie_len;
H
Hante Meuleman 已提交
3989 3990 3991 3992
	struct brcmf_fil_action_frame_le *action_frame;
	struct brcmf_fil_af_params_le *af_params;
	bool ack;
	s32 chan_nr;
3993
	u32 freq;
3994 3995 3996 3997 3998 3999 4000

	brcmf_dbg(TRACE, "Enter\n");

	*cookie = 0;

	mgmt = (const struct ieee80211_mgmt *)buf;

4001 4002 4003 4004
	if (!ieee80211_is_mgmt(mgmt->frame_control)) {
		brcmf_err("Driver only allows MGMT packet type\n");
		return -EPERM;
	}
4005

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

4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023
	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)
4024
			vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
4025 4026 4027 4028 4029 4030
		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 已提交
4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045
	} 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);
4046 4047 4048 4049 4050 4051 4052 4053 4054
		/* 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 已提交
4055 4056 4057 4058 4059 4060
		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",
4061
			  *cookie, le16_to_cpu(action_frame->len), freq);
H
Hante Meuleman 已提交
4062

4063
		ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
H
Hante Meuleman 已提交
4064 4065 4066 4067 4068
						  af_params);

		cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
					GFP_KERNEL);
		kfree(af_params);
4069 4070 4071
	} else {
		brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control);
		brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len);
4072
	}
4073

H
Hante Meuleman 已提交
4074
exit:
4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100
	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;
}

4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133
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);
}

4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155
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,
4156
				    struct net_device *ndev, const u8 *peer,
4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180
				    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;
}

4181
static struct cfg80211_ops wl_cfg80211_ops = {
4182 4183
	.add_virtual_intf = brcmf_cfg80211_add_iface,
	.del_virtual_intf = brcmf_cfg80211_del_iface,
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203
	.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,
4204
	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
H
Hante Meuleman 已提交
4205 4206
	.start_ap = brcmf_cfg80211_start_ap,
	.stop_ap = brcmf_cfg80211_stop_ap,
4207
	.change_beacon = brcmf_cfg80211_change_beacon,
H
Hante Meuleman 已提交
4208
	.del_station = brcmf_cfg80211_del_station,
4209 4210
	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
4211 4212 4213 4214
	.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,
4215 4216
	.start_p2p_device = brcmf_p2p_start_device,
	.stop_p2p_device = brcmf_p2p_stop_device,
4217 4218
	.crit_proto_start = brcmf_cfg80211_crit_proto_start,
	.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
4219
	.tdls_oper = brcmf_cfg80211_tdls_oper,
4220 4221
};

4222
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
4223 4224
					   enum nl80211_iftype type,
					   bool pm_block)
4225 4226
{
	struct brcmf_cfg80211_vif *vif;
4227

4228
	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
4229
		  sizeof(*vif));
4230 4231 4232 4233 4234
	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
	if (!vif)
		return ERR_PTR(-ENOMEM);

	vif->wdev.wiphy = cfg->wiphy;
4235
	vif->wdev.iftype = type;
4236

4237 4238 4239
	vif->pm_block = pm_block;
	vif->roam_off = -1;

4240 4241
	brcmf_init_prof(&vif->profile);

4242 4243
	list_add_tail(&vif->list, &cfg->vif_list);
	return vif;
4244 4245
}

4246
void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
4247
{
4248 4249
	list_del(&vif->list);
	kfree(vif);
4250 4251
}

4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263
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);
}

4264
static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
4265
{
4266 4267
	u32 event = e->event_code;
	u32 status = e->status;
4268 4269

	if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
4270
		brcmf_dbg(CONN, "Processing set ssid\n");
4271 4272 4273 4274 4275 4276
		return true;
	}

	return false;
}

4277
static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
4278
{
4279 4280
	u32 event = e->event_code;
	u16 flags = e->flags;
4281

4282 4283 4284
	if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) ||
	    (event == BRCMF_E_DISASSOC_IND) ||
	    ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {
4285
		brcmf_dbg(CONN, "Processing link down\n");
4286 4287 4288 4289 4290
		return true;
	}
	return false;
}

4291
static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
4292 4293
			       const struct brcmf_event_msg *e)
{
4294 4295
	u32 event = e->event_code;
	u32 status = e->status;
4296 4297

	if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
4298 4299
		brcmf_dbg(CONN, "Processing Link %s & no network found\n",
			  e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
4300 4301 4302 4303
		return true;
	}

	if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
4304
		brcmf_dbg(CONN, "Processing connecting & no network found\n");
4305 4306 4307 4308 4309 4310
		return true;
	}

	return false;
}

4311
static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
4312
{
4313
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4314 4315 4316 4317 4318 4319 4320 4321 4322

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

4323 4324
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
			       struct brcmf_if *ifp)
4325
{
4326
	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
4327
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4328 4329 4330 4331
	u32 req_len;
	u32 resp_len;
	s32 err = 0;

4332
	brcmf_clear_assoc_ies(cfg);
4333

4334 4335
	err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
				       cfg->extra_buf, WL_ASSOC_INFO_MAX);
4336
	if (err) {
4337
		brcmf_err("could not get assoc info (%d)\n", err);
4338 4339
		return err;
	}
4340
	assoc_info =
4341
		(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
4342 4343
	req_len = le32_to_cpu(assoc_info->req_len);
	resp_len = le32_to_cpu(assoc_info->resp_len);
4344
	if (req_len) {
4345
		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
4346 4347
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
4348
		if (err) {
4349
			brcmf_err("could not get assoc req (%d)\n", err);
4350 4351 4352 4353
			return err;
		}
		conn_info->req_ie_len = req_len;
		conn_info->req_ie =
4354
		    kmemdup(cfg->extra_buf, conn_info->req_ie_len,
4355 4356 4357 4358 4359 4360
			    GFP_KERNEL);
	} else {
		conn_info->req_ie_len = 0;
		conn_info->req_ie = NULL;
	}
	if (resp_len) {
4361
		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
4362 4363
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
4364
		if (err) {
4365
			brcmf_err("could not get assoc resp (%d)\n", err);
4366 4367 4368 4369
			return err;
		}
		conn_info->resp_ie_len = resp_len;
		conn_info->resp_ie =
4370
		    kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
4371 4372 4373 4374 4375
			    GFP_KERNEL);
	} else {
		conn_info->resp_ie_len = 0;
		conn_info->resp_ie = NULL;
	}
4376 4377
	brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
		  conn_info->req_ie_len, conn_info->resp_ie_len);
4378 4379 4380 4381 4382

	return err;
}

static s32
4383
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
4384 4385 4386
		       struct net_device *ndev,
		       const struct brcmf_event_msg *e)
{
4387 4388
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4389 4390
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
4391
	struct ieee80211_channel *notify_channel = NULL;
4392
	struct ieee80211_supported_band *band;
4393
	struct brcmf_bss_info_le *bi;
F
Franky Lin 已提交
4394
	struct brcmu_chan ch;
4395 4396
	u32 freq;
	s32 err = 0;
4397
	u8 *buf;
4398

4399
	brcmf_dbg(TRACE, "Enter\n");
4400

4401
	brcmf_get_assoc_ies(cfg, ifp);
4402
	memcpy(profile->bssid, e->addr, ETH_ALEN);
4403
	brcmf_update_bss_info(cfg, ifp);
4404

4405 4406 4407 4408 4409 4410 4411 4412
	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);
4413
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
4414
				     buf, WL_BSS_INFO_MAX);
4415 4416 4417

	if (err)
		goto done;
4418

4419
	bi = (struct brcmf_bss_info_le *)(buf + 4);
F
Franky Lin 已提交
4420 4421
	ch.chspec = le16_to_cpu(bi->chanspec);
	cfg->d11inf.decchspec(&ch);
4422

F
Franky Lin 已提交
4423
	if (ch.band == BRCMU_CHAN_BAND_2G)
4424 4425 4426 4427
		band = wiphy->bands[IEEE80211_BAND_2GHZ];
	else
		band = wiphy->bands[IEEE80211_BAND_5GHZ];

F
Franky Lin 已提交
4428
	freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
4429 4430
	notify_channel = ieee80211_get_channel(wiphy, freq);

4431 4432
done:
	kfree(buf);
4433
	cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
4434 4435
			conn_info->req_ie, conn_info->req_ie_len,
			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4436
	brcmf_dbg(CONN, "Report roaming result\n");
4437

4438
	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
4439
	brcmf_dbg(TRACE, "Exit\n");
4440 4441 4442 4443
	return err;
}

static s32
4444
brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
4445 4446 4447
		       struct net_device *ndev, const struct brcmf_event_msg *e,
		       bool completed)
{
4448 4449
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4450
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
4451

4452
	brcmf_dbg(TRACE, "Enter\n");
4453

4454 4455
	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
			       &ifp->vif->sme_state)) {
4456
		if (completed) {
4457
			brcmf_get_assoc_ies(cfg, ifp);
4458
			memcpy(profile->bssid, e->addr, ETH_ALEN);
4459 4460 4461
			brcmf_update_bss_info(cfg, ifp);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
4462 4463
		}
		cfg80211_connect_result(ndev,
4464
					(u8 *)profile->bssid,
4465 4466 4467 4468 4469 4470 4471
					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);
4472 4473
		brcmf_dbg(CONN, "Report connect result - connection %s\n",
			  completed ? "succeeded" : "failed");
4474
	}
4475
	brcmf_dbg(TRACE, "Exit\n");
4476
	return 0;
4477 4478 4479
}

static s32
4480
brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
H
Hante Meuleman 已提交
4481 4482 4483
			       struct net_device *ndev,
			       const struct brcmf_event_msg *e, void *data)
{
4484
	static int generation;
4485 4486
	u32 event = e->event_code;
	u32 reason = e->reason;
H
Hante Meuleman 已提交
4487 4488
	struct station_info sinfo;

4489
	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
4490 4491 4492 4493 4494 4495
	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 已提交
4496 4497

	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4498 4499
	    (reason == BRCMF_E_STATUS_SUCCESS)) {
		memset(&sinfo, 0, sizeof(sinfo));
H
Hante Meuleman 已提交
4500 4501
		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
		if (!data) {
4502
			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
H
Hante Meuleman 已提交
4503 4504 4505
			return -EINVAL;
		}
		sinfo.assoc_req_ies = data;
4506
		sinfo.assoc_req_ies_len = e->datalen;
H
Hante Meuleman 已提交
4507 4508
		generation++;
		sinfo.generation = generation;
4509
		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
H
Hante Meuleman 已提交
4510 4511 4512
	} else if ((event == BRCMF_E_DISASSOC_IND) ||
		   (event == BRCMF_E_DEAUTH_IND) ||
		   (event == BRCMF_E_DEAUTH)) {
4513
		cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
H
Hante Meuleman 已提交
4514
	}
4515
	return 0;
H
Hante Meuleman 已提交
4516 4517
}

4518
static s32
4519
brcmf_notify_connect_status(struct brcmf_if *ifp,
4520 4521
			    const struct brcmf_event_msg *e, void *data)
{
4522 4523
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct net_device *ndev = ifp->ndev;
4524
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4525
	struct ieee80211_channel *chan;
4526 4527
	s32 err = 0;

4528
	if (brcmf_is_apmode(ifp->vif)) {
4529
		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4530
	} else if (brcmf_is_linkup(e)) {
4531
		brcmf_dbg(CONN, "Linkup\n");
4532
		if (brcmf_is_ibssmode(ifp->vif)) {
4533
			chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);
4534
			memcpy(profile->bssid, e->addr, ETH_ALEN);
4535
			wl_inform_ibss(cfg, ndev, e->addr);
4536
			cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);
4537 4538 4539 4540
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
4541
		} else
4542
			brcmf_bss_connect_done(cfg, ndev, e, true);
4543
	} else if (brcmf_is_linkdown(e)) {
4544
		brcmf_dbg(CONN, "Linkdown\n");
4545
		if (!brcmf_is_ibssmode(ifp->vif)) {
4546
			brcmf_bss_connect_done(cfg, ndev, e, false);
4547
		}
4548
		brcmf_link_down(ifp->vif);
4549
		brcmf_init_prof(ndev_to_prof(ndev));
4550 4551
		if (ndev != cfg_to_ndev(cfg))
			complete(&cfg->vif_disabled);
4552
	} else if (brcmf_is_nonetwork(cfg, e)) {
4553
		if (brcmf_is_ibssmode(ifp->vif))
4554 4555
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
4556
		else
4557
			brcmf_bss_connect_done(cfg, ndev, e, false);
4558 4559 4560 4561 4562 4563
	}

	return err;
}

static s32
4564
brcmf_notify_roaming_status(struct brcmf_if *ifp,
4565 4566
			    const struct brcmf_event_msg *e, void *data)
{
4567
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4568 4569
	u32 event = e->event_code;
	u32 status = e->status;
4570 4571

	if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
4572
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
4573
			brcmf_bss_roaming_done(cfg, ifp->ndev, e);
4574
		else
4575
			brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
4576 4577
	}

4578
	return 0;
4579 4580 4581
}

static s32
4582
brcmf_notify_mic_status(struct brcmf_if *ifp,
4583 4584
			const struct brcmf_event_msg *e, void *data)
{
4585
	u16 flags = e->flags;
4586 4587 4588 4589 4590 4591 4592
	enum nl80211_key_type key_type;

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

4593
	cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
4594 4595 4596 4597 4598
				     NULL, GFP_KERNEL);

	return 0;
}

4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617
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 */
4618 4619
		if (!cfg->vif_event.vif) {
			mutex_unlock(&event->vif_event_lock);
4620
			return -EBADF;
4621
		}
4622 4623 4624

		ifp->vif = vif;
		vif->ifp = ifp;
4625 4626 4627 4628 4629
		if (ifp->ndev) {
			vif->wdev.netdev = ifp->ndev;
			ifp->ndev->ieee80211_ptr = &vif->wdev;
			SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
		}
4630 4631
		mutex_unlock(&event->vif_event_lock);
		wake_up(&event->vif_wq);
4632
		return 0;
4633 4634 4635 4636 4637 4638 4639 4640

	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;

4641 4642 4643 4644 4645
	case BRCMF_E_IF_CHANGE:
		mutex_unlock(&event->vif_event_lock);
		wake_up(&event->vif_wq);
		return 0;

4646 4647 4648 4649 4650 4651 4652
	default:
		mutex_unlock(&event->vif_event_lock);
		break;
	}
	return -EINVAL;
}

4653 4654 4655 4656 4657 4658 4659 4660 4661
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;
}

4662
static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
4663
{
4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683
	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);
4684 4685
	brcmf_fweh_register(cfg->pub, BRCMF_E_IF,
			    brcmf_notify_vif_event);
4686
	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG,
4687
			    brcmf_p2p_notify_rx_mgmt_p2p_probereq);
4688 4689
	brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE,
			    brcmf_p2p_notify_listen_complete);
4690 4691
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX,
			    brcmf_p2p_notify_action_frame_rx);
H
Hante Meuleman 已提交
4692 4693
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE,
			    brcmf_p2p_notify_action_tx_complete);
4694 4695
	brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
			    brcmf_p2p_notify_action_tx_complete);
4696 4697
}

4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713
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)
4714
		goto init_priv_mem_out;
4715 4716
	cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
	if (!cfg->escan_ioctl_buf)
H
Hante Meuleman 已提交
4717
		goto init_priv_mem_out;
4718 4719
	cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!cfg->extra_buf)
4720
		goto init_priv_mem_out;
4721 4722
	cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
	if (!cfg->pmk_list)
4723 4724 4725 4726 4727
		goto init_priv_mem_out;

	return 0;

init_priv_mem_out:
4728
	brcmf_deinit_priv_mem(cfg);
4729 4730 4731 4732

	return -ENOMEM;
}

4733
static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4734 4735 4736
{
	s32 err = 0;

4737 4738
	cfg->scan_request = NULL;
	cfg->pwr_save = true;
4739 4740
	cfg->active_scan = true;	/* we do active scan per default */
	cfg->dongle_up = false;		/* dongle is not up yet */
4741
	err = brcmf_init_priv_mem(cfg);
4742 4743
	if (err)
		return err;
4744
	brcmf_register_event_handlers(cfg);
4745 4746 4747
	mutex_init(&cfg->usr_sync);
	brcmf_init_escan(cfg);
	brcmf_init_conf(cfg->conf);
4748
	init_completion(&cfg->vif_disabled);
4749 4750 4751
	return err;
}

4752
static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
4753
{
4754 4755 4756
	cfg->dongle_up = false;	/* dongle down */
	brcmf_abort_scanning(cfg);
	brcmf_deinit_priv_mem(cfg);
4757 4758
}

4759 4760 4761 4762 4763 4764
static void init_vif_event(struct brcmf_cfg80211_vif_event *event)
{
	init_waitqueue_head(&event->vif_wq);
	mutex_init(&event->vif_event_lock);
}

4765
static s32
4766
brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)
4767 4768
{
	s32 err = 0;
4769 4770
	__le32 roamtrigger[2];
	__le32 roam_delta[2];
4771 4772 4773 4774 4775

	/*
	 * Setup timeout if Beacons are lost and roam is
	 * off to report link down
	 */
4776
	if (brcmf_roamoff) {
4777
		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
4778
		if (err) {
4779
			brcmf_err("bcn_timeout error (%d)\n", err);
4780 4781 4782 4783 4784 4785 4786 4787
			goto dongle_rom_out;
		}
	}

	/*
	 * Enable/Disable built-in roaming to allow supplicant
	 * to take care of roaming
	 */
4788 4789 4790
	brcmf_dbg(INFO, "Internal Roaming = %s\n",
		  brcmf_roamoff ? "Off" : "On");
	err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));
4791
	if (err) {
4792
		brcmf_err("roam_off error (%d)\n", err);
4793 4794 4795
		goto dongle_rom_out;
	}

4796 4797
	roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
	roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
4798
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
4799
				     (void *)roamtrigger, sizeof(roamtrigger));
4800
	if (err) {
4801
		brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
4802 4803 4804
		goto dongle_rom_out;
	}

4805 4806
	roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
	roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
4807
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
4808
				     (void *)roam_delta, sizeof(roam_delta));
4809
	if (err) {
4810
		brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
4811 4812 4813 4814 4815 4816 4817 4818
		goto dongle_rom_out;
	}

dongle_rom_out:
	return err;
}

static s32
4819
brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
4820
		      s32 scan_unassoc_time, s32 scan_passive_time)
4821 4822 4823
{
	s32 err = 0;

4824
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
4825
				    scan_assoc_time);
4826 4827
	if (err) {
		if (err == -EOPNOTSUPP)
4828
			brcmf_dbg(INFO, "Scan assoc time is not supported\n");
4829
		else
4830
			brcmf_err("Scan assoc time error (%d)\n", err);
4831 4832
		goto dongle_scantime_out;
	}
4833
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
4834
				    scan_unassoc_time);
4835 4836
	if (err) {
		if (err == -EOPNOTSUPP)
4837
			brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
4838
		else
4839
			brcmf_err("Scan unassoc time error (%d)\n", err);
4840 4841 4842
		goto dongle_scantime_out;
	}

4843
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
4844
				    scan_passive_time);
4845 4846
	if (err) {
		if (err == -EOPNOTSUPP)
4847
			brcmf_dbg(INFO, "Scan passive time is not supported\n");
4848
		else
4849
			brcmf_err("Scan passive time error (%d)\n", err);
4850 4851 4852 4853 4854 4855 4856
		goto dongle_scantime_out;
	}

dongle_scantime_out:
	return err;
}

4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894
/* 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;
4895

4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913
	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[])
4914 4915
{
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
4916 4917 4918
	struct ieee80211_supported_band *band;
	struct ieee80211_channel *channel;
	struct wiphy *wiphy;
4919
	struct brcmf_chanspec_list *list;
F
Franky Lin 已提交
4920
	struct brcmu_chan ch;
4921
	int err;
4922 4923 4924
	u8 *pbuf;
	u32 i, j;
	u32 total;
4925 4926
	u32 chaninfo;
	u32 chcnt[2] = { 0, 0 };
4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939
	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);
4940
		goto fail_pbuf;
4941 4942
	}

4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978
	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;
	}
4979 4980 4981

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

F
Franky Lin 已提交
4985
		if (ch.band == BRCMU_CHAN_BAND_2G) {
4986
			band = wiphy->bands[IEEE80211_BAND_2GHZ];
F
Franky Lin 已提交
4987
		} else if (ch.band == BRCMU_CHAN_BAND_5G) {
4988
			band = wiphy->bands[IEEE80211_BAND_5GHZ];
4989
		} else {
4990
			brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
4991 4992
			continue;
		}
4993
		if (!(bw_cap[band->band] & WLC_BW_40MHZ_BIT) &&
4994
		    ch.bw == BRCMU_CHAN_BW_40)
4995
			continue;
4996
		if (!(bw_cap[band->band] & WLC_BW_80MHZ_BIT) &&
4997 4998
		    ch.bw == BRCMU_CHAN_BW_80)
			continue;
4999 5000 5001 5002 5003 5004

		channel = band->channels;
		index = band->n_channels;
		for (j = 0; j < band->n_channels; j++) {
			if (channel[j].hw_value == ch.chnum) {
				index = j;
5005 5006 5007
				break;
			}
		}
5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022
		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.
5023
			 */
5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038
			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;
5039 5040
			}
		}
5041 5042
		if (index == band->n_channels)
			band->n_channels++;
5043
	}
5044 5045 5046 5047 5048 5049 5050 5051
	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:
5052 5053 5054 5055
	kfree(pbuf);
	return err;
}

5056
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg)
5057
{
5058 5059
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
	struct ieee80211_supported_band *band;
5060
	struct brcmf_fil_bwcap_le band_bwcap;
5061 5062
	struct brcmf_chanspec_list *list;
	u8 *pbuf;
5063 5064
	u32 val;
	int err;
5065 5066 5067
	struct brcmu_chan ch;
	u32 num_chan;
	int i, j;
5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083

	/* 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);
	}
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127

	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);
		}
	}
5128 5129 5130
	return err;
}

5131 5132 5133 5134 5135 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
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");
	}
}
5171

5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 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
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;
}

5221
static int brcmf_setup_wiphybands(struct wiphy *wiphy)
5222
{
5223
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
5224
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
5225 5226
	u32 nmode = 0;
	u32 vhtmode = 0;
5227
	u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT };
D
Daniel Kim 已提交
5228 5229
	u32 rxchain;
	u32 nchain;
5230
	int err;
5231
	s32 i;
5232
	struct ieee80211_supported_band *band;
5233

5234
	(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);
5235 5236 5237 5238
	err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
	if (err) {
		brcmf_err("nmode error (%d)\n", err);
	} else {
5239
		brcmf_get_bwcap(ifp, bw_cap);
5240
	}
5241 5242 5243
	brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n",
		  nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ],
		  bw_cap[IEEE80211_BAND_5GHZ]);
5244

D
Daniel Kim 已提交
5245 5246 5247 5248 5249 5250 5251 5252 5253 5254
	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);

5255
	err = brcmf_construct_chaninfo(cfg, bw_cap);
5256
	if (err) {
5257
		brcmf_err("brcmf_construct_chaninfo failed (%d)\n", err);
5258 5259 5260
		return err;
	}

5261 5262 5263 5264
	wiphy = cfg_to_wiphy(cfg);
	for (i = 0; i < ARRAY_SIZE(wiphy->bands); i++) {
		band = wiphy->bands[i];
		if (band == NULL)
5265
			continue;
5266

5267 5268 5269 5270
		if (nmode)
			brcmf_update_ht_cap(band, bw_cap, nchain);
		if (vhtmode)
			brcmf_update_vht_cap(band, bw_cap, nchain);
5271 5272
	}

5273
	return 0;
5274 5275
}

5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339
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;
}

5340
static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
5341
{
5342
	struct ieee80211_iface_combination ifc_combo;
5343 5344 5345 5346 5347 5348 5349 5350 5351 5352
	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 */
5353
	ifc_combo = brcmf_iface_combos[0];
5354
	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
5355 5356 5357 5358
		ifc_combo.num_different_channels = 2;
	wiphy->iface_combinations = kmemdup(&ifc_combo,
					    sizeof(ifc_combo),
					    GFP_KERNEL);
5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376
	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;

5377
	return brcmf_setup_wiphybands(wiphy);
5378 5379
}

5380
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
5381 5382 5383
{
	struct net_device *ndev;
	struct wireless_dev *wdev;
5384
	struct brcmf_if *ifp;
5385 5386 5387
	s32 power_mode;
	s32 err = 0;

5388
	if (cfg->dongle_up)
5389 5390
		return err;

5391
	ndev = cfg_to_ndev(cfg);
5392
	wdev = ndev->ieee80211_ptr;
5393 5394 5395 5396
	ifp = netdev_priv(ndev);

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

5398 5399
	brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
			      WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
5400

5401
	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
5402
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
5403 5404
	if (err)
		goto default_conf_out;
5405 5406
	brcmf_dbg(INFO, "power save set to %s\n",
		  (power_mode ? "enabled" : "disabled"));
5407

5408
	err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);
5409 5410
	if (err)
		goto default_conf_out;
5411 5412
	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
					  NULL, NULL);
5413
	if (err)
5414 5415
		goto default_conf_out;

5416 5417
	brcmf_configure_arp_offload(ifp, true);

5418
	cfg->dongle_up = true;
5419
default_conf_out:
5420 5421 5422 5423 5424

	return err;

}

5425
static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
5426
{
5427
	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5428

5429
	return brcmf_config_dongle(ifp->drvr->config);
5430 5431
}

5432
static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
5433
{
5434
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5435

5436 5437 5438 5439
	/*
	 * While going down, if associated with AP disassociate
	 * from AP to save power
	 */
5440 5441
	if (check_vif_up(ifp->vif)) {
		brcmf_link_down(ifp->vif);
5442 5443 5444 5445 5446 5447 5448 5449

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

5450
	brcmf_abort_scanning(cfg);
5451
	clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
5452 5453 5454 5455

	return 0;
}

5456
s32 brcmf_cfg80211_up(struct net_device *ndev)
5457
{
5458 5459
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5460 5461
	s32 err = 0;

5462
	mutex_lock(&cfg->usr_sync);
5463
	err = __brcmf_cfg80211_up(ifp);
5464
	mutex_unlock(&cfg->usr_sync);
5465 5466 5467 5468

	return err;
}

5469
s32 brcmf_cfg80211_down(struct net_device *ndev)
5470
{
5471 5472
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
5473 5474
	s32 err = 0;

5475
	mutex_lock(&cfg->usr_sync);
5476
	err = __brcmf_cfg80211_down(ifp);
5477
	mutex_unlock(&cfg->usr_sync);
5478 5479 5480 5481

	return err;
}

5482 5483 5484 5485 5486 5487 5488
enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
{
	struct wireless_dev *wdev = &ifp->vif->wdev;

	return wdev->iftype;
}

5489
bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
5490 5491 5492 5493 5494
{
	struct brcmf_cfg80211_vif *vif;

	list_for_each_entry(vif, &cfg->vif_list, list) {
		if (test_bit(state, &vif->sme_state))
5495
			return true;
5496
	}
5497
	return false;
5498
}
5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541

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

5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555
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);
}

5556 5557 5558 5559 5560 5561 5562 5563 5564 5565
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;
5566
	u16 *cap = NULL;
5567 5568 5569 5570 5571 5572 5573

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

	ifp = netdev_priv(ndev);
5574 5575 5576
	wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
	if (!wiphy) {
		brcmf_err("Could not allocate wiphy device\n");
5577
		return NULL;
5578 5579
	}
	set_wiphy_dev(wiphy, busdev);
5580 5581 5582 5583 5584 5585 5586 5587

	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);
5588 5589
	if (IS_ERR(vif))
		goto wiphy_out;
5590 5591 5592 5593 5594 5595 5596 5597 5598

	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);
5599 5600
		brcmf_free_vif(vif);
		goto wiphy_out;
5601 5602 5603
	}
	ifp->vif = vif;

5604 5605
	/* determine d11 io type before wiphy setup */
	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION, &io_type);
5606
	if (err) {
5607 5608
		brcmf_err("Failed to get D11 version (%d)\n", err);
		goto priv_out;
5609
	}
5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632
	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;
5633 5634 5635 5636 5637
	}

	/* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(),
	 * setup 40MHz in 2GHz band and enable OBSS scanning.
	 */
5638 5639
	if (cap && (*cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
		err = brcmf_enable_bw40_2g(cfg);
5640 5641 5642
		if (!err)
			err = brcmf_fil_iovar_int_set(ifp, "obss_coex",
						      BRCMF_OBSS_COEX_AUTO);
5643 5644
		else
			*cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5645 5646
	}

5647
	err = brcmf_p2p_attach(cfg);
5648
	if (err) {
5649 5650 5651 5652 5653 5654 5655 5656
		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;
5657 5658
	}

5659
	err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);
5660
	if (err) {
5661 5662
		brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err);
		wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_TDLS;
5663 5664 5665 5666
	}

	return cfg;

5667 5668 5669
wiphy_unreg_out:
	wiphy_unregister(cfg->wiphy);
priv_out:
5670 5671
	wl_deinit_priv(cfg);
	brcmf_free_vif(vif);
5672 5673
wiphy_out:
	brcmf_free_wiphy(wiphy);
5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685
	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);
	wl_deinit_priv(cfg);
5686
	brcmf_free_wiphy(cfg->wiphy);
5687
}