From 1c7cb99e2dfb47c1b652e9cf6580d36791939ec8 Mon Sep 17 00:00:00 2001 From: "Howard M. Harte" Date: Fri, 27 May 2011 16:07:36 -0700 Subject: [PATCH] Update to 5.90.125.22: * Add support for SoftAP, keepalive, ARP offload. * Clean up cfg80211 and p2p code. * Update Makefile to support new features. Change-Id: I1e7a16acd400d7baf5625ca8ba6552a6f1c80661 Signed-off-by: Howard M. Harte --- drivers/net/wireless/bcmdhd/Makefile | 5 +- drivers/net/wireless/bcmdhd/dhd.h | 10 + drivers/net/wireless/bcmdhd/dhd_cdc.c | 6 +- drivers/net/wireless/bcmdhd/dhd_common.c | 257 +++++- drivers/net/wireless/bcmdhd/dhd_custom_gpio.c | 68 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 36 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/include/linuxver.h | 2 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 13 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 1108 +++++++++++++----------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 72 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 495 ++--------- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 30 +- drivers/net/wireless/bcmdhd/wldev_common.c | 238 +++++ drivers/net/wireless/bcmdhd/wldev_common.h | 91 ++ 15 files changed, 1451 insertions(+), 988 deletions(-) create mode 100644 drivers/net/wireless/bcmdhd/wldev_common.c create mode 100644 drivers/net/wireless/bcmdhd/wldev_common.h diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index b9aaf79..410f1f0 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -6,13 +6,14 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Werror -Dlinux -DBCMDRIVER \ -DCUSTOMER_HW3 -DCUSTOM_OOB_GPIO_NUM=135 -DOOB_INTR_ONLY \ -DMMC_SDIO_ABORT -DCONFIG_FIRST_SCAN -DBCMSDIO -DBCMLXSDMMC \ -DBCMPLATFORM_BUS -DHW_OOB -DNEW_COMPAT_WIRELESS -DWL_CFG80211 \ - -DWLP2P -DWIFI_ACT_FRAME \ + -DWLP2P -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DKEEP_ALIVE -DCSCAN \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ dhd_linux_sched.o wl_cfg80211.o bcmwifi.o dhd_sdio.o wl_cfgp2p.o \ bcmevent.o dhd_bta.o hndpmu.o bcmsdh.o dhd_cdc.o bcmsdh_linux.o \ - dhd_common.o linux_osl.o bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o + dhd_common.o linux_osl.o bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o \ + wldev_common.o obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 961a66d..bb39913 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -484,6 +484,9 @@ extern uint dhd_sdiod_drive_strength; /* Override to force tx queueing all the time */ extern uint dhd_force_tx_queueing; +/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ +#define KEEP_ALIVE_PERIOD 55000 +#define NULL_PKT_STR "null_pkt" #ifdef SDTEST /* Echo packet generator (SDIO), pkts/s */ @@ -641,4 +644,11 @@ int dhd_os_wlfc_unblock(dhd_pub_t *pub); extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); +#ifdef ARP_OFFLOAD_SUPPORT +/* dhd_commn arp offload wrapers */ +void dhd_aoe_hostip_clr(dhd_pub_t *dhd); +void dhd_aoe_arp_clr(dhd_pub_t *dhd); +int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); +void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr); +#endif /* ARP_OFFLOAD_SUPPORT */ #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index b4270e0..fb0d5ad 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -116,7 +116,7 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) return ret; } -static int +int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) { dhd_prot_t *prot = dhd->prot; @@ -203,7 +203,7 @@ done: return ret; } -static int +int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) { dhd_prot_t *prot = dhd->prot; @@ -271,6 +271,7 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) goto done; } + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ASSERT(len <= WLC_IOCTL_MAXLEN); @@ -2294,6 +2295,7 @@ dhd_prot_init(dhd_pub_t *dhd) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + /* Get the device rev info */ memset(&revinfo, 0, sizeof(revinfo)); ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index ae92489..b1d9e7c 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -41,8 +41,15 @@ #include #include +#ifdef WL_CFG80211 +#include +#endif #include #include +#ifdef SET_RANDOM_MAC_SOFTAP +#include +#include +#endif #ifdef PROP_TXSTATUS #include @@ -80,6 +87,13 @@ extern int dhd_iscan_in_progress(void *h); void dhd_iscan_lock(void); void dhd_iscan_unlock(void); extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); +#if defined(SOFTAP) +extern bool ap_fw_loaded; +#endif + +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on); +#endif /* KEEP_ALIVE */ /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN @@ -1025,12 +1039,30 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, } #endif /* PROP_TXSTATUS */ - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { +#ifdef WL_CFG80211 + if (wl_cfg80211_is_progress_ifchange()) { + DHD_ERROR(("%s: ifidx %d for %s action %d\n", + __FUNCTION__, ifevent->ifidx, + event->ifname, ifevent->action)); if (ifevent->action == WLC_E_IF_ADD) - dhd_add_if(dhd_pub->info, ifevent->ifidx, - NULL, event->ifname, - event->addr.octet, - ifevent->flags, ifevent->bssidx); + wl_cfg80211_notify_ifchange(); + return (BCME_OK); + } +#endif /* WL_CFG80211 */ + if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { + if (ifevent->action == WLC_E_IF_ADD) { + if (dhd_add_if(dhd_pub->info, ifevent->ifidx, + NULL, event->ifname, + event->addr.octet, + ifevent->flags, ifevent->bssidx)) { + DHD_ERROR(("%s: dhd_add_if failed!!" + " ifidx: %d for %s\n", + __FUNCTION__, + ifevent->ifidx, + event->ifname)); + return (BCME_ERROR); + } + } else dhd_del_if(dhd_pub->info, ifevent->ifidx); } else { @@ -1114,6 +1146,7 @@ wl_event_to_host_order(wl_event_msg_t * evt) void dhd_print_buf(void *pbuf, int len, int bytes_per_line) { +#ifdef DHD_DEBUG int i, j = 0; unsigned char *buf = pbuf; @@ -1132,6 +1165,7 @@ dhd_print_buf(void *pbuf, int len, int bytes_per_line) } } printf("\n"); +#endif /* DHD_DEBUG */ } #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) @@ -1366,6 +1400,10 @@ fail: MFREE(dhd->osh, buf, BUF_SIZE); } +/* ========================== */ +/* ==== ARP OFFLOAD SUPPORT = */ +/* ========================== */ +#ifdef ARP_OFFLOAD_SUPPORT void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) { @@ -1400,6 +1438,86 @@ dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) __FUNCTION__, arp_enable)); } +void dhd_aoe_arp_clr(dhd_pub_t *dhd) +{ + int ret = 0; + int iov_len = 0; + char iovbuf[128]; + + if (dhd == NULL) return; + + iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0)) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void dhd_aoe_hostip_clr(dhd_pub_t *dhd) +{ + int ret = 0; + int iov_len = 0; + char iovbuf[128]; + + if (dhd == NULL) return; + + iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0) + DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); +} + +void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr) +{ + int iov_len = 0; + char iovbuf[32]; + int retcode; + + iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf)); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); + + if (retcode) + DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", + __FUNCTION__, retcode)); + else + DHD_TRACE(("%s: sARP H ipaddr entry added \n", + __FUNCTION__)); +} + + +int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen) +{ +#define MAX_IPV4_ENTRIES 8 + + int retcode, i; + int iov_len = 0; + uint32 *ptr32 = buf; + bool clr_bottom = FALSE; + + if (!buf) + return -1; + + iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0); + + /* clean up the buf, ascii reminder */ + for (i = 0; i < MAX_IPV4_ENTRIES; i++) { + + if (!clr_bottom) { + if (*ptr32 == 0) + clr_bottom = TRUE; + } else { + *ptr32 = 0; + } + ptr32++; + } + + if (retcode) { + DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", + __FUNCTION__, retcode)); + + return -1; + } + return 0; +} +#endif /* ARP_OFFLOAD_SUPPORT */ int dhd_preinit_ioctls(dhd_pub_t *dhd) { @@ -1411,10 +1529,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; + uint bcn_timeout = 4; int arpoe = 1; int arp_ol = 0xf; int scan_assoc_time = 40; - int scan_unassoc_time = 80; + int scan_unassoc_time = 40; const char *str; wl_pkt_filter_t pkt_filter; wl_pkt_filter_t *pkt_filterp; @@ -1426,18 +1545,67 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) char *ptr; uint filter_mode = 1; uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ +#if defined(SOFTAP) + uint dtim = 1; +#endif #ifdef AP uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ uint32 apsta = 1; /* Enable APSTA mode */ #endif +#ifdef GET_CUSTOM_MAC_ENABLE + struct ether_addr ea_addr; +#endif /* GET_CUSTOM_MAC_ENABLE */ - /* Get the device MAC address */ +#ifdef GET_CUSTOM_MAC_ENABLE + /* + ** Read MAC address from external customer place + ** NOTE that default mac address has to be present in otp or nvram file + ** to bring up firmware but unique per board mac address maybe provided + ** by customer code + */ + ret = dhd_custom_get_mac_address(ea_addr.octet); + if (!ret) { + bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + } else + memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); + } +#else + /* Get the default device MAC address directly from firmware */ strcpy(iovbuf, "cur_etheraddr"); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); return BCME_NOTUP; } memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); +#endif /* GET_CUSTOM_MAC_ENABLE */ + +#ifdef SET_RANDOM_MAC_SOFTAP + if (strstr(fw_path, "apsta") != NULL) { + uint rand_mac; + + srandom32((uint)jiffies); + rand_mac = random32(); + iovbuf[0] = 0x02; /* locally administered bit */ + iovbuf[1] = 0x1A; + iovbuf[2] = 0x11; + iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; + iovbuf[4] = (unsigned char)(rand_mac >> 8); + iovbuf[5] = (unsigned char)(rand_mac >> 16); + + printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]); + + bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); + if (ret < 0) { + DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + } else + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); + } +#endif /* SET_RANDOM_MAC_SOFTAP */ /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { @@ -1472,6 +1640,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + /* Setup timeout if Beacons are lost and roam is off to report link down */ + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #ifdef AP /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); @@ -1481,6 +1652,24 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif +#if defined(SOFTAP) + if (ap_fw_loaded == TRUE) { + dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); + } +#endif + +#if defined(KEEP_ALIVE) + { + /* Set Keep Alive : be sure to use FW with -keepalive */ + int res; + + if (ap_fw_loaded == FALSE) { + if ((res = dhd_keep_alive_onoff(dhd, 1)) < 0) + DHD_ERROR(("%s set keeplive failed %d\n", + __FUNCTION__, res)); + } + } +#endif /* Force STA UP */ ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0); @@ -1518,6 +1707,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, sizeof(scan_assoc_time), TRUE, 0); dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, @@ -1579,6 +1769,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* set mode to allow pattern */ bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#ifdef ARP_OFFLOAD_SUPPORT + /* Set and enable ARP offload feature */ + if (dhd_arp_enable) + dhd_arp_offload_set(dhd, dhd_arp_mode); + dhd_arp_offload_enable(dhd, dhd_arp_enable); +#endif /* ARP_OFFLOAD_SUPPORT */ done: @@ -2030,6 +2226,53 @@ dhd_pno_get_status(dhd_pub_t *dhd) #endif /* PNO_SUPPORT */ +#if defined(KEEP_ALIVE) +int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on) +{ + char buf[256]; + char *buf_ptr = buf; + wl_keep_alive_pkt_t keep_alive_pkt; + char * str; + int str_len, buf_len; + int res = -1; + int keep_alive_period = KEEP_ALIVE_PERIOD; /* in ms */ + + DHD_TRACE(("%s: param=%d\n", __FUNCTION__, ka_on)); + + if (ka_on) { /* on suspend */ + keep_alive_pkt.period_msec = keep_alive_period; + + } else { + /* on resume, turn off keep_alive packets */ + keep_alive_pkt.period_msec = 0; + } + + /* IOC var name */ + str = "keep_alive"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + /* set ptr to IOCTL payload after the var name */ + buf_ptr += buf_len; /* include term Z */ + + /* copy Keep-alive attributes from local var keep_alive_pkt */ + str = NULL_PKT_STR; + keep_alive_pkt.len_bytes = strlen(str); + + memcpy(buf_ptr, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN); + buf_ptr += WL_KEEP_ALIVE_FIXED_LEN; + + /* copy packet data */ + memcpy(buf_ptr, str, keep_alive_pkt.len_bytes); + buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes); +/* + res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); +*/ + return res; +} +#endif /* defined(KEEP_ALIVE) */ /* Android ComboSCAN support */ /* diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c index b11e4b3..88d0da2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c @@ -89,12 +89,12 @@ int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) #ifdef CUSTOMER_HW2 host_oob_irq = wifi_get_irq_number(irq_flags_ptr); -#else /* for NOT CUSTOMER_HW2 */ +#else #if defined(CUSTOM_OOB_GPIO_NUM) if (dhd_oob_gpio_num < 0) { dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; } -#endif +#endif /* CUSTOMER_HW2 */ if (dhd_oob_gpio_num < 0) { WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", @@ -199,18 +199,48 @@ dhd_custom_get_mac_address(unsigned char *buf) const struct cntry_locales_custom translate_custom_table[] = { /* Table should be filled out based on custom platform regulatory requirement */ #ifdef EXAMPLE_TABLE + {"", "XY", 4}, /* Universal if Country code is unknown or empty */ {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ - {"EU", "EU", 05}, /* input ISO "CA" to : US regrev 69 */ - {"FR", "EU", 05}, - {"DE", "EU", 05}, - {"IE", "EU", 05}, - {"GB", "EU", 05}, /* input ISO "GB" to : EU regrev 05 */ - {"KR", "XY", 03}, - {"AU", "XY", 03}, - {"CN", "XY", 03}, /* input ISO "CN" to : XY regrev 03 */ - {"TW", "XY", 03}, - {"AR", "XY", 03} + {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3}, + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, #endif /* EXMAPLE_TABLE */ }; @@ -232,11 +262,17 @@ void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) return; for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - break; + if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { + memcpy(cspec->ccode, + translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[i].custom_locale_rev; + return; } } +#ifdef EXAMPLE_TABLE + /* if no country code matched return first universal code from translate_custom_table */ + memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); + cspec->rev = translate_custom_table[0].custom_locale_rev; +#endif /* EXMAPLE_TABLE */ return; } diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index facf6c0..c51b832 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -936,7 +936,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) int ret; osl_t *osh; uint8 *frame; - uint16 len, pad = 0; + uint16 len, pad1 = 0; uint32 swheader; uint retries = 0; bcmsdh_info_t *sdh; @@ -972,10 +972,10 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) #endif /* WLMEDIA_HTSF */ /* Add alignment padding, allocate new packet if needed */ - if ((pad = ((uintptr)frame % DHD_SDALIGN))) { - if (PKTHEADROOM(osh, pkt) < pad) { - DHD_INFO(("%s: insufficient headroom %d for %d pad\n", - __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad)); + if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) { + if (PKTHEADROOM(osh, pkt) < pad1) { + DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", + __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); bus->dhd->tx_realloc++; new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); if (!new) { @@ -994,16 +994,16 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) pkt = new; frame = (uint8*)PKTDATA(osh, pkt); ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); - pad = 0; + pad1 = 0; } else { - PKTPUSH(osh, pkt, pad); + PKTPUSH(osh, pkt, pad1); frame = (uint8*)PKTDATA(osh, pkt); - ASSERT((pad + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); - bzero(frame, pad + SDPCM_HDRLEN); + ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); + bzero(frame, pad1 + SDPCM_HDRLEN); } } - ASSERT(pad < DHD_SDALIGN); + ASSERT(pad1 < DHD_SDALIGN); /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ len = (uint16)PKTLEN(osh, pkt); @@ -1012,7 +1012,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) /* Software tag: channel, sequence number, data offset */ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | - (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); @@ -1029,12 +1029,12 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) /* Raise len to next SDIO block to eliminate tail command */ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - uint16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) + uint16 pad2 = bus->blocksize - (len % bus->blocksize); + if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) #ifdef NOTUSED - if (pad <= PKTTAILROOM(osh, pkt)) + if (pad2 <= PKTTAILROOM(osh, pkt)) #endif /* NOTUSED */ - len += pad; + len += pad2; } else if (len % DHD_SDALIGN) { len += DHD_SDALIGN - (len % DHD_SDALIGN); } @@ -1087,7 +1087,7 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) done: /* restore pkt buffer pointer before calling tx complete routine */ - PKTPULL(osh, pkt, SDPCM_HDRLEN + pad); + PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); #ifdef PROP_TXSTATUS if (bus->dhd->wlfc_state) { dhd_os_sdunlock(bus->dhd); @@ -5791,7 +5791,7 @@ dhdsdio_download_code_array(struct dhd_bus *bus) /* Download image */ while ((offset + MEMBLOCK) < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, dlarray + offset, MEMBLOCK); + bcmerror = dhdsdio_membytes(bus, TRUE, offset, (uint8 *) (dlarray + offset), MEMBLOCK); if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", __FUNCTION__, bcmerror, MEMBLOCK, offset)); @@ -5803,7 +5803,7 @@ dhdsdio_download_code_array(struct dhd_bus *bus) if (offset < sizeof(dlarray)) { bcmerror = dhdsdio_membytes(bus, TRUE, offset, - dlarray + offset, sizeof(dlarray) - offset); + (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); if (bcmerror) { DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 1b8a3e8..9a79a1e 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 125 -#define EPI_INCREMENTAL_NUMBER 14 +#define EPI_INCREMENTAL_NUMBER 22 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 125, 14 +#define EPI_VERSION 5, 90, 125, 22 -#define EPI_VERSION_NUM 0x055a7d0e +#define EPI_VERSION_NUM 0x055a7d16 #define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "5.90.125.14" +#define EPI_VERSION_STR "5.90.125.22" #endif diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index ddcf8df..fd399cb 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -136,7 +136,7 @@ typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) #include #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) #include #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index c824692..d78ecfc 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -633,8 +633,17 @@ typedef struct _pmkid_cand_list { pmkid_cand_t pmkid_cand[1]; } pmkid_cand_list_t; - - +typedef struct wl_assoc_info { + uint32 req_len; + uint32 resp_len; + uint32 flags; + struct dot11_assoc_req req; + struct ether_addr reassoc_bssid; /* used in reassoc's */ + struct dot11_assoc_resp resp; +} wl_assoc_info_t; + +/* flags */ +#define WLC_ASSOC_REQ_IS_REASSOC 0x01 /* assoc req was actually a reassoc */ #define WLC_TXFILTER_OVERRIDE_DISABLED 0 #define WLC_TXFILTER_OVERRIDE_ENABLED 1 diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index ce28a05..f2480e9 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -29,6 +29,10 @@ #include #include +#ifdef CONFIG_SYSCTL +#include +#endif + #include #include #include @@ -62,13 +66,14 @@ #include #include +#include #include #include static struct sdio_func *cfg80211_sdio_func; static struct wl_dev *wl_cfg80211_dev; -u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; +u32 wl_dbg_level = WL_DBG_ERR; #define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin" #define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt" @@ -76,7 +81,44 @@ u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #define MAX_WAIT_TIME 3000 +static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; + +#ifdef CONFIG_SYSCTL +#define MAC_STRING_LEN (sizeof(u8) * 17) +u8 wl_sysctl_macstring[2][MAC_STRING_LEN]; +static ctl_table wl_sysctl_child[] = { + { + .procname = "p2p_dev_addr", + .data = &wl_sysctl_macstring[0], + .maxlen = MAC_STRING_LEN, + .mode = 0444, + .child = NULL, + .proc_handler = proc_dostring, + }, + { + .procname = "p2p_int_addr", + .data = &wl_sysctl_macstring[1], + .maxlen = MAC_STRING_LEN, + .mode = 0444, + .child = NULL, + .proc_handler = proc_dostring, + }, + {0} +}; +static ctl_table wl_sysctl_table[] = { + { + .procname = "wifi", + .data = NULL, + .maxlen = 0, + .mode = 0555, + .child = wl_sysctl_child, + .proc_handler = proc_dostring, + }, + {0} +}; +static struct ctl_table_header *wl_sysctl_hdr; +#endif /* CONFIG_SYSCTL */ /* Data Element Definitions */ #define WPS_ID_CONFIG_METHODS 0x1008 @@ -90,7 +132,9 @@ u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; /* * cfg80211_ops api/callback list */ - +static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody); static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid); @@ -119,15 +163,9 @@ static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm); static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm); -#ifdef NEW_COMPAT_WIRELESS static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool unicast, bool multicast); -#else -static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, - u8 key_idx); -#endif /* NEW_COMPAT_WIRELESS */ static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool pairwise, const u8 *mac_addr, struct key_params *params); @@ -161,7 +199,7 @@ static void wl_init_eq_lock(struct wl_priv *wl); static void wl_init_event_handler(struct wl_priv *wl); static struct wl_event_q *wl_deq_event(struct wl_priv *wl); static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, - const wl_event_msg_t *msg, void *data); + const wl_event_msg_t *msg, void *data, gfp_t gfp); static void wl_put_event(struct wl_event_q *e); static void wl_wakeup_event(struct wl_priv *wl); static s32 wl_notify_connect_status(struct wl_priv *wl, @@ -195,8 +233,6 @@ static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name, static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval); -static s32 wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, - u32 len); /* * cfg80211 set_wiphy_params utilities @@ -275,18 +311,18 @@ static void *wl_get_drvdata(struct wl_dev *dev); /* * ibss mode utilities */ -static bool wl_is_ibssmode(struct wl_priv *wl); +static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); static __used bool wl_is_ibssstarter(struct wl_priv *wl); /* * dongle up/down , default configuration utilities */ static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); -static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e); +static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); static void wl_link_up(struct wl_priv *wl); static void wl_link_down(struct wl_priv *wl); -static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype); +static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); static s32 __wl_cfg80211_up(struct wl_priv *wl); static s32 __wl_cfg80211_down(struct wl_priv *wl); static s32 wl_dongle_probecap(struct wl_priv *wl); @@ -297,7 +333,6 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev); * dongle configuration utilities */ #ifndef EMBEDDED_PLATFORM -/* static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype); */ static s32 wl_dongle_country(struct net_device *ndev, u8 ccode); static s32 wl_dongle_up(struct net_device *ndev, u32 up); static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); @@ -325,12 +360,6 @@ static void wl_iscan_timer(unsigned long data); static void wl_term_iscan(struct wl_priv *wl); static s32 wl_init_iscan(struct wl_priv *wl); static s32 wl_iscan_thread(void *data); -static s32 wl_dev_iovar_setbuf(struct net_device *dev, s8 *iovar, - void *param, s32 paramlen, void *bufptr, - s32 buflen); -static s32 wl_dev_iovar_getbuf(struct net_device *dev, s8 *iovar, - void *param, s32 paramlen, void *bufptr, - s32 buflen); static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action); static s32 wl_do_iscan(struct wl_priv *wl); @@ -344,11 +373,7 @@ static s32 wl_iscan_done(struct wl_priv *wl); static s32 wl_iscan_pending(struct wl_priv *wl); static s32 wl_iscan_inprogress(struct wl_priv *wl); static s32 wl_iscan_aborted(struct wl_priv *wl); -#ifdef NOT_YET -static s32 wl_dongle_save_eventmsg(struct wl_priv *wl); -static s32 wl_dongle_disable_eventmsg(struct wl_priv *wl); -static s32 wl_dongle_restore_eventmsg(struct wl_priv *wl); -#endif /* NOT_YET */ + /* * fw/nvram downloading handler */ @@ -365,7 +390,7 @@ static __used u32 wl_find_msb(u16 bit16); static __used s32 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, s32 err); -static void wl_set_mpc(struct net_device *ndev, int mpc); +static void wl_set_mpc(struct net_device *ndev, s32 mpc); /* * debufs support @@ -469,7 +494,7 @@ static struct ieee80211_rate __wl_rates[] = { RATETAB_ENT(WLC_RATE_24M, 0), RATETAB_ENT(WLC_RATE_36M, 0), RATETAB_ENT(WLC_RATE_48M, 0), - RATETAB_ENT(WLC_RATE_54M, 0), + RATETAB_ENT(WLC_RATE_54M, 0) }; #define wl_a_rates (__wl_rates + 4) @@ -491,7 +516,7 @@ static struct ieee80211_channel __wl_2ghz_channels[] = { CHAN2G(11, 2462, 0), CHAN2G(12, 2467, 0), CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), + CHAN2G(14, 2484, 0) }; static struct ieee80211_channel __wl_5ghz_a_channels[] = { @@ -513,7 +538,7 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = { CHAN5G(192, 0), CHAN5G(196, 0), CHAN5G(200, 0), CHAN5G(204, 0), CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0), + CHAN5G(216, 0) }; static struct ieee80211_channel __wl_5ghz_n_channels[] = { @@ -571,7 +596,7 @@ static struct ieee80211_channel __wl_5ghz_n_channels[] = { CHAN5G(214, 0), CHAN5G(216, 0), CHAN5G(218, 0), CHAN5G(220, 0), CHAN5G(222, 0), CHAN5G(224, 0), - CHAN5G(226, 0), CHAN5G(228, 0), + CHAN5G(226, 0), CHAN5G(228, 0) }; static struct ieee80211_supported_band __wl_band_2ghz = { @@ -579,7 +604,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = { .channels = __wl_2ghz_channels, .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, - .n_bitrates = wl_g_rates_size, + .n_bitrates = wl_g_rates_size }; static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -587,7 +612,7 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .channels = __wl_5ghz_a_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, + .n_bitrates = wl_a_rates_size }; static struct ieee80211_supported_band __wl_band_5ghz_n = { @@ -595,7 +620,7 @@ static struct ieee80211_supported_band __wl_band_5ghz_n = { .channels = __wl_5ghz_n_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size, + .n_bitrates = wl_a_rates_size }; static const u32 __wl_cipher_suites[] = { @@ -603,7 +628,7 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, - WLAN_CIPHER_SUITE_AES_CMAC, + WLAN_CIPHER_SUITE_AES_CMAC }; /* There isn't a lot of sense in it, but you can transmit anything you like */ @@ -653,7 +678,7 @@ wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_DEAUTH >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4) - }, + } }; static void swap_key_from_BE(struct wl_wsec_key *key) @@ -678,33 +703,6 @@ static void swap_key_to_BE(struct wl_wsec_key *key) key->iv_initialized = dtoh32(key->iv_initialized); } -static s32 -wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len) -{ - struct ifreq ifr; - struct wl_ioctl ioc; - mm_segment_t fs; - s32 err = 0; - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - strcpy(ifr.ifr_name, dev->name); - ifr.ifr_data = (caddr_t)&ioc; - - fs = get_fs(); - set_fs(get_ds()); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -#else - err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - set_fs(fs); - - return err; -} - /* For debug: Dump the contents of the encoded wps ie buffe */ static void wl_dbg_dump_wps_ie(char *wps_ie) @@ -777,13 +775,14 @@ wl_dbg_dump_wps_ie(char *wps_ie) static struct net_device * wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { s32 err; s32 timeout = -1; s32 wlif_type; s32 index = 0; + s32 mode = 0; chanspec_t chspec; struct wl_priv *wl = WL_PRIV_GET(); struct net_device *_ndev; @@ -796,19 +795,19 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MESH_POINT: WL_ERR(("Unsupported interface type\n")); - wl->conf->mode = WL_MODE_IBSS; + mode = WL_MODE_IBSS; return NULL; case NL80211_IFTYPE_MONITOR: return wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: - wlif_type = WL_P2P_IF_CLIENT; - wl->conf->mode = WL_MODE_BSS; + wlif_type = WL_P2P_IF_CLIENT; + mode = WL_MODE_BSS; break; case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_AP: wlif_type = WL_P2P_IF_GO; - wl->conf->mode = WL_MODE_AP; + mode = WL_MODE_AP; break; default: WL_ERR(("Unsupported interface type\n")); @@ -821,6 +820,26 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return NULL; } + if (test_bit(WLP2P_STATUS_IF_DELETING, &wl->p2p_status) == 1) { + /* wait till IF_DEL is complete + * release the lock for the unregister to proceed + */ + rtnl_unlock(); + WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n", __func__)); + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (test_bit(WLP2P_STATUS_IF_DELETING, &wl->p2p_status) == FALSE), + msecs_to_jiffies(MAX_WAIT_TIME)); + + /* put back the rtnl_lock again */ + rtnl_lock(); + if (timeout > 0) { + WL_ERR(("IF DEL is Success\n")); + + } else { + WL_ERR(("%s: timeount < 0, return -EAGAIN\n", __func__)); + return ERR_PTR(-EAGAIN); + } + } if (!wl->p2p_on && strstr(name, WL_P2P_INTERFACE_PREFIX)) { wl->p2p_on = true; wl_cfgp2p_init_discovery(wl); @@ -836,16 +855,16 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, /* For P2P mode, use P2P-specific driver features to create the * bss: "wl p2p_ifadd" */ - clear_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); + set_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); err = wl_cfgp2p_ifadd(wl, &wl->p2p_int_addr, htod32(wlif_type), chspec); if (unlikely(err)) return ERR_PTR(-ENOMEM); timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, - (test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status) == TRUE), + (test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status) == FALSE), msecs_to_jiffies(MAX_WAIT_TIME)); - if (timeout > 0 && test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status)) { + if (timeout > 0 && (!test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status))) { struct wireless_dev *vwdev; vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL); @@ -859,17 +878,17 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, wl->vwdev[index] = vwdev; vwdev->iftype = (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION - : NL80211_IFTYPE_AP; + : NL80211_IFTYPE_AP; _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); _ndev->ieee80211_ptr = vwdev; SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); vwdev->netdev = _ndev; set_bit(WL_STATUS_READY, &wl->status); wl->p2p_vif_created = TRUE; + set_mode_by_netdev(wl, _ndev, mode); wl = wdev_to_wl(vwdev); return _ndev; - } else { clear_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); WL_ERR((" virtual interface(%s) is not created \n", wl->p2p_vir_ifname)); @@ -892,6 +911,9 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wl_cfg80211_scan_abort(wl, dev); } wl_cfgp2p_ifdel(wl, &p2p_mac); + WL_ERR(("ifdel command sent to Firmware.. " + "and we just come out without waiting..")); + set_bit(WLP2P_STATUS_IF_DELETING, &wl->p2p_status); } @@ -901,15 +923,16 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) static s32 wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { s32 ap = 0; s32 infra = 0; s32 err = BCME_OK; - chanspec_t chspec; s32 timeout = -1; s32 wlif_type; + s32 mode = 0; + chanspec_t chspec; struct wl_priv *wl = WL_PRIV_GET(); CHECK_SYS_UP(); switch (type) { @@ -921,17 +944,17 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, type)); break; case NL80211_IFTYPE_ADHOC: - wl->conf->mode = WL_MODE_IBSS; + mode = WL_MODE_IBSS; break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wl->conf->mode = WL_MODE_BSS; + mode = WL_MODE_BSS; infra = 1; break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_P2P_GO: - wl->conf->mode = WL_MODE_AP; + mode = WL_MODE_AP; ap = 1; break; default: @@ -951,7 +974,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, (test_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status) == TRUE), msecs_to_jiffies(MAX_WAIT_TIME)); - + set_mode_by_netdev(wl, ndev, mode); clear_bit(WLP2P_STATUS_IF_CHANGING, &wl->p2p_status); clear_bit(WLP2P_STATUS_IF_CHANGED, &wl->p2p_status); } @@ -971,12 +994,12 @@ wl_cfg80211_notify_ifadd(struct net_device *net) } WL_DBG(("IF_ADD event called from dongle, old interface name: %s, new name: %s\n", - net->name, wl->p2p_vir_ifname)); + net->name, wl->p2p_vir_ifname)); /* Assign the net device to CONNECT BSSCFG */ strncpy(net->name, wl->p2p_vir_ifname, IFNAMSIZ - 1); wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net; wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = P2PAPI_BSSCFG_CONNECTION; - set_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); + clear_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status); wake_up_interruptible(&wl->dongle_event_wait); return ret; } @@ -992,7 +1015,7 @@ wl_cfg80211_notify_ifdel(struct net_device *net) } WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n", - net->name, wl->p2p_vir_ifname)); + net->name, wl->p2p_vir_ifname)); if (wl->p2p_vif_created) { s32 index = 0; memset(wl->p2p_vir_ifname, '\0', IFNAMSIZ); @@ -1000,6 +1023,7 @@ wl_cfg80211_notify_ifdel(struct net_device *net) wl_to_p2p_bss_ndev(wl, index) = NULL; wl_to_p2p_bss_bssidx(wl, index) = 0; wl->p2p_vif_created = FALSE; + set_mode_by_netdev(wl, net, -1); wl_cfgp2p_clear_management_ie(wl, index); index = get_idx_vwdev_by_netdev(wl, net); @@ -1007,10 +1031,24 @@ wl_cfg80211_notify_ifdel(struct net_device *net) if (index >= 0) { free_vwdev_by_index(wl, index); } + /* Another option.. Make the IF_ADD wait, if the IF_DEL is not complete.. */ + clear_bit(WLP2P_STATUS_IF_DELETING, &wl->p2p_status); + WL_ERR(("Cleared IF_DELETING status bit\n")); + wake_up_interruptible(&wl->dongle_event_wait); + WL_ERR(("Cleared IF_DELETING status bit DONE WAKEUP Interruptible\n")); } return 0; } +s32 +wl_cfg80211_is_progress_ifadd(void) +{ + s32 is_progress = 0; + struct wl_priv *wl = WL_PRIV_GET(); + if (test_bit(WLP2P_STATUS_IF_ADD, &wl->p2p_status)) + is_progress = 1; + return is_progress; +} s32 wl_cfg80211_is_progress_ifchange(void) @@ -1055,42 +1093,18 @@ static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid) } static s32 -wl_dev_iovar_setbuf(struct net_device *dev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(unlikely(!iolen)); - - return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen); -} - -static s32 -wl_dev_iovar_getbuf(struct net_device *dev, s8 * iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - - iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); - BUG_ON(unlikely(!iolen)); - - return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen); -} - -static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) { s32 params_size = - (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); + (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); struct wl_iscan_params *params; s32 err = 0; if (ssid && ssid->SSID_len) - params_size += sizeof(struct wlc_ssid); + params_size += sizeof(struct wlc_ssid); params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); if (unlikely(!params)) - return -ENOMEM; + return -ENOMEM; memset(params, 0, params_size); BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN)); @@ -1101,13 +1115,13 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) params->scan_duration = htod16(0); /* params_size += offsetof(wl_iscan_params_t, params); */ - err = wl_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size, + err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, iscan->ioctl_buf, WLC_IOCTL_SMLEN); if (unlikely(err)) { - if (err == -EBUSY) { + if (err == -EBUSY) { WL_INFO(("system busy : iscan canceled\n")); } else { - WL_ERR(("error (%d)\n", err)); + WL_ERR(("error (%d)\n", err)); } } kfree(params); @@ -1128,8 +1142,8 @@ static s32 wl_do_iscan(struct wl_priv *wl) iscan->state = WL_ISCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; - err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); + err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan), FALSE); if (unlikely(err)) { WL_DBG(("error (%d)\n", err)); return err; @@ -1185,8 +1199,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); params->sync_id = htod16(0x1234); - wl_dev_iovar_setbuf(ndev, "escan", params, params_size, - wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); + wldev_iovar_setbuf(ndev, "escan", params, params_size, + wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); kfree(params); } else if (wl->p2p_on && wl->p2p_scan) { @@ -1195,7 +1209,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint num_chans = scan_request->n_channels; WL_INFO((" chann number : %d\n", num_chans)); default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), - GFP_KERNEL); + GFP_KERNEL); if (default_chan_list == NULL) { WL_ERR(("channel list allocation failed \n")); err = -ENOMEM; @@ -1205,7 +1219,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint { default_chan_list[i] = ieee80211_frequency_to_channel( - scan_request->channels[i]->center_freq); + scan_request->channels[i]->center_freq); } if (num_chans == 3 && ( (default_chan_list[0] == SOCIAL_CHAN_1) && @@ -1219,8 +1233,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint } } - err = wl_cfgp2p_escan(wl, wl->active_scan, num_chans, default_chan_list, - search_state, action, + err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list, + search_state, action, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); kfree(default_chan_list); } @@ -1242,8 +1256,8 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl wl->escan_info.wiphy = wiphy; wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; - err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); + err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan), FALSE); if (unlikely(err)) { WL_DBG(("error (%d)\n", err)); return err; @@ -1346,7 +1360,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (wl->p2p_on && wl->p2p_scan) { - err = wl_cfgp2p_enable_discovery(wl, request->ie, request->ie_len); + err = wl_cfgp2p_enable_discovery(wl, ndev, request->ie, request->ie_len); if (unlikely(err)) { goto scan_out; @@ -1374,15 +1388,15 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); passive_scan = wl->active_scan ? 0 : 1; - err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan)); + err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); goto scan_out; } wl_set_mpc(ndev, 0); - err = wl_dev_ioctl(ndev, WLC_SCAN, &sr->ssid, - sizeof(sr->ssid)); + err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, + sizeof(sr->ssid), FALSE); if (err) { if (err == -EBUSY) { WL_INFO(("system busy : scan for \"%s\" " @@ -1430,7 +1444,7 @@ static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); BUG_ON(unlikely(!len)); - err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len); + err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -1452,7 +1466,7 @@ wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); BUG_ON(unlikely(!len)); - err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len); + err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -1491,7 +1505,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL); retry = htod32(retry); - err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry)); + err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), FALSE); if (unlikely(err)) { WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); return err; @@ -1507,14 +1521,14 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) CHECK_SYS_UP(); if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (wl->conf->rts_threshold != wiphy->rts_threshold)) { + (wl->conf->rts_threshold != wiphy->rts_threshold)) { wl->conf->rts_threshold = wiphy->rts_threshold; err = wl_set_rts(ndev, wl->conf->rts_threshold); if (!err) return err; } if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (wl->conf->frag_threshold != wiphy->frag_threshold)) { + (wl->conf->frag_threshold != wiphy->frag_threshold)) { wl->conf->frag_threshold = wiphy->frag_threshold; err = wl_set_frag(ndev, wl->conf->frag_threshold); if (!err) @@ -1563,14 +1577,14 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, ssid.ssid_len = params->ssid_len; do { if (unlikely - (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == - -EBUSY)) { + (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == + -EBUSY)) { wl_delay(150); } else { break; } } while (++scan_retry < WL_SCAN_RETRY_MAX); - /* to allow scan_inform to paropagate to cfg80211 plane */ + /* to allow scan_inform to propagate to cfg80211 plane */ rtnl_unlock(); /* wait 4 secons till scan done.... */ @@ -1602,8 +1616,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, else memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); - err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, - sizeof(join_params)); + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, + sizeof(join_params), FALSE); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -1642,7 +1656,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) val = WPA_AUTH_DISABLED; WL_DBG(("setting wpa_auth to 0x%0x\n", val)); - err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, val); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set wpa_auth failed (%d)\n", err)); return err; @@ -1681,7 +1695,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) break; } - err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, val); + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); return err; @@ -1747,9 +1761,9 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("pval (%d) gval (%d)\n", pval, gval)); if (is_wps_conn(sme)) { - err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, 4); + err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); } else { - err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, pval | gval); + err = wldev_iovar_setint_bsscfg(dev, "wsec", pval | gval, bssidx); } if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); @@ -1808,7 +1822,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) WL_DBG(("setting wpa_auth to %d\n", val)); - err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, val); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); if (unlikely(err)) { WL_ERR(("could not set wpa_auth (%d)\n", err)); return err; @@ -1866,7 +1880,8 @@ wl_set_set_sharedkey(struct net_device *dev, key.len, key.index, key.algo)); WL_DBG(("key \"%s\"\n", key.data)); swap_key_from_BE(&key); - err = wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + ioctlbuf, sizeof(ioctlbuf), bssidx); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; @@ -1874,7 +1889,7 @@ wl_set_set_sharedkey(struct net_device *dev, if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { WL_DBG(("set auth_type to shared key\n")); val = 1; /* shared key */ - err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, val); + err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); return err; @@ -1896,10 +1911,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; WL_TRACE(("In\n")); + CHECK_SYS_UP(); if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ if (wl->p2p_on && is_wps_conn(sme)) { - WL_DBG(("p2p index : %d\n", wl_cfgp2p_find_idx(wl, dev))); /* Have to apply WPS IE + P2P IE in assoc req frame */ wl_cfgp2p_set_managment_ie(wl, dev, @@ -1909,13 +1924,21 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len); wl_cfgp2p_set_managment_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); + } else if (wl->p2p_on && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { + /* This is the connect req after WPS is done [credentials exchanged] + * currently identified with WPA_VERSION_2 . + * Update the previously set IEs with + * the newly received IEs from Supplicant. This will remove the WPS IE from + * the Assoc Req. + */ + wl_cfgp2p_set_managment_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), + VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); } + } else { WL_ERR(("No P2PIE in beacon \n")); } - - CHECK_SYS_UP(); if (unlikely(!sme->ssid)) { WL_ERR(("Invalid ssid\n")); return -EOPNOTSUPP; @@ -1967,7 +1990,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, join_params.ssid.SSID_len)); } - err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size); + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -1993,8 +2016,8 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, scbval.val = reason_code; memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); - err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t)); + err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -2035,7 +2058,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, /* Make sure radio is off or on as far as software is concerned */ disable = WL_RADIO_SW_DISABLE << 16; disable = htod32(disable); - err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable)); + err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_RADIO error (%d)\n", err)); return err; @@ -2076,15 +2099,9 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) return err; } -#ifdef NEW_COMPAT_WIRELESS -static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, +static s32 +wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool unicast, bool multicast) -#else -static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, - struct net_device *dev, - u8 key_idx) -#endif /* NEW_COMPAT_WIRELESS */ { struct wl_priv *wl = WL_PRIV_GET(); u32 index; @@ -2094,23 +2111,17 @@ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, WL_DBG(("key index (%d)\n", key_idx)); CHECK_SYS_UP(); - /* TODO: wl_cfgp2p_bssiovar_get seems to have a problem here - * roll back to old way - err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); - */ - UNUSED_PARAMETER(bssidx); - err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)); + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); return err; } - wsec = dtoh32(wsec); if (wsec & WEP_ENABLED) { /* Just select a new current key */ index = (u32) key_idx; index = htod32(index); - err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, - sizeof(index)); + err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, + sizeof(index), FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -2138,7 +2149,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, if (key.len == 0) { /* key delete */ swap_key_from_BE(&key); - wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, + sizeof(ioctlbuf), bssidx); if (unlikely(err)) { WL_ERR(("key delete error (%d)\n", err)); return err; @@ -2165,7 +2177,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 *ivptr; ivptr = (u8 *) params->seq; key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | - (ivptr[3] << 8) | ivptr[2]; + (ivptr[3] << 8) | ivptr[2]; key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; key.iv_initialized = true; } @@ -2199,7 +2211,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, #ifdef CONFIG_WIRELESS_EXT dhd_wait_pend8021x(dev); #endif - wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, + sizeof(ioctlbuf), bssidx); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; @@ -2227,12 +2240,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, bssidx = wl_cfgp2p_find_idx(wl, dev); if (mac_addr) { -#if defined(P2P_CONFLICT_GONE) wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); goto exit; -#else - return wl_add_keyext(wiphy, dev, key_idx, mac_addr, params); -#endif /* defined(P2P_CONFLICT_GONE) */ } memset(&key, 0, sizeof(key)); @@ -2283,23 +2292,22 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, /* Set the new key/index */ swap_key_from_BE(&key); - err = wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, + sizeof(ioctlbuf), bssidx); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; } -#if defined(P2P_CONFLICT_GONE) + exit: -#endif - val = WEP_ENABLED; - err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("get wsec error (%d)\n", err)); return err; } - wsec &= ~(WEP_ENABLED); + wsec |= val; - err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); if (unlikely(err)) { WL_ERR(("set wsec error (%d)\n", err)); return err; @@ -2309,7 +2317,7 @@ exit: /* TODO: Removed in P2P, check later --lm */ val = 1; /* assume shared key. otherwise 0 */ val = htod32(val); - err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); + err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); return err; @@ -2325,8 +2333,6 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, struct wl_wsec_key key; struct wl_priv *wl = WL_PRIV_GET(); s32 err = 0; - s32 val; - s32 wsec = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); WL_DBG(("Enter\n")); @@ -2340,7 +2346,8 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ swap_key_from_BE(&key); - wl_cfgp2p_bssiovar_set(dev, "wsec_key", bssidx, &key, sizeof(key)); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, + sizeof(ioctlbuf), bssidx); if (unlikely(err)) { if (err == -EINVAL) { if (key.index >= DOT11_MAX_DEFAULT_KEYS) { @@ -2353,26 +2360,11 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, return err; } - val = 0; - err = wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); - if (unlikely(err)) { - WL_ERR(("get wsec error (%d)\n", err)); - return err; - } - - wsec &= ~(WEP_ENABLED); - wsec |= val; - err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); - if (unlikely(err)) { - WL_ERR(("set wsec error (%d)\n", err)); - return err; - } - #ifdef NOT_YET /* TODO: Removed in P2P twig, check later --lin */ val = 0; /* assume open key. otherwise 1 */ val = htod32(val); - err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val)); + err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_AUTH error (%d)\n", err)); return err; @@ -2403,12 +2395,11 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len); memcpy(params.key, key.data, params.key_len); - wl_cfgp2p_bssiovar_get(dev, "wsec", bssidx, &wsec, sizeof(wsec)); + wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); return err; } - wsec = dtoh32(wsec); switch (wsec) { case WEP_ENABLED: sec = wl_read_prof(wl, WL_PROF_SEC); @@ -2458,13 +2449,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); if (unlikely - (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) { + (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) { WL_ERR(("Wrong Mac address\n")); return -ENOENT; } /* Report the current tx rate */ - err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)); + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), FALSE); if (err) { WL_ERR(("Could not get rate (%d)\n", err)); } else { @@ -2477,8 +2468,8 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { memset(&scb_val, 0, sizeof(scb_val)); scb_val.val = 0; - err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t)); + err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t), FALSE); if (unlikely(err)) { WL_ERR(("Could not get rssi (%d)\n", err)); return err; @@ -2490,7 +2481,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } #if defined(ANDROID_WIRELESS_PATCH) - err = wl_dev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed)); + err = wldev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed), FALSE); sinfo->link_speed = sinfo->link_speed / 2; /* Convert internal 500Kbps to Mpbs */ if (!err) sinfo->filled |= STATION_LINK_SPEED; @@ -2512,7 +2503,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, pm = enabled ? PM_FAST : PM_OFF; pm = htod32(pm); WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); - err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm)); + err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE); if (unlikely(err)) { if (err == -ENODEV) WL_DBG(("net_device is not ready yet\n")); @@ -2566,8 +2557,8 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(); /* addr param is always NULL. ignore it */ /* Get current rateset */ - err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, - sizeof(rateset)); + err = wldev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, + sizeof(rateset), FALSE); if (unlikely(err)) { WL_ERR(("could not get current rateset (%d)\n", err)); return err; @@ -2808,14 +2799,20 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) err = -ENOMEM; } /* Do a scan abort to stop the driver's scan engine */ - err = wl_dev_ioctl(ndev, WLC_SCAN, params, params_size); + err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, FALSE); if (err < 0) { WL_ERR(("scan abort failed \n")); } - clear_bit(WL_STATUS_SCANNING, &wl->status); + /* Report the scan abort to CFG driver too + * We will report it from the thread context, not from this context. + */ - if (wl->p2p_on && test_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status)) - clear_bit(WLP2P_STATUS_SCANNING, &wl->p2p_status); + { + wl_event_msg_t msg; + msg.event_type = hton32(WLC_E_ESCAN_RESULT); + msg.status = WLC_E_STATUS_ABORT; + wl_cfg80211_event(ndev, &msg, NULL, GFP_ATOMIC); + } return err; } static s32 @@ -2847,7 +2844,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, * without turning on P2P */ - err = wl_cfgp2p_enable_discovery(wl, NULL, 0); + err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0); if (unlikely(err)) { goto exit; @@ -2892,9 +2889,12 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, u32 p2pie_len = 0; u32 wpsie_len = 0; u16 fc; + bool ack = FALSE; WL_DBG(("Enter \n")); /* find bssidx based on ndev */ bssidx = wl_cfgp2p_find_idx(wl, dev); + /* cookie generation */ + *cookie = (unsigned long) buf; if (bssidx == -1) { @@ -2908,47 +2908,16 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, * channel. */ wl_cfgp2p_discover_enable_search(wl, FALSE); + /* Abort the dwell time of any previous off-channel action frame that may + * be still in effect. Sending off-channel action frames relies on the + * driver's scan engine. If a previous off-channel action frame tx is + * still in progress (including the dwell time), then this new action + * frame will not be sent out. + */ + wl_cfg80211_scan_abort(wl, dev); } mgmt = (const struct ieee80211_mgmt *) buf; fc = mgmt->frame_control; - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_ASSOC_REQ: - WL_DBG(("packet type: IEEE80211_STYPE_ASSOC_REQ, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_ASSOC_RESP: - WL_DBG(("packet type: IEEE80211_STYPE_ASSOC_RESP, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_REASSOC_REQ: - WL_DBG(("packet type: IEEE80211_STYPE_REASSOC_REQ, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_REASSOC_RESP: - WL_DBG(("packet type: IEEE80211_STYPE_REASSOC_RESP, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_PROBE_REQ: - WL_DBG(("packet type: IEEE80211_STYPE_PROBE_REQ, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_PROBE_RESP: - WL_DBG(("packet type: IEEE80211_STYPE_PROBE_RESP, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_BEACON: - WL_DBG(("packet type: IEEE80211_STYPE_BEACON, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_ATIM: - WL_DBG(("packet type: IEEE80211_STYPE_ATIM, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_DISASSOC: - WL_DBG(("packet type: IEEE80211_STYPE_DISASSOC, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_AUTH: - WL_DBG(("packet type: IEEE80211_STYPE_AUTH, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_DEAUTH: - WL_DBG(("packet type: IEEE80211_STYPE_DEAUTH, bssidx : %d\n", bssidx)); - break; - case IEEE80211_STYPE_ACTION: - WL_DBG(("packet type: IEEE80211_STYPE_ACTION, bssidx : %d\n", bssidx)); - break; - } if (fc != IEEE80211_STYPE_ACTION) { if (wl->p2p_on && (fc == IEEE80211_STYPE_PROBE_RESP)) { s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; @@ -2960,8 +2929,10 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, /* Have to change p2p device address in dev_info attribute * because Supplicant use primary eth0 address */ + #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */ wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_INFO); + #endif } if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len)) != NULL) { @@ -3011,7 +2982,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, * Dwell time to stay off-channel to wait for a response action frame * after transmitting an GO Negotiation action frame */ - af_params->dwell_time = 200; + af_params->dwell_time = WL_DWELL_TIME; memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); @@ -3019,21 +2990,28 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, wifi_p2p_pub_act_frame_t *act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); /* - * Have to change intented address from GO REQ or GO RSP + * Have to change intented address from GO REQ or GO RSP and INVITE REQ * because wpa-supplicant use eth0 primary address */ - if (act_frm->subtype == P2P_PAF_GON_REQ || act_frm->subtype == P2P_PAF_GON_RSP) { + if ((act_frm->subtype == P2P_PAF_GON_REQ)|| + (act_frm->subtype == P2P_PAF_GON_RSP)|| + (act_frm->subtype == P2P_PAF_GON_CONF)|| + (act_frm->subtype == P2P_PAF_INVITE_REQ)) { p2p_ie = wl_cfgp2p_find_p2pie(act_frm->elts, action_frame->len - P2P_PUB_AF_FIXED_LEN); + #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */ wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_int_addr, P2P_SEID_INTINTADDR); wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_INFO); + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, + P2P_SEID_GROUP_ID); + #endif } } - err = wl_cfgp2p_tx_action_frame(wl, af_params, bssidx); - cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL); + ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? FALSE : TRUE; + cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL); kfree(af_params); exit: @@ -3092,7 +3070,7 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, channel = ieee80211_frequency_to_channel(chan->center_freq); WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", dev->ifindex, channel_type, channel)); - wl_dev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)); + wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), FALSE); return err; } @@ -3179,17 +3157,17 @@ wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) break; } /* set auth */ - err = wl_cfgp2p_bssiovar_setint(dev, "auth", bssidx, auth); + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); if (err < 0) { WL_ERR(("auth error %d\n", err)); } /* set wsec */ - err = wl_cfgp2p_bssiovar_setint(dev, "wsec", bssidx, wsec); + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); if (err < 0) { WL_ERR(("wsec error %d\n", err)); } /* set upper-layer auth */ - err = wl_cfgp2p_bssiovar_setint(dev, "wpa_auth", bssidx, wpa_auth); + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); if (err < 0) { WL_ERR(("wpa_auth error %d\n", err)); } @@ -3230,62 +3208,70 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", info->interval, info->dtim_period, info->head_len, info->tail_len)); + + /* + * !!! The following code was NOT indented properly, PLEASE merge your code + * to SVN verion becuase your merger tool may IGNORE tabs/spaces + */ if (wl->p2p_on && (bssidx >= wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { - /* We don't need to set beacon for P2P_GO, - * but need to parse ssid from beacon_parameters - * because there is no way to set ssid - */ - ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; - /* find the SSID */ - if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], info->head_len - ie_offset, - DOT11_MNG_SSID_ID)) != NULL) { - memcpy(wl->p2p_ssid.SSID, ssid_ie->data, ssid_ie->len); - wl->p2p_ssid.SSID_len = ssid_ie->len; - WL_DBG(("SSID (%s) in Head \n", ssid_ie->data)); + /* We don't need to set beacon for P2P_GO, + * but need to parse ssid from beacon_parameters + * because there is no way to set ssid + */ + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], + info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + memcpy(wl->p2p_ssid.SSID, ssid_ie->data, ssid_ie->len); + wl->p2p_ssid.SSID_len = ssid_ie->len; + WL_DBG(("SSID (%s) in Head \n", ssid_ie->data)); - } else { - WL_ERR(("No SSID in beacon \n")); - } + } else { + WL_ERR(("No SSID in beacon \n")); + } - /* find the WPSIE */ - if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { - wpsie_len = wps_ie->length + sizeof(wps_ie->tag) + sizeof(wps_ie->length); - /* - * Should be compared with saved ie before saving it - */ + /* find the WPSIE */ + if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { + wpsie_len = wps_ie->length + sizeof(wps_ie->tag) + sizeof(wps_ie->length); + /* + * Should be compared with saved ie before saving it + */ if (wl_dbg_level & WL_DBG_INFO) wl_dbg_dump_wps_ie((char *) wps_ie); - memcpy(beacon_ie, wps_ie, wpsie_len); - } else { - WL_ERR(("No WPSIE in beacon \n")); - } + memcpy(beacon_ie, wps_ie, wpsie_len); + } else { + WL_ERR(("No WPSIE in beacon \n")); + } - /* find the P2PIE */ - if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) { - /* Total length of P2P Information Element */ - p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); - /* Have to change device address in dev_id attribute because Supplicant - * use primary eth0 address - */ - wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID); - memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len); + /* find the P2PIE */ + if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) { + /* Total length of P2P Information Element */ + p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); + #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */ + /* Have to change device address in dev_id attribute because Supplicant + * use primary eth0 address + */ + wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID); + #endif + memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len); - } else { - WL_ERR(("No P2PIE in beacon \n")); - } + } else { + WL_ERR(("No P2PIE in beacon \n")); + } wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, - beacon_ie, wpsie_len + p2pie_len); + beacon_ie, wpsie_len + p2pie_len); wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG, - beacon_ie, wpsie_len + p2pie_len); + beacon_ie, wpsie_len + p2pie_len); /* find the WPA_IE */ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail, info->tail_len)) != NULL) { WL_DBG((" WPA IE is found\n")); } /* find the RSN_IE */ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, - DOT11_MNG_RSN_ID)) != NULL) { + DOT11_MNG_RSN_ID)) != NULL) { WL_DBG((" WPA2 IE is found\n")); } is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); @@ -3294,16 +3280,16 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, wl_check_wpa2ie(dev, wpa2_ie, bssidx); wl_check_wpaie(dev, (bcm_tlv_t *)wpa_ie, bssidx); - err = wl_dev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32)); - if (err < 0) { + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), FALSE); + if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); - } + } - err = wl_cfgp2p_bssiovar_set(dev, "ssid", bssidx, &wl->p2p_ssid, - sizeof(wl->p2p_ssid)); + err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p_ssid, + sizeof(wl->p2p_ssid), ioctlbuf, sizeof(ioctlbuf), bssidx); - wl_cfgp2p_bss(dev, bssidx, 1); - } + wl_cfgp2p_bss(dev, bssidx, 1); + } } return 0; } @@ -3364,7 +3350,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_beacon = wl_cfg80211_set_beacon, #if defined(ANDROID_WIRELESS_PATCH) .drv_start = wl_cfg80211_drv_start, - .drv_stop = wl_cfg80211_drv_stop, + .drv_stop = wl_cfg80211_drv_stop #endif }; @@ -3410,23 +3396,24 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | - (BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)); + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = __wl_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); -#ifdef NEW_COMPAT_WIRELESS wdev->wiphy->max_remain_on_channel_duration = 5000; -#endif wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes; #ifndef WL_POWERSAVE_DISABLED wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; #else wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; #endif /* !WL_POWERSAVE_DISABLED */ - + wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK | + WIPHY_FLAG_4ADDR_AP | + WIPHY_FLAG_4ADDR_STATION | + WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS; err = wiphy_register(wdev->wiphy); if (unlikely(err < 0)) { WL_ERR(("Couldn not register wiphy device (%d)\n", err)); @@ -3490,7 +3477,7 @@ static s32 wl_inform_bss(struct wl_priv *wl) static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) { - struct wiphy *wiphy = wl_to_wiphy(wl); + struct wiphy *wiphy = wiphy_from_scan(wl); struct ieee80211_mgmt *mgmt; struct ieee80211_channel *channel; struct ieee80211_supported_band *band; @@ -3548,7 +3535,11 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) offsetof(struct wl_cfg80211_bss_info, frame_buf)); notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, u.beacon.variable) + wl_get_ielen(wl); +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(notif_bss_info->channel); +#else freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); +#endif channel = ieee80211_get_channel(wiphy, freq); WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", @@ -3570,42 +3561,21 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) return err; } -static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e) +static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev) { - /* To SK, chagne NOT_YET to 1 if you don't like this - * But in general WLC_E_SET_SSID is more reliable --lin - */ -#ifdef NOT_YET - u32 event = ntoh32(e->event_type); - u16 flags = ntoh16(e->flags); - - if (event == WLC_E_LINK) { - if (flags & WLC_EVENT_MSG_LINK) { - if (wl_is_ibssmode(wl)) { - if (wl_is_ibssstarter(wl)) { - } - } else { - return true; - } - } - } - return false; -#else u32 event = ntoh32(e->event_type); uint32 status = ntoh32(e->status); - WL_DBG(("event %d\n", event)); - /* was WLC_E_LINK here, changed as WLC_E_SET_SSID is more reliable -- lin */ + WL_DBG(("event %d, status %d\n", event, status)); if (event == WLC_E_SET_SSID) { if (status == WLC_E_STATUS_SUCCESS) { - if (!wl_is_ibssmode(wl)) + if (!wl_is_ibssmode(wl, ndev)) return true; } } WL_DBG(("wl_is_linkup false\n")); return false; -#endif /* NOT_YET */ } static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) @@ -3636,39 +3606,91 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) return false; } -static bool wl_is_newsta(struct wl_priv *wl, const wl_event_msg_t *e) -{ - u32 event = ntoh32(e->event_type); - u32 status = ntoh32(e->status); - - if (event == WLC_E_ASSOC_IND && (status == WLC_E_STATUS_SUCCESS)) { - return true; - } - return false; -} - static s32 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { bool act; + bool isfree = FALSE; s32 err = 0; + s32 freq; + s32 channel; u8 body[200]; + u32 event = ntoh32(e->event_type); + u32 reason = ntoh32(e->reason); + u32 len = ntoh32(e->datalen); + u16 fc = 0; + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; + struct ieee80211_supported_band *band; + struct ether_addr da; + struct ether_addr bssid; + struct wiphy *wiphy = wl_to_wiphy(wl); + channel_info_t ci; + memset(body, 0, sizeof(body)); WL_DBG(("Enter \n")); - if (wl->conf->mode == WL_MODE_AP) { - if (wl_is_newsta(wl, e)) { - u32 len = ntoh32(e->datalen); - memcpy(body, e->addr.octet, ETHER_ADDR_LEN); - memcpy(&body[ETHER_ADDR_LEN], data, len); - cfg80211_send_rx_assoc(ndev, body, len + ETHER_ADDR_LEN); + if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { + memcpy(body, data, len); + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + &da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx); + wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DEAUTH; + break; + case WLC_E_DEAUTH: + fc = FC_DEAUTH; + break; + default: + fc = 0; + goto exit; } + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), FALSE))) + return err; + + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); +#else + freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + &mgmt_frame, &len, body); + if (err < 0) + goto exit; + isfree = TRUE; + + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } + } else { - WL_ERR(("event %d ", ntoh32(e->event_type))); - if (wl_is_linkup(wl, e)) { + WL_DBG(("wl_notify_connect_status : event %d status : %d \n", + ntoh32(e->event_type), ntoh32(e->status))); + if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); - if (wl_is_ibssmode(wl)) { + if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); @@ -3684,14 +3706,14 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, wl_update_prof(wl, e, &act, WL_PROF_ACT); } else if (wl_is_linkdown(wl, e)) { if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { - printk("link down, call cfg80211_disconnected"); + printk("link down, call cfg80211_disconnected "); cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); clear_bit(WL_STATUS_CONNECTED, &wl->status); wl_link_down(wl); wl_init_prof(wl->profile); } } else if (wl_is_nonetwork(wl, e)) { - printk("connect failed wl->status 0x%x", (int)wl->status); + printk("connect failed e->status 0x%x", (int)ntoh32(e->status)); if (test_bit(WL_STATUS_CONNECTING, &wl->status)) wl_bss_connect_done(wl, ndev, e, data, false); } else { @@ -3699,6 +3721,9 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } printk("\n"); } +exit: + if (isfree) + kfree(mgmt_frame); return err; } @@ -3726,7 +3751,7 @@ wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX); BUG_ON(unlikely(!buflen)); - return wl_dev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen); + return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, FALSE); } static s32 @@ -3739,8 +3764,8 @@ wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX); BUG_ON(unlikely(!len)); - err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, - WL_IOCTL_LEN_MAX); + err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, + WL_IOCTL_LEN_MAX, FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -3752,10 +3777,8 @@ wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) { - struct wl_assoc_ielen *assoc_info; + wl_assoc_info_t assoc_info; struct wl_connect_info *conn_info = wl_to_conn(wl); - u32 req_len; - u32 resp_len; s32 err = 0; WL_DBG(("Enter \n")); @@ -3765,31 +3788,35 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) WL_ERR(("could not get assoc info (%d)\n", err)); return err; } - assoc_info = (struct wl_assoc_ielen *)wl->extra_buf; - req_len = assoc_info->req_len; - resp_len = assoc_info->resp_len; - if (req_len) { + memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t)); + assoc_info.req_len = htod32(assoc_info.req_len); + assoc_info.resp_len = htod32(assoc_info.resp_len); + assoc_info.flags = htod32(assoc_info.flags); + if (assoc_info.req_len) { err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); return err; } - conn_info->req_ie_len = req_len; + conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req); + if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { + conn_info->req_ie_len -= ETHER_ADDR_LEN; + } conn_info->req_ie = kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL); } else { conn_info->req_ie_len = 0; conn_info->req_ie = NULL; } - if (resp_len) { + if (assoc_info.resp_len) { err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); return err; } - conn_info->resp_ie_len = resp_len; + conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); conn_info->resp_ie = kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL); } else { @@ -3803,7 +3830,7 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) } static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, - size_t *join_params_size) + size_t *join_params_size) { chanspec_t chanspec = 0; @@ -3832,6 +3859,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, WL_DBG(("%s join_params->params.chanspec_list[0]= %X\n", __FUNCTION__, join_params->params.chanspec_list[0])); + } } @@ -3849,7 +3877,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) struct wiphy *wiphy; wiphy = wl_to_wiphy(wl); - if (wl_is_ibssmode(wl)) + if (wl_is_ibssmode(wl, ndev)) return err; ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID); @@ -3861,8 +3889,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) if (unlikely(!bss)) { WL_DBG(("Could not find the AP\n")); *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); - err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO, - wl->extra_buf, WL_EXTRA_BUF_MAX); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO, + wl->extra_buf, WL_EXTRA_BUF_MAX, FALSE); if (unlikely(err)) { WL_ERR(("Could not get bss info %d\n", err)); goto update_bss_info_out; @@ -3896,8 +3924,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) * information out of probe response. * so we speficially query dtim information to dongle. */ - err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period)); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD, + &dtim_period, sizeof(dtim_period), FALSE); if (unlikely(err)) { WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); goto update_bss_info_out; @@ -4009,8 +4037,8 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, if (unlikely(!wl->scan_request)) { } rtnl_lock(); - err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, - sizeof(channel_inform)); + err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, + sizeof(channel_inform), FALSE); if (unlikely(err)) { WL_ERR(("scan busy (%d)\n", err)); goto scan_done_out; @@ -4025,7 +4053,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, bss_list = wl->bss_list; memset(bss_list, 0, len); bss_list->buflen = htod32(len); - err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len); + err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, FALSE); if (unlikely(err)) { WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); err = -EINVAL; @@ -4049,40 +4077,111 @@ scan_done_out: rtnl_unlock(); return err; } +static s32 +wl_frame_get_mgmt(u16 fc, const struct ether_addr *da, + const struct ether_addr *sa, const struct ether_addr *bssid, + u8 **pheader, u32 *body_len, u8 *pbody) +{ + struct dot11_management_header *hdr; + u32 totlen = 0; + s32 err = 0; + u8 *offset; + u32 prebody_len = *body_len; + switch (fc) { + case FC_ASSOC_REQ: + /* capability , listen interval */ + totlen = DOT11_ASSOC_REQ_FIXED_LEN; + *body_len += DOT11_ASSOC_REQ_FIXED_LEN; + break; + case FC_REASSOC_REQ: + /* capability, listen inteval, ap address */ + totlen = DOT11_REASSOC_REQ_FIXED_LEN; + *body_len += DOT11_REASSOC_REQ_FIXED_LEN; + break; + } + totlen += DOT11_MGMT_HDR_LEN + prebody_len; + *pheader = kzalloc(totlen, GFP_KERNEL); + if (*pheader == NULL) { + WL_ERR(("memory alloc failed \n")); + return -ENOMEM; + } + hdr = (struct dot11_management_header *) (*pheader); + hdr->fc = htol16(fc); + hdr->durid = 0; + hdr->seq = 0; + offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len); + bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN); + bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN); + bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN); + bcopy((const char*)pbody, offset, prebody_len); + *body_len = totlen; + return err; +} static s32 wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { struct ieee80211_supported_band *band; - s32 freq; struct wiphy *wiphy = wl_to_wiphy(wl); - + struct ether_addr da; + struct ether_addr bssid; + bool isfree = FALSE; + s32 err = 0; + s32 freq; wl_event_rx_frame_data_t *rxframe = (wl_event_rx_frame_data_t*)data; - - u8 *mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + u32 event = ntoh32(e->event_type); + u8 *mgmt_frame; + u8 bsscfgidx = e->bsscfgidx; u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t); - u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK) & 0x0f); - if (channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; else band = wiphy->bands[IEEE80211_BAND_5GHZ]; + +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(COMPAT_WIRELESS) + freq = ieee80211_channel_to_frequency(channel); +#else freq = ieee80211_channel_to_frequency(channel, band->band); +#endif + if (event == WLC_E_ACTION_FRAME_RX) { + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + &da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx); + wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE); + err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, + &mgmt_frame, &mgmt_frame_len, + (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); + if (err < 0) { + WL_ERR(("%s: Error in receiving action frame len %d channel %d freq %d\n", + __func__, mgmt_frame_len, channel, freq)); + goto exit; + } + isfree = TRUE; + } else { + mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); + } cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__, mgmt_frame_len, ntoh32(e->datalen), channel, freq)); + + if (isfree) + kfree(mgmt_frame); +exit: return 0; } static void wl_init_conf(struct wl_conf *conf) { + s32 i = 0; WL_DBG(("Enter \n")); - conf->mode = (u32)-1; + for (i = 0; i <= VWDEV_CNT; i++) { + conf->mode[i].type = -1; + conf->mode[i].ndev = NULL; + } conf->frag_threshold = (u32)-1; conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; @@ -4100,9 +4199,10 @@ static void wl_init_event_handler(struct wl_priv *wl) memset(wl->evt_handler, 0, sizeof(wl->evt_handler)); wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; - wl->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; + /* wl->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; */ wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status; wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; + wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; @@ -4115,18 +4215,6 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; - /* Used to be like this... - el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; - el->handler[WLC_E_JOIN] = wl_notify_connect_status; - el->handler[WLC_E_LINK] = wl_notify_connect_status; - el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; - el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; - el->handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; - el->handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; - el->handler[WLC_E_ROAM] = wl_notify_roaming_status; - el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; - el->handler[WLC_E_SET_SSID] = wl_notify_connect_status; - */ } static s32 wl_init_priv_mem(struct wl_priv *wl) @@ -4307,7 +4395,7 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, memset(&list, 0, sizeof(list)); list.results.buflen = htod32(WL_ISCAN_BUF_MAX); - err = wl_dev_iovar_getbuf(iscan->dev, "iscanresults", &list, + err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, WL_ISCAN_BUF_MAX); if (unlikely(err)) { @@ -4557,6 +4645,15 @@ static s32 wl_escan_handler(struct wl_priv *wl, rtnl_unlock(); } } + else if (status == WLC_E_STATUS_ABORT) { + wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + if (likely(wl->scan_request)) { + rtnl_lock(); + WL_INFO(("ESCAN COMPLETED\n")); + wl_notify_escan_complete(wl, true); + rtnl_unlock(); + } + } exit: return err; } @@ -4603,8 +4700,8 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->scan_request = NULL; wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); - wl->iscan_on = true; - wl->escan_on = false; + wl->iscan_on = false; + wl->escan_on = true; wl->roam_on = false; wl->iscan_kickstart = false; wl->active_scan = true; @@ -4645,6 +4742,48 @@ static void wl_deinit_priv(struct wl_priv *wl) wl_deinit_priv_mem(wl); } +#ifdef CONFIG_SYSCTL +s32 wl_cfg80211_sysctl_export_devaddr(void *data) +{ + /* Export the p2p_dev_addr via sysctl interface + * so that wpa_supplicant can access it + */ + dhd_pub_t *dhd = (dhd_pub_t *)data; + struct wl_priv *wl = WL_PRIV_GET(); + + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p_dev_addr, &wl->p2p_int_addr); + + sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p_dev_addr.octet)); + sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p_int_addr.octet)); + + return 0; +} +#endif /* CONFIG_SYSCTL */ + +s32 wl_cfg80211_attach_post(struct net_device *ndev) +{ + struct wl_priv * wl = NULL; + s32 err = 0; + WL_TRACE(("In\n")); + if (unlikely(!ndev)) { + WL_ERR(("ndev is invaild\n")); + return -ENODEV; + } + wl = WL_PRIV_GET(); + if (wl && !test_bit(WL_STATUS_READY, &wl->status)) { + if (wl->wdev && + wl_cfgp2p_is_p2p_supported(wl, ndev)) { + WL_INFO(("P2P is supported on Firmware \n")); + wl->wdev->wiphy->interface_modes |= + (BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO)); + } + } else + return -ENODEV; + + set_bit(WL_STATUS_READY, &wl->status); + return err; +} s32 wl_cfg80211_attach(struct net_device *ndev, void *data) { struct wireless_dev *wdev; @@ -4690,9 +4829,13 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) goto cfg80211_attach_out; } +#ifdef CONFIG_SYSCTL + if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) { + WL_ERR(("%s: sysctl register failed!! \n", __func__)); + goto cfg80211_attach_out; + } +#endif wl_set_drvdata(wl_cfg80211_dev, ci); - set_bit(WL_STATUS_READY, &wl->status); - return err; cfg80211_attach_out: @@ -4709,6 +4852,10 @@ void wl_cfg80211_detach(void) WL_TRACE(("In\n")); +#ifdef CONFIG_SYSCTL + if (wl_sysctl_hdr) + unregister_sysctl_table(wl_sysctl_hdr); +#endif rfkill_unregister(wl->rfkill); rfkill_destroy(wl->rfkill); @@ -4758,7 +4905,7 @@ static s32 wl_event_handler(void *data) } void -wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) +wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data, gfp_t gfp) { u32 event_type = ntoh32(e->event_type); struct wl_priv *wl = WL_PRIV_GET(); @@ -4769,7 +4916,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); #endif /* (WL_DBG_LEVEL > 0) */ - if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) + if (likely(!wl_enq_event(wl, ndev, event_type, e, data, gfp))) wl_wakeup_event(wl); } @@ -4816,7 +4963,7 @@ static struct wl_event_q *wl_deq_event(struct wl_priv *wl) static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg, - void *data) + void *data, gfp_t gfp) { struct wl_event_q *e; s32 err = 0; @@ -4827,7 +4974,7 @@ wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_ev if (data) data_len = ntoh32(msg->datalen); evtq_size = sizeof(struct wl_event_q) + data_len; - e = kzalloc(evtq_size, GFP_KERNEL); + e = kzalloc(evtq_size, gfp); if (unlikely(!e)) { WL_ERR(("event alloc failed\n")); return -ENOMEM; @@ -4866,12 +5013,11 @@ struct sdio_func *wl_cfg80211_get_sdio_func(void) return cfg80211_sdio_func; } -static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) +static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) { s32 infra = 0; - s32 ap = 0; s32 err = 0; - + s32 mode = 0; switch (iftype) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: @@ -4880,8 +5026,10 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) err = -EINVAL; return err; case NL80211_IFTYPE_ADHOC: + mode = WL_MODE_IBSS; break; case NL80211_IFTYPE_STATION: + mode = WL_MODE_BSS; infra = 1; break; default: @@ -4890,69 +5038,16 @@ static s32 wl_dongle_mode(struct net_device *ndev, s32 iftype) return err; } infra = htod32(infra); - ap = htod32(ap); - WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra)); - err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)); + err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_INFRA error (%d)\n", err)); return err; } - err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)); - if (unlikely(err)) { - WL_ERR(("WLC_SET_AP error (%d)\n", err)); - return err; - } - - return -EINPROGRESS; -} -#ifdef NOT_YET -static s32 wl_dongle_save_eventmsg(struct wl_priv *wl) -{ - s8 eventmask[WL_EVENTING_MASK_LEN]; - s32 err = 0; - struct net_device *ndev = wl_to_prmry_ndev(wl); - /* Room for "event_msgs" + '\0' + bitvec */ - err = wl_cfgp2p_bssiovar_get(ndev, "event_msgs", 0, - eventmask, WL_EVENTING_MASK_LEN); - if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); - } else { - memcpy(wl->last_eventmask, eventmask, WL_EVENTING_MASK_LEN); - } - return err; -} - -static s32 wl_dongle_disable_eventmsg(struct wl_priv *wl) -{ - s8 eventmask[WL_EVENTING_MASK_LEN]; - s32 err = 0; - struct net_device *ndev = wl_to_prmry_ndev(wl); - /* Only Enable IF EVENT */ - setbit(eventmask, WLC_E_IF); - - err = wl_cfgp2p_bssiovar_set(ndev, "event_msgs", 0, - eventmask, WL_EVENTING_MASK_LEN); - if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); - } - return err; -} + set_mode_by_netdev(wl, ndev, mode); - -static s32 wl_dongle_restore_eventmsg(struct wl_priv *wl) -{ - s32 err = 0; - struct net_device *ndev = wl_to_prmry_ndev(wl); - err = wl_cfgp2p_bssiovar_set(ndev, "event_msgs", 0, - wl->last_eventmask, WL_EVENTING_MASK_LEN); - if (unlikely(err)) { - WL_ERR(("Get event_msgs error (%d)\n", err)); - } - - return err; + return 0; } -#endif /* NOT_YET */ static s32 wl_dongle_eventmsg(struct net_device *ndev) { @@ -4964,7 +5059,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) /* Setup event_msgs */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("Get event_msgs error (%d)\n", err)); goto dongle_eventmsg_out; @@ -4977,6 +5072,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) setbit(eventmask, WLC_E_REASSOC); setbit(eventmask, WLC_E_REASSOC_IND); setbit(eventmask, WLC_E_DEAUTH_IND); + setbit(eventmask, WLC_E_DEAUTH); setbit(eventmask, WLC_E_DISASSOC_IND); setbit(eventmask, WLC_E_DISASSOC); setbit(eventmask, WLC_E_JOIN); @@ -4991,12 +5087,13 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) setbit(eventmask, WLC_E_SCAN_COMPLETE); setbit(eventmask, WLC_E_ACTION_FRAME_RX); setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE); + setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE); setbit(eventmask, WLC_E_P2P_PROBREQ_MSG); setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); setbit(eventmask, WLC_E_ESCAN_RESULT); bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("Set event_msgs error (%d)\n", err)); goto dongle_eventmsg_out; @@ -5019,7 +5116,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) { s32 err = 0; - err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up)); + err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), FALSE); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); } @@ -5031,7 +5128,7 @@ static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) s32 err = 0; WL_TRACE(("In\n")); - err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode)); + err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), FALSE); if (unlikely(err)) { WL_ERR(("WLC_SET_PM error (%d)\n", err)); } @@ -5048,14 +5145,14 @@ wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) /* Match Host and Dongle rx alignment */ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("txglomalign error (%d)\n", err)); goto dongle_glom_out; } /* disable glom option per default */ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("txglom error (%d)\n", err)); goto dongle_glom_out; @@ -5075,7 +5172,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) if (roamvar) { bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("bcn_timeout error (%d)\n", err)); goto dongle_rom_out; @@ -5083,7 +5180,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) } /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (unlikely(err)) { WL_ERR(("roam_off error (%d)\n", err)); goto dongle_rom_out; @@ -5098,8 +5195,8 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, { s32 err = 0; - err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, - sizeof(scan_assoc_time)); + err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, + sizeof(scan_assoc_time), FALSE); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("Scan assoc time is not supported\n")); @@ -5108,8 +5205,8 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, } goto dongle_scantime_out; } - err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, - sizeof(scan_unassoc_time)); + err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, + sizeof(scan_unassoc_time), FALSE); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("Scan unassoc time is not supported\n")); @@ -5133,7 +5230,7 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) /* Set ARP offload */ bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (err) { if (err == -EOPNOTSUPP) WL_INFO(("arpoe is not supported\n")); @@ -5143,7 +5240,7 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) goto dongle_offload_out; } bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (err) { if (err == -EOPNOTSUPP) WL_INFO(("arp_ol is not supported\n")); @@ -5242,7 +5339,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) memcpy((char *)pkt_filterp, &pkt_filter, WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len); + err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, FALSE); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter not supported\n")); @@ -5255,7 +5352,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) /* set mode to allow pattern */ bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); - err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter_mode not supported\n")); @@ -5315,8 +5412,7 @@ s32 wl_config_dongle(struct wl_priv *wl, bool need_lock) wl_dongle_filter(ndev, 1); #endif /* !EMBEDDED_PLATFORM */ - /* TODO: Check if this is ever needed */ - err = wl_dongle_mode(ndev, wdev->iftype); + err = wl_dongle_mode(wl, ndev, wdev->iftype); if (unlikely(err && err != -EINPROGRESS)) goto default_conf_out; err = wl_dongle_probecap(wl); @@ -5342,8 +5438,8 @@ static s32 wl_update_wiphybands(struct wl_priv *wl) s8 phy; s32 err = 0; - err = wl_dev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list, - sizeof(phy_list)); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list, + sizeof(phy_list), FALSE); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -5402,6 +5498,8 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl_cfgp2p_down(wl); + wl_debugfs_remove_netdev(wl); return err; @@ -5515,9 +5613,9 @@ void wl_cfg80211_dbg_level(u32 level) /* wl_dbg_level = level; */ } -static bool wl_is_ibssmode(struct wl_priv *wl) +static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev) { - return wl->conf->mode == WL_MODE_IBSS; + return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; } static __used bool wl_is_ibssstarter(struct wl_priv *wl) @@ -5594,6 +5692,7 @@ static void wl_link_down(struct wl_priv *wl) { struct wl_connect_info *conn_info = wl_to_conn(wl); + WL_DBG(("In\n")); wl->link_up = false; kfree(conn_info->req_ie); conn_info->req_ie = NULL; @@ -5731,8 +5830,19 @@ s8 *wl_cfg80211_get_nvramname(void) return wl->fw->nvram_name; } -static void wl_set_mpc(struct net_device *ndev, int mpc) +static void wl_set_mpc(struct net_device *ndev, s32 mpc) { + + s32 err = 0; + + WL_TRACE(("In\n")); + err = wl_dev_intvar_set(ndev, "mpc", mpc); + if (unlikely(err)) { + WL_ERR(("fail to set mpc\n")); + return; + } + WL_DBG(("MPC : %d\n", mpc)); + } static int wl_debugfs_add_netdev_params(struct wl_priv *wl) @@ -5798,7 +5908,7 @@ static __used void wl_dongle_poweroff(struct wl_priv *wl) } static const struct rfkill_ops wl_rfkill_ops = { - .set_block = wl_rfkill_set, + .set_block = wl_rfkill_set }; static int wl_rfkill_set(void *data, bool blocked) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index bb2f0e4..4ec91e8 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -110,13 +110,14 @@ do { \ * as kernel memory allows */ #define WL_FILE_NAME_MAX 256 +#define WL_DWELL_TIME 200 /* WiFi Direct */ #define WL_P2P_WILDCARD_SSID "DIRECT-" #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN "11" - +#define VWDEV_CNT 3 /* dongle status */ enum wl_status { WL_STATUS_READY = 0, @@ -169,16 +170,12 @@ enum wl_cfgp2p_status { WLP2P_STATUS_SEARCH_ENABLED, WLP2P_STATUS_IF_ADD, WLP2P_STATUS_IF_DEL, + WLP2P_STATUS_IF_DELETING, WLP2P_STATUS_IF_CHANGING, WLP2P_STATUS_IF_CHANGED, WLP2P_STATUS_LISTEN_EXPIRED, WLP2P_STATUS_ACTION_TX_COMPLETED, - WLP2P_STATUS_GROUP_OWNER, - WLP2P_STATUS_GROUP_CLIENT, - WLP2P_STATUS_SCANNING, - WLP2P_STATUS_SCAN_ABORTING, - WLP2P_STATUS_CONNECTING, - WLP2P_STATUS_CONNECTED + WLP2P_STATUS_SCANNING }; /* beacon / probe_response */ struct beacon_proberesp { @@ -190,7 +187,10 @@ struct beacon_proberesp { /* dongle configuration */ struct wl_conf { - u32 mode; /* adhoc , infrastructure or ap */ + struct net_mode { + struct net_device *ndev; + s32 type; + } mode [VWDEV_CNT + 1]; /* adhoc , infrastructure or ap */ u32 frag_threshold; u32 rts_threshold; u32 retry_short; @@ -354,7 +354,7 @@ struct escan_info { u8 escan_buf[ESCAN_BUF_SIZE]; struct wiphy *wiphy; }; -#define VWDEV_CNT 3 + /* dongle private data of cfg80211 interface */ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ @@ -457,9 +457,9 @@ static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct return bss = bss ? (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; } -static inline int alloc_idx_vwdev(struct wl_priv *wl) +static inline s32 alloc_idx_vwdev(struct wl_priv *wl) { - int i = 0; + s32 i = 0; for (i = 0; i < VWDEV_CNT; i++) { if (wl->vwdev[i] == NULL) return i; @@ -467,9 +467,9 @@ static inline int alloc_idx_vwdev(struct wl_priv *wl) return -1; } -static inline int get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev) +static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev) { - int i = 0; + s32 i = 0; for (i = 0; i < VWDEV_CNT; i++) { if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev)) return i; @@ -477,6 +477,43 @@ static inline int get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device return -1; } +static inline s32 get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + s32 i = 0; + for (i = 0; i <= VWDEV_CNT; i++) { + if (wl->conf->mode[i].ndev != NULL && (wl->conf->mode[i].ndev == ndev)) + return wl->conf->mode[i].type; + } + return -1; +} +static inline void set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, s32 type) +{ + s32 i = 0; + for (i = 0; i <= VWDEV_CNT; i++) { + if (type == -1) { + /* free the info of netdev */ + if (wl->conf->mode[i].ndev == ndev) { + wl->conf->mode[i].ndev = NULL; + wl->conf->mode[i].type = -1; + break; + } + + } else { + if ((wl->conf->mode[i].ndev != NULL)&& + (wl->conf->mode[i].ndev == ndev)) { + /* update type of ndev */ + wl->conf->mode[i].type = type; + break; + } + else if ((wl->conf->mode[i].ndev == NULL)&& + (wl->conf->mode[i].type == -1)) { + wl->conf->mode[i].ndev = ndev; + wl->conf->mode[i].type = type; + break; + } + } + } +} #define free_vwdev_by_index(wl, __i) do { \ if (wl->vwdev[__i] != NULL) \ kfree(wl->vwdev[__i]); \ @@ -494,16 +531,20 @@ static inline int get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device (!_sme->crypto.n_ciphers_pairwise) && \ (!_sme->crypto.cipher_group)) extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); +extern s32 wl_cfg80211_attach_post(struct net_device *ndev); extern void wl_cfg80211_detach(void); /* event handler from dongle */ -extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); +extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, + void *data, gfp_t gfp); extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */ extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */ extern s32 wl_cfg80211_up(void); /* dongle up */ extern s32 wl_cfg80211_down(void); /* dongle down */ extern s32 wl_cfg80211_notify_ifadd(struct net_device *net); extern s32 wl_cfg80211_notify_ifdel(struct net_device *net); +extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_is_progress_ifchange(void); +extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_notify_ifchange(void); extern void wl_cfg80211_dbg_level(u32 level); extern void *wl_cfg80211_request_fw(s8 *file_name); @@ -511,6 +552,9 @@ extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size); extern void wl_cfg80211_release_fw(void); extern s8 *wl_cfg80211_get_fwname(void); extern s8 *wl_cfg80211_get_nvramname(void); +#ifdef CONFIG_SYSCTL +extern s32 wl_cfg80211_sysctl_export_devaddr(void *data); +#endif /* do scan abort */ extern s32 diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index a87631c..730a25f 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -21,6 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $ * $Id$ */ @@ -47,6 +48,7 @@ #include #include +#include /* dword align allocation */ @@ -96,350 +98,12 @@ static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; static s8 scanparambuf[WLC_IOCTL_SMLEN]; static s8 *smbuf = ioctlbuf; +static bool +wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); static s32 wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete); -static s32 -wl_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) -{ - struct ifreq ifr; - struct wl_ioctl ioc; - mm_segment_t fs; - s32 err = 0; - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - strcpy(ifr.ifr_name, dev->name); - ifr.ifr_data = (caddr_t)&ioc; - fs = get_fs(); - set_fs(get_ds()); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -#else - err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - set_fs(fs); - - return err; -} - -/* - * Format an iovar buffer. - * iovar name is converted to lower case - */ -static s32 -wl_cfgp2p_iovar_mkbuf(const s8 *name, s8 *data, u32 datalen, - s8 *iovar_buf, u32 buflen, u32 *perr) -{ - u32 iovar_len; - iovar_len = (u32) strlen(name) + 1; - - if ((iovar_len + datalen) > buflen) { - - CFGP2P_ERR(("buf too short, %u < %u\n", buflen, (iovar_len + datalen))); - *perr = BCME_BUFTOOSHORT; - return 0; - } - - /* copy data to the buffer past the end of the iovar name string */ - if (datalen > 0) { - memmove(&iovar_buf[iovar_len], data, datalen); - } - - /* copy the name to the beginning of the buffer */ - strcpy(iovar_buf, name); - - - *perr = 0; - return (iovar_len + datalen); -} - -/* - * Format a bsscfg indexed iovar buffer. - * This is a common implementation called by most OSL implementations of - * p2posl_bssiovar_mkbuf(). DO NOT call this function directly from the - * common code -- call p2posl_bssiovar_mkbuf() instead to allow the OSL to - * override the common implementation if necessary. - */ -static s32 -wl_cfgp2p_bssiovar_mkbuf(const s8 *iovar, s32 bssidx, - void *param, s32 paramlen, void *bufptr, s32 buflen, s32 *perr) -{ - const s8 *prefix = "bsscfg:"; - s8 *p; - u32 prefixlen; - u32 namelen; - u32 iolen; - - if (bssidx == 0) { - return wl_cfgp2p_iovar_mkbuf(iovar, (s8 *)param, paramlen, - (s8 *) bufptr, buflen, perr); - } - - prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ - namelen = (u32) strlen(iovar) + 1; /* lengh of iovar name + null */ - iolen = prefixlen + namelen + sizeof(u32) + paramlen; - - if (buflen < 0 || iolen > (u32)buflen) { - CFGP2P_ERR(("buf too short, %u < %u\n", buflen, iolen)); - *perr = BCME_BUFTOOSHORT; - return 0; - } - p = (s8 *)bufptr; - - /* copy prefix, no null */ - memcpy(p, prefix, prefixlen); - p += prefixlen; - - /* copy iovar name including null */ - memcpy(p, iovar, namelen); - p += namelen; - - /* bss config index as first param */ - bssidx = htod32(bssidx); - memcpy(p, &bssidx, sizeof(u32)); - p += sizeof(u32); - - /* parameter buffer follows */ - if (paramlen) - memcpy(p, param, paramlen); - - *perr = 0; - - return iolen; - -} - -/* - * Set a bss-indexed iovar on the primary ioctl interface, providing both - * parameter and i/o buffers. - */ - -static s32 -wl_cfgp2p_bssiovar_setbuf(struct net_device *dev, const s8 *iovar, s32 bssidx, - void *param, s32 paramlen, void *bufptr, s32 buflen) -{ - s32 iolen; - s32 err; - iolen = wl_cfgp2p_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, - buflen, &err); - - if (err) - return err; - - return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen, TRUE); -} -/* - * Get a named & bss indexed driver iovar using the primary ioctl interface. - */ -static s32 -wl_cfgp2p_bssiovar_getbuf(struct net_device *dev, const s8 *iovar, int bssidx, - void *param, s32 paramlen, void *bufptr, s32 buflen) -{ - s32 err; - s32 iolen; - iolen = wl_cfgp2p_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &err); - - if (unlikely(err)) - return err; - - return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, iolen, FALSE); -} - - -/* - * Get named & bss indexed driver variable to buffer value - * using the primary ioctl interface. - */ -s32 -wl_cfgp2p_bssiovar_get(struct net_device *dev, const s8 *iovar, s32 bssidx, - void *outbuf, s32 len) -{ - s32 err; - - if (len > (s32)sizeof(ioctlbuf)) { - err = wl_cfgp2p_bssiovar_getbuf(dev, iovar, bssidx, NULL, 0, - outbuf, len); - } else { - memset(smbuf, 0, sizeof(ioctlbuf)); - - err = wl_cfgp2p_bssiovar_getbuf(dev, iovar, bssidx, NULL, 0, - smbuf, sizeof(ioctlbuf)); - - if (err == 0) - memcpy(outbuf, smbuf, len); - } - return err; -} -/* - * Set named & bss indexed driver variable to buffer value - * on the primary ioctl interface. - */ -s32 -wl_cfgp2p_bssiovar_set(struct net_device *dev, const s8 *iovar, s32 bssidx, - void *param, s32 paramlen) -{ - - memset(smbuf, 0, sizeof(ioctlbuf)); - - return wl_cfgp2p_bssiovar_setbuf(dev, iovar, bssidx, param, paramlen, smbuf, - sizeof(ioctlbuf)); -} - - -/* - * Set named & bsscfg indexed driver variable to int value - * on the primary ioctl interface. - */ - -s32 -wl_cfgp2p_bssiovar_setint(struct net_device *dev, const s8 *iovar, s32 bssidx, - s32 val) -{ - - val = htod32(val); - - return wl_cfgp2p_bssiovar_set(dev, iovar, bssidx, &val, sizeof(int)); -} - - -s32 -wl_cfgp2p_set_int_bss(struct net_device *dev, s32 ioctl_cmd, s32 val, s32 bssidx) -{ - s32 setval = htod32(val); - return wl_dev_ioctl(dev, WLC_SET_VAR, &setval, sizeof(setval), TRUE); -} - - -s32 -wl_cfgp2p_get_int_bss(struct net_device *dev, s32 ioctl_cmd, s32 *val, s32 bssidx) -{ - s32 ret; - ret = wl_dev_ioctl(dev, WLC_GET_VAR, val, sizeof(*val), FALSE); - if (ret >= 0) { - val = dtoh32(val); - } - return ret; -} - -s32 -wl_cfgp2p_iovar_getbuf_bss(struct net_device *dev, const s8 *iovar, void *param, - s32 paramlen, void *bufptr, s32 buflen, s32 bssidx) -{ - s32 err; - - wl_cfgp2p_iovar_mkbuf(iovar, (s8 *)param, paramlen, (s8 *) bufptr, buflen, - &err); - - if (unlikely(err)) { - CFGP2P_ERR((" mkbuf err %d\n", err)); - } - - return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen, FALSE); -} -/* - * Set a named iovar on a specified BSS, providing both parameter and i/o - * buffers. The iovar name is converted to lower case. - */ -s32 -wl_cfgp2p_iovar_setbuf_bss(struct net_device *dev, const s8 *iovar, - void *param, s32 paramlen, void *bufptr, s32 buflen) -{ - s32 err = BCME_OK; - s32 iolen; - CFGP2P_DBG((" enter\n")); - - iolen = wl_cfgp2p_iovar_mkbuf(iovar, (char *) param, paramlen, (s8 *)bufptr, - buflen, &err); - - if (unlikely(err)) { - CFGP2P_ERR(("iovar = %s\n", iovar)); - return err; - } - err = wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen, TRUE); - CFGP2P_DBG((" leave\n")); - return err; -} - -/* - * Set a named iovar given the parameter buffer, on a specified BSS. - * The iovar name is converted to lower case. - */ -s32 -wl_cfgp2p_iovar_set_bss(struct net_device *dev, const s8 *iovar, void *param, - s32 paramlen) -{ - - s32 ret; - memset(smbuf, 0, sizeof(ioctlbuf)); - CFGP2P_DBG((" enter\n")); - ret = wl_cfgp2p_iovar_setbuf_bss(dev, iovar, param, paramlen, smbuf, - sizeof(ioctlbuf)); - - if (unlikely(ret != 0)) { - CFGP2P_ERR(("set iovar %s failed (%d)\n", - iovar, ret)); - } - CFGP2P_DBG((" leave\n")); - return ret; -} -/* - * Get a parameterless iovar into a given buffer. - * iovar name is converted to lower case - */ -s32 -wl_cfgp2p_iovar_get_bss(struct net_device *dev, const s8 *iovar, void *outbuf, s32 len, - s32 bssidx) -{ - s32 err; - - /* use the return buffer if it is bigger than what we have on the stack */ - if (len > (s32)sizeof(ioctlbuf)) { - err = wl_cfgp2p_iovar_getbuf_bss(dev, iovar, NULL, 0, outbuf, len, bssidx); - } else { - memset(smbuf, 0, sizeof(ioctlbuf)); - err = wl_cfgp2p_iovar_getbuf_bss(dev, iovar, NULL, 0, smbuf, sizeof(ioctlbuf), - bssidx); - if (err == 0) - memcpy(outbuf, smbuf, len); - } - - return err; -} - -/* - * Set named iovar given an integer parameter, on the specified BSS. - * iovar name is converted to lower case - */ -s32 -wl_cfgp2p_iovar_setint_bss(struct net_device *dev, const s8 *iovar, s32 val) -{ - CFGP2P_DBG((" enter\n")); - val = htod32(val); - return wl_cfgp2p_iovar_set_bss(dev, iovar, &val, sizeof(int)); -} - -/* - * Get the named integer iovar on the specified BSS. - * iovar name is converted to lower case - */ -s32 -wl_cfgp2p_iovar_getint_bss(struct net_device *dev, const s8*iovar, s32 *pval, s32 bssidx) -{ - s32 ret; - - ret = wl_cfgp2p_iovar_get_bss(dev, iovar, pval, sizeof(s32), bssidx); - if (ret >= 0) - { - *pval = dtoh32(*pval); - } - return ret; -} - /* * Initialize variables related to P2P * @@ -521,7 +185,8 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, (if_type == WL_P2P_IF_GO) ? "go" : "client", (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); - err = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifadd", &ifreq, sizeof(ifreq)); + err = wldev_iovar_setbuf(netdev, "p2p_ifadd", &ifreq, sizeof(ifreq), + ioctlbuf, sizeof(ioctlbuf)); return err; } @@ -540,7 +205,8 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5])); - ret = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifdel", mac, sizeof(*mac)); + ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), + ioctlbuf, sizeof(ioctlbuf)); if (unlikely(ret < 0)) { printk("'wl p2p_ifdel' error %d\n", ret); @@ -571,7 +237,8 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, (if_type == WL_P2P_IF_GO) ? "go" : "client", (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); - err = wl_cfgp2p_iovar_set_bss(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq)); + err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), + ioctlbuf, sizeof(ioctlbuf)); if (unlikely(err < 0)) { printk("'wl p2p_ifupd' error %d\n", err); @@ -597,7 +264,7 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5])); - ret = wl_cfgp2p_iovar_getbuf_bss(dev, "p2p_if", mac, sizeof(*mac), + ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)); if (ret == 0) { @@ -615,7 +282,7 @@ wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) struct net_device *ndev = wl_to_prmry_ndev(wl); CFGP2P_DBG(("enter\n")); - ret = wl_cfgp2p_iovar_setint_bss(ndev, "p2p_disc", on); + ret = wldev_iovar_setint(ndev, "p2p_disc", on); if (unlikely(ret < 0)) { CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret)); @@ -656,8 +323,8 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, discovery_mode.state = mode; discovery_mode.chspec = CH20MHZ_CHSPEC(channel); discovery_mode.dwell = listen_ms; - ret = wl_cfgp2p_bssiovar_set(dev, "p2p_state", bssidx, &discovery_mode, - sizeof(discovery_mode)); + ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, + sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx); return ret; } @@ -669,7 +336,7 @@ wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) s32 ret; struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); - ret = wl_cfgp2p_iovar_getint_bss(dev, "p2p_dev", index, 0); + ret = wldev_iovar_getint(dev, "p2p_dev", index); CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret)); if (unlikely(ret < 0)) { @@ -765,7 +432,7 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl) * Returns 0 if success. */ s32 -wl_cfgp2p_enable_discovery(struct wl_priv *wl, const u8 *ie, u32 ie_len) +wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len) { s32 ret = BCME_OK; if (test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status)) { @@ -786,13 +453,13 @@ wl_cfgp2p_enable_discovery(struct wl_priv *wl, const u8 *ie, u32 ie_len) * P2P probe responses have the privacy bit set in the 802.11 WPA IE. * Some peer devices may not initiate WPS with us if this bit is not set. */ - ret = wl_cfgp2p_bssiovar_setint(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), - "wsec", wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), AES_ENABLED); + ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), + "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); if (unlikely(ret < 0)) { CFGP2P_ERR((" wsec error %d\n", ret)); } set_ie: - ret = wl_cfgp2p_set_managment_ie(wl, wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), + ret = wl_cfgp2p_set_managment_ie(wl, dev, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE), VNDR_IE_PRBREQ_FLAG, ie, ie_len); @@ -844,7 +511,8 @@ exit: } s32 -wl_cfgp2p_escan(struct wl_priv *wl, u16 active, u32 num_chans, u16 *channels, +wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, + u32 num_chans, u16 *channels, s32 search_state, u16 action, u32 bssidx) { s32 ret = BCME_OK; @@ -933,10 +601,19 @@ wl_cfgp2p_escan(struct wl_priv *wl, u16 active, u32 num_chans, u16 *channels, CFGP2P_INFO(("\n")); - ret = wl_cfgp2p_bssiovar_setbuf(wl_to_p2p_bss_ndev(wl, bssidx), "p2p_scan", bssidx, - memblk, memsize, smbuf, sizeof(ioctlbuf)); + ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_scan", + memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx); return ret; } +/* Check whether pointed-to IE looks like WPA. */ +#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) +/* Check whether pointed-to IE looks like WPS. */ +#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) +/* Check whether the given IE looks like WFA P2P IE. */ +#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ + (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) /* Delete and Set a management ie to firmware * Parameters: * @wl : wl_private data @@ -965,7 +642,8 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi u8 delete = 0; #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) - + if (bssidx == -1) + return BCME_BADARG; if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); switch (pktflag) { @@ -1019,9 +697,9 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi while (pos < *mgmt_ie_len) { ie_id = ie_buf[pos++]; ie_len = ie_buf[pos++]; - CFGP2P_INFO(("DELELED ID(%d), Len(%d),\ - OUI(%02x:%02x:%02x)\n",\ - ie_id, ie_len, ie_buf[pos],\ + CFGP2P_INFO(("DELELED ID(%d), Len(%d)," + "OUI(%02x:%02x:%02x)\n", + ie_id, ie_len, ie_buf[pos], ie_buf[pos+1], ie_buf[pos+2])); ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, VNDR_SPEC_ELEMENT_ID, @@ -1039,10 +717,15 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi while (pos < p2p_ie_len) { ie_id = ie_buf[pos++]; ie_len = ie_buf[pos++]; - CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI : %02x:%02x:%02x\n", - ie_id, ie_len, ie_buf[pos], ie_buf[pos+1], ie_buf[pos+2])); - ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, - VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete); + if ((ie_id == DOT11_MNG_VS_ID) && + (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) || + wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) { + CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :" + "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos], + ie_buf[pos+1], ie_buf[pos+2])); + ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, + VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete); + } pos += ie_len; } } @@ -1083,15 +766,7 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) return BCME_OK; } -/* Check whether pointed-to IE looks like WPA. */ -#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) -/* Check whether pointed-to IE looks like WPS. */ -#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE) -/* Check whether the given IE looks like WFA P2P IE. */ -#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ - (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P) + /* Is any of the tlvs the expected entry? If * not update the tlvs buffer pointer/length. @@ -1106,6 +781,8 @@ wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u return TRUE; } + if (tlvs == NULL) + return FALSE; /* point to the next ie */ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; /* calculate the length of the rest of the buffer */ @@ -1196,7 +873,9 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, = (uchar)(data_len + VNDR_IE_MIN_LEN); memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3); memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len); - err = wl_cfgp2p_bssiovar_set(ndev, "vndr_ie", bssidx, ie_setbuf, buf_len); + err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len, + ioctlbuf, sizeof(ioctlbuf), bssidx); + CFGP2P_INFO(("vndr_ie iovar returns %d\n", err)); kfree(ie_setbuf); return err; @@ -1255,24 +934,18 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, /* * Timer expire callback function for LISTEN + * We can't report cfg80211_remain_on_channel_expired from Timer ISR context, + * so lets do it from thread context. */ static void wl_cfgp2p_listen_expired(unsigned long data) { + wl_event_msg_t msg; struct wl_priv *wl = (struct wl_priv *) data; CFGP2P_DBG((" Enter\n")); - - if (test_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status) == 0) { - CFGP2P_ERR((" WLC_E_P2P_DISC_LISTEN_COMPLETE does not occur\n")); - set_bit(WLP2P_STATUS_LISTEN_EXPIRED, &wl->p2p_status); - - cfg80211_remain_on_channel_expired( - wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), - wl->cache_cookie, &wl->remain_on_chan, - wl->remain_on_chan_type, GFP_KERNEL); - } - + msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE); + wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL, GFP_ATOMIC); } /* @@ -1300,6 +973,7 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) s32 ret = BCME_OK; CFGP2P_DBG((" Enter\n")); + CFGP2P_INFO(("Channel : %d, Duration : %d\n", channel, duration_ms)); if (unlikely(test_bit(WLP2P_STATUS_DISCOVERY_ON, &wl->p2p_status) == 0)) { CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); @@ -1371,19 +1045,21 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, { s32 ret = BCME_OK; u32 event_type = ntoh32(e->event_type); - + u32 status = ntoh32(e->status); CFGP2P_DBG((" Enter\n")); if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received\n")); + CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); + if (status == WLC_E_STATUS_SUCCESS) + set_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status); + else + CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + wake_up_interruptible(&wl->dongle_event_wait); + } else { + CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," + "status : %d\n", status)); - }else { - CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received\n")); } - set_bit(WLP2P_STATUS_ACTION_TX_COMPLETED, &wl->p2p_status); - - wake_up_interruptible(&wl->dongle_event_wait); - return ret; } @@ -1396,7 +1072,8 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, * 802.11 ack has been received for the sent action frame. */ s32 -wl_cfgp2p_tx_action_frame(struct wl_priv *wl, wl_af_params_t *af_params, s32 bssidx) +wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx) { s32 ret = BCME_OK; s32 timeout = 0; @@ -1411,8 +1088,9 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, wl_af_params_t *af_params, s32 bss if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - ret = wl_cfgp2p_bssiovar_setbuf(wl_to_p2p_bss_ndev(wl, bssidx), "actframe", - bssidx, af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf)); + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", + af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx); + if (ret < 0) { CFGP2P_ERR((" sending action frame is failed\n")); @@ -1499,9 +1177,11 @@ wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_i CFGP2P_INFO(("Device ID ATTR FOUND\n")); } else if (subelt_id == P2P_SEID_DEV_INFO) { memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); - CFGP2P_INFO(("Device ID ATTR FOUND\n")); - } - return; + CFGP2P_INFO(("Device INFO ATTR FOUND\n")); + } else if (subelt_id == P2P_SEID_GROUP_ID) { + memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN); + CFGP2P_INFO(("GROUP ID ATTR FOUND\n")); + } return; } else { CFGP2P_DBG(("OTHER id : %d\n", subelt_id)); } @@ -1524,7 +1204,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) /* Check if the BSS is up */ *(int*)getbuf = -1; - result = wl_cfgp2p_iovar_getbuf_bss(ndev, "bss", &bsscfg_idx, + result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0); if (result != 0) { CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result)); @@ -1555,7 +1235,8 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up) bss_setbuf.cfg = htod32(bsscfg_idx); bss_setbuf.val = htod32(val); CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); - ret = wl_cfgp2p_iovar_set_bss(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf)); + ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), + ioctlbuf, sizeof(ioctlbuf)); if (ret != 0) { CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); @@ -1566,12 +1247,12 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up) /* Check if 'p2p' is supported in the driver */ s32 -wl_cfgp2p_is_p2p_supported(struct wl_priv *wl) +wl_cfgp2p_is_p2p_supported(struct wl_priv *wl, struct net_device *ndev) { s32 ret = BCME_OK; s32 is_p2p_supported = 0; - ret = wl_cfgp2p_iovar_getint_bss(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY), "p2p", - &is_p2p_supported, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)); + ret = wldev_iovar_getint(ndev, "p2p", + &is_p2p_supported); if (ret < 0) { CFGP2P_ERR(("wl p2p error %d\n", ret)); return 0; @@ -1581,3 +1262,11 @@ wl_cfgp2p_is_p2p_supported(struct wl_priv *wl) return is_p2p_supported; } + +s32 +wl_cfgp2p_down(struct wl_priv *wl) +{ + if (wl->listen_timer) + del_timer_sync(wl->listen_timer); + return 0; +} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index b208f25..9fb2c9e 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -23,7 +23,6 @@ * * $Id: wl_cfg80211.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $ */ - #ifndef _wl_cfgp2p_h_ #define _wl_cfgp2p_h_ #include @@ -50,12 +49,13 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index); extern s32 wl_cfgp2p_init_discovery(struct wl_priv *wl); extern s32 -wl_cfgp2p_enable_discovery(struct wl_priv *wl, const u8 *ie, u32 ie_len); +wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len); extern s32 wl_cfgp2p_disable_discovery(struct wl_priv *wl); extern s32 -wl_cfgp2p_escan(struct wl_priv *wl, u16 active, u32 num_chans, u16 *channels, - s32 search_state, u16 action, u32 bssidx); +wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans, + u16 *channels, + s32 search_state, u16 action, u32 bssidx); extern wpa_ie_fixed_t * wl_cfgp2p_find_wpaie(u8 *parse, u32 len); @@ -89,7 +89,8 @@ extern s32 wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); extern s32 -wl_cfgp2p_tx_action_frame(struct wl_priv *wl, wl_af_params_t *af_params, s32 bssidx); +wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, + wl_af_params_t *af_params, s32 bssidx); extern void wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr, @@ -97,20 +98,6 @@ wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *o extern void wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id); - -extern s32 -wl_cfgp2p_bssiovar_set(struct net_device *dev, const s8 *iovar, s32 bssidx, - void *param, s32 paramlen); -extern s32 -wl_cfgp2p_bssiovar_get(struct net_device *dev, const s8 *iovar, s32 bssidx, - void *outbuf, s32 len); -extern s32 -wl_cfgp2p_bssiovar_setint(struct net_device *dev, const s8 *iovar, s32 bssidx, s32 val); -extern s32 -wl_cfgp2p_iovar_set_bss(struct net_device *dev, const s8 *iovar, void *param, s32 paramlen); -extern s32 -wl_cfgp2p_iovar_get_bss(struct net_device *dev, const s8 *iovar, void *outbuf, s32 len, s32 bssidx); - extern bool wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); @@ -119,7 +106,10 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up); extern s32 -wl_cfgp2p_is_p2p_supported(struct wl_priv *wl); +wl_cfgp2p_is_p2p_supported(struct wl_priv *wl, struct net_device *ndev); + +extern s32 +wl_cfgp2p_down(struct wl_priv *wl); /* WiFi Direct */ #define SOCIAL_CHAN_1 1 diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c new file mode 100644 index 0000000..c81fcca --- /dev/null +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -0,0 +1,238 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $ + */ + +#include +#include + +#define htod32(i) i +#define htod16(i) i +#define dtoh32(i) i +#define dtoh16(i) i +#define htodchanspec(i) i +#define dtohchanspec(i) i + +s32 wldev_ioctl( + struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set) +{ + s32 ret = 0; + struct ifreq ifr; + struct wl_ioctl ioc; + mm_segment_t fs; + s32 err = 0; + + memset(&ioc, 0, sizeof(ioc)); + ioc.cmd = cmd; + ioc.buf = arg; + ioc.len = len; + ioc.set = set; + strcpy(ifr.ifr_name, dev->name); + ifr.ifr_data = (caddr_t)&ioc; + + fs = get_fs(); + set_fs(get_ds()); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + err = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#else + err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + set_fs(fs); + + return ret; +} + +/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +s32 wldev_mkiovar( + s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, u32 buflen) +{ + s32 iolen = 0; + + iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen); + return iolen; +} + +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen) +{ + s32 ret = 0; + s32 iovar_len = 0; + + iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + ret = wldev_ioctl(dev, WLC_GET_VAR, buf, iovar_len, FALSE); + return ret; +} + + +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen) +{ + s32 ret = 0; + s32 iovar_len; + + iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + return ret; +} + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + memset(iovar_buf, 0, sizeof(iovar_buf)); + return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf)); +} + + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + memset(iovar_buf, 0, sizeof(iovar_buf)); + err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf)); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} + +/** Format a bsscfg indexed iovar buffer. The bsscfg index will be + * taken care of in dhd_ioctl_entry. Internal use only, not exposed to + * wl_iw, wl_cfg80211 and wl_cfgp2p + */ +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx) +{ + const s8 *prefix = "bsscfg:"; + s8 *p; + u32 prefixlen; + u32 namelen; + u32 iolen; + + if (bssidx == 0) { + return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen, + (s8 *) iovar_buf, buflen); + } + + prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */ + namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */ + iolen = prefixlen + namelen + sizeof(u32) + paramlen; + + if (buflen < 0 || iolen > (u32)buflen) + { + printk("wldev_mkiovar_bsscfg buffer is too short\n"); + return BCME_BUFTOOSHORT; + } + + p = (s8 *)iovar_buf; + + /* copy prefix, no null */ + memcpy(p, prefix, prefixlen); + p += prefixlen; + + /* copy iovar name including null */ + memcpy(p, iovar_name, namelen); + p += namelen; + + /* bss config index as first param */ + bssidx = htod32(bssidx); + memcpy(p, &bssidx, sizeof(u32)); + p += sizeof(u32); + + /* parameter buffer follows */ + if (paramlen) + memcpy(p, param, paramlen); + + return iolen; + +} + +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx) +{ + s32 ret = 0; + s32 iovar_len = 0; + + iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + ret = wldev_ioctl(dev, WLC_GET_VAR, buf, iovar_len, FALSE); + return ret; + +} + +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx) +{ + s32 ret = 0; + s32 iovar_len; + + iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + return ret; +} + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + + val = htod32(val); + memset(iovar_buf, 0, sizeof(iovar_buf)); + return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, + sizeof(iovar_buf), bssidx); +} + + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx) +{ + s8 iovar_buf[WLC_IOCTL_SMLEN]; + s32 err; + + memset(iovar_buf, 0, sizeof(iovar_buf)); + err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, + sizeof(iovar_buf), bssidx); + if (err == 0) + { + memcpy(pval, iovar_buf, sizeof(*pval)); + *pval = dtoh32(*pval); + } + return err; +} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h new file mode 100644 index 0000000..eae7d24 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -0,0 +1,91 @@ +/* + * Common function shared by Linux WEXT, cfg80211 and p2p drivers + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $ + */ +#ifndef __WLDEV_COMMON_H__ +#define __WLDEV_COMMON_H__ + +/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or + * netdev_ops->ndo_do_ioctl in new kernels) + * @dev: the net_device handle + */ + +s32 wldev_ioctl( + struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); + +/** Retrieve named IOVARs, this function calls wl_dev_ioctl with + WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen); + +/** Set named IOVARs, this function calls wl_dev_ioctl with + WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen); + +s32 wldev_iovar_setint( + struct net_device *dev, s8 *iovar, s32 val); + +s32 wldev_iovar_getint( + struct net_device *dev, s8 *iovar, s32 *pval); + + +s32 wldev_mkiovar( + s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, u32 buflen); + + +/** The following function can be implemented if there is a need for bsscfg + indexed IOVARs + */ + +s32 wldev_mkiovar_bsscfg( + const s8 *iovar_name, s8 *param, s32 paramlen, + s8 *iovar_buf, s32 buflen, s32 bssidx); + +/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + WLC_GET_VAR IOCTL code + */ +s32 wldev_iovar_getbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx); + +/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with + WLC_SET_VAR IOCTL code + */ +s32 wldev_iovar_setbuf_bsscfg( + struct net_device *dev, s8 *iovar_name, + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx); + +s32 wldev_iovar_getint_bsscfg( + struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); + +s32 wldev_iovar_setint_bsscfg( + struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); + +#endif /* __WLDEV_COMMON_H__ */ -- 2.7.4