Home | History | Annotate | Download | only in sys
      1 /*
      2  * DHD Protocol Module for CDC and BDC.
      3  *
      4  * Copyright (C) 1999-2010, 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_cdc.c,v 1.22.4.2.4.7.2.34 2010/01/21 22:08:34 Exp $
     25  *
     26  * BDC is like CDC, except it includes a header for data packets to convey
     27  * packet priority over the bus, and flags (e.g. to indicate checksum status
     28  * for dongle offload).
     29  */
     30 
     31 #include <typedefs.h>
     32 #include <osl.h>
     33 
     34 #include <bcmutils.h>
     35 #include <bcmcdc.h>
     36 #include <bcmendian.h>
     37 
     38 #include <dngl_stats.h>
     39 #include <dhd.h>
     40 #include <dhd_proto.h>
     41 #include <dhd_bus.h>
     42 #include <dhd_dbg.h>
     43 
     44 
     45 /* Packet alignment for most efficient SDIO (can change based on platform) */
     46 #ifndef DHD_SDALIGN
     47 #define DHD_SDALIGN	32
     48 #endif
     49 #if !ISPOWEROF2(DHD_SDALIGN)
     50 #error DHD_SDALIGN is not a power of 2!
     51 #endif
     52 
     53 #define RETRIES 2		/* # of retries to retrieve matching ioctl response */
     54 #define BUS_HEADER_LEN	(16+DHD_SDALIGN)	/* Must be atleast SDPCM_RESERVE
     55 				 * defined in dhd_sdio.c (amount of header tha might be added)
     56 				 * plus any space that might be needed for alignment padding.
     57 				 */
     58 #define ROUND_UP_MARGIN	2048 	/* Biggest SDIO block size possible for
     59 				 * round off at the end of buffer
     60 				 */
     61 
     62 typedef struct dhd_prot {
     63 	uint16 reqid;
     64 	uint8 pending;
     65 	uint32 lastcmd;
     66 	uint8 bus_header[BUS_HEADER_LEN];
     67 	cdc_ioctl_t msg;
     68 	unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
     69 } dhd_prot_t;
     70 
     71 static int
     72 dhdcdc_msg(dhd_pub_t *dhd)
     73 {
     74 	dhd_prot_t *prot = dhd->prot;
     75 	int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
     76 	int ret;
     77 
     78 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
     79 
     80 	dhd_os_wake_lock(dhd);
     81 
     82 	/* NOTE : cdc->msg.len holds the desired length of the buffer to be
     83 	 *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
     84 	 *	  is actually sent to the dongle
     85 	 */
     86 	if (len > CDC_MAX_MSG_SIZE)
     87 		len = CDC_MAX_MSG_SIZE;
     88 
     89 	/* Send request */
     90 	ret = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
     91 	dhd_os_wake_unlock(dhd);
     92 	return ret;
     93 }
     94 
     95 static int
     96 dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
     97 {
     98 	int ret;
     99 	dhd_prot_t *prot = dhd->prot;
    100 
    101 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    102 
    103 	do {
    104 		ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, len+sizeof(cdc_ioctl_t));
    105 		if (ret < 0)
    106 			break;
    107 	} while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
    108 
    109 	return ret;
    110 }
    111 
    112 int
    113 dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
    114 {
    115 	dhd_prot_t *prot = dhd->prot;
    116 	cdc_ioctl_t *msg = &prot->msg;
    117 	void *info;
    118 	int ret = 0, retries = 0;
    119 	uint32 id, flags = 0;
    120 
    121 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    122 	DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
    123 
    124 
    125 	/* Respond "bcmerror" and "bcmerrorstr" with local cache */
    126 	if (cmd == WLC_GET_VAR && buf)
    127 	{
    128 		if (!strcmp((char *)buf, "bcmerrorstr"))
    129 		{
    130 			strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
    131 			goto done;
    132 		}
    133 		else if (!strcmp((char *)buf, "bcmerror"))
    134 		{
    135 			*(int *)buf = dhd->dongle_error;
    136 			goto done;
    137 		}
    138 	}
    139 
    140 	memset(msg, 0, sizeof(cdc_ioctl_t));
    141 
    142 	msg->cmd = htol32(cmd);
    143 	msg->len = htol32(len);
    144 	msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
    145 	CDC_SET_IF_IDX(msg, ifidx);
    146 	msg->flags = htol32(msg->flags);
    147 
    148 	if (buf)
    149 		memcpy(prot->buf, buf, len);
    150 
    151 	if ((ret = dhdcdc_msg(dhd)) < 0) {
    152 		DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
    153 		goto done;
    154 	}
    155 
    156 retry:
    157 	/* wait for interrupt and get first fragment */
    158 	if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
    159 		goto done;
    160 
    161 	flags = ltoh32(msg->flags);
    162 	id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
    163 
    164 	if ((id < prot->reqid) && (++retries < RETRIES))
    165 		goto retry;
    166 	if (id != prot->reqid) {
    167 		DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
    168 		           dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
    169 		ret = -EINVAL;
    170 		goto done;
    171 	}
    172 
    173 	/* Check info buffer */
    174 	info = (void*)&msg[1];
    175 
    176 	/* Copy info buffer */
    177 	if (buf)
    178 	{
    179 		if (ret < (int)len)
    180 			len = ret;
    181 		memcpy(buf, info, len);
    182 	}
    183 
    184 	/* Check the ERROR flag */
    185 	if (flags & CDCF_IOC_ERROR)
    186 	{
    187 		ret = ltoh32(msg->status);
    188 		/* Cache error from dongle */
    189 		dhd->dongle_error = ret;
    190 	}
    191 
    192 done:
    193 	return ret;
    194 }
    195 
    196 static int
    197 dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
    198 {
    199 	dhd_prot_t *prot = dhd->prot;
    200 	cdc_ioctl_t *msg = &prot->msg;
    201 	int ret = 0;
    202 	uint32 flags, id;
    203 
    204 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    205 	DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
    206 
    207 	memset(msg, 0, sizeof(cdc_ioctl_t));
    208 
    209 	msg->cmd = htol32(cmd);
    210 	msg->len = htol32(len);
    211 	msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
    212 	CDC_SET_IF_IDX(msg, ifidx);
    213 	msg->flags |= htol32(msg->flags);
    214 
    215 	if (buf)
    216 		memcpy(prot->buf, buf, len);
    217 
    218 	if ((ret = dhdcdc_msg(dhd)) < 0)
    219 		goto done;
    220 
    221 	if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
    222 		goto done;
    223 
    224 	flags = ltoh32(msg->flags);
    225 	id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
    226 
    227 	if (id != prot->reqid) {
    228 		DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
    229 		           dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
    230 		ret = -EINVAL;
    231 		goto done;
    232 	}
    233 
    234 	/* Check the ERROR flag */
    235 	if (flags & CDCF_IOC_ERROR)
    236 	{
    237 		ret = ltoh32(msg->status);
    238 		/* Cache error from dongle */
    239 		dhd->dongle_error = ret;
    240 	}
    241 
    242 done:
    243 	return ret;
    244 }
    245 
    246 extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void* arg2);
    247 int
    248 dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
    249 {
    250 	dhd_prot_t *prot = dhd->prot;
    251 	int ret = -1;
    252 
    253 	if (dhd->busstate == DHD_BUS_DOWN) {
    254 		DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
    255 		return ret;
    256 	}
    257 	dhd_os_proto_block(dhd);
    258 
    259 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    260 
    261 	ASSERT(len <= WLC_IOCTL_MAXLEN);
    262 
    263 	if (len > WLC_IOCTL_MAXLEN)
    264 		goto done;
    265 
    266 	if (prot->pending == TRUE) {
    267 		DHD_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
    268 			ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
    269 			(unsigned long)prot->lastcmd));
    270 		if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
    271 			DHD_TRACE(("iovar cmd=%s\n", (char*)buf));
    272 		}
    273 		goto done;
    274 	}
    275 
    276 	prot->pending = TRUE;
    277 	prot->lastcmd = ioc->cmd;
    278 	if (ioc->set)
    279 		ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len);
    280 	else {
    281 		ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len);
    282 		if (ret > 0)
    283 			ioc->used = ret - sizeof(cdc_ioctl_t);
    284 	}
    285 
    286 	/* Too many programs assume ioctl() returns 0 on success */
    287 	if (ret >= 0)
    288 		ret = 0;
    289 	else {
    290 		cdc_ioctl_t *msg = &prot->msg;
    291 		ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
    292 	}
    293 
    294 	/* Intercept the wme_dp ioctl here */
    295 	if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
    296 		int slen, val = 0;
    297 
    298 		slen = strlen("wme_dp") + 1;
    299 		if (len >= (int)(slen + sizeof(int)))
    300 			bcopy(((char *)buf + slen), &val, sizeof(int));
    301 		dhd->wme_dp = (uint8) ltoh32(val);
    302 	}
    303 
    304 	prot->pending = FALSE;
    305 
    306 done:
    307 	dhd_os_proto_unblock(dhd);
    308 
    309 	return ret;
    310 }
    311 
    312 int
    313 dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
    314                   void *params, int plen, void *arg, int len, bool set)
    315 {
    316 	return BCME_UNSUPPORTED;
    317 }
    318 
    319 void
    320 dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
    321 {
    322 	bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
    323 }
    324 
    325 #ifdef APSTA_PINGTEST
    326 extern struct ether_addr guest_eas[MAX_GUEST];
    327 #endif
    328 
    329 void
    330 dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
    331 {
    332 #ifdef BDC
    333 	struct bdc_header *h;
    334 #ifdef APSTA_PINGTEST
    335 	struct	ether_header *eh;
    336 	int i;
    337 #ifdef DHD_DEBUG
    338 	char eabuf1[ETHER_ADDR_STR_LEN];
    339 	char eabuf2[ETHER_ADDR_STR_LEN];
    340 #endif /* DHD_DEBUG */
    341 #endif /* APSTA_PINGTEST */
    342 #endif /* BDC */
    343 
    344 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    345 
    346 #ifdef BDC
    347 	/* Push BDC header used to convey priority for buses that don't */
    348 
    349 #ifdef APSTA_PINGTEST
    350 	eh = (struct ether_header *)PKTDATA(dhd->osh, pktbuf);
    351 #endif
    352 
    353 	PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
    354 
    355 	h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
    356 
    357 	h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
    358 	if (PKTSUMNEEDED(pktbuf))
    359 		h->flags |= BDC_FLAG_SUM_NEEDED;
    360 
    361 
    362 	h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
    363 	h->flags2 = 0;
    364 #ifdef APSTA_PINGTEST
    365 	for (i = 0; i < MAX_GUEST; ++i) {
    366 		if (!ETHER_ISNULLADDR(eh->ether_dhost) &&
    367 		    bcmp(eh->ether_dhost, guest_eas[i].octet, ETHER_ADDR_LEN) == 0) {
    368 			DHD_TRACE(("send on if 1; sa %s, da %s\n",
    369 			       bcm_ether_ntoa((struct ether_addr *)(eh->ether_shost), eabuf1),
    370 			       bcm_ether_ntoa((struct ether_addr *)(eh->ether_dhost), eabuf2)));
    371 			/* assume all guest STAs are on interface 1 */
    372 			h->flags2 = 1;
    373 			break;
    374 		}
    375 	}
    376 #endif /* APSTA_PINGTEST */
    377 	h->rssi = 0;
    378 #endif /* BDC */
    379 	BDC_SET_IF_IDX(h, ifidx);
    380 }
    381 
    382 
    383 bool
    384 dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, uint8 *fcbits)
    385 {
    386 #ifdef BDC
    387 	struct bdc_header *h;
    388 
    389 	if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
    390 		DHD_ERROR(("%s: rx data too short (%d < %d)\n",
    391 			__FUNCTION__, PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
    392 		return BCME_ERROR;
    393 	}
    394 
    395 	h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
    396 
    397 	*fcbits = h->priority >> BDC_PRIORITY_FC_SHIFT;
    398 	if ((h->flags2 & BDC_FLAG2_FC_FLAG) == BDC_FLAG2_FC_FLAG)
    399 		return TRUE;
    400 #endif
    401 	return FALSE;
    402 }
    403 
    404 
    405 int
    406 dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
    407 {
    408 #ifdef BDC
    409 	struct bdc_header *h;
    410 #endif
    411 
    412 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    413 
    414 #ifdef BDC
    415 	/* Pop BDC header used to convey priority for buses that don't */
    416 
    417 	if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
    418 		DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
    419 		           PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
    420 		return BCME_ERROR;
    421 	}
    422 
    423 	h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
    424 
    425 	if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
    426 		DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
    427 		           __FUNCTION__, *ifidx));
    428 		return BCME_ERROR;
    429 	}
    430 
    431 	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) {
    432 		DHD_ERROR(("%s: non-BDC packet received, flags 0x%x\n",
    433 		           dhd_ifname(dhd, *ifidx), h->flags));
    434 		return BCME_ERROR;
    435 	}
    436 
    437 	if (h->flags & BDC_FLAG_SUM_GOOD) {
    438 		DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
    439 		          dhd_ifname(dhd, *ifidx), h->flags));
    440 		PKTSETSUMGOOD(pktbuf, TRUE);
    441 	}
    442 
    443 	PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
    444 
    445 	PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
    446 #endif /* BDC */
    447 
    448 	return 0;
    449 }
    450 
    451 int
    452 dhd_prot_attach(dhd_pub_t *dhd)
    453 {
    454 	dhd_prot_t *cdc;
    455 
    456 #ifndef DHD_USE_STATIC_BUF
    457 	if (!(cdc = (dhd_prot_t *)MALLOC(dhd->osh, sizeof(dhd_prot_t)))) {
    458 		DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
    459 		goto fail;
    460 	}
    461 #else
    462 	if (!(cdc = (dhd_prot_t *)dhd_os_prealloc(DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) {
    463 		DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
    464 		goto fail;
    465 	}
    466 #endif /* DHD_USE_STATIC_BUF */
    467 	memset(cdc, 0, sizeof(dhd_prot_t));
    468 
    469 	/* ensure that the msg buf directly follows the cdc msg struct */
    470 	if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
    471 		DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
    472 		goto fail;
    473 	}
    474 
    475 	dhd->prot = cdc;
    476 #ifdef BDC
    477 	dhd->hdrlen += BDC_HEADER_LEN;
    478 #endif
    479 	dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
    480 	return 0;
    481 
    482 fail:
    483 #ifndef DHD_USE_STATIC_BUF
    484 	if (cdc != NULL)
    485 		MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
    486 #endif
    487 	return BCME_NOMEM;
    488 }
    489 
    490 /* ~NOTE~ What if another thread is waiting on the semaphore?  Holding it? */
    491 void
    492 dhd_prot_detach(dhd_pub_t *dhd)
    493 {
    494 #ifndef DHD_USE_STATIC_BUF
    495 	MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
    496 #endif
    497 	dhd->prot = NULL;
    498 }
    499 
    500 void
    501 dhd_prot_dstats(dhd_pub_t *dhd)
    502 {
    503 	/* No stats from dongle added yet, copy bus stats */
    504 	dhd->dstats.tx_packets = dhd->tx_packets;
    505 	dhd->dstats.tx_errors = dhd->tx_errors;
    506 	dhd->dstats.rx_packets = dhd->rx_packets;
    507 	dhd->dstats.rx_errors = dhd->rx_errors;
    508 	dhd->dstats.rx_dropped = dhd->rx_dropped;
    509 	dhd->dstats.multicast = dhd->rx_multicast;
    510 	return;
    511 }
    512 
    513 int dhd_set_suspend(int value, dhd_pub_t *dhd)
    514 {
    515 	int power_mode = PM_MAX;
    516 	wl_pkt_filter_enable_t	enable_parm;
    517 	char iovbuf[32];
    518 	int bcn_li_dtim = 3;
    519 #ifdef CUSTOMER_HW2
    520 	uint roamvar = 1;
    521 #endif /* CUSTOMER_HW2 */
    522 
    523 #define htod32(i) i
    524 
    525 	if (dhd && dhd->up) {
    526 		dhd_os_proto_block(dhd);
    527 		if (value) {
    528 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
    529 				(char *)&power_mode, sizeof(power_mode));
    530 			/* Enable packet filter, only allow unicast packet to send up */
    531 			enable_parm.id = htod32(100);
    532 			enable_parm.enable = htod32(1);
    533 			bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
    534 				sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
    535 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    536 			/* set bcn_li_dtim */
    537 			bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
    538 				4, iovbuf, sizeof(iovbuf));
    539 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    540 #ifdef CUSTOMER_HW2
    541 			/* Disable build-in roaming to allowed ext supplicant to take of romaing */
    542 			bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
    543 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    544 #endif /* CUSTOMER_HW2 */
    545 		} else {
    546 			power_mode = PM_FAST;
    547 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
    548 				sizeof(power_mode));
    549 			/* disable pkt filter */
    550 			enable_parm.id = htod32(100);
    551 			enable_parm.enable = htod32(0);
    552 			bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
    553 				sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
    554 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    555 			/* set bcn_li_dtim */
    556 			bcn_li_dtim = 0;
    557 			bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
    558 				4, iovbuf, sizeof(iovbuf));
    559 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    560 #ifdef CUSTOMER_HW2
    561 			roamvar = 0;
    562 			bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
    563 			dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    564 #endif /* CUSTOMER_HW2 */
    565 		}
    566 		dhd_os_proto_unblock(dhd);
    567 	}
    568 
    569 	return 0;
    570 }
    571 
    572 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
    573 
    574 /* Convert user's input in hex pattern to byte-size mask */
    575 static int
    576 wl_pattern_atoh(char *src, char *dst)
    577 {
    578 	int i;
    579 	if (strncmp(src, "0x", 2) != 0 &&
    580 	    strncmp(src, "0X", 2) != 0) {
    581 		printf("Mask invalid format. Needs to start with 0x\n");
    582 		return -1;
    583 	}
    584 	src = src + 2; /* Skip past 0x */
    585 	if (strlen(src) % 2 != 0) {
    586 		printf("Mask invalid format. Needs to be of even length\n");
    587 		return -1;
    588 	}
    589 	for (i = 0; *src != '\0'; i++) {
    590 		char num[3];
    591 		strncpy(num, src, 2);
    592 		num[2] = '\0';
    593 		dst[i] = (uint8)strtoul(num, NULL, 16);
    594 		src += 2;
    595 	}
    596 	return i;
    597 }
    598 
    599 int
    600 dhd_preinit_ioctls(dhd_pub_t *dhd)
    601 {
    602 	char eventmask[WL_EVENTING_MASK_LEN];
    603 	char iovbuf[WL_EVENTING_MASK_LEN + 12];	/*  Room for "event_msgs" + '\0' + bitvec  */
    604 	int ret;
    605 	uint up = 0;
    606 #ifdef CUSTOMER_HW2
    607 	uint roamvar = 0;
    608 #else
    609 	uint roamvar = 1;
    610 #endif
    611 	uint power_mode = PM_FAST;
    612 	uint32 dongle_align = DHD_SDALIGN;
    613 	uint32 glom = 0;
    614 
    615 	uint bcn_timeout = 3;
    616 	int arpoe = 1;
    617 	int arp_ol = 0xf;
    618 	int scan_assoc_time = 40;
    619 	int scan_unassoc_time = 80;
    620 	const char 				*str;
    621 	wl_pkt_filter_t		pkt_filter;
    622 	wl_pkt_filter_t		*pkt_filterp;
    623 	int						buf_len;
    624 	int						str_len;
    625 	uint32					mask_size;
    626 	uint32					pattern_size;
    627 	char buf[256];
    628 	uint filter_mode = 1;
    629 
    630 	dhd_os_proto_block(dhd);
    631 	/* Get the device MAC address */
    632 	strcpy(iovbuf, "cur_etheraddr");
    633 	if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
    634 		DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
    635 		dhd_os_proto_unblock(dhd);
    636 		return BCME_NOTUP;
    637 	}
    638 	memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
    639 
    640 	/* Set Country code */
    641 	if (dhd->country_code[0] != 0) {
    642 		if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
    643 			dhd->country_code, sizeof(dhd->country_code)) < 0) {
    644 			DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
    645 		}
    646 	}
    647 
    648 	/* Set PowerSave mode */
    649 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
    650 
    651 	/* Match Host and Dongle rx alignment */
    652 	bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
    653 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    654 
    655 	/* disable glom option per default */
    656 	bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
    657 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    658 	/* Setup timeout if Beacons are lost and roam is off to report link down */
    659 	if (roamvar) {
    660 		bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
    661 		dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    662 	}
    663 
    664 	/* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
    665 	bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
    666 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    667 
    668 	/* Force STA UP */
    669 	dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
    670 
    671 	/* Setup event_msgs */
    672 	bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
    673 	dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
    674 	bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
    675 
    676 	setbit(eventmask, WLC_E_SET_SSID);
    677 	setbit(eventmask, WLC_E_PRUNE);
    678 	setbit(eventmask, WLC_E_AUTH);
    679 	setbit(eventmask, WLC_E_REASSOC);
    680 	setbit(eventmask, WLC_E_REASSOC_IND);
    681 	setbit(eventmask, WLC_E_DEAUTH_IND);
    682 	setbit(eventmask, WLC_E_DISASSOC_IND);
    683 	setbit(eventmask, WLC_E_DISASSOC);
    684 	setbit(eventmask, WLC_E_JOIN);
    685 	setbit(eventmask, WLC_E_ASSOC_IND);
    686 	setbit(eventmask, WLC_E_PSK_SUP);
    687 	setbit(eventmask, WLC_E_LINK);
    688 	setbit(eventmask, WLC_E_NDIS_LINK);
    689 	setbit(eventmask, WLC_E_MIC_ERROR);
    690 	setbit(eventmask, WLC_E_PMKID_CACHE);
    691 	setbit(eventmask, WLC_E_TXFAIL);
    692 	setbit(eventmask, WLC_E_JOIN_START);
    693 	setbit(eventmask, WLC_E_SCAN_COMPLETE);
    694 
    695 	bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
    696 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    697 
    698 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
    699 		sizeof(scan_assoc_time));
    700 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
    701 		sizeof(scan_unassoc_time));
    702 
    703 	/* Set ARP offload */
    704 	bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
    705 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    706 	bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
    707 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    708 
    709 	/* add a default packet filter pattern */
    710 	str = "pkt_filter_add";
    711 	str_len = strlen(str);
    712 	strncpy(buf, str, str_len);
    713 	buf[ str_len ] = '\0';
    714 	buf_len = str_len + 1;
    715 
    716 	pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
    717 
    718 	/* Parse packet filter id. */
    719 	pkt_filter.id = htod32(100);
    720 
    721 	/* Parse filter polarity. */
    722 	pkt_filter.negate_match = htod32(0);
    723 
    724 	/* Parse filter type. */
    725 	pkt_filter.type = htod32(0);
    726 
    727 	/* Parse pattern filter offset. */
    728 	pkt_filter.u.pattern.offset = htod32(0);
    729 
    730 	/* Parse pattern filter mask. */
    731 	mask_size =	htod32(wl_pattern_atoh("0xff",
    732 		(char *) pkt_filterp->u.pattern.mask_and_pattern));
    733 
    734 	/* Parse pattern filter pattern. */
    735 	pattern_size = htod32(wl_pattern_atoh("0x00",
    736 		(char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
    737 
    738 	if (mask_size != pattern_size) {
    739 		DHD_ERROR(("Mask and pattern not the same size\n"));
    740 		dhd_os_proto_unblock(dhd);
    741 		return -EINVAL;
    742 	}
    743 
    744 	pkt_filter.u.pattern.size_bytes = mask_size;
    745 	buf_len += WL_PKT_FILTER_FIXED_LEN;
    746 	buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
    747 
    748 	/* Keep-alive attributes are set in local	variable (keep_alive_pkt), and
    749 	** then memcpy'ed into buffer (keep_alive_pktp) since there is no
    750 	** guarantee that the buffer is properly aligned.
    751 	*/
    752 	memcpy((char *)pkt_filterp, &pkt_filter,
    753 		WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
    754 
    755 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
    756 
    757 	/* set mode to allow pattern */
    758 	bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf));
    759 	dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
    760 
    761 	dhd_os_proto_unblock(dhd);
    762 	return 0;
    763 }
    764 
    765 int
    766 dhd_prot_init(dhd_pub_t *dhd)
    767 {
    768 	int ret = 0;
    769 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
    770 
    771 
    772 	ret = dhd_preinit_ioctls(dhd);
    773 
    774 	/* Always assumes wl for now */
    775 	dhd->iswl = TRUE;
    776 
    777 	return ret;
    778 }
    779 
    780 void
    781 dhd_prot_stop(dhd_pub_t *dhd)
    782 {
    783 	/* Nothing to do for CDC */
    784 }
    785