wl_cfg80211.c 116.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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>
#include <net/cfg80211.h>
22
#include <net/netlink.h>
23 24 25 26 27

#include <brcmu_utils.h>
#include <defs.h>
#include <brcmu_wifi.h>
#include "dhd.h"
28
#include "dhd_dbg.h"
29
#include "wl_cfg80211.h"
30
#include "fwil.h"
31

32 33 34 35 36 37 38 39 40 41 42 43
#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

44 45
#define BRCMF_IFACE_MAX_CNT		2

H
Hante Meuleman 已提交
46
#define TLV_LEN_OFF			1	/* length offset */
47
#define TLV_HDR_LEN			2	/* header length */
H
Hante Meuleman 已提交
48 49 50 51 52 53 54 55 56 57 58 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 84
#define TLV_BODY_OFF			2	/* body offset */
#define TLV_OUI_LEN			3	/* oui id length */
#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

#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
#define VNDR_IE_BEACON_FLAG		0x1
#define VNDR_IE_PRBRSP_FLAG		0x2
#define MAX_VNDR_IE_NUMBER		5

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

86 87 88
#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
	(sizeof(struct brcmf_assoc_params_le) - sizeof(u16))

89
static bool check_vif_up(struct brcmf_cfg80211_vif *vif)
90
{
91
	if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) {
92 93
		brcmf_dbg(INFO, "device is not ready : status (%lu)\n",
			  vif->sme_state);
94 95 96 97 98 99 100 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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 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
		return false;
	}
	return true;
}

#define CHAN2G(_channel, _freq, _flags) {			\
	.band			= IEEE80211_BAND_2GHZ,		\
	.center_freq		= (_freq),			\
	.hw_value		= (_channel),			\
	.flags			= (_flags),			\
	.max_antenna_gain	= 0,				\
	.max_power		= 30,				\
}

#define CHAN5G(_channel, _flags) {				\
	.band			= IEEE80211_BAND_5GHZ,		\
	.center_freq		= 5000 + (5 * (_channel)),	\
	.hw_value		= (_channel),			\
	.flags			= (_flags),			\
	.max_antenna_gain	= 0,				\
	.max_power		= 30,				\
}

#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

static struct ieee80211_channel __wl_2ghz_channels[] = {
	CHAN2G(1, 2412, 0),
	CHAN2G(2, 2417, 0),
	CHAN2G(3, 2422, 0),
	CHAN2G(4, 2427, 0),
	CHAN2G(5, 2432, 0),
	CHAN2G(6, 2437, 0),
	CHAN2G(7, 2442, 0),
	CHAN2G(8, 2447, 0),
	CHAN2G(9, 2452, 0),
	CHAN2G(10, 2457, 0),
	CHAN2G(11, 2462, 0),
	CHAN2G(12, 2467, 0),
	CHAN2G(13, 2472, 0),
	CHAN2G(14, 2484, 0),
};

static struct ieee80211_channel __wl_5ghz_a_channels[] = {
	CHAN5G(34, 0), CHAN5G(36, 0),
	CHAN5G(38, 0), CHAN5G(40, 0),
	CHAN5G(42, 0), CHAN5G(44, 0),
	CHAN5G(46, 0), CHAN5G(48, 0),
	CHAN5G(52, 0), CHAN5G(56, 0),
	CHAN5G(60, 0), CHAN5G(64, 0),
	CHAN5G(100, 0), CHAN5G(104, 0),
	CHAN5G(108, 0), CHAN5G(112, 0),
	CHAN5G(116, 0), CHAN5G(120, 0),
	CHAN5G(124, 0), CHAN5G(128, 0),
	CHAN5G(132, 0), CHAN5G(136, 0),
	CHAN5G(140, 0), CHAN5G(149, 0),
	CHAN5G(153, 0), CHAN5G(157, 0),
	CHAN5G(161, 0), CHAN5G(165, 0),
	CHAN5G(184, 0), CHAN5G(188, 0),
	CHAN5G(192, 0), CHAN5G(196, 0),
	CHAN5G(200, 0), CHAN5G(204, 0),
	CHAN5G(208, 0), CHAN5G(212, 0),
	CHAN5G(216, 0),
};

static struct ieee80211_channel __wl_5ghz_n_channels[] = {
	CHAN5G(32, 0), CHAN5G(34, 0),
	CHAN5G(36, 0), CHAN5G(38, 0),
	CHAN5G(40, 0), CHAN5G(42, 0),
	CHAN5G(44, 0), CHAN5G(46, 0),
	CHAN5G(48, 0), CHAN5G(50, 0),
	CHAN5G(52, 0), CHAN5G(54, 0),
	CHAN5G(56, 0), CHAN5G(58, 0),
	CHAN5G(60, 0), CHAN5G(62, 0),
	CHAN5G(64, 0), CHAN5G(66, 0),
	CHAN5G(68, 0), CHAN5G(70, 0),
	CHAN5G(72, 0), CHAN5G(74, 0),
	CHAN5G(76, 0), CHAN5G(78, 0),
	CHAN5G(80, 0), CHAN5G(82, 0),
	CHAN5G(84, 0), CHAN5G(86, 0),
	CHAN5G(88, 0), CHAN5G(90, 0),
	CHAN5G(92, 0), CHAN5G(94, 0),
	CHAN5G(96, 0), CHAN5G(98, 0),
	CHAN5G(100, 0), CHAN5G(102, 0),
	CHAN5G(104, 0), CHAN5G(106, 0),
	CHAN5G(108, 0), CHAN5G(110, 0),
	CHAN5G(112, 0), CHAN5G(114, 0),
	CHAN5G(116, 0), CHAN5G(118, 0),
	CHAN5G(120, 0), CHAN5G(122, 0),
	CHAN5G(124, 0), CHAN5G(126, 0),
	CHAN5G(128, 0), CHAN5G(130, 0),
	CHAN5G(132, 0), CHAN5G(134, 0),
	CHAN5G(136, 0), CHAN5G(138, 0),
	CHAN5G(140, 0), CHAN5G(142, 0),
	CHAN5G(144, 0), CHAN5G(145, 0),
	CHAN5G(146, 0), CHAN5G(147, 0),
	CHAN5G(148, 0), CHAN5G(149, 0),
	CHAN5G(150, 0), CHAN5G(151, 0),
	CHAN5G(152, 0), CHAN5G(153, 0),
	CHAN5G(154, 0), CHAN5G(155, 0),
	CHAN5G(156, 0), CHAN5G(157, 0),
	CHAN5G(158, 0), CHAN5G(159, 0),
	CHAN5G(160, 0), CHAN5G(161, 0),
	CHAN5G(162, 0), CHAN5G(163, 0),
	CHAN5G(164, 0), CHAN5G(165, 0),
	CHAN5G(166, 0), CHAN5G(168, 0),
	CHAN5G(170, 0), CHAN5G(172, 0),
	CHAN5G(174, 0), CHAN5G(176, 0),
	CHAN5G(178, 0), CHAN5G(180, 0),
	CHAN5G(182, 0), CHAN5G(184, 0),
	CHAN5G(186, 0), CHAN5G(188, 0),
	CHAN5G(190, 0), CHAN5G(192, 0),
	CHAN5G(194, 0), CHAN5G(196, 0),
	CHAN5G(198, 0), CHAN5G(200, 0),
	CHAN5G(202, 0), CHAN5G(204, 0),
	CHAN5G(206, 0), CHAN5G(208, 0),
	CHAN5G(210, 0), CHAN5G(212, 0),
	CHAN5G(214, 0), CHAN5G(216, 0),
	CHAN5G(218, 0), CHAN5G(220, 0),
	CHAN5G(222, 0), CHAN5G(224, 0),
	CHAN5G(226, 0), CHAN5G(228, 0),
};

static struct ieee80211_supported_band __wl_band_2ghz = {
	.band = IEEE80211_BAND_2GHZ,
	.channels = __wl_2ghz_channels,
	.n_channels = ARRAY_SIZE(__wl_2ghz_channels),
	.bitrates = wl_g_rates,
	.n_bitrates = wl_g_rates_size,
};

static struct ieee80211_supported_band __wl_band_5ghz_a = {
	.band = IEEE80211_BAND_5GHZ,
	.channels = __wl_5ghz_a_channels,
	.n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
	.bitrates = wl_a_rates,
	.n_bitrates = wl_a_rates_size,
};

static struct ieee80211_supported_band __wl_band_5ghz_n = {
	.band = IEEE80211_BAND_5GHZ,
	.channels = __wl_5ghz_n_channels,
	.n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
	.bitrates = wl_a_rates,
	.n_bitrates = wl_a_rates_size,
};

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

274 275 276 277 278 279 280
/* tag_ID/length/value_buffer tuple */
struct brcmf_tlv {
	u8 id;
	u8 len;
	u8 data[1];
};

H
Hante Meuleman 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
/* 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;
	struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
};

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
/* 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;
}

384 385 386 387 388 389 390 391 392 393 394 395
static u16 channel_to_chanspec(struct ieee80211_channel *ch)
{
	u16 chanspec;

	chanspec = ieee80211_frequency_to_channel(ch->center_freq);
	chanspec &= WL_CHANSPEC_CHAN_MASK;

	if (ch->band == IEEE80211_BAND_2GHZ)
		chanspec |= WL_CHANSPEC_BAND_2G;
	else
		chanspec |= WL_CHANSPEC_BAND_5G;

396 397 398
	chanspec |= WL_CHANSPEC_BW_20;
	chanspec |= WL_CHANSPEC_CTL_SB_NONE;

399 400 401
	return chanspec;
}

402 403 404 405 406 407 408 409 410 411 412 413 414 415
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));
}

416
static int
417
send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
418 419 420 421 422
{
	int err;
	struct brcmf_wsec_key_le key_le;

	convert_key_from_CPU(key, &key_le);
423

424 425
	brcmf_netdev_wait_pend8021x(ndev);

426
	err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
427
					sizeof(key_le));
428

429
	if (err)
430
		brcmf_err("wsec_key error (%d)\n", err);
431 432 433 434 435 436 437 438
	return err;
}

static s32
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
			 enum nl80211_iftype type, u32 *flags,
			 struct vif_params *params)
{
439
	struct brcmf_if *ifp = netdev_priv(ndev);
440
	struct brcmf_cfg80211_vif *vif = ifp->vif;
441
	s32 infra = 0;
H
Hante Meuleman 已提交
442
	s32 ap = 0;
443 444
	s32 err = 0;

445
	brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type);
446 447 448 449

	switch (type) {
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_WDS:
450 451
		brcmf_err("type (%d) : currently we do not support this type\n",
			  type);
452 453
		return -EOPNOTSUPP;
	case NL80211_IFTYPE_ADHOC:
454
		vif->mode = WL_MODE_IBSS;
455 456 457
		infra = 0;
		break;
	case NL80211_IFTYPE_STATION:
458
		vif->mode = WL_MODE_BSS;
459 460
		infra = 1;
		break;
H
Hante Meuleman 已提交
461
	case NL80211_IFTYPE_AP:
462
		vif->mode = WL_MODE_AP;
H
Hante Meuleman 已提交
463 464
		ap = 1;
		break;
465 466 467 468 469
	default:
		err = -EINVAL;
		goto done;
	}

H
Hante Meuleman 已提交
470
	if (ap) {
471
		set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state);
472
		brcmf_dbg(INFO, "IF Type = AP\n");
473
	} else {
474
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra);
H
Hante Meuleman 已提交
475
		if (err) {
476
			brcmf_err("WLC_SET_INFRA error (%d)\n", err);
H
Hante Meuleman 已提交
477 478 479
			err = -EAGAIN;
			goto done;
		}
480 481
		brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ?
			  "Adhoc" : "Infra");
482
	}
H
Hante Meuleman 已提交
483
	ndev->ieee80211_ptr->iftype = type;
484 485

done:
486
	brcmf_dbg(TRACE, "Exit\n");
487 488 489 490 491 492

	return err;
}

static void brcmf_set_mpc(struct net_device *ndev, int mpc)
{
493
	struct brcmf_if *ifp = netdev_priv(ndev);
494 495
	s32 err = 0;

496
	if (check_vif_up(ifp->vif)) {
497
		err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
498
		if (err) {
499
			brcmf_err("fail to set mpc\n");
500 501
			return;
		}
502
		brcmf_dbg(INFO, "MPC : %d\n", mpc);
503 504 505
	}
}

H
Hante Meuleman 已提交
506 507 508 509 510 511 512
static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
			     struct cfg80211_scan_request *request)
{
	u32 n_ssids;
	u32 n_channels;
	s32 i;
	s32 offset;
513
	u16 chanspec;
H
Hante Meuleman 已提交
514
	char *ptr;
515
	struct brcmf_ssid_le ssid_le;
H
Hante Meuleman 已提交
516

517
	memset(params_le->bssid, 0xFF, ETH_ALEN);
H
Hante Meuleman 已提交
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
	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 */
534 535
	brcmf_dbg(SCAN, "### List of channelspecs to scan ### %d\n",
		  n_channels);
H
Hante Meuleman 已提交
536 537
	if (n_channels > 0) {
		for (i = 0; i < n_channels; i++) {
538
			chanspec = channel_to_chanspec(request->channels[i]);
539 540
			brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
				  request->channels[i]->hw_value, chanspec);
541
			params_le->channel_list[i] = cpu_to_le16(chanspec);
H
Hante Meuleman 已提交
542 543
		}
	} else {
544
		brcmf_dbg(SCAN, "Scanning all channels\n");
H
Hante Meuleman 已提交
545 546
	}
	/* Copy ssid array if applicable */
547
	brcmf_dbg(SCAN, "### List of SSIDs to scan ### %d\n", n_ssids);
H
Hante Meuleman 已提交
548 549 550 551 552 553
	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++) {
554 555 556 557 558 559
			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)
560
				brcmf_dbg(SCAN, "%d: Broadcast scan\n", i);
H
Hante Meuleman 已提交
561
			else
562 563
				brcmf_dbg(SCAN, "%d: scan for  %s size =%d\n",
					  i, ssid_le.SSID, ssid_le.SSID_len);
564 565
			memcpy(ptr, &ssid_le, sizeof(ssid_le));
			ptr += sizeof(ssid_le);
