PageRenderTime 90ms CodeModel.GetById 24ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/wireless/bcmdhd/dhd_common.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 2451 lines | 1878 code | 381 blank | 192 comment | 381 complexity | b6c74bc5217f61cccb221d0bccae9147 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Broadcom Dongle Host Driver (DHD), common DHD core.
   3 *
   4 * Copyright (C) 1999-2011, Broadcom Corporation
   5 * 
   6 *         Unless you and Broadcom execute a separate written software license
   7 * agreement governing use of this software, this software is licensed to you
   8 * under the terms of the GNU General Public License version 2 (the "GPL"),
   9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10 * following added to such license:
  11 * 
  12 *      As a special exception, the copyright holders of this software give you
  13 * permission to link this software with independent modules, and to copy and
  14 * distribute the resulting executable under terms of your choice, provided that
  15 * you also meet, for each linked independent module, the terms and conditions of
  16 * the license of that module.  An independent module is a module which is not
  17 * derived from this software.  The special exception does not apply to any
  18 * modifications of the software.
  19 * 
  20 *      Notwithstanding the above, under no circumstances may you combine this
  21 * software in any way with any other Broadcom software provided under a license
  22 * other than the GPL, without Broadcom's express prior written consent.
  23 *
  24 * $Id: dhd_common.c 331276 2012-05-04 08:05:57Z $
  25 */
  26#include <typedefs.h>
  27#include <osl.h>
  28
  29#include <epivers.h>
  30#include <bcmutils.h>
  31
  32#include <bcmendian.h>
  33#include <dngl_stats.h>
  34#include <wlioctl.h>
  35#include <dhd.h>
  36
  37#include <proto/bcmevent.h>
  38
  39#include <dhd_bus.h>
  40#include <dhd_proto.h>
  41#include <dhd_dbg.h>
  42#include <msgtrace.h>
  43
  44#ifdef WL_CFG80211
  45#include <wl_cfg80211.h>
  46#endif
  47#include <proto/bt_amp_hci.h>
  48#include <dhd_bta.h>
  49#ifdef SET_RANDOM_MAC_SOFTAP
  50#include <linux/random.h>
  51#include <linux/jiffies.h>
  52#endif
  53
  54#ifdef PROP_TXSTATUS
  55#include <wlfc_proto.h>
  56#include <dhd_wlfc.h>
  57#endif
  58
  59
  60#ifdef WLMEDIA_HTSF
  61extern void htsf_update(struct dhd_info *dhd, void *data);
  62#endif
  63int dhd_msg_level = DHD_ERROR_VAL;
  64
  65
  66#include <wl_iw.h>
  67
  68char fw_path[MOD_PARAM_PATHLEN];
  69char nv_path[MOD_PARAM_PATHLEN];
  70
  71#ifdef SOFTAP
  72char fw_path2[MOD_PARAM_PATHLEN];
  73extern bool softap_enabled;
  74#endif
  75
  76/* Last connection success/failure status */
  77uint32 dhd_conn_event;
  78uint32 dhd_conn_status;
  79uint32 dhd_conn_reason;
  80
  81#define htod32(i) i
  82#define htod16(i) i
  83#define dtoh32(i) i
  84#define dtoh16(i) i
  85extern int dhd_iscan_request(void * dhdp, uint16 action);
  86extern void dhd_ind_scan_confirm(void *h, bool status);
  87extern int dhd_iscan_in_progress(void *h);
  88void dhd_iscan_lock(void);
  89void dhd_iscan_unlock(void);
  90extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
  91bool ap_cfg_running = FALSE;
  92bool ap_fw_loaded = FALSE;
  93
  94
  95#ifdef DHD_DEBUG
  96const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
  97	__DATE__ " at " __TIME__;
  98#else
  99const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
 100#endif
 101
 102void dhd_set_timer(void *bus, uint wdtick);
 103
 104/* IOVar table */
 105enum {
 106	IOV_VERSION = 1,
 107	IOV_MSGLEVEL,
 108	IOV_BCMERRORSTR,
 109	IOV_BCMERROR,
 110	IOV_WDTICK,
 111	IOV_DUMP,
 112	IOV_CLEARCOUNTS,
 113	IOV_LOGDUMP,
 114	IOV_LOGCAL,
 115	IOV_LOGSTAMP,
 116	IOV_GPIOOB,
 117	IOV_IOCTLTIMEOUT,
 118	IOV_HCI_CMD,		/* HCI command */
 119	IOV_HCI_ACL_DATA,	/* HCI data packet */
 120#if defined(DHD_DEBUG)
 121	IOV_CONS,
 122	IOV_DCONSOLE_POLL,
 123#endif /* defined(DHD_DEBUG) */
 124#ifdef PROP_TXSTATUS
 125	IOV_PROPTXSTATUS_ENABLE,
 126	IOV_PROPTXSTATUS_MODE,
 127#endif
 128	IOV_BUS_TYPE,
 129#ifdef WLMEDIA_HTSF
 130	IOV_WLPKTDLYSTAT_SZ,
 131#endif
 132	IOV_CHANGEMTU,
 133	IOV_LAST
 134};
 135
 136const bcm_iovar_t dhd_iovars[] = {
 137	{"version",	IOV_VERSION,	0,	IOVT_BUFFER,	sizeof(dhd_version) },
 138#ifdef DHD_DEBUG
 139	{"msglevel",	IOV_MSGLEVEL,	0,	IOVT_UINT32,	0 },
 140#endif /* DHD_DEBUG */
 141	{"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER,	BCME_STRLEN },
 142	{"bcmerror",	IOV_BCMERROR,	0,	IOVT_INT8,	0 },
 143	{"wdtick",	IOV_WDTICK, 0,	IOVT_UINT32,	0 },
 144	{"dump",	IOV_DUMP,	0,	IOVT_BUFFER,	DHD_IOCTL_MAXLEN },
 145#ifdef DHD_DEBUG
 146	{"cons",	IOV_CONS,	0,	IOVT_BUFFER,	0 },
 147	{"dconpoll",	IOV_DCONSOLE_POLL, 0,	IOVT_UINT32,	0 },
 148#endif
 149	{"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID,	0 },
 150	{"gpioob",	IOV_GPIOOB,	0,	IOVT_UINT32,	0 },
 151	{"ioctl_timeout",	IOV_IOCTLTIMEOUT,	0,	IOVT_UINT32,	0 },
 152	{"HCI_cmd",	IOV_HCI_CMD,	0,	IOVT_BUFFER,	0},
 153	{"HCI_ACL_data", IOV_HCI_ACL_DATA, 0,	IOVT_BUFFER,	0},
 154#ifdef PROP_TXSTATUS
 155	{"proptx",	IOV_PROPTXSTATUS_ENABLE,	0,	IOVT_UINT32,	0 },
 156	/*
 157	set the proptxtstatus operation mode:
 158	0 - Do not do any proptxtstatus flow control
 159	1 - Use implied credit from a packet status
 160	2 - Use explicit credit
 161	*/
 162	{"ptxmode",	IOV_PROPTXSTATUS_MODE,	0,	IOVT_UINT32,	0 },
 163#endif
 164	{"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
 165#ifdef WLMEDIA_HTSF
 166	{"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
 167#endif
 168	{"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
 169	{NULL, 0, 0, 0, 0 }
 170};
 171
 172struct dhd_cmn *
 173dhd_common_init(osl_t *osh)
 174{
 175	dhd_cmn_t *cmn;
 176
 177	/* Init global variables at run-time, not as part of the declaration.
 178	 * This is required to support init/de-init of the driver. Initialization
 179	 * of globals as part of the declaration results in non-deterministic
 180	 * behavior since the value of the globals may be different on the
 181	 * first time that the driver is initialized vs subsequent initializations.
 182	 */
 183	/* Allocate private bus interface state */
 184	if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) {
 185		DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__));
 186		return NULL;
 187	}
 188	memset(cmn, 0, sizeof(dhd_cmn_t));
 189	cmn->osh = osh;
 190
 191#ifdef CONFIG_BCMDHD_FW_PATH
 192	bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
 193#else /* CONFIG_BCMDHD_FW_PATH */
 194	fw_path[0] = '\0';
 195#endif /* CONFIG_BCMDHD_FW_PATH */
 196#ifdef CONFIG_BCMDHD_NVRAM_PATH
 197	bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
 198#else /* CONFIG_BCMDHD_NVRAM_PATH */
 199	nv_path[0] = '\0';
 200#endif /* CONFIG_BCMDHD_NVRAM_PATH */
 201#ifdef SOFTAP
 202	fw_path2[0] = '\0';
 203#endif
 204	return cmn;
 205}
 206
 207void
 208dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn)
 209{
 210	osl_t *osh;
 211	dhd_cmn_t *cmn;
 212
 213	if (dhd_pub != NULL)
 214		cmn = dhd_pub->cmn;
 215	else
 216		cmn = sa_cmn;
 217
 218	if (!cmn)
 219		return;
 220
 221	osh = cmn->osh;
 222
 223	if (dhd_pub != NULL)
 224	dhd_pub->cmn = NULL;
 225	MFREE(osh, cmn, sizeof(dhd_cmn_t));
 226}
 227
 228static int
 229dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
 230{
 231	char eabuf[ETHER_ADDR_STR_LEN];
 232
 233	struct bcmstrbuf b;
 234	struct bcmstrbuf *strbuf = &b;
 235
 236	bcm_binit(strbuf, buf, buflen);
 237
 238	/* Base DHD info */
 239	bcm_bprintf(strbuf, "%s\n", dhd_version);
 240	bcm_bprintf(strbuf, "\n");
 241	bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
 242	            dhdp->up, dhdp->txoff, dhdp->busstate);
 243	bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
 244	            dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
 245	bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
 246	            dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
 247	bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
 248
 249	bcm_bprintf(strbuf, "dongle stats:\n");
 250	bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
 251	            dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
 252	            dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
 253	bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
 254	            dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
 255	            dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
 256	bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
 257
 258	bcm_bprintf(strbuf, "bus stats:\n");
 259	bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
 260	            dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
 261	bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
 262	            dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
 263	bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
 264	            dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
 265	bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n",
 266	            dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
 267	bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n",
 268	            dhdp->rx_readahead_cnt, dhdp->tx_realloc);
 269	bcm_bprintf(strbuf, "\n");
 270
 271	/* Add any prot info */
 272	dhd_prot_dump(dhdp, strbuf);
 273	bcm_bprintf(strbuf, "\n");
 274
 275	/* Add any bus info */
 276	dhd_bus_dump(dhdp, strbuf);
 277
 278	return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
 279}
 280
 281int
 282dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
 283{
 284	wl_ioctl_t ioc;
 285
 286	ioc.cmd = cmd;
 287	ioc.buf = arg;
 288	ioc.len = len;
 289	ioc.set = set;
 290
 291	return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
 292}
 293
 294
 295int
 296dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
 297{
 298	int ret;
 299
 300	dhd_os_proto_block(dhd_pub);
 301
 302	ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
 303	if (ret)
 304		dhd_os_check_hang(dhd_pub, ifindex, ret);
 305
 306	dhd_os_proto_unblock(dhd_pub);
 307	return ret;
 308}
 309
 310static int
 311dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
 312            void *params, int plen, void *arg, int len, int val_size)
 313{
 314	int bcmerror = 0;
 315	int32 int_val = 0;
 316
 317	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 318	DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
 319
 320	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
 321		goto exit;
 322
 323	if (plen >= (int)sizeof(int_val))
 324		bcopy(params, &int_val, sizeof(int_val));
 325
 326	switch (actionid) {
 327	case IOV_GVAL(IOV_VERSION):
 328		/* Need to have checked buffer length */
 329		bcm_strncpy_s((char*)arg, len, dhd_version, len);
 330		break;
 331
 332	case IOV_GVAL(IOV_MSGLEVEL):
 333		int_val = (int32)dhd_msg_level;
 334		bcopy(&int_val, arg, val_size);
 335		break;
 336
 337	case IOV_SVAL(IOV_MSGLEVEL):
 338		dhd_msg_level = int_val;
 339#ifdef WL_CFG80211
 340		/* Enable DHD and WL logs in oneshot */
 341		if (dhd_msg_level & DHD_WL_VAL)
 342			wl_cfg80211_enable_trace(dhd_msg_level);
 343#endif
 344		break;
 345	case IOV_GVAL(IOV_BCMERRORSTR):
 346		bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
 347		((char *)arg)[BCME_STRLEN - 1] = 0x00;
 348		break;
 349
 350	case IOV_GVAL(IOV_BCMERROR):
 351		int_val = (int32)dhd_pub->bcmerror;
 352		bcopy(&int_val, arg, val_size);
 353		break;
 354
 355	case IOV_GVAL(IOV_WDTICK):
 356		int_val = (int32)dhd_watchdog_ms;
 357		bcopy(&int_val, arg, val_size);
 358		break;
 359
 360	case IOV_SVAL(IOV_WDTICK):
 361		if (!dhd_pub->up) {
 362			bcmerror = BCME_NOTUP;
 363			break;
 364		}
 365		dhd_os_wd_timer(dhd_pub, (uint)int_val);
 366		break;
 367
 368	case IOV_GVAL(IOV_DUMP):
 369		bcmerror = dhd_dump(dhd_pub, arg, len);
 370		break;
 371
 372#ifdef DHD_DEBUG
 373	case IOV_GVAL(IOV_DCONSOLE_POLL):
 374		int_val = (int32)dhd_console_ms;
 375		bcopy(&int_val, arg, val_size);
 376		break;
 377
 378	case IOV_SVAL(IOV_DCONSOLE_POLL):
 379		dhd_console_ms = (uint)int_val;
 380		break;
 381
 382	case IOV_SVAL(IOV_CONS):
 383		if (len > 0)
 384			bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
 385		break;
 386#endif /* DHD_DEBUG */
 387
 388	case IOV_SVAL(IOV_CLEARCOUNTS):
 389		dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
 390		dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
 391		dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
 392		dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
 393		dhd_pub->rx_dropped = 0;
 394		dhd_pub->rx_readahead_cnt = 0;
 395		dhd_pub->tx_realloc = 0;
 396		dhd_pub->wd_dpc_sched = 0;
 397		memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
 398		dhd_bus_clearcounts(dhd_pub);
 399#ifdef PROP_TXSTATUS
 400		/* clear proptxstatus related counters */
 401		if (dhd_pub->wlfc_state) {
 402			athost_wl_status_info_t *wlfc =
 403			        (athost_wl_status_info_t*)dhd_pub->wlfc_state;
 404			wlfc_hanger_t* hanger;
 405
 406			memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t));
 407
 408			hanger = (wlfc_hanger_t*)wlfc->hanger;
 409			hanger->pushed = 0;
 410			hanger->popped = 0;
 411			hanger->failed_slotfind = 0;
 412			hanger->failed_to_pop = 0;
 413			hanger->failed_to_push = 0;
 414		}
 415#endif /* PROP_TXSTATUS */
 416		break;
 417
 418
 419	case IOV_GVAL(IOV_IOCTLTIMEOUT): {
 420		int_val = (int32)dhd_os_get_ioctl_resp_timeout();
 421		bcopy(&int_val, arg, sizeof(int_val));
 422		break;
 423	}
 424
 425	case IOV_SVAL(IOV_IOCTLTIMEOUT): {
 426		if (int_val <= 0)
 427			bcmerror = BCME_BADARG;
 428		else
 429			dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
 430		break;
 431	}
 432
 433	case IOV_SVAL(IOV_HCI_CMD): {
 434		amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg;
 435
 436		/* sanity check: command preamble present */
 437		if (len < HCI_CMD_PREAMBLE_SIZE)
 438			return BCME_BUFTOOSHORT;
 439
 440		/* sanity check: command parameters are present */
 441		if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen))
 442			return BCME_BUFTOOSHORT;
 443
 444		dhd_bta_docmd(dhd_pub, cmd, len);
 445		break;
 446	}
 447
 448	case IOV_SVAL(IOV_HCI_ACL_DATA): {
 449		amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg;
 450
 451		/* sanity check: HCI header present */
 452		if (len < HCI_ACL_DATA_PREAMBLE_SIZE)
 453			return BCME_BUFTOOSHORT;
 454
 455		/* sanity check: ACL data is present */
 456		if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen))
 457			return BCME_BUFTOOSHORT;
 458
 459		dhd_bta_tx_hcidata(dhd_pub, ACL_data, len);
 460		break;
 461	}
 462
 463#ifdef PROP_TXSTATUS
 464	case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE):
 465		int_val = dhd_pub->wlfc_enabled? 1 : 0;
 466		bcopy(&int_val, arg, val_size);
 467		break;
 468
 469	case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE):
 470		dhd_pub->wlfc_enabled = int_val? 1 : 0;
 471		break;
 472
 473	case IOV_GVAL(IOV_PROPTXSTATUS_MODE): {
 474		athost_wl_status_info_t *wlfc =
 475		        (athost_wl_status_info_t*)dhd_pub->wlfc_state;
 476		int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0;
 477		bcopy(&int_val, arg, val_size);
 478		break;
 479	}
 480
 481	case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
 482		if (dhd_pub->wlfc_state) {
 483			athost_wl_status_info_t *wlfc =
 484			        (athost_wl_status_info_t*)dhd_pub->wlfc_state;
 485			wlfc->proptxstatus_mode = int_val & 0xff;
 486		}
 487		break;
 488#endif /* PROP_TXSTATUS */
 489
 490	case IOV_GVAL(IOV_BUS_TYPE):
 491		/* The dhd application queries the driver to check if its usb or sdio.  */
 492#ifdef BCMDHDUSB
 493		int_val = BUS_TYPE_USB;
 494#endif
 495		int_val = BUS_TYPE_SDIO;
 496		bcopy(&int_val, arg, val_size);
 497		break;
 498
 499
 500#ifdef WLMEDIA_HTSF
 501	case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
 502		int_val = dhd_pub->htsfdlystat_sz;
 503		bcopy(&int_val, arg, val_size);
 504		break;
 505
 506	case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
 507		dhd_pub->htsfdlystat_sz = int_val & 0xff;
 508		printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
 509		break;
 510#endif
 511	case IOV_SVAL(IOV_CHANGEMTU):
 512		int_val &= 0xffff;
 513		bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
 514		break;
 515
 516	default:
 517		bcmerror = BCME_UNSUPPORTED;
 518		break;
 519	}
 520
 521exit:
 522	DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
 523	return bcmerror;
 524}
 525
 526/* Store the status of a connection attempt for later retrieval by an iovar */
 527void
 528dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
 529{
 530	/* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
 531	 * because an encryption/rsn mismatch results in both events, and
 532	 * the important information is in the WLC_E_PRUNE.
 533	 */
 534	if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
 535	      dhd_conn_event == WLC_E_PRUNE)) {
 536		dhd_conn_event = event;
 537		dhd_conn_status = status;
 538		dhd_conn_reason = reason;
 539	}
 540}
 541
 542bool
 543dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
 544{
 545	void *p;
 546	int eprec = -1;		/* precedence to evict from */
 547	bool discard_oldest;
 548
 549	/* Fast case, precedence queue is not full and we are also not
 550	 * exceeding total queue length
 551	 */
 552	if (!pktq_pfull(q, prec) && !pktq_full(q)) {
 553		pktq_penq(q, prec, pkt);
 554		return TRUE;
 555	}
 556
 557	/* Determine precedence from which to evict packet, if any */
 558	if (pktq_pfull(q, prec))
 559		eprec = prec;
 560	else if (pktq_full(q)) {
 561		p = pktq_peek_tail(q, &eprec);
 562		ASSERT(p);
 563		if (eprec > prec || eprec < 0)
 564			return FALSE;
 565	}
 566
 567	/* Evict if needed */
 568	if (eprec >= 0) {
 569		/* Detect queueing to unconfigured precedence */
 570		ASSERT(!pktq_pempty(q, eprec));
 571		discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
 572		if (eprec == prec && !discard_oldest)
 573			return FALSE;		/* refuse newer (incoming) packet */
 574		/* Evict packet according to discard policy */
 575		p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
 576		ASSERT(p);
 577
 578		PKTFREE(dhdp->osh, p, TRUE);
 579	}
 580
 581	/* Enqueue */
 582	p = pktq_penq(q, prec, pkt);
 583	ASSERT(p);
 584
 585	return TRUE;
 586}
 587
 588static int
 589dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
 590	void *params, int plen, void *arg, int len, bool set)
 591{
 592	int bcmerror = 0;
 593	int val_size;
 594	const bcm_iovar_t *vi = NULL;
 595	uint32 actionid;
 596
 597	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 598
 599	ASSERT(name);
 600	ASSERT(len >= 0);
 601
 602	/* Get MUST have return space */
 603	ASSERT(set || (arg && len));
 604
 605	/* Set does NOT take qualifiers */
 606	ASSERT(!set || (!params && !plen));
 607
 608	if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
 609		bcmerror = BCME_UNSUPPORTED;
 610		goto exit;
 611	}
 612
 613	DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
 614		name, (set ? "set" : "get"), len, plen));
 615
 616	/* set up 'params' pointer in case this is a set command so that
 617	 * the convenience int and bool code can be common to set and get
 618	 */
 619	if (params == NULL) {
 620		params = arg;
 621		plen = len;
 622	}
 623
 624	if (vi->type == IOVT_VOID)
 625		val_size = 0;
 626	else if (vi->type == IOVT_BUFFER)
 627		val_size = len;
 628	else
 629		/* all other types are integer sized */
 630		val_size = sizeof(int);
 631
 632	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
 633
 634	bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
 635
 636exit:
 637	return bcmerror;
 638}
 639
 640int
 641dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
 642{
 643	int bcmerror = 0;
 644
 645	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 646
 647	if (!buf) {
 648		return BCME_BADARG;
 649	}
 650
 651	switch (ioc->cmd) {
 652	case DHD_GET_MAGIC:
 653		if (buflen < sizeof(int))
 654			bcmerror = BCME_BUFTOOSHORT;
 655		else
 656			*(int*)buf = DHD_IOCTL_MAGIC;
 657		break;
 658
 659	case DHD_GET_VERSION:
 660		if (buflen < sizeof(int))
 661			bcmerror = -BCME_BUFTOOSHORT;
 662		else
 663			*(int*)buf = DHD_IOCTL_VERSION;
 664		break;
 665
 666	case DHD_GET_VAR:
 667	case DHD_SET_VAR: {
 668		char *arg;
 669		uint arglen;
 670
 671		/* scan past the name to any arguments */
 672		for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
 673			;
 674
 675		if (*arg) {
 676			bcmerror = BCME_BUFTOOSHORT;
 677			break;
 678		}
 679
 680		/* account for the NUL terminator */
 681		arg++, arglen--;
 682
 683		/* call with the appropriate arguments */
 684		if (ioc->cmd == DHD_GET_VAR)
 685			bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
 686			buf, buflen, IOV_GET);
 687		else
 688			bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
 689		if (bcmerror != BCME_UNSUPPORTED)
 690			break;
 691
 692		/* not in generic table, try protocol module */
 693		if (ioc->cmd == DHD_GET_VAR)
 694			bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
 695				arglen, buf, buflen, IOV_GET);
 696		else
 697			bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
 698				NULL, 0, arg, arglen, IOV_SET);
 699		if (bcmerror != BCME_UNSUPPORTED)
 700			break;
 701
 702		/* if still not found, try bus module */
 703		if (ioc->cmd == DHD_GET_VAR) {
 704			bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
 705				arg, arglen, buf, buflen, IOV_GET);
 706		} else {
 707			bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
 708				NULL, 0, arg, arglen, IOV_SET);
 709		}
 710
 711		break;
 712	}
 713
 714	default:
 715		bcmerror = BCME_UNSUPPORTED;
 716	}
 717
 718	return bcmerror;
 719}
 720
 721#ifdef SHOW_EVENTS
 722static void
 723wl_show_host_event(wl_event_msg_t *event, void *event_data)
 724{
 725	uint i, status, reason;
 726	bool group = FALSE, flush_txq = FALSE, link = FALSE;
 727	const char *auth_str;
 728	const char *event_name;
 729	uchar *buf;
 730	char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
 731	uint event_type, flags, auth_type, datalen;
 732
 733	event_type = ntoh32(event->event_type);
 734	flags = ntoh16(event->flags);
 735	status = ntoh32(event->status);
 736	reason = ntoh32(event->reason);
 737	auth_type = ntoh32(event->auth_type);
 738	datalen = ntoh32(event->datalen);
 739
 740	/* debug dump of event messages */
 741	sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
 742	        (uchar)event->addr.octet[0]&0xff,
 743	        (uchar)event->addr.octet[1]&0xff,
 744	        (uchar)event->addr.octet[2]&0xff,
 745	        (uchar)event->addr.octet[3]&0xff,
 746	        (uchar)event->addr.octet[4]&0xff,
 747	        (uchar)event->addr.octet[5]&0xff);
 748
 749	event_name = "UNKNOWN";
 750	for (i = 0; i < (uint)bcmevent_names_size; i++)
 751		if (bcmevent_names[i].event == event_type)
 752			event_name = bcmevent_names[i].name;
 753
 754	if (flags & WLC_EVENT_MSG_LINK)
 755		link = TRUE;
 756	if (flags & WLC_EVENT_MSG_GROUP)
 757		group = TRUE;
 758	if (flags & WLC_EVENT_MSG_FLUSHTXQ)
 759		flush_txq = TRUE;
 760
 761	switch (event_type) {
 762	case WLC_E_START:
 763	case WLC_E_DEAUTH:
 764	case WLC_E_DISASSOC:
 765		DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
 766		break;
 767
 768	case WLC_E_ASSOC_IND:
 769	case WLC_E_REASSOC_IND:
 770
 771		DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
 772		break;
 773
 774	case WLC_E_ASSOC:
 775	case WLC_E_REASSOC:
 776		if (status == WLC_E_STATUS_SUCCESS) {
 777			DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
 778		} else if (status == WLC_E_STATUS_TIMEOUT) {
 779			DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
 780		} else if (status == WLC_E_STATUS_FAIL) {
 781			DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
 782			       event_name, eabuf, (int)reason));
 783		} else {
 784			DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
 785			       event_name, eabuf, (int)status));
 786		}
 787		break;
 788
 789	case WLC_E_DEAUTH_IND:
 790	case WLC_E_DISASSOC_IND:
 791		DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
 792		break;
 793
 794	case WLC_E_AUTH:
 795	case WLC_E_AUTH_IND:
 796		if (auth_type == DOT11_OPEN_SYSTEM)
 797			auth_str = "Open System";
 798		else if (auth_type == DOT11_SHARED_KEY)
 799			auth_str = "Shared Key";
 800		else {
 801			sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
 802			auth_str = err_msg;
 803		}
 804		if (event_type == WLC_E_AUTH_IND) {
 805			DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
 806		} else if (status == WLC_E_STATUS_SUCCESS) {
 807			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
 808				event_name, eabuf, auth_str));
 809		} else if (status == WLC_E_STATUS_TIMEOUT) {
 810			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
 811				event_name, eabuf, auth_str));
 812		} else if (status == WLC_E_STATUS_FAIL) {
 813			DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
 814			       event_name, eabuf, auth_str, (int)reason));
 815		}
 816
 817		break;
 818
 819	case WLC_E_JOIN:
 820	case WLC_E_ROAM:
 821	case WLC_E_SET_SSID:
 822		if (status == WLC_E_STATUS_SUCCESS) {
 823			DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
 824		} else if (status == WLC_E_STATUS_FAIL) {
 825			DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
 826		} else if (status == WLC_E_STATUS_NO_NETWORKS) {
 827			DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
 828		} else {
 829			DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
 830				event_name, (int)status));
 831		}
 832		break;
 833
 834	case WLC_E_BEACON_RX:
 835		if (status == WLC_E_STATUS_SUCCESS) {
 836			DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
 837		} else if (status == WLC_E_STATUS_FAIL) {
 838			DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
 839		} else {
 840			DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
 841		}
 842		break;
 843
 844	case WLC_E_LINK:
 845		DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
 846		break;
 847
 848	case WLC_E_MIC_ERROR:
 849		DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
 850		       event_name, eabuf, group, flush_txq));
 851		break;
 852
 853	case WLC_E_ICV_ERROR:
 854	case WLC_E_UNICAST_DECODE_ERROR:
 855	case WLC_E_MULTICAST_DECODE_ERROR:
 856		DHD_EVENT(("MACEVENT: %s, MAC %s\n",
 857		       event_name, eabuf));
 858		break;
 859
 860	case WLC_E_TXFAIL:
 861		DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
 862		break;
 863
 864	case WLC_E_SCAN_COMPLETE:
 865	case WLC_E_ASSOC_REQ_IE:
 866	case WLC_E_ASSOC_RESP_IE:
 867	case WLC_E_PMKID_CACHE:
 868		DHD_EVENT(("MACEVENT: %s\n", event_name));
 869		break;
 870
 871	case WLC_E_PFN_NET_FOUND:
 872	case WLC_E_PFN_NET_LOST:
 873	case WLC_E_PFN_SCAN_COMPLETE:
 874	case WLC_E_PFN_SCAN_NONE:
 875	case WLC_E_PFN_SCAN_ALLGONE:
 876		DHD_EVENT(("PNOEVENT: %s\n", event_name));
 877		break;
 878
 879	case WLC_E_PSK_SUP:
 880	case WLC_E_PRUNE:
 881		DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
 882		           event_name, (int)status, (int)reason));
 883		break;
 884
 885#ifdef WIFI_ACT_FRAME
 886	case WLC_E_ACTION_FRAME:
 887		DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
 888		break;
 889#endif /* WIFI_ACT_FRAME */
 890
 891	case WLC_E_TRACE: {
 892		static uint32 seqnum_prev = 0;
 893		msgtrace_hdr_t hdr;
 894		uint32 nblost;
 895		char *s, *p;
 896
 897		buf = (uchar *) event_data;
 898		memcpy(&hdr, buf, MSGTRACE_HDRLEN);
 899
 900		if (hdr.version != MSGTRACE_VERSION) {
 901			printf("\nMACEVENT: %s [unsupported version --> "
 902			       "dhd version:%d dongle version:%d]\n",
 903			       event_name, MSGTRACE_VERSION, hdr.version);
 904			/* Reset datalen to avoid display below */
 905			datalen = 0;
 906			break;
 907		}
 908
 909		/* There are 2 bytes available at the end of data */
 910		buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
 911
 912		if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
 913			printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
 914			       "discarded_bytes %d discarded_printf %d]\n",
 915			       ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
 916		}
 917
 918		nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
 919		if (nblost > 0) {
 920			printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
 921			       ntoh32(hdr.seqnum), nblost);
 922		}
 923		seqnum_prev = ntoh32(hdr.seqnum);
 924
 925		/* Display the trace buffer. Advance from \n to \n to avoid display big
 926		 * printf (issue with Linux printk )
 927		 */
 928		p = (char *)&buf[MSGTRACE_HDRLEN];
 929		while ((s = strstr(p, "\n")) != NULL) {
 930			*s = '\0';
 931			printf("%s\n", p);
 932			p = s+1;
 933		}
 934		printf("%s\n", p);
 935
 936		/* Reset datalen to avoid display below */
 937		datalen = 0;
 938		break;
 939	}
 940
 941
 942	case WLC_E_RSSI:
 943		DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
 944		break;
 945
 946	default:
 947		DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
 948		       event_name, event_type, eabuf, (int)status, (int)reason,
 949		       (int)auth_type));
 950		break;
 951	}
 952
 953	/* show any appended data */
 954	if (datalen) {
 955		buf = (uchar *) event_data;
 956		DHD_EVENT((" data (%d) : ", datalen));
 957		for (i = 0; i < datalen; i++)
 958			DHD_EVENT((" 0x%02x ", *buf++));
 959		DHD_EVENT(("\n"));
 960	}
 961}
 962#endif /* SHOW_EVENTS */
 963
 964int
 965wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
 966              wl_event_msg_t *event, void **data_ptr)
 967{
 968	/* check whether packet is a BRCM event pkt */
 969	bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
 970	uint8 *event_data;
 971	uint32 type, status, reason, datalen;
 972	uint16 flags;
 973	int evlen;
 974
 975	if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
 976		DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
 977		return (BCME_ERROR);
 978	}
 979
 980	/* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
 981	if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
 982		DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
 983		return (BCME_ERROR);
 984	}
 985
 986	*data_ptr = &pvt_data[1];
 987	event_data = *data_ptr;
 988
 989	/* memcpy since BRCM event pkt may be unaligned. */
 990	memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
 991
 992	type = ntoh32_ua((void *)&event->event_type);
 993	flags = ntoh16_ua((void *)&event->flags);
 994	status = ntoh32_ua((void *)&event->status);
 995	reason = ntoh32_ua((void *)&event->reason);
 996	datalen = ntoh32_ua((void *)&event->datalen);
 997	evlen = datalen + sizeof(bcm_event_t);
 998
 999	DHD_TRACE(("RX: event_type:%d flags:%d status:%d reason:%d \n",
1000								type, flags, status, reason));
1001
1002	switch (type) {
1003#ifdef PROP_TXSTATUS
1004	case WLC_E_FIFO_CREDIT_MAP:
1005		dhd_wlfc_event(dhd_pub->info);
1006		dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data);
1007		WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1008			"(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
1009			event_data[2],
1010			event_data[3], event_data[4], event_data[5]));
1011		break;
1012#endif
1013
1014	case WLC_E_IF:
1015		{
1016			dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
1017#ifdef PROP_TXSTATUS
1018			{
1019				uint8* ea = pvt_data->eth.ether_dhost;
1020				WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1021						"[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1022						ifevent->ifidx,
1023						((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"),
1024						((ifevent->is_AP == 0) ? "STA":"AP "),
1025						ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
1026				(void)ea;
1027
1028				dhd_wlfc_interface_event(dhd_pub->info,
1029					((ifevent->action == WLC_E_IF_ADD) ?
1030					eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
1031					ifevent->ifidx, ifevent->is_AP, ea);
1032
1033				/* dhd already has created an interface by default, for 0 */
1034				if (ifevent->ifidx == 0)
1035					break;
1036			}
1037#endif /* PROP_TXSTATUS */
1038
1039#ifdef WL_CFG80211
1040			if (wl_cfg80211_is_progress_ifchange()) {
1041				DHD_ERROR(("%s:  ifidx %d for %s action %d\n",
1042					__FUNCTION__, ifevent->ifidx,
1043					event->ifname, ifevent->action));
1044				if (ifevent->action == WLC_E_IF_ADD)
1045					wl_cfg80211_notify_ifchange();
1046				return (BCME_OK);
1047			}
1048#endif /* WL_CFG80211 */
1049				if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
1050					if (ifevent->action == WLC_E_IF_ADD) {
1051						if (dhd_add_if(dhd_pub->info, ifevent->ifidx,
1052							NULL, event->ifname,
1053							event->addr.octet,
1054							ifevent->flags, ifevent->bssidx)) {
1055							DHD_ERROR(("%s: dhd_add_if failed!!"
1056									" ifidx: %d for %s\n",
1057									__FUNCTION__,
1058									ifevent->ifidx,
1059									event->ifname));
1060							return (BCME_ERROR);
1061						}
1062					}
1063			else
1064				dhd_del_if(dhd_pub->info, ifevent->ifidx);
1065		} else {
1066#ifndef PROP_TXSTATUS
1067			DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1068			           __FUNCTION__, ifevent->ifidx, event->ifname));
1069#endif /* !PROP_TXSTATUS */
1070		}
1071			}
1072			/* send up the if event: btamp user needs it */
1073			*ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1074			/* push up to external supp/auth */
1075			dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1076			break;
1077
1078
1079#ifdef WLMEDIA_HTSF
1080	case WLC_E_HTSFSYNC:
1081		htsf_update(dhd_pub->info, event_data);
1082		break;
1083#endif /* WLMEDIA_HTSF */
1084	case WLC_E_NDIS_LINK: {
1085		uint32 temp = hton32(WLC_E_LINK);
1086
1087		memcpy((void *)(&pvt_data->event.event_type), &temp,
1088		       sizeof(pvt_data->event.event_type));
1089	}
1090		/* These are what external supplicant/authenticator wants */
1091		/* fall through */
1092	case WLC_E_LINK:
1093	case WLC_E_DEAUTH:
1094	case WLC_E_DEAUTH_IND:
1095	case WLC_E_DISASSOC:
1096	case WLC_E_DISASSOC_IND:
1097		DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1098		           __FUNCTION__, type, flags, status));
1099		/* fall through */
1100	default:
1101		*ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1102		/* push up to external supp/auth */
1103		dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1104		DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1105		           __FUNCTION__, type, flags, status));
1106
1107		/* put it back to WLC_E_NDIS_LINK */
1108		if (type == WLC_E_NDIS_LINK) {
1109			uint32 temp;
1110
1111			temp = ntoh32_ua((void *)&event->event_type);
1112			DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
1113
1114			temp = ntoh32(WLC_E_NDIS_LINK);
1115			memcpy((void *)(&pvt_data->event.event_type), &temp,
1116			       sizeof(pvt_data->event.event_type));
1117		}
1118		break;
1119	}
1120
1121#ifdef SHOW_EVENTS
1122	wl_show_host_event(event, (void *)event_data);
1123#endif /* SHOW_EVENTS */
1124
1125	return (BCME_OK);
1126}
1127
1128void
1129wl_event_to_host_order(wl_event_msg_t * evt)
1130{
1131	/* Event struct members passed from dongle to host are stored in network
1132	 * byte order. Convert all members to host-order.
1133	 */
1134	evt->event_type = ntoh32(evt->event_type);
1135	evt->flags = ntoh16(evt->flags);
1136	evt->status = ntoh32(evt->status);
1137	evt->reason = ntoh32(evt->reason);
1138	evt->auth_type = ntoh32(evt->auth_type);
1139	evt->datalen = ntoh32(evt->datalen);
1140	evt->version = ntoh16(evt->version);
1141}
1142
1143void
1144dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1145{
1146#ifdef DHD_DEBUG
1147	int i, j = 0;
1148	unsigned char *buf = pbuf;
1149
1150	if (bytes_per_line == 0) {
1151		bytes_per_line = len;
1152	}
1153
1154	for (i = 0; i < len; i++) {
1155		printf("%2.2x", *buf++);
1156		j++;
1157		if (j == bytes_per_line) {
1158			printf("\n");
1159			j = 0;
1160		} else {
1161			printf(":");
1162		}
1163	}
1164	printf("\n");
1165#endif /* DHD_DEBUG */
1166}
1167
1168#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1169
1170/* Convert user's input in hex pattern to byte-size mask */
1171static int
1172wl_pattern_atoh(char *src, char *dst)
1173{
1174	int i;
1175	if (strncmp(src, "0x", 2) != 0 &&
1176	    strncmp(src, "0X", 2) != 0) {
1177		DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1178		return -1;
1179	}
1180	src = src + 2; /* Skip past 0x */
1181	if (strlen(src) % 2 != 0) {
1182		DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1183		return -1;
1184	}
1185	for (i = 0; *src != '\0'; i++) {
1186		char num[3];
1187		bcm_strncpy_s(num, sizeof(num), src, 2);
1188		num[2] = '\0';
1189		dst[i] = (uint8)strtoul(num, NULL, 16);
1190		src += 2;
1191	}
1192	return i;
1193}
1194
1195void
1196dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1197{
1198	char				*argv[8];
1199	int					i = 0;
1200	const char 			*str;
1201	int					buf_len;
1202	int					str_len;
1203	char				*arg_save = 0, *arg_org = 0;
1204	int					rc;
1205	char				buf[128];
1206	wl_pkt_filter_enable_t	enable_parm;
1207	wl_pkt_filter_enable_t	* pkt_filterp;
1208
1209	if (!arg)
1210		return;
1211
1212	if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1213		DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1214		goto fail;
1215	}
1216	arg_org = arg_save;
1217	memcpy(arg_save, arg, strlen(arg) + 1);
1218
1219	argv[i] = bcmstrtok(&arg_save, " ", 0);
1220
1221	i = 0;
1222	if (argv[i] == NULL) {
1223		DHD_ERROR(("No args provided\n"));
1224		goto fail;
1225	}
1226
1227	str = "pkt_filter_enable";
1228	str_len = strlen(str);
1229	bcm_strncpy_s(buf, sizeof(buf), str, str_len);
1230	buf[str_len] = '\0';
1231	buf_len = str_len + 1;
1232
1233	pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1234
1235	/* Parse packet filter id. */
1236	enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1237
1238	/* Parse enable/disable value. */
1239	enable_parm.enable = htod32(enable);
1240
1241	buf_len += sizeof(enable_parm);
1242	memcpy((char *)pkt_filterp,
1243	       &enable_parm,
1244	       sizeof(enable_parm));
1245
1246	/* Enable/disable the specified filter. */
1247	rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1248	rc = rc >= 0 ? 0 : rc;
1249	if (rc)
1250		DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1251		__FUNCTION__, arg, rc));
1252	else
1253		DHD_TRACE(("%s: successfully added pktfilter %s\n",
1254		__FUNCTION__, arg));
1255
1256	/* Contorl the master mode */
1257	bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
1258	rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
1259	rc = rc >= 0 ? 0 : rc;
1260	if (rc)
1261		DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1262		__FUNCTION__, arg, rc));
1263
1264fail:
1265	if (arg_org)
1266		MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1267}
1268
1269void
1270dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
1271{
1272	const char 			*str;
1273	wl_pkt_filter_t		pkt_filter;
1274	wl_pkt_filter_t		*pkt_filterp;
1275	int					buf_len;
1276	int					str_len;
1277	int 				rc;
1278	uint32				mask_size;
1279	uint32				pattern_size;
1280	char				*argv[8], * buf = 0;
1281	int					i = 0;
1282	char				*arg_save = 0, *arg_org = 0;
1283#define BUF_SIZE		2048
1284
1285	if (!arg)
1286		return;
1287
1288	if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1289		DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1290		goto fail;
1291	}
1292
1293	arg_org = arg_save;
1294
1295	if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1296		DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1297		goto fail;
1298	}
1299
1300	memcpy(arg_save, arg, strlen(arg) + 1);
1301
1302	if (strlen(arg) > BUF_SIZE) {
1303		DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
1304		goto fail;
1305	}
1306
1307	argv[i] = bcmstrtok(&arg_save, " ", 0);
1308	while (argv[i++])
1309		argv[i] = bcmstrtok(&arg_save, " ", 0);
1310
1311	i = 0;
1312	if (argv[i] == NULL) {
1313		DHD_ERROR(("No args provided\n"));
1314		goto fail;
1315	}
1316
1317	str = "pkt_filter_add";
1318	str_len = strlen(str);
1319	bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
1320	buf[ str_len ] = '\0';
1321	buf_len = str_len + 1;
1322
1323	pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1324
1325	/* Parse packet filter id. */
1326	pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1327
1328	if (argv[++i] == NULL) {
1329		DHD_ERROR(("Polarity not provided\n"));
1330		goto fail;
1331	}
1332
1333	/* Parse filter polarity. */
1334	pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1335
1336	if (argv[++i] == NULL) {
1337		DHD_ERROR(("Filter type not provided\n"));
1338		goto fail;
1339	}
1340
1341	/* Parse filter type. */
1342	pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1343
1344	if (argv[++i] == NULL) {
1345		DHD_ERROR(("Offset not provided\n"));
1346		goto fail;
1347	}
1348
1349	/* Parse pattern filter offset. */
1350	pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1351
1352	if (argv[++i] == NULL) {
1353		DHD_ERROR(("Bitmask not provided\n"));
1354		goto fail;
1355	}
1356
1357	/* Parse pattern filter mask. */
1358	mask_size =
1359		htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
1360
1361	if (argv[++i] == NULL) {
1362		DHD_ERROR(("Pattern not provided\n"));
1363		goto fail;
1364	}
1365
1366	/* Parse pattern filter pattern. */
1367	pattern_size =
1368		htod32(wl_pattern_atoh(argv[i],
1369	         (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
1370
1371	if (mask_size != pattern_size) {
1372		DHD_ERROR(("Mask and pattern not the same size\n"));
1373		goto fail;
1374	}
1375
1376	pkt_filter.u.pattern.size_bytes = mask_size;
1377	buf_len += WL_PKT_FILTER_FIXED_LEN;
1378	buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1379
1380	/* Keep-alive attributes are set in local	variable (keep_alive_pkt), and
1381	** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1382	** guarantee that the buffer is properly aligned.
1383	*/
1384	memcpy((char *)pkt_filterp,
1385	       &pkt_filter,
1386	       WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1387
1388	rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1389	rc = rc >= 0 ? 0 : rc;
1390
1391	if (rc)
1392		DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1393		__FUNCTION__, arg, rc));
1394	else
1395		DHD_TRACE(("%s: successfully added pktfilter %s\n",
1396		__FUNCTION__, arg));
1397
1398fail:
1399	if (arg_org)
1400		MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1401
1402	if (buf)
1403		MFREE(dhd->osh, buf, BUF_SIZE);
1404}
1405
1406/* ========================== */
1407/* ==== ARP OFFLOAD SUPPORT = */
1408/* ========================== */
1409#ifdef ARP_OFFLOAD_SUPPORT
1410void
1411dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
1412{
1413	char iovbuf[32];
1414	int retcode;
1415
1416	bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1417	retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1418	retcode = retcode >= 0 ? 0 : retcode;
1419	if (retcode)
1420		DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1421		__FUNCTION__, arp_mode, retcode));
1422	else
1423		DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1424		__FUNCTION__, arp_mode));
1425}
1426
1427void
1428dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
1429{
1430	char iovbuf[32];
1431	int retcode;
1432
1433	bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1434	retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1435	retcode = retcode >= 0 ? 0 : retcode;
1436	if (retcode)
1437		DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1438		__FUNCTION__, arp_enable, retcode));
1439	else
1440		DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1441		__FUNCTION__, arp_enable));
1442}
1443
1444void
1445dhd_aoe_arp_clr(dhd_pub_t *dhd)
1446{
1447	int ret = 0;
1448	int iov_len = 0;
1449	char iovbuf[128];
1450
1451	if (dhd == NULL) return;
1452
1453	iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
1454	if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
1455		DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1456}
1457
1458void
1459dhd_aoe_hostip_clr(dhd_pub_t *dhd)
1460{
1461	int ret = 0;
1462	int iov_len = 0;
1463	char iovbuf[128];
1464
1465	if (dhd == NULL) return;
1466
1467	iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
1468	if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0)
1469		DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1470}
1471
1472void
1473dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
1474{
1475	int iov_len = 0;
1476	char iovbuf[32];
1477	int retcode;
1478
1479	iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf));
1480	retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
1481
1482	if (retcode)
1483		DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
1484		__FUNCTION__, retcode));
1485	else
1486		DHD_TRACE(("%s: sARP H ipaddr entry added \n",
1487		__FUNCTION__));
1488}
1489
1490int
1491dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
1492{
1493	int retcode, i;
1494	int iov_len = 0;
1495	uint32 *ptr32 = buf;
1496	bool clr_bottom = FALSE;
1497
1498	if (!buf)
1499		return -1;
1500
1501	iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
1502	retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0);
1503
1504	if (retcode) {
1505		DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
1506		__FUNCTION__, retcode));
1507
1508		return -1;
1509	}
1510
1511	/* clean up the buf, ascii reminder */
1512	for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
1513		if (!clr_bottom) {
1514			if (*ptr32 == 0)
1515				clr_bottom = TRUE;
1516		} else {
1517			*ptr32 = 0;
1518		}
1519		ptr32++;
1520	}
1521
1522	return 0;
1523}
1524#endif /* ARP_OFFLOAD_SUPPORT  */
1525
1526/* send up locally generated event */
1527void
1528dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
1529{
1530	switch (ntoh32(event->event_type)) {
1531	case WLC_E_BTA_HCI_EVENT:
1532		break;
1533	default:
1534		break;
1535	}
1536
1537	/* Call per-port handler. */
1538	dhd_sendup_event(dhdp, event, data);
1539}
1540
1541#ifdef SIMPLE_ISCAN
1542
1543uint iscan_thread_id = 0;
1544iscan_buf_t * iscan_chain = 0;
1545
1546iscan_buf_t *
1547dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1548{
1549	iscan_buf_t *iscanbuf_alloc = 0;
1550	iscan_buf_t *iscanbuf_head;
1551
1552	DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1553	dhd_iscan_lock();
1554
1555	iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
1556	if (iscanbuf_alloc == NULL)
1557		goto fail;
1558
1559	iscanbuf_alloc->next = NULL;
1560	iscanbuf_head = *iscanbuf;
1561
1562	DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1563		   "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1564		   __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
1565
1566	if (iscanbuf_head == NULL) {
1567		*iscanbuf = iscanbuf_alloc;
1568		DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
1569		goto fail;
1570	}
1571
1572	while (iscanbuf_head->next)
1573		iscanbuf_head = iscanbuf_head->next;
1574
1575	iscanbuf_head->next = iscanbuf_alloc;
1576
1577fail:
1578	dhd_iscan_unlock();
1579	return iscanbuf_alloc;
1580}
1581
1582void
1583dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1584{
1585	iscan_buf_t *iscanbuf_free = 0;
1586	iscan_buf_t *iscanbuf_prv = 0;
1587	iscan_buf_t *iscanbuf_cur;
1588	dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1589	DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1590
1591	dhd_iscan_lock();
1592
1593	iscanbuf_cur = iscan_chain;
1594
1595	/* If iscan_delete is null then delete the entire
1596	 * chain or else delete specific one provided
1597	 */
1598	if (!iscan_delete) {
1599		while (iscanbuf_cur) {
1600			iscanbuf_free = iscanbuf_cur;
1601			iscanbuf_cur = iscanbuf_cur->next;
1602			iscanbuf_free->next = 0;
1603			MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1604		}
1605		iscan_chain = 0;
1606	} else {
1607		while (iscanbuf_cur) {
1608			if (iscanbuf_cur == iscan_delete)
1609				break;
1610			iscanbuf_prv = iscanbuf_cur;
1611			iscanbuf_cur = iscanbuf_cur->next;
1612		}
1613		if (iscanbuf_prv)
1614			iscanbuf_prv->next = iscan_delete->next;
1615
1616		iscan_delete->next = 0;
1617		MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1618
1619		if (!iscanbuf_prv)
1620			iscan_chain = 0;
1621	}
1622	dhd_iscan_unlock();
1623}
1624
1625iscan_buf_t *
1626dhd_iscan_result_buf(void)
1627{
1628	return iscan_chain;
1629}
1630
1631int
1632dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size)
1633{
1634	int rc = -1;
1635	dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1636	char *buf;
1637	char iovar[] = "iscan";
1638	uint32 allocSize = 0;
1639	wl_ioctl_t ioctl;
1640
1641	if (pParams) {
1642		allocSize = (size + strlen(iovar) + 1);
1643		if ((allocSize < size) || (allocSize < strlen(iovar)))
1644		{
1645			DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n",
1646				__FUNCTION__, allocSize, size, strlen(iovar)));
1647			goto cleanUp;
1648		}
1649		buf = MALLOC(dhd->osh, allocSize);
1650
1651		if (buf == NULL)
1652			{
1653			DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize));
1654			goto cleanUp;
1655			}
1656		ioctl.cmd = WLC_SET_VAR;
1657		bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize);
1658		rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize);
1659	}
1660
1661cleanUp:
1662	if (buf) {
1663		MFREE(dhd->osh, buf, allocSize);
1664	}
1665
1666	return rc;
1667}
1668
1669static int
1670dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1671{
1672	wl_iscan_results_t *list_buf;
1673	wl_iscan_results_t list;
1674	wl_scan_results_t *results;
1675	iscan_buf_t *iscan_cur;
1676	int status = -1;
1677	dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1678	int rc;
1679	wl_ioctl_t ioctl;
1680
1681	DHD_ISCAN(("%s: Enter\n", __FUNCTION__));
1682
1683	iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1684	if (!iscan_cur) {
1685		DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
1686		dhd_iscan_free_buf(dhdp, 0);
1687		dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1688		dhd_ind_scan_confirm(dhdp, FALSE);
1689		goto fail;
1690	}
1691
1692	dhd_iscan_lock();
1693
1694	memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1695	list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
1696	results = &list_buf->results;
1697	results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1698	results->version = 0;
1699	results->count = 0;
1700
1701	memset(&list, 0, sizeof(list));
1702	list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1703	bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1704		iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1705	ioctl.cmd = WLC_GET_VAR;
1706	ioctl.set = FALSE;
1707	rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1708
1709	results->buflen = dtoh32(results->buflen);
1710	results->version = dtoh32(results->version);
1711	*scan_count = results->count = dtoh32(results->count);
1712	status = dtoh32(list_buf->status);
1713	DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status));
1714
1715	dhd_iscan_unlock();
1716
1717	if (!(*scan_count)) {
1718		 /* TODO: race condition when FLUSH already called */
1719		dhd_iscan_free_buf(dhdp, 0);
1720	}
1721fail:
1722	return status;
1723}
1724
1725#endif /* SIMPLE_ISCAN */
1726
1727/*
1728 * returns = TRUE if associated, FALSE if not associated
1729 * third paramter retval can return error from error
1730 */
1731bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
1732{
1733	char bssid[6], zbuf[6];
1734	int ret;
1735
1736	bzero(bssid, 6);
1737	bzero(zbuf, 6);
1738
1739	ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
1740	DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
1741
1742	if (retval)
1743		*retval = ret;
1744
1745	if (ret == BCME_NOTASSOCIATED) {
1746		DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
1747	}
1748
1749	if (ret < 0)
1750		return FALSE;
1751
1752	if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
1753		/*  STA is assocoated BSSID is non zero */
1754
1755		if (bss_buf) {
1756			/* return bss if caller provided buf */
1757			memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
1758		}
1759		return TRUE;
1760	} else {
1761		DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
1762		return FALSE;
1763	}
1764}
1765
1766/* Function to estimate possible DTIM_SKIP value */
1767int
1768dhd_get_dtim_skip(dhd_pub_t *dhd)
1769{
1770	int bcn_li_dtim;
1771	int ret = -1;
1772	int dtim_assoc = 0;
1773
1774	if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
1775		bcn_li_dtim = 3;
1776	else
1777		bcn_li_dtim = dhd->dtim_skip;
1778
1779	/* Check if associated */
1780	if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
1781		DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
1782		goto exit;
1783	}
1784
1785	/* if assoc grab ap's dtim value */
1786	if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
1787		&dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) {
1788		DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1789		goto exit;
1790	}
1791
1792	DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n",
1793		__FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL));
1794
1795	/* if not assocated just eixt */
1796	if (dtim_assoc == 0) {
1797		goto exit;
1798	}
1799
1800	/* check if sta listen interval fits into AP dtim */
1801	if (dtim_assoc > LISTEN_INTERVAL) {
1802		/* AP DTIM to big for our Listen Interval : no dtim skiping */
1803		bcn_li_dtim = 1;
1804		DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
1805			__FUNCTION__, dtim_assoc, LISTEN_INTERVAL));
1806		goto exit;
1807	}
1808
1809	if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) {
1810		/* Round up dtim_skip to fit into STAs Listen Interval */
1811		bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc);
1812		DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
1813	}
1814
1815exit:
1816	return bcn_li_dtim;
1817}
1818
1819/* Check if HostAPD or WFD mode setup */
1820bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd)
1821{
1822#ifdef  WL_CFG80211
1823#ifndef WL_ENABLE_P2P_IF
1824	/* To be back compatble with ICS MR1 release where p2p interface
1825	 * disable but wlan0 used for p2p
1826	 */
1827	if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) ||
1828		((dhd->op_mode & WFD_MASK) == WFD_MASK)) {
1829		return TRUE;
1830	}
1831	else
1832#else
1833	/* concurent mode with p2p interface for wfd and wlan0 for sta */
1834	if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) ||
1835		((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) {
1836		DHD_ERROR(("%s P2P enabled for  mode=%d\n", __FUNCTION__, dhd->op_mode));
1837		return TRUE;
1838	}
1839	else
1840#endif /* WL_ENABLE_P2P_IF */
1841#endif /* WL_CFG80211 */
1842		return FALSE;
1843}
1844
1845#ifdef PNO_SUPPORT
1846int
1847dhd_pno_clean(dhd_pub_t *dhd)
1848{
1849	char iovbuf[128];
1850	int pfn_enabled = 0;
1851	int iov_len = 0;
1852	int ret;
1853
1854	/* Disable pfn */
1855	iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1856	if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) {
1857		/* clear pfn */
1858		iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1859		if (iov_len) {
1860			if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1861			                            iov_len, TRUE, 0)) < 0) {
1862				DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1863			}
1864		}
1865		else {
1866			ret = -1;
1867			DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
1868		}
1869	}
1870	else
1871		DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1872
1873	return ret;
1874}
1875
1876int
1877dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1878{
1879	char iovbuf[128];
1880	int ret = -1;
1881
1882	if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1883		DHD_ERROR(("%s error exit\n", __FUNCTION__));
1884		return ret;
1885	}
1886
1887
1888	memset(iovbuf, 0, sizeof(iovbuf));
1889
1890#ifndef WL_SCHED_SCAN
1891	if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
1892		return (ret);
1893
1894	if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) {
1895		DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
1896		return ret;
1897	}
1898#endif /* !WL_SCHED_SCAN */
1899
1900	/* Enable/disable PNO */
1901	if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
1902		if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
1903			iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
1904			DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
1905			return ret;
1906		}
1907		else {
1908			dhd->pno_enable = pfn_enabled;
1909			DHD_TRACE(("%s set pno as %s\n",
1910				__FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"));
1911		}
1912	}
1913	else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
1914
1915	return ret;
1916}
1917
1918/* Function to execute combined scan */
1919int
1920dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
1921	int pno_repeat, int pno_freq_expo_max)
1922{
1923	int err = -1;
1924	char iovbuf[128];
1925	int k, i;
1926	wl_pfn_param_t pfn_param;
1927	wl_pfn_t	pfn_element;
1928	uint len = 0;
1929
1930	DH

Large files files are truncated, but you can click here to view the full file