diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_cfg80211.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 611 |
1 files changed, 89 insertions, 522 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 781a78b..987912f 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -1,7 +1,7 @@ /* * Linux cfg80211 driver - Dongle Host Driver (DHD) related * - * Copyright (C) 1999-2012, Broadcom Corporation + * Copyright (C) 1999-2014, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you @@ -24,11 +24,13 @@ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ */ +#include <linux/vmalloc.h> #include <net/rtnetlink.h> #include <bcmutils.h> #include <wldev_common.h> #include <wl_cfg80211.h> +#include <brcm_nl80211.h> #include <dhd_cfg80211.h> #ifdef PKT_FILTER_SUPPORT @@ -36,7 +38,7 @@ #include <dhd.h> #endif -extern struct wl_priv *wlcfg_drv_priv; +extern struct bcm_cfg80211 *g_bcm_cfg; #ifdef PKT_FILTER_SUPPORT extern uint dhd_pkt_filter_enable; @@ -58,27 +60,27 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up); * Function implementations */ -s32 dhd_cfg80211_init(struct wl_priv *wl) +s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg) { dhd_dongle_up = FALSE; return 0; } -s32 dhd_cfg80211_deinit(struct wl_priv *wl) +s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg) { dhd_dongle_up = FALSE; return 0; } -s32 dhd_cfg80211_down(struct wl_priv *wl) +s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg) { dhd_dongle_up = FALSE; return 0; } -s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) +s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val) { - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); dhd->op_mode |= val; WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode)); #ifdef ARP_OFFLOAD_SUPPORT @@ -92,9 +94,9 @@ s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) return 0; } -s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) +s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg) { - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE); WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode)); @@ -109,6 +111,22 @@ s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) return 0; } +struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name, + uint8 *mac, uint8 bssidx) +{ + return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE); +} + +int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_register_if(cfg->pub, ifidx, FALSE); +} + +int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev) +{ + return dhd_remove_if(cfg->pub, ifidx, FALSE); +} + static s32 wl_dongle_up(struct net_device *ndev, u32 up) { s32 err = 0; @@ -119,7 +137,8 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) } return err; } -s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) + +s32 dhd_config_dongle(struct bcm_cfg80211 *cfg) { #ifndef DHD_SDALIGN #define DHD_SDALIGN 32 @@ -133,10 +152,7 @@ s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) return err; } - ndev = wl_to_prmry_ndev(wl); - - if (need_lock) - rtnl_lock(); + ndev = bcmcfg_to_prmry_ndev(cfg); err = wl_dongle_up(ndev, 0); if (unlikely(err)) { @@ -146,8 +162,7 @@ s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) dhd_dongle_up = true; default_conf_out: - if (need_lock) - rtnl_unlock(); + return err; } @@ -156,14 +171,19 @@ default_conf_out: int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) { struct sk_buff *reply; - struct wl_priv *wl; + struct bcm_cfg80211 *cfg; dhd_pub_t *dhd; - dhd_ioctl_t *ioc = data; + struct bcm_nlmsg_hdr *nlioc = data; + dhd_ioctl_t ioc = { 0 }; int err = 0; + void *buf = NULL, *cur; + u16 buflen; + u16 maxmsglen = PAGE_SIZE - 0x100; + bool newbuf = false; - WL_TRACE(("entry: cmd = %d\n", ioc->cmd)); - wl = wiphy_priv(wiphy); - dhd = wl->pub; + WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); + cfg = wiphy_priv(wiphy); + dhd = cfg->pub; DHD_OS_WAKE_LOCK(dhd); @@ -175,520 +195,67 @@ int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) return OSL_ERROR(BCME_DONGLE_DOWN); } - /* currently there is only one wiphy for ifidx 0 */ - err = dhd_ioctl_process(dhd, 0, ioc); - if (err) - goto done; - - /* response data is in ioc->buf so return ioc here */ - reply = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(*ioc)); - nla_put(reply, NL80211_ATTR_TESTDATA, sizeof(*ioc), ioc); - err = cfg80211_testmode_reply(reply); -done: - DHD_OS_WAKE_UNLOCK(dhd); - return err; -} -#endif /* CONFIG_NL80211_TESTMODE */ - -/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ -#define COEX_DHCP - -#if defined(COEX_DHCP) - -/* use New SCO/eSCO smart YG suppression */ -#define BT_DHCP_eSCO_FIX -/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ -#define BT_DHCP_USE_FLAGS -/* T1 start SCO/ESCo priority suppression */ -#define BT_DHCP_OPPR_WIN_TIME 2500 -/* T2 turn off SCO/SCO supperesion is (timeout) */ -#define BT_DHCP_FLAG_FORCE_TIME 5500 + len -= sizeof(struct bcm_nlmsg_hdr); -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - -/* - * get named driver variable to uint register value and return error indication - * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) - */ -static int -dev_wlc_intvar_get_reg(struct net_device *dev, char *name, - uint reg, int *retval) -{ - union { - char buf[WLC_IOCTL_SMLEN]; - int val; - } var; - int error; - - bcm_mkiovar(name, (char *)(®), sizeof(reg), - (char *)(&var), sizeof(var.buf)); - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); - - *retval = dtoh32(var.val); - return (error); -} - -static int -dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - char ioctlbuf_local[1024]; -#else - static char ioctlbuf_local[1024]; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); - - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); -} -/* -get named driver variable to uint register value and return error indication -calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -*/ -static int -dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -{ - char reg_addr[8]; - - memset(reg_addr, 0, sizeof(reg_addr)); - memcpy((char *)®_addr[0], (char *)addr, 4); - memcpy((char *)®_addr[4], (char *)val, 4); - - return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -} - -static bool btcoex_is_sco_active(struct net_device *dev) -{ - int ioc_res = 0; - bool res = FALSE; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27)); - - if (ioc_res < 0) { - WL_ERR(("ioc read btc params error\n")); - break; - } - - if ((param27 & 0x6) == 2) { /* count both sco & esco */ - sco_id_cnt++; - } - - if (sco_id_cnt > 2) { - WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n", sco_id_cnt, i)); - res = TRUE; - break; - } - - msleep(5); - } - - return res; -} - -#if defined(BT_DHCP_eSCO_FIX) -/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -static int set_btc_esco_params(struct net_device *dev, bool trump_sco) -{ - static bool saved_status = FALSE; - - char buf_reg50va_dhcp_on[8] = - { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; - char buf_reg51va_dhcp_on[8] = - { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg64va_dhcp_on[8] = - { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg65va_dhcp_on[8] = - { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg71va_dhcp_on[8] = - { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - uint32 regaddr; - static uint32 saved_reg50; - static uint32 saved_reg51; - static uint32 saved_reg64; - static uint32 saved_reg65; - static uint32 saved_reg71; - - if (trump_sco) { - /* this should reduce eSCO agressive retransmit - * w/o breaking it - */ - - /* 1st save current */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { - saved_status = TRUE; - WL_TRACE(("saved bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, - saved_reg64, saved_reg65, saved_reg71)); + if (nlioc->len > 0) { + if (nlioc->len <= len) { + buf = (void *)nlioc + nlioc->offset; + *(char *)(buf + nlioc->len) = '\0'; } else { - WL_ERR((":%s: save btc_params failed\n", - __FUNCTION__)); - saved_status = FALSE; - return -1; + if (nlioc->len > DHD_IOCTL_MAXLEN) + nlioc->len = DHD_IOCTL_MAXLEN; + buf = vzalloc(nlioc->len); + if (!buf) + return -ENOMEM; + newbuf = true; + memcpy(buf, (void *)nlioc + nlioc->offset, len); + *(char *)(buf + len) = '\0'; } - - WL_TRACE(("override with [50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - *(u32 *)(buf_reg50va_dhcp_on+4), - *(u32 *)(buf_reg51va_dhcp_on+4), - *(u32 *)(buf_reg64va_dhcp_on+4), - *(u32 *)(buf_reg65va_dhcp_on+4), - *(u32 *)(buf_reg71va_dhcp_on+4))); - - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg50va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg51va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg64va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg65va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg71va_dhcp_on[0], 8); - - saved_status = TRUE; - } else if (saved_status) { - /* restore previously saved bt params */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - - regaddr = 50; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg50); - regaddr = 51; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg51); - regaddr = 64; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg64); - regaddr = 65; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg65); - regaddr = 71; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg71); - - WL_TRACE(("restore bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, saved_reg64, - saved_reg65, saved_reg71)); - - saved_status = FALSE; - } else { - WL_ERR((":%s att to restore not saved BTCOEX params\n", - __FUNCTION__)); - return -1; } - return 0; -} -#endif /* BT_DHCP_eSCO_FIX */ -static void -wl_cfg80211_bt_setflag(struct net_device *dev, bool set) -{ -#if defined(BT_DHCP_USE_FLAGS) - char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#endif - - -#if defined(BT_DHCP_eSCO_FIX) - /* set = 1, save & turn on 0 - off & restore prev settings */ - set_btc_esco_params(dev, set); -#endif - -#if defined(BT_DHCP_USE_FLAGS) - WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); - if (set == TRUE) - /* Forcing bt_flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_dhcp_on[0], - sizeof(buf_flag7_dhcp_on)); - else - /* Restoring default bt flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], - sizeof(buf_flag7_default)); -#endif -} - -static void wl_cfg80211_bt_timerfunc(ulong data) -{ - struct btcoex_info *bt_local = (struct btcoex_info *)data; - WL_TRACE(("Enter\n")); - bt_local->timer_on = 0; - schedule_work(&bt_local->work); -} - -static void wl_cfg80211_bt_handler(struct work_struct *work) -{ - struct btcoex_info *btcx_inf; - - btcx_inf = container_of(work, struct btcoex_info, work); - - if (btcx_inf->timer_on) { - btcx_inf->timer_on = 0; - del_timer_sync(&btcx_inf->timer); + ioc.cmd = nlioc->cmd; + ioc.len = nlioc->len; + ioc.set = nlioc->set; + ioc.driver = nlioc->magic; + err = dhd_ioctl_process(dhd, 0, &ioc, buf); + if (err) { + WL_TRACE(("dhd_ioctl_process return err %d\n", err)); + err = OSL_ERROR(err); + goto done; } - switch (btcx_inf->bt_state) { - case BT_DHCP_START: - /* DHCP started - * provide OPPORTUNITY window to get DHCP address - */ - WL_TRACE(("bt_dhcp stm: started \n")); - btcx_inf->bt_state = BT_DHCP_OPPR_WIN; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME)); - btcx_inf->timer_on = 1; + cur = buf; + while (nlioc->len > 0) { + buflen = nlioc->len > maxmsglen ? maxmsglen : nlioc->len; + nlioc->len -= buflen; + reply = cfg80211_testmode_alloc_reply_skb(wiphy, buflen+4); + if (!reply) { + WL_ERR(("Failed to allocate reply msg\n")); + err = -ENOMEM; break; - - case BT_DHCP_OPPR_WIN: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T1 expiration\n")); - goto btc_coex_idle; - } - - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME)); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_FLAG_FORCE_TIMEOUT: - if (btcx_inf->dhcp_done) { - WL_TRACE(("DHCP Done before T2 expiration\n")); - } else { - /* Noo dhcp during T1+T2, restore BT priority */ - WL_TRACE(("DHCP wait interval T2:%d msec expired\n", - BT_DHCP_FLAG_FORCE_TIME)); - } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - - default: - WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - } - - net_os_wake_unlock(btcx_inf->dev); -} - -int wl_cfg80211_btcoex_init(struct wl_priv *wl) -{ - struct btcoex_info *btco_inf = NULL; - - btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); - if (!btco_inf) - return -ENOMEM; - - btco_inf->bt_state = BT_DHCP_IDLE; - btco_inf->ts_dhcp_start = 0; - btco_inf->ts_dhcp_ok = 0; - /* Set up timer for BT */ - btco_inf->timer_ms = 10; - init_timer(&btco_inf->timer); - btco_inf->timer.data = (ulong)btco_inf; - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; - - btco_inf->dev = wl->wdev->netdev; - - INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); - - wl->btcoex_info = btco_inf; - return 0; -} - -void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) -{ - if (!wl->btcoex_info) - return; - - if (wl->btcoex_info->timer_on) { - wl->btcoex_info->timer_on = 0; - del_timer_sync(&wl->btcoex_info->timer); - } - - cancel_work_sync(&wl->btcoex_info->work); - - kfree(wl->btcoex_info); - wl->btcoex_info = NULL; -} - -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) -{ - - struct wl_priv *wl = wlcfg_drv_priv; - char powermode_val = 0; - char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; - char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; - char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - - uint32 regaddr; - static uint32 saved_reg66; - static uint32 saved_reg41; - static uint32 saved_reg68; - static bool saved_status = FALSE; - -#ifdef COEX_DHCP - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; - struct btcoex_info *btco_inf = wl->btcoex_info; -#endif /* COEX_DHCP */ - -#ifdef PKT_FILTER_SUPPORT - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); -#endif - - /* Figure out powermode 1 or o command */ - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); - - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - WL_TRACE_HW4(("DHCP session starts\n")); - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 1; - - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n")); - dhd_enable_packet_filter(0, dhd); } -#endif - /* Retrieve and saved orig regs value */ - if ((saved_status == FALSE) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - - /* Disable PM mode during dhpc session */ - - /* Disable PM mode during dhpc session */ -#ifdef COEX_DHCP - /* Start BT timer only for SCO connection */ - if (btcoex_is_sco_active(dev)) { - /* btc_params 66 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg66va_dhcp_on[0], - sizeof(buf_reg66va_dhcp_on)); - /* btc_params 41 0x33 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg41va_dhcp_on[0], - sizeof(buf_reg41va_dhcp_on)); - /* btc_params 68 0x190 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg68va_dhcp_on[0], - sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, btco_inf->timer.expires); - WL_TRACE(("enable BT DHCP Timer\n")); - } -#endif /* COEX_DHCP */ - } - else if (saved_status == TRUE) { - WL_ERR(("was called w/o DHCP OFF. Continue\n")); - } - } - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { - - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 0; - WL_TRACE_HW4(("DHCP is complete \n")); - - /* Enable packet filtering */ - if (dhd->early_suspended) { - WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n")); - dhd_enable_packet_filter(1, dhd); - } -#endif - - /* Restoring PM mode */ - -#ifdef COEX_DHCP - /* Stop any bt timer because DHCP session is done */ - WL_TRACE(("disable BT DHCP Timer\n")); - if (btco_inf->timer_on) { - btco_inf->timer_on = 0; - del_timer_sync(&btco_inf->timer); - - if (btco_inf->bt_state != BT_DHCP_IDLE) { - /* need to restore original btc flags & extra btc params */ - WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state)); - /* wake up btcoex thread to restore btlags+params */ - schedule_work(&btco_inf->work); - } + if (nla_put(reply, BCM_NLATTR_DATA, buflen, cur) || + nla_put_u16(reply, BCM_NLATTR_LEN, buflen)) { + kfree_skb(reply); + err = -ENOBUFS; + break; } - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); -#endif /* COEX_DHCP */ - - /* Restore original values */ - if (saved_status == TRUE) { - regaddr = 66; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg66); - regaddr = 41; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg41); - regaddr = 68; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg68); - - WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); + do { + err = cfg80211_testmode_reply(reply); + } while (err == -EAGAIN); + if (err) { + WL_ERR(("testmode reply failed:%d\n", err)); + break; } - saved_status = FALSE; - + cur += buflen; } - else { - WL_ERR(("Unkwown yet power setting, ignored\n")); - } - - snprintf(command, 3, "OK"); - return (strlen("OK")); +done: + if (newbuf) + vfree(buf); + DHD_OS_WAKE_UNLOCK(dhd); + return err; } -#endif +#endif /* CONFIG_NL80211_TESTMODE */ |