H
Hante Meuleman 已提交
566 567
		}
	} else {
568
		brcmf_dbg(SCAN, "Broadcast scan %p\n", request->ssids);
H
Hante Meuleman 已提交
569
		if ((request->ssids) && request->ssids->ssid_len) {
570 571 572
			brcmf_dbg(SCAN, "SSID %s len=%d\n",
				  params_le->ssid_le.SSID,
				  request->ssids->ssid_len);
H
Hante Meuleman 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585
			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
586
brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
H
Hante Meuleman 已提交
587 588 589 590 591 592 593
			    struct net_device *ndev,
			    bool aborted, bool fw_abort)
{
	struct brcmf_scan_params_le params_le;
	struct cfg80211_scan_request *scan_request;
	s32 err = 0;

594
	brcmf_dbg(SCAN, "Enter\n");
H
Hante Meuleman 已提交
595 596 597

	/* clear scan request, because the FW abort can cause a second call */
	/* to this functon and might cause a double cfg80211_scan_done      */
598 599
	scan_request = cfg->scan_request;
	cfg->scan_request = NULL;
H
Hante Meuleman 已提交
600

601 602
	if (timer_pending(&cfg->escan_timeout))
		del_timer_sync(&cfg->escan_timeout);
H
Hante Meuleman 已提交
603 604 605

	if (fw_abort) {
		/* Do a scan abort to stop the driver's scan engine */
606
		brcmf_dbg(SCAN, "ABORT scan in firmware\n");
H
Hante Meuleman 已提交
607
		memset(&params_le, 0, sizeof(params_le));
608
		memset(params_le.bssid, 0xFF, ETH_ALEN);
H
Hante Meuleman 已提交
609 610 611 612 613 614 615 616 617 618
		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 */
619 620
		err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
					     &params_le, sizeof(params_le));
H
Hante Meuleman 已提交
621
		if (err)
622
			brcmf_err("Scan abort  failed\n");
H
Hante Meuleman 已提交
623
	}
624 625 626 627
	/*
	 * e-scan can be initiated by scheduled scan
	 * which takes precedence.
	 */
628
	if (cfg->sched_escan) {
629
		brcmf_dbg(SCAN, "scheduled scan completed\n");
630
		cfg->sched_escan = false;
631
		if (!aborted)
632
			cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
633 634
		brcmf_set_mpc(ndev, 1);
	} else if (scan_request) {
635 636
		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
			  aborted ? "Aborted" : "Done");
H
Hante Meuleman 已提交
637 638 639
		cfg80211_scan_done(scan_request, aborted);
		brcmf_set_mpc(ndev, 1);
	}
640
	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
641
		brcmf_err("Scan complete while device not scanning\n");
H
Hante Meuleman 已提交
642 643 644 645 646 647 648
		return -EPERM;
	}

	return err;
}

static s32
649
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
H
Hante Meuleman 已提交
650 651 652 653 654 655 656
		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;

657
	brcmf_dbg(SCAN, "E-SCAN START\n");
H
Hante Meuleman 已提交
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677

	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);
	brcmf_escan_prep(&params->params_le, request);
	params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
	params->action = cpu_to_le16(action);
	params->sync_id = cpu_to_le16(0x1234);

678 679
	err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
				       params, params_size);
H
Hante Meuleman 已提交
680 681
	if (err) {
		if (err == -EBUSY)
682
			brcmf_dbg(INFO, "system busy : escan canceled\n");
H
Hante Meuleman 已提交
683
		else
684
			brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
685 686 687 688 689 690 691 692
	}

	kfree(params);
exit:
	return err;
}

static s32
693
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
H
Hante Meuleman 已提交
694 695 696
	       struct net_device *ndev, struct cfg80211_scan_request *request)
{
	s32 err;
697
	u32 passive_scan;
H
Hante Meuleman 已提交
698 699
	struct brcmf_scan_results *results;

700
	brcmf_dbg(SCAN, "Enter\n");
701 702 703
	cfg->escan_info.ndev = ndev;
	cfg->escan_info.wiphy = wiphy;
	cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
704
	passive_scan = cfg->active_scan ? 0 : 1;
705
	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
706
				    passive_scan);
H
Hante Meuleman 已提交
707
	if (err) {
708
		brcmf_err("error (%d)\n", err);
H
Hante Meuleman 已提交
709 710 711
		return err;
	}
	brcmf_set_mpc(ndev, 0);
712
	results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
713 714 715 716
	results->version = 0;
	results->count = 0;
	results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;

717
	err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START);
H
Hante Meuleman 已提交
718 719 720 721 722 723 724 725 726 727
	if (err)
		brcmf_set_mpc(ndev, 1);
	return err;
}

static s32
brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
		     struct cfg80211_scan_request *request,
		     struct cfg80211_ssid *this_ssid)
{
728
	struct brcmf_if *ifp = netdev_priv(ndev);
729
	struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
H
Hante Meuleman 已提交
730
	struct cfg80211_ssid *ssids;
731
	struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
732
	u32 passive_scan;
H
Hante Meuleman 已提交
733 734 735 736 737
	bool escan_req;
	bool spec_scan;
	s32 err;
	u32 SSID_len;

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

740
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
741
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
H
Hante Meuleman 已提交
742 743
		return -EAGAIN;
	}
744
	if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
745 746
		brcmf_err("Scanning being aborted: status (%lu)\n",
			  cfg->scan_status);
H
Hante Meuleman 已提交
747 748
		return -EAGAIN;
	}
749
	if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
750
		brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
H
Hante Meuleman 已提交
751 752 753 754
		return -EAGAIN;
	}

	/* Arm scan timeout timer */
755
	mod_timer(&cfg->escan_timeout, jiffies +
H
Hante Meuleman 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768
			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;
	}

769
	cfg->scan_request = request;
770
	set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
H
Hante Meuleman 已提交
771
	if (escan_req) {
772
		err = brcmf_do_escan(cfg, wiphy, ndev, request);
773
		if (err)
H
Hante Meuleman 已提交
774 775
			goto scan_out;
	} else {
776 777
		brcmf_dbg(SCAN, "ssid \"%s\", ssid_len (%d)\n",
			  ssids->ssid, ssids->ssid_len);
H
Hante Meuleman 已提交
778 779 780 781 782 783 784 785 786
		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
787
			brcmf_dbg(SCAN, "Broadcast scan\n");
H
Hante Meuleman 已提交
788

789
		passive_scan = cfg->active_scan ? 0 : 1;
790
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
791
					    passive_scan);
H
Hante Meuleman 已提交
792
		if (err) {
793
			brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
794 795 796
			goto scan_out;
		}
		brcmf_set_mpc(ndev, 0);
797
		err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
798
					     &sr->ssid_le, sizeof(sr->ssid_le));
H
Hante Meuleman 已提交
799 800
		if (err) {
			if (err == -EBUSY)
801 802
				brcmf_dbg(INFO, "BUSY: scan for \"%s\" canceled\n",
					  sr->ssid_le.SSID);
H
Hante Meuleman 已提交
803
			else
804
				brcmf_err("WLC_SCAN error (%d)\n", err);
H
Hante Meuleman 已提交
805 806 807 808 809 810 811 812 813

			brcmf_set_mpc(ndev, 1);
			goto scan_out;
		}
	}

	return 0;

scan_out:
814
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
815 816 817
	if (timer_pending(&cfg->escan_timeout))
		del_timer_sync(&cfg->escan_timeout);
	cfg->scan_request = NULL;
H
Hante Meuleman 已提交
818 819 820
	return err;
}

821
static s32
822
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
823
{
J
Johannes Berg 已提交
824
	struct net_device *ndev = request->wdev->netdev;
825 826
	s32 err = 0;

827
	brcmf_dbg(TRACE, "Enter\n");
828

829
	if (!check_vif_up(container_of(request->wdev,
830
				       struct brcmf_cfg80211_vif, wdev)))
831 832
		return -EIO;

833
	err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
H
Hante Meuleman 已提交
834

835
	if (err)
836
		brcmf_err("scan error (%d)\n", err);
837

838
	brcmf_dbg(TRACE, "Exit\n");
839 840 841 842 843 844 845
	return err;
}

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

846 847
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "rtsthresh",
				      rts_threshold);
848
	if (err)
849
		brcmf_err("Error (%d)\n", err);
850 851 852 853 854 855 856 857

	return err;
}

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

858 859
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "fragthresh",
				      frag_threshold);
860
	if (err)
861
		brcmf_err("Error (%d)\n", err);
862 863 864 865 866 867 868

	return err;
}

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

871
	err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
872
	if (err) {
873
		brcmf_err("cmd (%d) , error (%d)\n", cmd, err);
874 875 876 877 878 879 880
		return err;
	}
	return err;
}

static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
881 882
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
883
	struct brcmf_if *ifp = netdev_priv(ndev);
884 885
	s32 err = 0;

886
	brcmf_dbg(TRACE, "Enter\n");
887
	if (!check_vif_up(ifp->vif))
888 889 890
		return -EIO;

	if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
891 892 893
	    (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
		cfg->conf->rts_threshold = wiphy->rts_threshold;
		err = brcmf_set_rts(ndev, cfg->conf->rts_threshold);
894 895 896 897
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
898 899 900
	    (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
		cfg->conf->frag_threshold = wiphy->frag_threshold;
		err = brcmf_set_frag(ndev, cfg->conf->frag_threshold);
901 902 903 904
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_LONG
905 906 907
	    && (cfg->conf->retry_long != wiphy->retry_long)) {
		cfg->conf->retry_long = wiphy->retry_long;
		err = brcmf_set_retry(ndev, cfg->conf->retry_long, true);
908 909 910 911
		if (!err)
			goto done;
	}
	if (changed & WIPHY_PARAM_RETRY_SHORT
912 913 914
	    && (cfg->conf->retry_short != wiphy->retry_short)) {
		cfg->conf->retry_short = wiphy->retry_short;
		err = brcmf_set_retry(ndev, cfg->conf->retry_short, false);
915 916 917 918 919
		if (!err)
			goto done;
	}

done:
920
	brcmf_dbg(TRACE, "Exit\n");
921 922 923 924 925 926 927 928
	return err;
}

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

929
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
930 931 932
{
	s32 err = 0;

933
	brcmf_dbg(TRACE, "Enter\n");
934

935
	if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state)) {
936
		brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
937
		err = brcmf_fil_cmd_data_set(vif->ifp,
938
					     BRCMF_C_DISASSOC, NULL, 0);
939
		if (err)
940
			brcmf_err("WLC_DISASSOC failed (%d)\n", err);
941
		clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
942
	}
943
	clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
944
	brcmf_dbg(TRACE, "Exit\n");
945 946 947 948 949 950
}

static s32
brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_ibss_params *params)
{
951
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
952 953
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
954 955 956 957 958
	struct brcmf_join_params join_params;
	size_t join_params_size = 0;
	s32 err = 0;
	s32 wsec = 0;
	s32 bcnprd;
959
	u16 chanspec;
960

961
	brcmf_dbg(TRACE, "Enter\n");
962
	if (!check_vif_up(ifp->vif))
963 964 965
		return -EIO;

	if (params->ssid)
966
		brcmf_dbg(CONN, "SSID: %s\n", params->ssid);
967
	else {
968
		brcmf_dbg(CONN, "SSID: NULL, Not supported\n");
969 970 971
		return -EOPNOTSUPP;
	}

972
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
973 974

	if (params->bssid)
975
		brcmf_dbg(CONN, "BSSID: %pM\n", params->bssid);
976
	else
977
		brcmf_dbg(CONN, "No BSSID specified\n");
978

979
	if (params->chandef.chan)
980 981
		brcmf_dbg(CONN, "channel: %d\n",
			  params->chandef.chan->center_freq);
982
	else
983
		brcmf_dbg(CONN, "no channel specified\n");
984 985

	if (params->channel_fixed)
986
		brcmf_dbg(CONN, "fixed channel required\n");
987
	else
988
		brcmf_dbg(CONN, "no fixed channel required\n");
989 990

	if (params->ie && params->ie_len)
991
		brcmf_dbg(CONN, "ie len: %d\n", params->ie_len);
992
	else
993
		brcmf_dbg(CONN, "no ie specified\n");
994 995

	if (params->beacon_interval)
996 997
		brcmf_dbg(CONN, "beacon interval: %d\n",
			  params->beacon_interval);
998
	else
999
		brcmf_dbg(CONN, "no beacon interval specified\n");
1000 1001

	if (params->basic_rates)
1002
		brcmf_dbg(CONN, "basic rates: %08X\n", params->basic_rates);
1003
	else
1004
		brcmf_dbg(CONN, "no basic rates specified\n");
1005 1006

	if (params->privacy)
1007
		brcmf_dbg(CONN, "privacy required\n");
1008
	else
1009
		brcmf_dbg(CONN, "no privacy required\n");
1010 1011 1012 1013 1014

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

1015
	err = brcmf_fil_iovar_int_set(ifp, "wsec", wsec);
1016
	if (err) {
1017
		brcmf_err("wsec failed (%d)\n", err);
1018 1019 1020 1021 1022 1023 1024 1025 1026
		goto done;
	}

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

H
Hante Meuleman 已提交
1027
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
1028
	if (err) {
1029
		brcmf_err("WLC_SET_BCNPRD failed (%d)\n", err);
1030 1031 1032 1033 1034 1035 1036
		goto done;
	}

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

	/* SSID */
1037 1038 1039 1040
	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);
1041 1042 1043 1044 1045 1046 1047
	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;
1048
		memcpy(profile->bssid, params->bssid, ETH_ALEN);
1049
	} else {
1050
		memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1051
		memset(profile->bssid, 0, ETH_ALEN);
1052 1053 1054
	}

	/* Channel */
1055
	if (params->chandef.chan) {
1056 1057
		u32 target_channel;

1058
		cfg->channel =
1059
			ieee80211_frequency_to_channel(
1060
				params->chandef.chan->center_freq);
1061 1062
		if (params->channel_fixed) {
			/* adding chanspec */
1063 1064 1065 1066 1067
			chanspec = channel_to_chanspec(params->chandef.chan);
			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);
1068 1069 1070
		}

		/* set channel for starter */
1071
		target_channel = cfg->channel;
H
Hante Meuleman 已提交
1072
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
1073
					    target_channel);
1074
		if (err) {
1075
			brcmf_err("WLC_SET_CHANNEL failed (%d)\n", err);
1076 1077 1078
			goto done;
		}
	} else
1079
		cfg->channel = 0;
1080

1081
	cfg->ibss_starter = false;
1082 1083


1084
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1085
				     &join_params, join_params_size);
1086
	if (err) {
1087
		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
1088 1089 1090 1091 1092
		goto done;
	}

done:
	if (err)
1093
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1094
	brcmf_dbg(TRACE, "Exit\n");
1095 1096 1097 1098 1099 1100
	return err;
}

static s32
brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
{
1101
	struct brcmf_if *ifp = netdev_priv(ndev);
1102 1103
	s32 err = 0;

1104
	brcmf_dbg(TRACE, "Enter\n");
1105
	if (!check_vif_up(ifp->vif))
1106 1107
		return -EIO;

1108
	brcmf_link_down(ifp->vif);
1109

1110
	brcmf_dbg(TRACE, "Exit\n");
1111 1112 1113 1114 1115 1116 1117

	return err;
}

