PageRenderTime 87ms CodeModel.GetById 22ms app.highlight 52ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/net/wireless/bcmdhd_34/dhd_common.c

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

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