static s32 brcmf_set_wpa_version(struct net_device *ndev,
				 struct cfg80211_connect_params *sme)
{
1118
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
	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;
1129
	brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val);
1130
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val);
1131
	if (err) {
1132
		brcmf_err("set wpa_auth failed (%d)\n", err);
1133 1134
		return err;
	}
1135
	sec = &profile->sec;
1136 1137 1138 1139 1140 1141 1142
	sec->wpa_versions = sme->crypto.wpa_versions;
	return err;
}

static s32 brcmf_set_auth_type(struct net_device *ndev,
			       struct cfg80211_connect_params *sme)
{
1143
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1144 1145 1146 1147 1148 1149 1150
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	switch (sme->auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		val = 0;
1151
		brcmf_dbg(CONN, "open system\n");
1152 1153 1154
		break;
	case NL80211_AUTHTYPE_SHARED_KEY:
		val = 1;
1155
		brcmf_dbg(CONN, "shared key\n");
1156 1157 1158
		break;
	case NL80211_AUTHTYPE_AUTOMATIC:
		val = 2;
1159
		brcmf_dbg(CONN, "automatic\n");
1160 1161
		break;
	case NL80211_AUTHTYPE_NETWORK_EAP:
1162
		brcmf_dbg(CONN, "network eap\n");
1163 1164
	default:
		val = 2;
1165
		brcmf_err("invalid auth type (%d)\n", sme->auth_type);
1166 1167 1168
		break;
	}

1169
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val);
1170
	if (err) {
1171
		brcmf_err("set auth failed (%d)\n", err);
1172 1173
		return err;
	}
1174
	sec = &profile->sec;
1175 1176 1177 1178 1179 1180 1181 1182
	sec->auth_type = sme->auth_type;
	return err;
}

static s32
brcmf_set_set_cipher(struct net_device *ndev,
		     struct cfg80211_connect_params *sme)
{
1183
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
	struct brcmf_cfg80211_security *sec;
	s32 pval = 0;
	s32 gval = 0;
	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:
1205 1206
			brcmf_err("invalid cipher pairwise (%d)\n",
				  sme->crypto.ciphers_pairwise[0]);
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
			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:
1226 1227
			brcmf_err("invalid cipher group (%d)\n",
				  sme->crypto.cipher_group);
1228 1229 1230 1231
			return -EINVAL;
		}
	}

1232
	brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval);
1233
	err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval);
1234
	if (err) {
1235
		brcmf_err("error (%d)\n", err);
1236 1237 1238
		return err;
	}

1239
	sec = &profile->sec;
1240 1241 1242 1243 1244 1245 1246 1247 1248
	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)
{
1249
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1250 1251 1252 1253 1254
	struct brcmf_cfg80211_security *sec;
	s32 val = 0;
	s32 err = 0;

	if (sme->crypto.n_akm_suites) {
1255 1256
		err = brcmf_fil_iovar_int_get(netdev_priv(ndev),
					      "wpa_auth", &val);
1257
		if (err) {
1258
			brcmf_err("could not get wpa_auth (%d)\n", err);
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
			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:
1270 1271
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
				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:
1283 1284
				brcmf_err("invalid cipher group (%d)\n",
					  sme->crypto.cipher_group);
1285 1286 1287 1288
				return -EINVAL;
			}
		}

1289
		brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
1290 1291
		err = brcmf_fil_iovar_int_set(netdev_priv(ndev),
					      "wpa_auth", val);
1292
		if (err) {
1293
			brcmf_err("could not set wpa_auth (%d)\n", err);
1294 1295 1296
			return err;
		}
	}
1297
	sec = &profile->sec;
1298 1299 1300 1301 1302 1303
	sec->wpa_auth = sme->crypto.akm_suites[0];

	return err;
}

static s32
1304 1305
brcmf_set_sharedkey(struct net_device *ndev,
		    struct cfg80211_connect_params *sme)
1306
{
1307
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
1308 1309 1310 1311 1312
	struct brcmf_cfg80211_security *sec;
	struct brcmf_wsec_key key;
	s32 val;
	s32 err = 0;

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

1315 1316 1317
	if (sme->key_len == 0)
		return 0;

1318
	sec = &profile->sec;
1319 1320
	brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n",
		  sec->wpa_versions, sec->cipher_pairwise);
1321 1322 1323 1324

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

1325 1326 1327
	if (!(sec->cipher_pairwise &
	    (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)))
		return 0;
1328

1329 1330 1331 1332
	memset(&key, 0, sizeof(key));
	key.len = (u32) sme->key_len;
	key.index = (u32) sme->key_idx;
	if (key.len > sizeof(key.data)) {
1333
		brcmf_err("Too long key length (%u)\n", key.len);
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
		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:
1346 1347
		brcmf_err("Invalid algorithm (%d)\n",
			  sme->crypto.ciphers_pairwise[0]);
1348 1349 1350
		return -EINVAL;
	}
	/* Set the new key/index */
1351 1352 1353
	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);
1354
	err = send_key_to_dongle(ndev, &key);
1355 1356 1357 1358
	if (err)
		return err;

	if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
1359
		brcmf_dbg(CONN, "set auth_type to shared key\n");
1360
		val = WL_AUTH_SHARED_KEY;	/* shared key */
1361
		err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val);
1362
		if (err)
1363
			brcmf_err("set auth failed (%d)\n", err);
1364 1365 1366 1367
	}
	return err;
}

1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
static
enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
					   enum nl80211_auth_type type)
{
	u32 ci;
	if (type == NL80211_AUTHTYPE_AUTOMATIC) {
		/* shift to ignore chip revision */
		ci = brcmf_get_chip_info(ifp) >> 4;
		switch (ci) {
		case 43236:
			brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n");
			return NL80211_AUTHTYPE_OPEN_SYSTEM;
		default:
			break;
		}
	}
	return type;
}

1387 1388
static s32
brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
1389
		       struct cfg80211_connect_params *sme)
1390
{
1391
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1392 1393
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1394 1395 1396 1397
	struct ieee80211_channel *chan = sme->channel;
	struct brcmf_join_params join_params;
	size_t join_params_size;
	struct brcmf_ssid ssid;
1398
	u16 chanspec;
1399 1400 1401

	s32 err = 0;

1402
	brcmf_dbg(TRACE, "Enter\n");
1403
	if (!check_vif_up(ifp->vif))
1404 1405 1406
		return -EIO;

	if (!sme->ssid) {
1407
		brcmf_err("Invalid ssid\n");
1408 1409 1410
		return -EOPNOTSUPP;
	}

1411
	set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1412 1413

	if (chan) {
1414
		cfg->channel =
1415
			ieee80211_frequency_to_channel(chan->center_freq);
1416 1417 1418 1419
		chanspec = channel_to_chanspec(chan);
		brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
			  cfg->channel, chan->center_freq, chanspec);
	} else {
1420
		cfg->channel = 0;
1421 1422
		chanspec = 0;
	}
1423

1424
	brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
1425 1426 1427

	err = brcmf_set_wpa_version(ndev, sme);
	if (err) {
1428
		brcmf_err("wl_set_wpa_version failed (%d)\n", err);
1429 1430 1431
		goto done;
	}

1432
	sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type);
1433 1434
	err = brcmf_set_auth_type(ndev, sme);
	if (err) {
1435
		brcmf_err("wl_set_auth_type failed (%d)\n", err);
1436 1437 1438 1439 1440
		goto done;
	}

	err = brcmf_set_set_cipher(ndev, sme);
	if (err) {
1441
		brcmf_err("wl_set_set_cipher failed (%d)\n", err);
1442 1443 1444 1445 1446
		goto done;
	}

	err = brcmf_set_key_mgmt(ndev, sme);
	if (err) {
1447
		brcmf_err("wl_set_key_mgmt failed (%d)\n", err);
1448 1449 1450
		goto done;
	}

1451
	err = brcmf_set_sharedkey(ndev, sme);
1452
	if (err) {
1453
		brcmf_err("brcmf_set_sharedkey failed (%d)\n", err);
1454 1455 1456 1457 1458 1459
		goto done;
	}

	memset(&join_params, 0, sizeof(join_params));
	join_params_size = sizeof(join_params.ssid_le);

1460 1461 1462 1463 1464
	profile->ssid.SSID_len = min_t(u32,
				       sizeof(ssid.SSID), (u32)sme->ssid_len);
	memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len);
	memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len);
	join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);
1465

1466
	memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
1467 1468

	if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
1469 1470
		brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n",
			  ssid.SSID, ssid.SSID_len);
1471

1472 1473 1474 1475 1476
	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);
	}
1477
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
1478
				     &join_params, join_params_size);
1479
	if (err)
1480
		brcmf_err("WLC_SET_SSID failed (%d)\n", err);
1481 1482 1483

done:
	if (err)
1484
		clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
1485
	brcmf_dbg(TRACE, "Exit\n");
1486 1487 1488 1489 1490 1491 1492
	return err;
}

static s32
brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
		       u16 reason_code)
{
1493 1494
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1495 1496 1497
	struct brcmf_scb_val_le scbval;
	s32 err = 0;

1498
	brcmf_dbg(TRACE, "Enter. Reason code = %d\n", reason_code);
1499
	if (!check_vif_up(ifp->vif))
1500 1501
		return -EIO;

1502
	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
1503

1504
	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
1505
	scbval.val = cpu_to_le32(reason_code);
1506
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_DISASSOC,
1507
				     &scbval, sizeof(scbval));
1508
	if (err)
1509
		brcmf_err("error (%d)\n", err);
1510

1511
	brcmf_dbg(TRACE, "Exit\n");
1512 1513 1514 1515
	return err;
}

static s32
1516
brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
1517
			    enum nl80211_tx_power_setting type, s32 mbm)
1518 1519
{

1520
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1521 1522
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct brcmf_if *ifp = netdev_priv(ndev);
1523 1524 1525
	u16 txpwrmw;
	s32 err = 0;
	s32 disable = 0;
1526
	s32 dbm = MBM_TO_DBM(mbm);
1527

1528
	brcmf_dbg(TRACE, "Enter\n");
1529
	if (!check_vif_up(ifp->vif))
1530 1531 1532 1533 1534 1535 1536 1537
		return -EIO;

	switch (type) {
	case NL80211_TX_POWER_AUTOMATIC:
		break;
	case NL80211_TX_POWER_LIMITED:
	case NL80211_TX_POWER_FIXED:
		if (dbm < 0) {
1538
			brcmf_err("TX_POWER_FIXED - dbm is negative\n");
1539 1540 1541 1542 1543 1544 1545
			err = -EINVAL;
			goto done;
		}
		break;
	}
	/* Make sure radio is off or on as far as software is concerned */
	disable = WL_RADIO_SW_DISABLE << 16;
1546
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_RADIO, disable);
1547
	if (err)
1548
		brcmf_err("WLC_SET_RADIO error (%d)\n", err);
1549 1550 1551 1552 1553

	if (dbm > 0xffff)
		txpwrmw = 0xffff;
	else
		txpwrmw = (u16) dbm;
1554 1555
	err = brcmf_fil_iovar_int_set(ifp, "qtxpower",
				      (s32)brcmf_mw_to_qdbm(txpwrmw));
1556
	if (err)
1557
		brcmf_err("qtxpower error (%d)\n", err);
1558
	cfg->conf->tx_power = dbm;
1559 1560

done:
1561
	brcmf_dbg(TRACE, "Exit\n");
1562 1563 1564
	return err;
}

1565 1566 1567
static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
				       struct wireless_dev *wdev,
				       s32 *dbm)
1568
{
1569
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1570
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
1571 1572 1573 1574
	s32 txpwrdbm;
	u8 result;
	s32 err = 0;

1575
	brcmf_dbg(TRACE, "Enter\n");
1576
	if (!check_vif_up(ifp->vif))
1577 1578
		return -EIO;

1579
	err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &txpwrdbm);
1580
	if (err) {
1581
		brcmf_err("error (%d)\n", err);
1582 1583 1584 1585
		goto done;
	}

	result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
1586
	*dbm = (s32) brcmf_qdbm_to_mw(result);
1587 1588

done:
1589
	brcmf_dbg(TRACE, "Exit\n");
1590 1591 1592 1593 1594 1595 1596
	return err;
}

static s32
brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
			       u8 key_idx, bool unicast, bool multicast)
{
1597
	struct brcmf_if *ifp = netdev_priv(ndev);
1598 1599 1600 1601
	u32 index;
	u32 wsec;
	s32 err = 0;

1602
	brcmf_dbg(TRACE, "Enter\n");
1603
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1604
	if (!check_vif_up(ifp->vif))
1605 1606
		return -EIO;

1607
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
1608
	if (err) {
1609
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
1610 1611 1612 1613 1614 1615
		goto done;
	}

	if (wsec & WEP_ENABLED) {
		/* Just select a new current key */
		index = key_idx;
1616
		err = brcmf_fil_cmd_int_set(ifp,
1617
					    BRCMF_C_SET_KEY_PRIMARY, index);
1618
		if (err)
1619
			brcmf_err("error (%d)\n", err);
1620 1621
	}
done:
1622
	brcmf_dbg(TRACE, "Exit\n");
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
	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)
{
	struct brcmf_wsec_key key;
	s32 err = 0;

	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 */
1643
		err = send_key_to_dongle(ndev, &key);
1644
		if (err)
1645
			brcmf_err("key delete error (%d)\n", err);
1646 1647
	} else {
		if (key.len > sizeof(key.data)) {
1648
			brcmf_err("Invalid key length (%d)\n", key.len);
1649 1650 1651
			return -EINVAL;
		}

1652
		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
		memcpy(key.data, params->key, key.len);

		if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
			u8 keybuf[8];
			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;
1676
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
1677 1678 1679
			break;
		case WLAN_CIPHER_SUITE_WEP104:
			key.algo = CRYPTO_ALGO_WEP128;
1680
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
1681 1682 1683
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			key.algo = CRYPTO_ALGO_TKIP;
1684
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
1685 1686 1687
			break;
		case WLAN_CIPHER_SUITE_AES_CMAC:
			key.algo = CRYPTO_ALGO_AES_CCM;
1688
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
1689 1690 1691
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			key.algo = CRYPTO_ALGO_AES_CCM;
1692
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
1693 1694
			break;
		default:
1695
			brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
1696 1697
			return -EINVAL;
		}
1698
		err = send_key_to_dongle(ndev, &key);
1699
		if (err)
1700
			brcmf_err("wsec_key error (%d)\n", err);
1701 1702 1703 1704 1705 1706 1707 1708 1709
	}
	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)
{
1710
	struct brcmf_if *ifp = netdev_priv(ndev);
1711 1712 1713 1714 1715 1716
	struct brcmf_wsec_key key;
	s32 val;
	s32 wsec;
	s32 err = 0;
	u8 keybuf[8];

1717
	brcmf_dbg(TRACE, "Enter\n");
1718
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1719
	if (!check_vif_up(ifp->vif))
1720 1721 1722
		return -EIO;

	if (mac_addr) {
1723
		brcmf_dbg(TRACE, "Exit");
1724 1725 1726 1727 1728 1729 1730 1731
		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)) {
1732
		brcmf_err("Too long key length (%u)\n", key.len);
1733 1734 1735 1736 1737 1738 1739 1740 1741
		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;
1742
		val = WEP_ENABLED;
1743
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
1744 1745 1746
		break;
	case WLAN_CIPHER_SUITE_WEP104:
		key.algo = CRYPTO_ALGO_WEP128;
1747
		val = WEP_ENABLED;
1748
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
1749 1750
		break;
	case WLAN_CIPHER_SUITE_TKIP:
1751
		if (ifp->vif->mode != WL_MODE_AP) {
1752
			brcmf_dbg(CONN, "Swapping key\n");
H
Hante Meuleman 已提交
1753 1754 1755 1756
			memcpy(keybuf, &key.data[24], sizeof(keybuf));
			memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
			memcpy(&key.data[16], keybuf, sizeof(keybuf));
		}
1757
		key.algo = CRYPTO_ALGO_TKIP;
1758
		val = TKIP_ENABLED;
1759
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
1760 1761 1762
		break;
	case WLAN_CIPHER_SUITE_AES_CMAC:
		key.algo = CRYPTO_ALGO_AES_CCM;
1763
		val = AES_ENABLED;
1764
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
1765 1766 1767
		break;
	case WLAN_CIPHER_SUITE_CCMP:
		key.algo = CRYPTO_ALGO_AES_CCM;
1768
		val = AES_ENABLED;
1769
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
1770 1771
		break;
	default:
1772
		brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
1773 1774 1775 1776
		err = -EINVAL;
		goto done;
	}

1777
	err = send_key_to_dongle(ndev, &key);
1778 1779 1780
	if (err)
		goto done;

1781
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
1782
	if (err) {
1783
		brcmf_err("get wsec error (%d)\n", err);
1784 1785 1786
		goto done;
	}
	wsec |= val;
1787
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
1788
	if (err) {
1789
		brcmf_err("set wsec error (%d)\n", err);
1790 1791 1792 1793
		goto done;
	}

done:
1794
	brcmf_dbg(TRACE, "Exit\n");
1795 1796 1797 1798 1799 1800 1801
	return err;
}

static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
		    u8 key_idx, bool pairwise, const u8 *mac_addr)
{
1802
	struct brcmf_if *ifp = netdev_priv(ndev);
1803 1804 1805
	struct brcmf_wsec_key key;
	s32 err = 0;

1806
	brcmf_dbg(TRACE, "Enter\n");
1807
	if (!check_vif_up(ifp->vif))
1808 1809
		return -EIO;

1810 1811
	if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
		/* we ignore this key index in this case */
1812
		brcmf_err("invalid key index (%d)\n", key_idx);
1813 1814 1815
		return -EINVAL;
	}

1816 1817 1818 1819 1820 1821
	memset(&key, 0, sizeof(key));

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

1822
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1823 1824

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

1827
	brcmf_dbg(TRACE, "Exit\n");
1828 1829 1830 1831 1832 1833 1834 1835 1836
	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;
1837 1838
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1839 1840 1841 1842
	struct brcmf_cfg80211_security *sec;
	s32 wsec;
	s32 err = 0;

1843
	brcmf_dbg(TRACE, "Enter\n");
1844
	brcmf_dbg(CONN, "key index (%d)\n", key_idx);
1845
	if (!check_vif_up(ifp->vif))
1846 1847 1848 1849
		return -EIO;

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

1850
	err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
1851
	if (err) {
1852
		brcmf_err("WLC_GET_WSEC error (%d)\n", err);
1853 1854 1855 1856
		/* Ignore this error, may happen during DISASSOC */
		err = -EAGAIN;
		goto done;
	}
1857
	switch (wsec & ~SES_OW_ENABLED) {
1858
	case WEP_ENABLED:
1859
		sec = &profile->sec;
1860 1861
		if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
			params.cipher = WLAN_CIPHER_SUITE_WEP40;
1862
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
1863 1864
		} else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
			params.cipher = WLAN_CIPHER_SUITE_WEP104;
1865
			brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
1866 1867 1868 1869
		}
		break;
	case TKIP_ENABLED:
		params.cipher = WLAN_CIPHER_SUITE_TKIP;
1870
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
1871 1872 1873
		break;
	case AES_ENABLED:
		params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
1874
		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
1875 1876
		break;
	default:
1877
		brcmf_err("Invalid algo (0x%x)\n", wsec);
1878 1879 1880 1881 1882 1883
		err = -EINVAL;
		goto done;
	}
	callback(cookie, &params);

done:
1884
	brcmf_dbg(TRACE, "Exit\n");
1885 1886 1887 1888 1889 1890 1891
	return err;
}

static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
				    struct net_device *ndev, u8 key_idx)
{
1892
	brcmf_dbg(INFO, "Not supported\n");
1893 1894 1895 1896 1897 1898

	return -EOPNOTSUPP;
}

static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
H
Hante Meuleman 已提交
1899
			   u8 *mac, struct station_info *sinfo)
1900
{
1901 1902
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
1903 1904 1905 1906
	struct brcmf_scb_val_le scb_val;
	int rssi;
	s32 rate;
	s32 err = 0;
1907
	u8 *bssid = profile->bssid;
1908
	struct brcmf_sta_info_le sta_info_le;
1909

1910
	brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);
1911
	if (!check_vif_up(ifp->vif))
1912 1913
		return -EIO;

1914
	if (ifp->vif->mode == WL_MODE_AP) {
1915
		memcpy(&sta_info_le, mac, ETH_ALEN);
1916
		err = brcmf_fil_iovar_data_get(ifp, "sta_info",
1917
					       &sta_info_le,
1918
					       sizeof(sta_info_le));
H
Hante Meuleman 已提交
1919
		if (err < 0) {
1920
			brcmf_err("GET STA INFO failed, %d\n", err);
H
Hante Meuleman 已提交
1921 1922 1923
			goto done;
		}
		sinfo->filled = STATION_INFO_INACTIVE_TIME;
1924 1925
		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 已提交
1926
			sinfo->filled |= STATION_INFO_CONNECTED_TIME;
1927
			sinfo->connected_time = le32_to_cpu(sta_info_le.in);
H
Hante Meuleman 已提交
1928
		}
1929 1930
		brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
			  sinfo->inactive_time, sinfo->connected_time);
1931
	} else if (ifp->vif->mode == WL_MODE_BSS) {
H
Hante Meuleman 已提交
1932
		if (memcmp(mac, bssid, ETH_ALEN)) {
1933 1934
			brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",
				  mac, bssid);
H
Hante Meuleman 已提交
1935 1936 1937 1938
			err = -ENOENT;
			goto done;
		}
		/* Report the current tx rate */
1939
	err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate);
1940
		if (err) {
1941
			brcmf_err("Could not get rate (%d)\n", err);
H
Hante Meuleman 已提交
1942
			goto done;
1943
		} else {
H
Hante Meuleman 已提交
1944 1945
			sinfo->filled |= STATION_INFO_TX_BITRATE;
			sinfo->txrate.legacy = rate * 5;
1946
			brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
1947
		}
1948

1949 1950
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED,
			     &ifp->vif->sme_state)) {
H
Hante Meuleman 已提交
1951
			memset(&scb_val, 0, sizeof(scb_val));
1952 1953
			err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI,
						     &scb_val, sizeof(scb_val));
H
Hante Meuleman 已提交
1954
			if (err) {
1955
				brcmf_err("Could not get rssi (%d)\n", err);
H
Hante Meuleman 已提交
1956 1957 1958 1959 1960
				goto done;
			} else {
				rssi = le32_to_cpu(scb_val.val);
				sinfo->filled |= STATION_INFO_SIGNAL;
				sinfo->signal = rssi;
1961
				brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
H
Hante Meuleman 已提交
1962 1963 1964 1965
			}
		}
	} else
		err = -EPERM;
1966
done:
1967
	brcmf_dbg(TRACE, "Exit\n");
1968 1969 1970 1971 1972 1973 1974 1975 1976
	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;
1977
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
1978
	struct brcmf_if *ifp = netdev_priv(ndev);
1979

1980
	brcmf_dbg(TRACE, "Enter\n");
1981 1982 1983 1984 1985

	/*
	 * 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
1986
	 * preference in cfg struct to apply this to
1987 1988
	 * FW later while initializing the dongle
	 */
1989
	cfg->pwr_save = enabled;
1990
	if (!check_vif_up(ifp->vif)) {
1991

1992
		brcmf_dbg(INFO, "Device is not ready, storing the value in cfg_info struct\n");
1993 1994 1995 1996
		goto done;
	}

	pm = enabled ? PM_FAST : PM_OFF;
1997
	brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
1998

1999
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
2000 2001
	if (err) {
		if (err == -ENODEV)
2002
			brcmf_err("net_device is not ready yet\n");
2003
		else
2004
			brcmf_err("error (%d)\n", err);
2005 2006
	}
done:
2007
	brcmf_dbg(TRACE, "Exit\n");
2008 2009 2010
	return err;
}

2011
static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
2012
				   struct brcmf_bss_info_le *bi)
2013
{
2014
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
	struct ieee80211_channel *notify_channel;
	struct cfg80211_bss *bss;
	struct ieee80211_supported_band *band;
	s32 err = 0;
	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) {
2028
		brcmf_err("Bss info is larger than buffer. Discarding\n");
2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048
		return 0;
	}

	channel = bi->ctl_ch ? bi->ctl_ch :
				CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));

	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;

2049 2050 2051 2052 2053
	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);
2054 2055

	bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
2056
		0, notify_capability, notify_interval, notify_ie,
2057 2058
		notify_ielen, notify_signal, GFP_KERNEL);

2059 2060 2061 2062
	if (!bss)
		return -ENOMEM;

	cfg80211_put_bss(bss);
2063 2064 2065 2066

	return err;
}

2067 2068 2069 2070 2071 2072 2073 2074 2075
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));
}

2076
static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
2077 2078
{
	struct brcmf_scan_results *bss_list;
2079
	struct brcmf_bss_info_le *bi = NULL;	/* must be initialized */
2080 2081 2082
	s32 err = 0;
	int i;

2083
	bss_list = cfg->bss_list;
2084 2085
	if (bss_list->count != 0 &&
	    bss_list->version != BRCMF_BSS_INFO_VERSION) {
2086 2087
		brcmf_err("Version %d != WL_BSS_INFO_VERSION\n",
			  bss_list->version);
2088 2089
		return -EOPNOTSUPP;
	}
2090
	brcmf_dbg(SCAN, "scanned AP count (%d)\n", bss_list->count);
2091
	for (i = 0; i < bss_list->count; i++) {
2092
		bi = next_bss_le(bss_list, bi);
2093
		err = brcmf_inform_single_bss(cfg, bi);
2094 2095 2096 2097 2098 2099
		if (err)
			break;
	}
	return err;
}

2100
static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
2101 2102
			  struct net_device *ndev, const u8 *bssid)
{
2103
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2104
	struct ieee80211_channel *notify_channel;
2105
	struct brcmf_bss_info_le *bi = NULL;
2106
	struct ieee80211_supported_band *band;
2107
	struct cfg80211_bss *bss;
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117
	u8 *buf = NULL;
	s32 err = 0;
	u16 channel;
	u32 freq;
	u16 notify_capability;
	u16 notify_interval;
	u8 *notify_ie;
	size_t notify_ielen;
	s32 notify_signal;

2118
	brcmf_dbg(TRACE, "Enter\n");
2119 2120 2121 2122 2123 2124 2125 2126 2127

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

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

2128 2129
	err = brcmf_fil_cmd_data_get(netdev_priv(ndev), BRCMF_C_GET_BSS_INFO,
				     buf, WL_BSS_INFO_MAX);
2130
	if (err) {
2131
		brcmf_err("WLC_GET_BSS_INFO failed: %d\n", err);
2132 2133 2134
		goto CleanUp;
	}

2135
	bi = (struct brcmf_bss_info_le *)(buf + 4);
2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153

	channel = bi->ctl_ch ? bi->ctl_ch :
				CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));

	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;

2154 2155 2156 2157
	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);
2158

2159
	bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
2160
		0, notify_capability, notify_interval,
2161 2162
		notify_ie, notify_ielen, notify_signal, GFP_KERNEL);

2163 2164 2165 2166 2167 2168 2169
	if (!bss) {
		err = -ENOMEM;
		goto CleanUp;
	}

	cfg80211_put_bss(bss);

2170 2171 2172 2173
CleanUp:

	kfree(buf);

2174
	brcmf_dbg(TRACE, "Exit\n");
2175 2176 2177 2178

	return err;
}

2179
static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif)
2180
{
2181
	return vif->mode == WL_MODE_IBSS;
2182 2183
}

2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
/*
 * 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
 */
static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
{
	struct brcmf_tlv *elt;
	int totlen;

	elt = (struct brcmf_tlv *) buf;
	totlen = buflen;

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

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

2205 2206
		elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN));
		totlen -= (len + TLV_HDR_LEN);
2207 2208 2209 2210 2211
	}

	return NULL;
}

H
Hante Meuleman 已提交
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
/* Is any of the tlvs the expected entry? If
 * not update the tlvs buffer pointer/length.
 */
static bool
brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,
		 u8 *oui, u32 oui_len, u8 type)
{
	/* 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;
2224 2225
	}

H
Hante Meuleman 已提交
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
	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;
}

F
Franky Lin 已提交
2238
static struct brcmf_vs_tlv *
H
Hante Meuleman 已提交
2239 2240 2241 2242
brcmf_find_wpaie(u8 *parse, u32 len)
{
	struct brcmf_tlv *ie;

2243
	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {
H
Hante Meuleman 已提交
2244 2245 2246 2247
		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len,
				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))
			return (struct brcmf_vs_tlv *)ie;
	}
2248 2249 2250
	return NULL;
}

2251
static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg)
2252
{
2253 2254 2255
	struct net_device *ndev = cfg_to_ndev(cfg);
	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
	struct brcmf_if *ifp = netdev_priv(ndev);
2256
	struct brcmf_bss_info_le *bi;
2257
	struct brcmf_ssid *ssid;
2258
	struct brcmf_tlv *tim;
2259 2260 2261 2262 2263 2264
	u16 beacon_interval;
	u8 dtim_period;
	size_t ie_len;
	u8 *ie;
	s32 err = 0;

2265
	brcmf_dbg(TRACE, "Enter\n");
2266
	if (brcmf_is_ibssmode(ifp->vif))
2267 2268
		return err;

2269
	ssid = &profile->ssid;
2270

2271
	*(__le32 *)cfg->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
2272
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
2273
				     cfg->extra_buf, WL_EXTRA_BUF_MAX);
2274
	if (err) {
2275
		brcmf_err("Could not get bss info %d\n", err);
2276 2277 2278
		goto update_bss_info_out;
	}

2279 2280
	bi = (struct brcmf_bss_info_le *)(cfg->extra_buf + 4);
	err = brcmf_inform_single_bss(cfg, bi);
2281 2282 2283 2284 2285 2286 2287
	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);

2288
	tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
2289 2290 2291 2292 2293 2294 2295 2296 2297
	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;
2298
		err = brcmf_fil_iovar_int_get(ifp, "dtim_assoc", &var);
2299
		if (err) {
2300
			brcmf_err("wl dtim_assoc failed (%d)\n", err);
2301 2302 2303 2304 2305 2306
			goto update_bss_info_out;
		}
		dtim_period = (u8)var;
	}

update_bss_info_out:
2307
	brcmf_dbg(TRACE, "Exit");
2308 2309 2310
	return err;
}

2311
static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
2312
{
2313
	struct escan_info *escan = &cfg->escan_info;
2314

2315
	set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2316
	if (cfg->scan_request) {
2317
		escan->escan_state = WL_ESCAN_STATE_IDLE;
2318
		brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
2319
	}
2320 2321
	clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
	clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
2322 2323
}

H
Hante Meuleman 已提交
2324 2325
static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
{
2326 2327
	struct brcmf_cfg80211_info *cfg =
			container_of(work, struct brcmf_cfg80211_info,
H
Hante Meuleman 已提交
2328 2329
				     escan_timeout_work);

2330 2331
	brcmf_notify_escan_complete(cfg,
		cfg->escan_info.ndev, true, true);
H
Hante Meuleman 已提交
2332 2333 2334 2335
}

static void brcmf_escan_timeout(unsigned long data)
{
2336 2337
	struct brcmf_cfg80211_info *cfg =
			(struct brcmf_cfg80211_info *)data;
H
Hante Meuleman 已提交
2338

2339
	if (cfg->scan_request) {
2340
		brcmf_err("timer expired\n");
2341
		schedule_work(&cfg->escan_timeout_work);
H
Hante Meuleman 已提交
2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
	}
}

static s32
brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
			      struct brcmf_bss_info_le *bss_info_le)
{
	if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
		(CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
		CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
		bss_info_le->SSID_len == bss->SSID_len &&
		!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
		if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
			(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
2356 2357 2358
			s16 bss_rssi = le16_to_cpu(bss->RSSI);
			s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI);

H
Hante Meuleman 已提交
2359 2360 2361
			/* preserve max RSSI if the measurements are
			* both on-channel or both off-channel
			*/
2362
			if (bss_info_rssi > bss_rssi)
H
Hante Meuleman 已提交
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
				bss->RSSI = bss_info_le->RSSI;
		} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
			(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
			/* preserve the on-channel rssi measurement
			* if the new measurement is off channel
			*/
			bss->RSSI = bss_info_le->RSSI;
			bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
		}
		return 1;
	}
	return 0;
}

static s32
2378
brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
H
Hante Meuleman 已提交
2379 2380
			     const struct brcmf_event_msg *e, void *data)
{
2381 2382
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct net_device *ndev = ifp->ndev;
H
Hante Meuleman 已提交
2383 2384 2385 2386 2387 2388 2389 2390
	s32 status;
	s32 err = 0;
	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;
2391
	bool aborted;
H
Hante Meuleman 已提交
2392

2393
	status = e->status;
H
Hante Meuleman 已提交
2394

2395
	if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2396 2397
		brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
			  !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
H
Hante Meuleman 已提交
2398 2399 2400 2401
		return -EPERM;
	}

	if (status == BRCMF_E_STATUS_PARTIAL) {
2402
		brcmf_dbg(SCAN, "ESCAN Partial result\n");
H
Hante Meuleman 已提交
2403 2404
		escan_result_le = (struct brcmf_escan_result_le *) data;
		if (!escan_result_le) {
2405
			brcmf_err("Invalid escan result (NULL pointer)\n");
H
Hante Meuleman 已提交
2406 2407
			goto exit;
		}
2408
		if (!cfg->scan_request) {
2409
			brcmf_dbg(SCAN, "result without cfg80211 request\n");
H
Hante Meuleman 已提交
2410 2411 2412 2413
			goto exit;
		}

		if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2414 2415
			brcmf_err("Invalid bss_count %d: ignoring\n",
				  escan_result_le->bss_count);
H
Hante Meuleman 已提交
2416 2417 2418 2419 2420 2421 2422
			goto exit;
		}
		bss_info_le = &escan_result_le->bss_info_le;

		bi_length = le32_to_cpu(bss_info_le->length);
		if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
					WL_ESCAN_RESULTS_FIXED_SIZE)) {
2423 2424
			brcmf_err("Invalid bss_info length %d: ignoring\n",
				  bi_length);
H
Hante Meuleman 已提交
2425 2426 2427
			goto exit;
		}

2428
		if (!(cfg_to_wiphy(cfg)->interface_modes &
H
Hante Meuleman 已提交
2429 2430 2431
					BIT(NL80211_IFTYPE_ADHOC))) {
			if (le16_to_cpu(bss_info_le->capability) &
						WLAN_CAPABILITY_IBSS) {
2432
				brcmf_err("Ignoring IBSS result\n");
H
Hante Meuleman 已提交
2433 2434 2435 2436 2437
				goto exit;
			}
		}

		list = (struct brcmf_scan_results *)
2438
				cfg->escan_info.escan_buf;
H
Hante Meuleman 已提交
2439
		if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2440
			brcmf_err("Buffer is too small: ignoring\n");
H
Hante Meuleman 已提交
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450
			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;
			if (brcmf_compare_update_same_bss(bss, bss_info_le))
				goto exit;
		}
2451
		memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
H
Hante Meuleman 已提交
2452 2453 2454 2455 2456
			bss_info_le, bi_length);
		list->version = le32_to_cpu(bss_info_le->version);
		list->buflen += bi_length;
		list->count++;
	} else {
2457 2458 2459 2460 2461
		cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
		if (cfg->scan_request) {
			cfg->bss_list = (struct brcmf_scan_results *)
				cfg->escan_info.escan_buf;
			brcmf_inform_bss(cfg);
2462
			aborted = status != BRCMF_E_STATUS_SUCCESS;
2463
			brcmf_notify_escan_complete(cfg, ndev, aborted,
2464
						    false);
H
Hante Meuleman 已提交
2465
		} else
2466
			brcmf_err("Unexpected scan result 0x%x\n", status);
H
Hante Meuleman 已提交
2467 2468 2469 2470 2471
	}
exit:
	return err;
}

2472
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
H
Hante Meuleman 已提交
2473
{
2474 2475
	brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
			    brcmf_cfg80211_escan_handler);
2476 2477 2478 2479 2480 2481 2482
	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 已提交
2483 2484
}

2485
static __always_inline void brcmf_delay(u32 ms)
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
{
	if (ms < 1000 / HZ) {
		cond_resched();
		mdelay(ms);
	} else {
		msleep(ms);
	}
}

static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
2497
	brcmf_dbg(TRACE, "Enter\n");
2498 2499 2500 2501 2502 2503 2504

	return 0;
}

static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
				  struct cfg80211_wowlan *wow)
{
2505 2506
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
	struct net_device *ndev = cfg_to_ndev(cfg);
2507
	struct brcmf_cfg80211_vif *vif;
2508

2509
	brcmf_dbg(TRACE, "Enter\n");
2510 2511

	/*
2512 2513
	 * if the primary net_device is not READY there is nothing
	 * we can do but pray resume goes smoothly.
2514
	 */
2515 2516 2517
	vif = ((struct brcmf_if *)netdev_priv(ndev))->vif;
	if (!check_vif_up(vif))
		goto exit;
2518

2519 2520 2521
	list_for_each_entry(vif, &cfg->vif_list, list) {
		if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
			continue;
2522
		/*
2523 2524
		 * While going to suspend if associated with AP disassociate
		 * from AP to save power while system is in suspended state
2525
		 */
2526 2527 2528 2529 2530 2531 2532
		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);
2533 2534
	}

2535 2536
	/* end any scanning */
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
2537
		brcmf_abort_scanning(cfg);
2538 2539

	/* Turn off watchdog timer */
2540
	brcmf_set_mpc(ndev, 1);
2541

2542
exit:
2543
	brcmf_dbg(TRACE, "Exit\n");
2544 2545
	/* clear any scanning activity */
	cfg->scan_status = 0;
2546 2547 2548 2549 2550 2551 2552 2553
	return 0;
}

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

2556 2557
	pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);

2558
	brcmf_dbg(CONN, "No of elements %d\n", pmkid_len);
2559
	for (i = 0; i < pmkid_len; i++) {
2560 2561
		brcmf_dbg(CONN, "PMKID[%d]: %pM =\n", i,
			  &pmk_list->pmkids.pmkid[i].BSSID);
2562
		for (j = 0; j < WLAN_PMKID_LEN; j++)
2563 2564
			brcmf_dbg(CONN, "%02x\n",
				  pmk_list->pmkids.pmkid[i].PMKID[j]);
2565 2566 2567
	}

	if (!err)
2568 2569
		brcmf_fil_iovar_data_set(netdev_priv(ndev), "pmkid_info",
					 (char *)pmk_list, sizeof(*pmk_list));
2570 2571 2572 2573 2574 2575 2576 2577

	return err;
}

static s32
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
			 struct cfg80211_pmksa *pmksa)
{
2578
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2579
	struct brcmf_if *ifp = netdev_priv(ndev);
2580
	struct pmkid_list *pmkids = &cfg->pmk_list->pmkids;
2581 2582
	s32 err = 0;
	int i;
2583
	int pmkid_len;
2584

2585
	brcmf_dbg(TRACE, "Enter\n");
2586
	if (!check_vif_up(ifp->vif))
2587 2588
		return -EIO;

2589 2590
	pmkid_len = le32_to_cpu(pmkids->npmkid);
	for (i = 0; i < pmkid_len; i++)
2591 2592 2593 2594 2595
		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);
2596 2597 2598 2599
		if (i == pmkid_len) {
			pmkid_len++;
			pmkids->npmkid = cpu_to_le32(pmkid_len);
		}
2600 2601 2602
	} else
		err = -EINVAL;

2603 2604
	brcmf_dbg(CONN, "set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
		  pmkids->pmkid[pmkid_len].BSSID);
2605
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2606
		brcmf_dbg(CONN, "%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
2607

2608
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2609

2610
	brcmf_dbg(TRACE, "Exit\n");
2611 2612 2613 2614 2615 2616 2617
	return err;
}

static s32
brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
		      struct cfg80211_pmksa *pmksa)
{
2618
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2619
	struct brcmf_if *ifp = netdev_priv(ndev);
2620 2621
	struct pmkid_list pmkid;
	s32 err = 0;
2622
	int i, pmkid_len;
2623

2624
	brcmf_dbg(TRACE, "Enter\n");
2625
	if (!check_vif_up(ifp->vif))
2626 2627 2628 2629 2630
		return -EIO;

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

2631 2632
	brcmf_dbg(CONN, "del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
		  &pmkid.pmkid[0].BSSID);
2633
	for (i = 0; i < WLAN_PMKID_LEN; i++)
2634
		brcmf_dbg(CONN, "%02x\n", pmkid.pmkid[0].PMKID[i]);
2635

2636
	pmkid_len = le32_to_cpu(cfg->pmk_list->pmkids.npmkid);
2637
	for (i = 0; i < pmkid_len; i++)
2638
		if (!memcmp
2639
		    (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
2640 2641 2642
		     ETH_ALEN))
			break;

2643 2644
	if ((pmkid_len > 0)
	    && (i < pmkid_len)) {
2645
		memset(&cfg->pmk_list->pmkids.pmkid[i], 0,
2646
		       sizeof(struct pmkid));
2647
		for (; i < (pmkid_len - 1); i++) {
2648 2649
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
2650
			       ETH_ALEN);
2651 2652
			memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
			       &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
2653 2654
			       WLAN_PMKID_LEN);
		}
2655
		cfg->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
2656 2657 2658
	} else
		err = -EINVAL;

2659
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2660

2661
	brcmf_dbg(TRACE, "Exit\n");
2662 2663 2664 2665 2666 2667 2668
	return err;

}

static s32
brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
{
2669
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2670
	struct brcmf_if *ifp = netdev_priv(ndev);
2671 2672
	s32 err = 0;

2673
	brcmf_dbg(TRACE, "Enter\n");
2674
	if (!check_vif_up(ifp->vif))
2675 2676
		return -EIO;

2677 2678
	memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
	err = brcmf_update_pmklist(ndev, cfg->pmk_list, err);
2679

2680
	brcmf_dbg(TRACE, "Exit\n");
2681 2682 2683 2684
	return err;

}

2685 2686 2687 2688 2689 2690 2691 2692 2693
/*
 * 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
2694
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
2695 2696
				const struct brcmf_event_msg *e, void *data)
{
2697 2698
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct net_device *ndev = ifp->ndev;
2699 2700 2701 2702
	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;
2703
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
2704 2705 2706 2707 2708 2709 2710
	int err = 0;
	int channel_req = 0;
	int band = 0;
	struct brcmf_pno_scanresults_le *pfn_result;
	u32 result_count;
	u32 status;

2711
	brcmf_dbg(SCAN, "Enter\n");
2712

2713
	if (e->event_code == BRCMF_E_PFN_NET_LOST) {
2714
		brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
		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);
2727
	brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
2728 2729 2730 2731
	if (result_count > 0) {
		int i;

		request = kzalloc(sizeof(*request), GFP_KERNEL);
2732 2733
		ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
		channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745
		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) {
2746 2747
				brcmf_err("Invalid netinfo ptr. index: %d\n",
					  i);
2748 2749 2750 2751
				err = -EINVAL;
				goto out_err;
			}

2752 2753
			brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
				  netinfo->SSID, netinfo->channel);
2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775
			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];

2776
		if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2777
			/* Abort any on-going scan */
2778
			brcmf_abort_scanning(cfg);
2779 2780
		}

2781
		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2782
		err = brcmf_do_escan(cfg, wiphy, ndev, request);
2783
		if (err) {
2784
			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
2785 2786
			goto out_err;
		}
2787 2788
		cfg->sched_escan = true;
		cfg->scan_request = request;
2789
	} else {
2790
		brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
		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 */
2812
	ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
2813 2814
	if (ret == 0) {
		/* clear pfn */
2815 2816
		ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
					       NULL, 0);
2817 2818
	}
	if (ret < 0)
2819
		brcmf_err("failed code %d\n", ret);
2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838

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

2839 2840
	return brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfn_set",
					&pfn_param, sizeof(pfn_param));
2841 2842 2843 2844 2845 2846 2847
}

static int
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
				struct net_device *ndev,
				struct cfg80211_sched_scan_request *request)
{
2848
	struct brcmf_if *ifp = netdev_priv(ndev);
2849
	struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
2850 2851 2852 2853
	struct brcmf_pno_net_param_le pfn;
	int i;
	int ret = 0;

2854 2855
	brcmf_dbg(SCAN, "Enter n_match_sets:%d   n_ssids:%d\n",
		  request->n_match_sets, request->n_ssids);
2856
	if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
2857
		brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
2858 2859 2860 2861
		return -EAGAIN;
	}

	if (!request || !request->n_ssids || !request->n_match_sets) {
2862 2863
		brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
			  request ? request->n_ssids : 0);
2864 2865 2866 2867 2868 2869
		return -EINVAL;
	}

	if (request->n_ssids > 0) {
		for (i = 0; i < request->n_ssids; i++) {
			/* Active scan req for ssids */
2870 2871
			brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
				  request->ssids[i].ssid);
2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883

			/*
			 * 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) {
2884
			brcmf_err("failed error=%d\n", ret);
2885 2886 2887 2888 2889 2890
			return ret;
		}

		/* configure pno */
		ret = brcmf_dev_pno_config(ndev);
		if (ret < 0) {
2891
			brcmf_err("PNO setup failed!! ret=%d\n", ret);
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903
			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) {
2904
				brcmf_err("skip broadcast ssid\n");
2905 2906 2907 2908 2909 2910 2911 2912 2913
				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);
2914
			ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
2915
						       sizeof(pfn));
2916 2917
			brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
				  ret == 0 ? "set" : "failed", ssid->ssid);
2918 2919
		}
		/* Enable the PNO */
2920
		if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
2921
			brcmf_err("PNO enable failed!! ret=%d\n", ret);
2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933
			return -EINVAL;
		}
	} else {
		return -EINVAL;
	}

	return 0;
}

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

2936
	brcmf_dbg(SCAN, "enter\n");
2937
	brcmf_dev_pno_clean(ndev);
2938 2939
	if (cfg->sched_escan)
		brcmf_notify_escan_complete(cfg, ndev, true, true);
2940 2941 2942
	return 0;
}

2943 2944 2945
#ifdef CONFIG_NL80211_TESTMODE
static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
{
2946
	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
2947
	struct net_device *ndev = cfg_to_ndev(cfg);
2948 2949 2950 2951
	struct brcmf_dcmd *dcmd = data;
	struct sk_buff *reply;
	int ret;

2952 2953
	brcmf_dbg(TRACE, "cmd %x set %d buf %p len %d\n", dcmd->cmd, dcmd->set,
		  dcmd->buf, dcmd->len);
2954 2955

	if (dcmd->set)
2956 2957
		ret = brcmf_fil_cmd_data_set(netdev_priv(ndev), dcmd->cmd,
					     dcmd->buf, dcmd->len);
2958
	else
2959 2960
		ret = brcmf_fil_cmd_data_get(netdev_priv(ndev), dcmd->cmd,
					     dcmd->buf, dcmd->len);
2961 2962 2963 2964 2965 2966 2967 2968 2969
	if (ret == 0) {
		reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*dcmd));
		nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*dcmd), dcmd);
		ret = cfg80211_testmode_reply(reply);
	}
	return ret;
}
#endif

2970
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
H
Hante Meuleman 已提交
2971 2972 2973 2974
{
	s32 err;

	/* set auth */
2975
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0);
H
Hante Meuleman 已提交
2976
	if (err < 0) {
2977
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
2978 2979 2980
		return err;
	}
	/* set wsec */
2981
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", 0);
H
Hante Meuleman 已提交
2982
	if (err < 0) {
2983
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
2984 2985 2986
		return err;
	}
	/* set upper-layer auth */
2987
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE);
H
Hante Meuleman 已提交
2988
	if (err < 0) {
2989
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
		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
brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
3006
		     bool is_rsn_ie)
H
Hante Meuleman 已提交
3007
{
3008
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022
	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;

3023
	brcmf_dbg(TRACE, "Enter\n");
H
Hante Meuleman 已提交
3024 3025 3026 3027 3028
	if (wpa_ie == NULL)
		goto exit;

	len = wpa_ie->len + TLV_HDR_LEN;
	data = (u8 *)wpa_ie;
3029
	offset = TLV_HDR_LEN;
H
Hante Meuleman 已提交
3030 3031
	if (!is_rsn_ie)
		offset += VS_IE_FIXED_HDR_LEN;
3032 3033
	else
		offset += WPA_IE_VERSION_LEN;
H
Hante Meuleman 已提交
3034 3035 3036 3037

	/* check for multicast cipher suite */
	if (offset + WPA_IE_MIN_OUI_LEN > len) {
		err = -EINVAL;
3038
		brcmf_err("no multicast cipher suite\n");
H
Hante Meuleman 已提交
3039 3040 3041 3042 3043
		goto exit;
	}

	if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
		err = -EINVAL;
3044
		brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065
		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;
3066
		brcmf_err("Invalid multi cast cipher info\n");
H
Hante Meuleman 已提交
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076
		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;
3077
		brcmf_err("no unicast cipher suite\n");
H
Hante Meuleman 已提交
3078 3079 3080 3081 3082
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3083
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100
			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:
3101
			brcmf_err("Ivalid unicast security info\n");
H
Hante Meuleman 已提交
3102 3103 3104 3105 3106 3107 3108 3109 3110
		}
		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;
3111
		brcmf_err("no auth key mgmt suite\n");
H
Hante Meuleman 已提交
3112 3113 3114 3115 3116
		goto exit;
	}
	for (i = 0; i < count; i++) {
		if (!brcmf_valid_wpa_oui(&data[offset], is_rsn_ie)) {
			err = -EINVAL;
3117
			brcmf_err("ivalid OUI\n");
H
Hante Meuleman 已提交
3118 3119 3120 3121 3122
			goto exit;
		}
		offset += TLV_OUI_LEN;
		switch (data[offset]) {
		case RSN_AKM_NONE:
3123
			brcmf_dbg(TRACE, "RSN_AKM_NONE\n");
H
Hante Meuleman 已提交
3124 3125 3126
			wpa_auth |= WPA_AUTH_NONE;
			break;
		case RSN_AKM_UNSPECIFIED:
3127
			brcmf_dbg(TRACE, "RSN_AKM_UNSPECIFIED\n");
H
Hante Meuleman 已提交
3128 3129 3130 3131
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_UNSPECIFIED) :
				    (wpa_auth |= WPA_AUTH_UNSPECIFIED);
			break;
		case RSN_AKM_PSK:
3132
			brcmf_dbg(TRACE, "RSN_AKM_PSK\n");
H
Hante Meuleman 已提交
3133 3134 3135 3136
			is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
				    (wpa_auth |= WPA_AUTH_PSK);
			break;
		default:
3137
			brcmf_err("Ivalid key mgmt info\n");
H
Hante Meuleman 已提交
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149
		}
		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 */
3150
		err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
3151
					       wme_bss_disable);
H
Hante Meuleman 已提交
3152
		if (err < 0) {
3153
			brcmf_err("wme_bss_disable error %d\n", err);
H
Hante Meuleman 已提交
3154 3155 3156 3157 3158 3159 3160
			goto exit;
		}
	}
	/* FOR WPS , set SES_OW_ENABLED */
	wsec = (pval | gval | SES_OW_ENABLED);

	/* set auth */
3161
	err = brcmf_fil_bsscfg_int_set(ifp, "auth", auth);
H
Hante Meuleman 已提交
3162
	if (err < 0) {
3163
		brcmf_err("auth error %d\n", err);
H
Hante Meuleman 已提交
3164 3165 3166
		goto exit;
	}
	/* set wsec */
3167
	err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
H
Hante Meuleman 已提交
3168
	if (err < 0) {
3169
		brcmf_err("wsec error %d\n", err);
H
Hante Meuleman 已提交
3170 3171 3172
		goto exit;
	}
	/* set upper-layer auth */
3173
	err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
H
Hante Meuleman 已提交
3174
	if (err < 0) {
3175
		brcmf_err("wpa_auth error %d\n", err);
H
Hante Meuleman 已提交
3176 3177 3178 3179 3180 3181 3182 3183
		goto exit;
	}

exit:
	return err;
}

static s32
3184
brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
H
Hante Meuleman 已提交
3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
		     struct parsed_vndr_ies *vndr_ies)
{
	s32 err = 0;
	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)) {
3203 3204
			brcmf_err("invalid vndr ie. length is too small %d\n",
				  vndrie->len);
H
Hante Meuleman 已提交
3205 3206 3207 3208 3209 3210
			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))) {
3211
			brcmf_dbg(TRACE, "Found WPA/WME oui. Do not add it\n");
H
Hante Meuleman 已提交
3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
			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++;

3224 3225 3226 3227 3228
		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 已提交
3229 3230 3231 3232

		if (vndr_ies->count >= MAX_VNDR_IE_NUMBER)
			break;
next:
3233 3234
		remaining_len -= (ie->len + TLV_HDR_LEN);
		if (remaining_len <= TLV_HDR_LEN)
H
Hante Meuleman 已提交
3235 3236
			ie = NULL;
		else
3237 3238
			ie = (struct brcmf_tlv *)(((u8 *)ie) + ie->len +
				TLV_HDR_LEN);
H
Hante Meuleman 已提交
3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
	}
	return err;
}

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

3264
static
3265 3266
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 已提交
3267
{
3268 3269
	struct brcmf_if *ifp;
	struct vif_saved_ie *saved_ie;
H
Hante Meuleman 已提交
3270 3271 3272 3273
	s32 err = 0;
	u8  *iovar_ie_buf;
	u8  *curr_ie_buf;
	u8  *mgmt_ie_buf = NULL;
3274
	int mgmt_ie_buf_len;
3275
	u32 *mgmt_ie_len;
H
Hante Meuleman 已提交
3276 3277 3278 3279 3280 3281 3282 3283
	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;
3284
	int remained_buf_len;
H
Hante Meuleman 已提交
3285

3286 3287 3288 3289 3290
	if (!vif)
		return -ENODEV;
	ifp = vif->ifp;
	saved_ie = &vif->saved_ie;

3291
	brcmf_dbg(TRACE, "bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
H
Hante Meuleman 已提交
3292 3293 3294 3295
	iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!iovar_ie_buf)
		return -ENOMEM;
	curr_ie_buf = iovar_ie_buf;
3296
	if (ifp->vif->mode == WL_MODE_AP) {
H
Hante Meuleman 已提交
3297 3298
		switch (pktflag) {
		case VNDR_IE_PRBRSP_FLAG:
3299 3300 3301
			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);
H
Hante Meuleman 已提交
3302 3303
			break;
		case VNDR_IE_BEACON_FLAG:
3304 3305 3306
			mgmt_ie_buf = saved_ie->beacon_ie;
			mgmt_ie_len = &saved_ie->beacon_ie_len;
			mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie);
H
Hante Meuleman 已提交
3307 3308 3309
			break;
		default:
			err = -EPERM;
3310
			brcmf_err("not suitable type\n");
H
Hante Meuleman 已提交
3311 3312 3313 3314
			goto exit;
		}
	} else {
		err = -EPERM;
3315
		brcmf_err("not suitable type\n");
H
Hante Meuleman 已提交
3316 3317 3318 3319 3320
		goto exit;
	}

	if (vndr_ie_len > mgmt_ie_buf_len) {
		err = -ENOMEM;
3321
		brcmf_err("extra IE size too big\n");
H
Hante Meuleman 已提交
3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336
		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;
		}
	}

3337
	if (mgmt_ie_buf && *mgmt_ie_len) {
H
Hante Meuleman 已提交
3338 3339 3340
		if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
		    (memcmp(mgmt_ie_buf, curr_ie_buf,
			    parsed_ie_buf_len) == 0)) {
3341
			brcmf_dbg(TRACE, "Previous mgmt IE equals to current IE\n");
H
Hante Meuleman 已提交
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
			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];

3352 3353 3354 3355 3356 3357
			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 已提交
3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378

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

3379 3380 3381
			/* verify remained buf size before copy data */
			if (remained_buf_len < (vndrie_info->vndrie.len +
							VNDR_IE_VSIE_OFFSET)) {
3382 3383
				brcmf_err("no space in mgmt_ie_buf: len left %d",
					  remained_buf_len);
3384 3385 3386 3387 3388
				break;
			}
			remained_buf_len -= (vndrie_info->ie_len +
					     VNDR_IE_VSIE_OFFSET);

3389 3390 3391 3392 3393 3394
			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 已提交
3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410

			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) {
3411
		err  = brcmf_fil_bsscfg_data_set(ifp, "vndr_ie", iovar_ie_buf,
3412
						 total_ie_buf_len);
H
Hante Meuleman 已提交
3413
		if (err)
3414
			brcmf_err("vndr ie set error : %d\n", err);
H
Hante Meuleman 已提交
3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426
	}

exit:
	kfree(iovar_ie_buf);
	return err;
}

static s32
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
			struct cfg80211_ap_settings *settings)
{
	s32 ie_offset;
3427
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3428 3429 3430 3431 3432 3433 3434
	struct brcmf_tlv *ssid_ie;
	struct brcmf_ssid_le ssid_le;
	s32 err = -EPERM;
	struct brcmf_tlv *rsn_ie;
	struct brcmf_vs_tlv *wpa_ie;
	struct brcmf_join_params join_params;

3435 3436 3437 3438 3439 3440 3441
	brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
		  cfg80211_get_chandef_type(&settings->chandef),
		  settings->beacon_interval,
		  settings->dtim_period);
	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 已提交
3442

3443
	if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) {
3444
		brcmf_err("Not in AP creation mode\n");
H
Hante Meuleman 已提交
3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459
		return -EPERM;
	}

	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);
3460
		brcmf_dbg(TRACE, "SSID is (%s) in Head\n", ssid_le.SSID);
H
Hante Meuleman 已提交
3461 3462 3463 3464 3465 3466
	} else {
		memcpy(ssid_le.SSID, settings->ssid, settings->ssid_len);
		ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
	}

	brcmf_set_mpc(ndev, 0);
3467
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
H
Hante Meuleman 已提交
3468
	if (err < 0) {
3469
		brcmf_err("BRCMF_C_DOWN error %d\n", err);
H
Hante Meuleman 已提交
3470 3471
		goto exit;
	}
3472
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1);
H
Hante Meuleman 已提交
3473
	if (err < 0) {
3474
		brcmf_err("SET INFRA error %d\n", err);
H
Hante Meuleman 已提交
3475 3476
		goto exit;
	}
3477
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1);
H
Hante Meuleman 已提交
3478
	if (err < 0) {
3479
		brcmf_err("setting AP mode failed %d\n", err);
H
Hante Meuleman 已提交
3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
		goto exit;
	}

	/* 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)) {
3492
		brcmf_dbg(TRACE, "WPA(2) IE is found\n");
H
Hante Meuleman 已提交
3493 3494
		if (wpa_ie != NULL) {
			/* WPA IE */
3495
			err = brcmf_configure_wpaie(ndev, wpa_ie, false);
H
Hante Meuleman 已提交
3496 3497 3498 3499 3500
			if (err < 0)
				goto exit;
		} else {
			/* RSN IE */
			err = brcmf_configure_wpaie(ndev,
3501
				(struct brcmf_vs_tlv *)rsn_ie, true);
H
Hante Meuleman 已提交
3502 3503 3504 3505
			if (err < 0)
				goto exit;
		}
	} else {
3506
		brcmf_dbg(TRACE, "No WPA(2) IEs found\n");
3507
		brcmf_configure_opensecurity(ifp);
H
Hante Meuleman 已提交
3508 3509
	}
	/* Set Beacon IEs to FW */
3510 3511 3512 3513
	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
				    VNDR_IE_BEACON_FLAG,
				    settings->beacon.tail,
				    settings->beacon.tail_len);
H
Hante Meuleman 已提交
3514
	if (err)
3515
		brcmf_err("Set Beacon IE Failed\n");
H
Hante Meuleman 已提交
3516
	else
3517
		brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n");
H
Hante Meuleman 已提交
3518 3519

	/* Set Probe Response IEs to FW */
3520 3521 3522 3523
	err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
				    VNDR_IE_PRBRSP_FLAG,
				    settings->beacon.proberesp_ies,
				    settings->beacon.proberesp_ies_len);
H
Hante Meuleman 已提交
3524
	if (err)
3525
		brcmf_err("Set Probe Resp IE Failed\n");
H
Hante Meuleman 已提交
3526
	else
3527
		brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n");
H
Hante Meuleman 已提交
3528 3529

	if (settings->beacon_interval) {
3530
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
3531
					    settings->beacon_interval);
H
Hante Meuleman 已提交
3532
		if (err < 0) {
3533
			brcmf_err("Beacon Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3534 3535 3536 3537
			goto exit;
		}
	}
	if (settings->dtim_period) {
3538
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_DTIMPRD,
3539
					    settings->dtim_period);
H
Hante Meuleman 已提交
3540
		if (err < 0) {
3541
			brcmf_err("DTIM Interval Set Error, %d\n", err);
H
Hante Meuleman 已提交
3542 3543 3544
			goto exit;
		}
	}
3545
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
H
Hante Meuleman 已提交
3546
	if (err < 0) {
3547
		brcmf_err("BRCMF_C_UP error (%d)\n", err);
H
Hante Meuleman 已提交
3548 3549 3550 3551 3552 3553 3554
		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 */
3555 3556
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
				     &join_params, sizeof(join_params));
H
Hante Meuleman 已提交
3557
	if (err < 0) {
3558
		brcmf_err("SET SSID error (%d)\n", err);
H
Hante Meuleman 已提交
3559 3560
		goto exit;
	}
3561 3562
	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 已提交
3563 3564 3565 3566 3567 3568 3569 3570 3571

exit:
	if (err)
		brcmf_set_mpc(ndev, 1);
	return err;
}

static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
3572
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3573 3574
	s32 err = -EPERM;

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

3577
	if (ifp->vif->mode == WL_MODE_AP) {
H
Hante Meuleman 已提交
3578 3579 3580
		/* Due to most likely deauths outstanding we sleep */
		/* first to make sure they get processed by fw. */
		msleep(400);
3581
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
H
Hante Meuleman 已提交
3582
		if (err < 0) {
3583
			brcmf_err("setting AP mode failed %d\n", err);
H
Hante Meuleman 已提交
3584 3585
			goto exit;
		}
3586
		err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
H
Hante Meuleman 已提交
3587
		if (err < 0) {
3588
			brcmf_err("BRCMF_C_UP error %d\n", err);
H
Hante Meuleman 已提交
3589 3590 3591
			goto exit;
		}
		brcmf_set_mpc(ndev, 1);
3592 3593
		clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
		clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
H
Hante Meuleman 已提交
3594 3595 3596 3597 3598 3599 3600 3601 3602 3603
	}
exit:
	return err;
}

static int
brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
			   u8 *mac)
{
	struct brcmf_scb_val_le scbval;
3604
	struct brcmf_if *ifp = netdev_priv(ndev);
H
Hante Meuleman 已提交
3605 3606 3607 3608 3609
	s32 err;

	if (!mac)
		return -EFAULT;

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

3612
	if (!check_vif_up(ifp->vif))
H
Hante Meuleman 已提交
3613 3614 3615 3616
		return -EIO;

	memcpy(&scbval.ea, mac, ETH_ALEN);
	scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
3617
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
3618
				     &scbval, sizeof(scbval));
H
Hante Meuleman 已提交
3619
	if (err)
3620
		brcmf_err("SCB_DEAUTHENTICATE_FOR_REASON failed %d\n", err);
H
Hante Meuleman 已提交
3621

3622
	brcmf_dbg(TRACE, "Exit\n");
H
Hante Meuleman 已提交
3623 3624 3625
	return err;
}

3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646
static struct cfg80211_ops wl_cfg80211_ops = {
	.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,
3647
	.flush_pmksa = brcmf_cfg80211_flush_pmksa,
H
Hante Meuleman 已提交
3648 3649 3650
	.start_ap = brcmf_cfg80211_start_ap,
	.stop_ap = brcmf_cfg80211_stop_ap,
	.del_station = brcmf_cfg80211_del_station,
3651 3652
	.sched_scan_start = brcmf_cfg80211_sched_scan_start,
	.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
3653 3654 3655
#ifdef CONFIG_NL80211_TESTMODE
	.testmode_cmd = brcmf_cfg80211_testmode
#endif
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673
};

static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
{
	s32 err = 0;

	switch (mode) {
	case WL_MODE_BSS:
		return NL80211_IFTYPE_STATION;
	case WL_MODE_IBSS:
		return NL80211_IFTYPE_ADHOC;
	default:
		return NL80211_IFTYPE_UNSPECIFIED;
	}

	return err;
}

3674 3675 3676 3677 3678 3679 3680 3681 3682
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;
}

3683
static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
3684
{
3685
	struct wiphy *wiphy;
3686 3687
	s32 err = 0;

3688 3689
	wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
	if (!wiphy) {
3690
		brcmf_err("Could not allocate wiphy device\n");
3691 3692 3693 3694 3695 3696 3697 3698 3699 3700
		return ERR_PTR(-ENOMEM);
	}
	set_wiphy_dev(wiphy, phydev);
	wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
	wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
				 BIT(NL80211_IFTYPE_ADHOC) |
				 BIT(NL80211_IFTYPE_AP);
	wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
	wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;	/* Set
3701 3702 3703 3704 3705 3706
						* it as 11a by default.
						* This will be updated with
						* 11n phy tables in
						* "ifconfig up"
						* if phy has 11n capability
						*/
3707 3708 3709 3710
	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;	/* enable power
3711 3712 3713
								 * save mode
								 * by default
								 */
3714 3715
	brcmf_wiphy_pno_params(wiphy);
	err = wiphy_register(wiphy);
3716
	if (err < 0) {
3717
		brcmf_err("Could not register wiphy device (%d)\n", err);
3718 3719
		wiphy_free(wiphy);
		return ERR_PTR(err);
3720
	}
3721 3722 3723 3724 3725 3726 3727 3728 3729
	return wiphy;
}

static
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
					   struct net_device *netdev,
					   s32 mode, bool pm_block)
{
	struct brcmf_cfg80211_vif *vif;
3730

3731 3732
	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
		return ERR_PTR(-ENOSPC);
3733

3734 3735 3736 3737 3738 3739 3740
	vif = kzalloc(sizeof(*vif), GFP_KERNEL);
	if (!vif)
		return ERR_PTR(-ENOMEM);

	vif->wdev.wiphy = cfg->wiphy;
	vif->wdev.netdev = netdev;
	vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode);
3741

3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
	if (netdev) {
		vif->ifp = netdev_priv(netdev);
		netdev->ieee80211_ptr = &vif->wdev;
		SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy));
	}

	vif->mode = mode;
	vif->pm_block = pm_block;
	vif->roam_off = -1;

3752 3753
	brcmf_init_prof(&vif->profile);

3754 3755 3756
	list_add_tail(&vif->list, &cfg->vif_list);
	cfg->vif_cnt++;
	return vif;
3757 3758
}

3759
static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
3760
{
3761 3762
	struct brcmf_cfg80211_info *cfg;
	struct wiphy *wiphy;
3763

3764 3765 3766 3767 3768 3769 3770 3771 3772
	wiphy = vif->wdev.wiphy;
	cfg = wiphy_priv(wiphy);
	list_del(&vif->list);
	cfg->vif_cnt--;

	kfree(vif);
	if (!cfg->vif_cnt) {
		wiphy_unregister(wiphy);
		wiphy_free(wiphy);
3773 3774 3775
	}
}

3776
static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
3777
{
3778 3779
	u32 event = e->event_code;
	u32 status = e->status;
3780 3781

	if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
3782
		brcmf_dbg(CONN, "Processing set ssid\n");
3783 3784 3785 3786 3787 3788
		return true;
	}

	return false;
}

3789
static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)
3790
{
3791 3792
	u32 event = e->event_code;
	u16 flags = e->flags;
3793 3794

	if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
3795
		brcmf_dbg(CONN, "Processing link down\n");
3796 3797 3798 3799 3800
		return true;
	}
	return false;
}

3801
static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
3802 3803
			       const struct brcmf_event_msg *e)
{
3804 3805
	u32 event = e->event_code;
	u32 status = e->status;
3806 3807

	if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
3808 3809
		brcmf_dbg(CONN, "Processing Link %s & no network found\n",
			  e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
3810 3811 3812 3813
		return true;
	}

	if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) {
3814
		brcmf_dbg(CONN, "Processing connecting & no network found\n");
3815 3816 3817 3818 3819 3820
		return true;
	}

	return false;
}

3821
static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg)
3822
{
3823
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3824 3825 3826 3827 3828 3829 3830 3831 3832

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

3833
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg)
3834
{
3835
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
3836
	struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
3837
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3838 3839 3840 3841
	u32 req_len;
	u32 resp_len;
	s32 err = 0;

3842
	brcmf_clear_assoc_ies(cfg);
3843

3844 3845
	err = brcmf_fil_iovar_data_get(ifp, "assoc_info",
				       cfg->extra_buf, WL_ASSOC_INFO_MAX);
3846
	if (err) {
3847
		brcmf_err("could not get assoc info (%d)\n", err);
3848 3849
		return err;
	}
3850
	assoc_info =
3851
		(struct brcmf_cfg80211_assoc_ielen_le *)cfg->extra_buf;
3852 3853
	req_len = le32_to_cpu(assoc_info->req_len);
	resp_len = le32_to_cpu(assoc_info->resp_len);
3854
	if (req_len) {
3855
		err = brcmf_fil_iovar_data_get(ifp, "assoc_req_ies",
3856 3857
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
3858
		if (err) {
3859
			brcmf_err("could not get assoc req (%d)\n", err);
3860 3861 3862 3863
			return err;
		}
		conn_info->req_ie_len = req_len;
		conn_info->req_ie =
3864
		    kmemdup(cfg->extra_buf, conn_info->req_ie_len,
3865 3866 3867 3868 3869 3870
			    GFP_KERNEL);
	} else {
		conn_info->req_ie_len = 0;
		conn_info->req_ie = NULL;
	}
	if (resp_len) {
3871
		err = brcmf_fil_iovar_data_get(ifp, "assoc_resp_ies",
3872 3873
					       cfg->extra_buf,
					       WL_ASSOC_INFO_MAX);
3874
		if (err) {
3875
			brcmf_err("could not get assoc resp (%d)\n", err);
3876 3877 3878 3879
			return err;
		}
		conn_info->resp_ie_len = resp_len;
		conn_info->resp_ie =
3880
		    kmemdup(cfg->extra_buf, conn_info->resp_ie_len,
3881 3882 3883 3884 3885
			    GFP_KERNEL);
	} else {
		conn_info->resp_ie_len = 0;
		conn_info->resp_ie = NULL;
	}
3886 3887
	brcmf_dbg(CONN, "req len (%d) resp len (%d)\n",
		  conn_info->req_ie_len, conn_info->resp_ie_len);
3888 3889 3890 3891 3892

	return err;
}

static s32
3893
brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
3894 3895 3896
		       struct net_device *ndev,
		       const struct brcmf_event_msg *e)
{
3897 3898
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
3899 3900
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
	struct wiphy *wiphy = cfg_to_wiphy(cfg);
3901
	struct ieee80211_channel *notify_channel = NULL;
3902
	struct ieee80211_supported_band *band;
3903
	struct brcmf_bss_info_le *bi;
3904 3905 3906
	u32 freq;
	s32 err = 0;
	u32 target_channel;
3907
	u8 *buf;
3908

3909
	brcmf_dbg(TRACE, "Enter\n");
3910

3911
	brcmf_get_assoc_ies(cfg);
3912
	memcpy(profile->bssid, e->addr, ETH_ALEN);
3913
	brcmf_update_bss_info(cfg);
3914

3915 3916 3917 3918 3919 3920 3921 3922
	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);
3923
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
3924
				     buf, WL_BSS_INFO_MAX);
3925 3926 3927

	if (err)
		goto done;
3928

3929 3930 3931
	bi = (struct brcmf_bss_info_le *)(buf + 4);
	target_channel = bi->ctl_ch ? bi->ctl_ch :
				      CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
3932 3933 3934 3935 3936 3937 3938 3939 3940

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

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

3941 3942
done:
	kfree(buf);
3943
	cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
3944 3945
			conn_info->req_ie, conn_info->req_ie_len,
			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
3946
	brcmf_dbg(CONN, "Report roaming result\n");
3947

3948
	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
3949
	brcmf_dbg(TRACE, "Exit\n");
3950 3951 3952 3953
	return err;
}

static s32
3954
brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg,
3955 3956 3957
		       struct net_device *ndev, const struct brcmf_event_msg *e,
		       bool completed)
{
3958 3959
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
3960
	struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
3961 3962
	s32 err = 0;

3963
	brcmf_dbg(TRACE, "Enter\n");
3964

3965 3966
	if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
			       &ifp->vif->sme_state)) {
3967
		if (completed) {
3968
			brcmf_get_assoc_ies(cfg);
3969
			memcpy(profile->bssid, e->addr, ETH_ALEN);
3970
			brcmf_update_bss_info(cfg);
3971 3972
		}
		cfg80211_connect_result(ndev,
3973
					(u8 *)profile->bssid,
3974 3975 3976 3977 3978 3979 3980 3981
					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);
		if (completed)
3982 3983
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
3984 3985
		brcmf_dbg(CONN, "Report connect result - connection %s\n",
			  completed ? "succeeded" : "failed");
3986
	}
3987
	brcmf_dbg(TRACE, "Exit\n");
3988 3989 3990 3991
	return err;
}

static s32
3992
brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
H
Hante Meuleman 已提交
3993 3994 3995
			       struct net_device *ndev,
			       const struct brcmf_event_msg *e, void *data)
{
3996
	static int generation;
3997 3998
	u32 event = e->event_code;
	u32 reason = e->reason;
H
Hante Meuleman 已提交
3999 4000
	struct station_info sinfo;

4001
	brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
H
Hante Meuleman 已提交
4002 4003

	if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
4004 4005
	    (reason == BRCMF_E_STATUS_SUCCESS)) {
		memset(&sinfo, 0, sizeof(sinfo));
H
Hante Meuleman 已提交
4006 4007
		sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
		if (!data) {
4008
			brcmf_err("No IEs present in ASSOC/REASSOC_IND");
H
Hante Meuleman 已提交
4009 4010 4011
			return -EINVAL;
		}
		sinfo.assoc_req_ies = data;
4012
		sinfo.assoc_req_ies_len = e->datalen;
H
Hante Meuleman 已提交
4013 4014
		generation++;
		sinfo.generation = generation;
4015
		cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL);
H
Hante Meuleman 已提交
4016 4017 4018
	} else if ((event == BRCMF_E_DISASSOC_IND) ||
		   (event == BRCMF_E_DEAUTH_IND) ||
		   (event == BRCMF_E_DEAUTH)) {
4019
		cfg80211_del_sta(ndev, e->addr, GFP_KERNEL);
H
Hante Meuleman 已提交
4020
	}
4021
	return 0;
H
Hante Meuleman 已提交
4022 4023
}

4024
static s32
4025
brcmf_notify_connect_status(struct brcmf_if *ifp,
4026 4027
			    const struct brcmf_event_msg *e, void *data)
{
4028 4029
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
	struct net_device *ndev = ifp->ndev;
4030
	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
4031 4032
	s32 err = 0;

4033
	if (ifp->vif->mode == WL_MODE_AP) {
4034
		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
4035
	} else if (brcmf_is_linkup(e)) {
4036
		brcmf_dbg(CONN, "Linkup\n");
4037
		if (brcmf_is_ibssmode(ifp->vif)) {
4038
			memcpy(profile->bssid, e->addr, ETH_ALEN);
4039
			wl_inform_ibss(cfg, ndev, e->addr);
4040
			cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
4041 4042 4043 4044
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
			set_bit(BRCMF_VIF_STATUS_CONNECTED,
				&ifp->vif->sme_state);
4045
		} else
4046
			brcmf_bss_connect_done(cfg, ndev, e, true);
4047
	} else if (brcmf_is_linkdown(e)) {
4048
		brcmf_dbg(CONN, "Linkdown\n");
4049
		if (!brcmf_is_ibssmode(ifp->vif)) {
4050
			brcmf_bss_connect_done(cfg, ndev, e, false);
4051
			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED,
4052
					       &ifp->vif->sme_state))
4053
				cfg80211_disconnected(ndev, 0, NULL, 0,
4054
						      GFP_KERNEL);
4055
		}
4056
		brcmf_link_down(ifp->vif);
4057
		brcmf_init_prof(ndev_to_prof(ndev));
4058
	} else if (brcmf_is_nonetwork(cfg, e)) {
4059
		if (brcmf_is_ibssmode(ifp->vif))
4060 4061
			clear_bit(BRCMF_VIF_STATUS_CONNECTING,
				  &ifp->vif->sme_state);
4062
		else
4063
			brcmf_bss_connect_done(cfg, ndev, e, false);
4064 4065 4066 4067 4068 4069
	}

	return err;
}

static s32
4070
brcmf_notify_roaming_status(struct brcmf_if *ifp,
4071 4072
			    const struct brcmf_event_msg *e, void *data)
{
4073
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4074
	s32 err = 0;
4075 4076
	u32 event = e->event_code;
	u32 status = e->status;
4077 4078

	if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
4079
		if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
4080
			brcmf_bss_roaming_done(cfg, ifp->ndev, e);
4081
		else
4082
			brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
4083 4084 4085 4086 4087 4088
	}

	return err;
}

static s32
4089
brcmf_notify_mic_status(struct brcmf_if *ifp,
4090 4091
			const struct brcmf_event_msg *e, void *data)
{
4092
	u16 flags = e->flags;
4093 4094 4095 4096 4097 4098 4099
	enum nl80211_key_type key_type;

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

4100
	cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114
				     NULL, GFP_KERNEL);

	return 0;
}

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

4115
static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
4116
{
4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136
	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);
4137 4138
}

4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154
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)
4155
		goto init_priv_mem_out;
4156 4157
	cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
	if (!cfg->escan_ioctl_buf)
H
Hante Meuleman 已提交
4158
		goto init_priv_mem_out;
4159 4160
	cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
	if (!cfg->extra_buf)
4161
		goto init_priv_mem_out;
4162 4163
	cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
	if (!cfg->pmk_list)
4164 4165 4166 4167 4168
		goto init_priv_mem_out;

	return 0;

init_priv_mem_out:
4169
	brcmf_deinit_priv_mem(cfg);
4170 4171 4172 4173

	return -ENOMEM;
}

4174
static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
4175 4176 4177
{
	s32 err = 0;

4178 4179 4180
	cfg->scan_request = NULL;
	cfg->pwr_save = true;
	cfg->roam_on = true;	/* roam on & off switch.
4181
				 we enable roam per default */
4182
	cfg->active_scan = true;	/* we do active scan for
4183
				 specific scan per default */
4184 4185
	cfg->dongle_up = false;	/* dongle is not up yet */
	err = brcmf_init_priv_mem(cfg);
4186 4187
	if (err)
		return err;
4188
	brcmf_register_event_handlers(cfg);
4189 4190 4191
	mutex_init(&cfg->usr_sync);
	brcmf_init_escan(cfg);
	brcmf_init_conf(cfg->conf);
4192 4193 4194 4195

	return err;
}

4196
static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
4197
{
4198 4199 4200
	cfg->dongle_up = false;	/* dongle down */
	brcmf_abort_scanning(cfg);
	brcmf_deinit_priv_mem(cfg);
4201 4202
}

A
Arend van Spriel 已提交
4203 4204
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
						  struct device *busdev)
4205
{
4206
	struct net_device *ndev = drvr->iflist[0]->ndev;
4207
	struct brcmf_cfg80211_info *cfg;
4208 4209 4210
	struct wiphy *wiphy;
	struct brcmf_cfg80211_vif *vif;
	struct brcmf_if *ifp;
4211 4212 4213
	s32 err = 0;

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

4218 4219 4220
	ifp = netdev_priv(ndev);
	wiphy = brcmf_setup_wiphy(busdev);
	if (IS_ERR(wiphy))
4221 4222
		return NULL;

4223 4224
	cfg = wiphy_priv(wiphy);
	cfg->wiphy = wiphy;
4225
	cfg->pub = drvr;
4226 4227 4228 4229 4230 4231 4232 4233
	INIT_LIST_HEAD(&cfg->vif_list);

	vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false);
	if (IS_ERR(vif)) {
		wiphy_free(wiphy);
		return NULL;
	}

4234
	err = wl_init_priv(cfg);
4235
	if (err) {
4236
		brcmf_err("Failed to init iwm_priv (%d)\n", err);
4237 4238 4239
		goto cfg80211_attach_out;
	}

4240
	ifp->vif = vif;
4241
	return cfg;
4242 4243

cfg80211_attach_out:
4244
	brcmf_free_vif(vif);
4245 4246 4247
	return NULL;
}

4248
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
4249
{
4250 4251 4252
	struct brcmf_cfg80211_vif *vif;
	struct brcmf_cfg80211_vif *tmp;

4253
	wl_deinit_priv(cfg);
4254 4255 4256
	list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
		brcmf_free_vif(vif);
	}
4257 4258 4259
}

static s32
4260
brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)
4261 4262
{
	s32 err = 0;
4263 4264
	__le32 roamtrigger[2];
	__le32 roam_delta[2];
4265 4266 4267 4268 4269 4270

	/*
	 * Setup timeout if Beacons are lost and roam is
	 * off to report link down
	 */
	if (roamvar) {
4271
		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);
4272
		if (err) {
4273
			brcmf_err("bcn_timeout error (%d)\n", err);
4274 4275 4276 4277 4278 4279 4280 4281
			goto dongle_rom_out;
		}
	}

	/*
	 * Enable/Disable built-in roaming to allow supplicant
	 * to take care of roaming
	 */
4282
	brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On");
4283
	err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar);
4284
	if (err) {
4285
		brcmf_err("roam_off error (%d)\n", err);
4286 4287 4288
		goto dongle_rom_out;
	}

4289 4290
	roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
	roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
4291
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
4292
				     (void *)roamtrigger, sizeof(roamtrigger));
4293
	if (err) {
4294
		brcmf_err("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
4295 4296 4297
		goto dongle_rom_out;
	}

4298 4299
	roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
	roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
4300
	err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
4301
				     (void *)roam_delta, sizeof(roam_delta));
4302
	if (err) {
4303
		brcmf_err("WLC_SET_ROAM_DELTA error (%d)\n", err);
4304 4305 4306 4307 4308 4309 4310 4311
		goto dongle_rom_out;
	}

dongle_rom_out:
	return err;
}

static s32
4312
brcmf_dongle_scantime(struct brcmf_if *ifp, s32 scan_assoc_time,
4313
		      s32 scan_unassoc_time, s32 scan_passive_time)
4314 4315 4316
{
	s32 err = 0;

4317
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
4318
				    scan_assoc_time);
4319 4320
	if (err) {
		if (err == -EOPNOTSUPP)
4321
			brcmf_dbg(INFO, "Scan assoc time is not supported\n");
4322
		else
4323
			brcmf_err("Scan assoc time error (%d)\n", err);
4324 4325
		goto dongle_scantime_out;
	}
4326
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
4327
				    scan_unassoc_time);
4328 4329
	if (err) {
		if (err == -EOPNOTSUPP)
4330
			brcmf_dbg(INFO, "Scan unassoc time is not supported\n");
4331
		else
4332
			brcmf_err("Scan unassoc time error (%d)\n", err);
4333 4334 4335
		goto dongle_scantime_out;
	}

4336
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_PASSIVE_TIME,
4337
				    scan_passive_time);
4338 4339
	if (err) {
		if (err == -EOPNOTSUPP)
4340
			brcmf_dbg(INFO, "Scan passive time is not supported\n");
4341
		else
4342
			brcmf_err("Scan passive time error (%d)\n", err);
4343 4344 4345 4346 4347 4348 4349
		goto dongle_scantime_out;
	}

dongle_scantime_out:
	return err;
}

4350
static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
4351
{
4352
	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
4353 4354 4355 4356 4357
	struct wiphy *wiphy;
	s32 phy_list;
	s8 phy;
	s32 err = 0;

H
Hante Meuleman 已提交
4358
	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
4359
				     &phy_list, sizeof(phy_list));
4360
	if (err) {
4361
		brcmf_err("error (%d)\n", err);
4362 4363 4364
		return err;
	}

4365
	phy = ((char *)&phy_list)[0];
4366
	brcmf_dbg(INFO, "%c phy\n", phy);
4367
	if (phy == 'n' || phy == 'a') {
4368
		wiphy = cfg_to_wiphy(cfg);
4369 4370 4371 4372 4373 4374
		wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
	}

	return err;
}

4375
static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
4376
{
4377
	return wl_update_wiphybands(cfg);
4378 4379
}

4380
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
4381 4382 4383
{
	struct net_device *ndev;
	struct wireless_dev *wdev;
4384
	struct brcmf_if *ifp;
4385 4386 4387
	s32 power_mode;
	s32 err = 0;

4388
	if (cfg->dongle_up)
4389 4390
		return err;

4391
	ndev = cfg_to_ndev(cfg);
4392
	wdev = ndev->ieee80211_ptr;
4393 4394 4395 4396
	ifp = netdev_priv(ndev);

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

4398 4399
	brcmf_dongle_scantime(ifp, WL_SCAN_CHANNEL_TIME,
			      WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
4400

4401
	power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
4402
	err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, power_mode);
4403 4404
	if (err)
		goto default_conf_out;
4405 4406
	brcmf_dbg(INFO, "power save set to %s\n",
		  (power_mode ? "enabled" : "disabled"));
4407

4408
	err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT);
4409 4410
	if (err)
		goto default_conf_out;
4411 4412
	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
					  NULL, NULL);
4413
	if (err)
4414
		goto default_conf_out;
4415
	err = brcmf_dongle_probecap(cfg);
4416 4417 4418
	if (err)
		goto default_conf_out;

4419
	cfg->dongle_up = true;
4420
default_conf_out:
4421 4422 4423 4424 4425

	return err;

}

4426
static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
4427
{
4428
	set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
4429

4430
	return brcmf_config_dongle(ifp->drvr->config);
4431 4432
}

4433
static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
4434
{
4435
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4436

4437 4438 4439 4440
	/*
	 * While going down, if associated with AP disassociate
	 * from AP to save power
	 */
4441 4442
	if (check_vif_up(ifp->vif)) {
		brcmf_link_down(ifp->vif);
4443 4444 4445 4446 4447 4448 4449 4450

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

4451
	brcmf_abort_scanning(cfg);
4452
	clear_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
4453 4454 4455 4456

	return 0;
}

4457
s32 brcmf_cfg80211_up(struct net_device *ndev)
4458
{
4459 4460
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4461 4462
	s32 err = 0;

4463
	mutex_lock(&cfg->usr_sync);
4464
	err = __brcmf_cfg80211_up(ifp);
4465
	mutex_unlock(&cfg->usr_sync);
4466 4467 4468 4469

	return err;
}

4470
s32 brcmf_cfg80211_down(struct net_device *ndev)
4471
{
4472 4473
	struct brcmf_if *ifp = netdev_priv(ndev);
	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
4474 4475
	s32 err = 0;

4476
	mutex_lock(&cfg->usr_sync);
4477
	err = __brcmf_cfg80211_down(ifp);
4478
	mutex_unlock(&cfg->usr_sync);
4479 4480 4481 4482

	return err;
}