From 2f66cb426e32ac6c731e4eda09aded204a800d64 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 18 Jul 2011 11:42:36 -0700 Subject: [PATCH] Update to 5.90.125.40 Add monitor interface support and fix cfg80211 management frame isses Add support for hostapd Use private command to get p2p device address Change-Id: Ie490e38f1af9f259ff4a96b2f7d367119c65c377 Signed-off-by: Howard M. Harte Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 68 +- drivers/net/wireless/bcmdhd/dhd_linux_mon.c | 331 ++++++ drivers/net/wireless/bcmdhd/dhd_sdio.c | 119 +- drivers/net/wireless/bcmdhd/wl_android.c | 19 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 1143 ++++++++++++++----- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 32 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 190 +-- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 32 +- drivers/net/wireless/bcmdhd/wl_iw.c | 26 +- 9 files changed, 1488 insertions(+), 472 deletions(-) create mode 100644 drivers/net/wireless/bcmdhd/dhd_linux_mon.c diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index e952ee1ccc22..ff9f9fa9c21a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -91,6 +91,7 @@ static histo_t vi_d1, vi_d2, vi_d3, vi_d4; #if defined(SOFTAP) extern bool ap_cfg_running; +extern bool ap_fw_loaded; #endif /* enable HOSTIP cache update from the host side when an eth0:N is up */ @@ -442,6 +443,12 @@ static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); static void dhd_dump_htsfhisto(histo_t *his, char *s); #endif /* WLMEDIA_HTSF */ +extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); + +/* Monitor interface */ +extern int dhd_monitor_init(void *dhd_pub); +extern int dhd_monitor_uninit(void); + #if defined(CONFIG_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); @@ -491,6 +498,7 @@ extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ /* && defined(DHD_GPL) */ + static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) { #ifdef PKT_FILTER_SUPPORT @@ -972,7 +980,7 @@ dhd_op_if(dhd_if_t *ifp) ret = -EOPNOTSUPP; } else { #if defined(SOFTAP) - if (ap_cfg_running && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { + if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { /* semaphore that the soft AP CODE waits on */ flags = dhd_os_spin_lock(&dhd->pub); @@ -992,6 +1000,9 @@ dhd_op_if(dhd_if_t *ifp) case WLC_E_IF_DEL: if (ifp->net != NULL) { DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__)); +#ifdef WL_CFG80211 + wl_cfg80211_ifdel_ops(ifp->net); +#endif netif_stop_queue(ifp->net); unregister_netdev(ifp->net); ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ @@ -1234,7 +1245,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) return ret; } -static int +int dhd_start_xmit(struct sk_buff *skb, struct net_device *net) { int ret; @@ -1462,7 +1473,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) } } - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) ifp = dhd->iflist[ifidx]; @@ -1473,6 +1483,14 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) dhdp->dstats.rx_bytes += skb->len; dhdp->rx_packets++; /* Local count */ + /* Dropping packets before registering net device to avoid kernel panic */ + if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { + DHD_ERROR(("%s: net device is NOT registered yet. drop [%s] packet\n", + __FUNCTION__, (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) ? "event" : "data")); + PKTFREE(dhdp->osh, pktbuf, TRUE); + continue; + } + if (in_interrupt()) { netif_rx(skb); } else { @@ -2363,7 +2381,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* updates firmware nvram path if it was provided as module parameters */ if ((firmware_path != NULL) && (firmware_path[0] != '\0')) strcpy(fw_path, firmware_path); @@ -2469,6 +2486,8 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) DHD_ERROR(("wl_cfg80211_attach failed\n")); goto fail; } + + dhd_monitor_init(&dhd->pub); dhd_state |= DHD_ATTACH_STATE_CFG80211; #endif #if defined(CONFIG_WIRELESS_EXT) @@ -2563,7 +2582,6 @@ fail: dhd_free(&dhd->pub); } - return NULL; } @@ -2665,7 +2683,11 @@ dhd_bus_start(dhd_pub_t *dhdp) setbit(dhdp->eventmask, WLC_E_TXFAIL); setbit(dhdp->eventmask, WLC_E_JOIN_START); setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE); - + setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_RX); + setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_COMPLETE); +#if defined(WLP2P) + setbit(dhdp->eventmask, WLC_E_P2P_PROBREQ_MSG); +#endif /* WLP2P */ #ifdef PNO_SUPPORT setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND); #endif /* PNO_SUPPORT */ @@ -2694,10 +2716,6 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_write_macaddr(dhd->pub.mac.octet); #endif -#if defined(CONFIG_SYSCTL) && defined(WL_CFG80211) - wl_cfg80211_sysctl_export_devaddr(&dhd->pub); -#endif - return 0; } @@ -2724,6 +2742,7 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in return ret; } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) static struct net_device_ops dhd_ops_pri = { .ndo_open = dhd_open, @@ -2848,6 +2867,8 @@ static int dhd_device_event(struct notifier_block *this, __FUNCTION__)); aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); } + else + aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); #endif break; @@ -2923,12 +2944,18 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) * We have to use the primary MAC for virtual interfaces */ memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); - if (ifidx == 1) { - DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__)); - /* ACCESSPOINT INTERFACE CASE */ - temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */ + /* + * Android sets the locally administered bit to indicate that this is a + * portable hotspot. This will not work in simultaneous AP/STA mode, + * nor with P2P. Need to set the Donlge's MAC address, and then use that. + */ + if (ifidx > 0) { + DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", + __func__, net->name)); + temp_addr[0] |= 0x02; } } + net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) net->ethtool_ops = &dhd_ethtool_ops; @@ -2951,11 +2978,11 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) DHD_ERROR(("couldn't register the net device, err %d\n", err)); goto fail; } - - printf("%s: Driver up: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + printf("Broadcom Dongle Host Driver: register interface [%s]" + " MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name, - dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2], - dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); + net->dev_addr[0], net->dev_addr[1], net->dev_addr[2], + net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]); #if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) wl_iw_iscan_set_scan_broadcast_prep(net, 1); @@ -3106,8 +3133,10 @@ void dhd_detach(dhd_pub_t *dhdp) } #ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { wl_cfg80211_detach(); + dhd_monitor_uninit(); + } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) @@ -3120,6 +3149,7 @@ void dhd_detach(dhd_pub_t *dhdp) wake_lock_destroy(&dhd->wl_rxwake); #endif } + } diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c new file mode 100644 index 000000000000..a51db01a870d --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c @@ -0,0 +1,331 @@ +/* + * Broadcom Dongle Host Driver (DHD), Linux monitor network interface + * + * 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: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Some external functions, TODO: move them to dhd_linux.h + */ +int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); + +/** + * Local declarations and defintions (not exposed) + */ +#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__) +#define MON_TRACE MON_PRINT + +typedef struct monitor_interface { + int radiotap_enabled; + struct net_device* real_ndev; /* The real interface that the monitor is on */ + struct net_device* mon_ndev; +} monitor_interface; + +typedef struct dhd_linux_monitor { + void *dhd_pub; + monitor_interface mon_if[DHD_MAX_IFS]; + int count; /* Number of total monitor interface */ + struct mutex lock; /* lock to protect count and mon_if */ +} dhd_linux_monitor_t; + +static dhd_linux_monitor_t g_monitor; + +static struct net_device* lookup_real_netdev(char *name); +static monitor_interface* ndev_to_monif(struct net_device *ndev); +static int dhd_mon_if_open(struct net_device *ndev); +static int dhd_mon_if_stop(struct net_device *ndev); +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static void dhd_mon_if_set_multicast_list(struct net_device *ndev); +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr); + +static const struct net_device_ops dhd_mon_if_ops = { + .ndo_open = dhd_mon_if_open, + .ndo_stop = dhd_mon_if_stop, + .ndo_start_xmit = dhd_mon_if_subif_start_xmit, + .ndo_set_multicast_list = dhd_mon_if_set_multicast_list, + .ndo_set_mac_address = dhd_mon_if_change_mac, +}; + +/** + * Local static function defintions + */ + +/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0" + * "p2p-eth0-0" is a match for "mon.p2p-eth0-0") + */ +static struct net_device* lookup_real_netdev(char *name) +{ + int i; + int last_name_len = 0; + struct net_device *ndev; + struct net_device *ndev_found = NULL; + + /* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so + * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0" + */ + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = dhd_idx2net(g_monitor.dhd_pub, i); + if (ndev && strstr(name, ndev->name)) { + if (strlen(ndev->name) > last_name_len) + ndev_found = ndev; + } + } + + return ndev_found; +} + +static monitor_interface* ndev_to_monif(struct net_device *ndev) +{ + int i; + + for (i = 0; i < DHD_MAX_IFS; i++) { + if (g_monitor.mon_if[i].mon_ndev == ndev) + return &g_monitor.mon_if[i]; + } + + return NULL; +} + +static int dhd_mon_if_open(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_stop(struct net_device *ndev) +{ + int ret = 0; + + MON_PRINT("enter\n"); + return ret; +} + +static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret = 0; + int rtap_len; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *rtap_hdr; + monitor_interface* mon_if; + + MON_PRINT("enter\n"); + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + goto fail; + } + + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + if (unlikely(rtap_hdr->it_version)) + goto fail; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (unlikely(skb->len < rtap_len)) + goto fail; + + MON_PRINT("radiotap len (should be 14): %d\n", rtap_len); + + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + dot11_hdr = (struct ieee80211_hdr *)skb->data; + + /* Check if the QoS bit is set */ + if (dot11_hdr->frame_control & 0x0080) + qos_len = 2; + + /* Check if this ia a Wireless Distribution System (WDS) frame + * which has 4 MAC addresses + */ + if ((dot11_hdr->frame_control & 0x0300) == 0x0300) + dot11_hdr_len += 6; + + memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); + memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); + + /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for + * for two MAC addresses + */ + skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); + pdata = (unsigned char*)skb->data; + memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); + memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr)); + + MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); + + /* Use the real net device to transmit the packet */ + ret = dhd_start_xmit(skb, mon_if->real_ndev); + + return ret; + +fail: + dev_kfree_skb(skb); + return 0; +} + +static void dhd_mon_if_set_multicast_list(struct net_device *ndev) +{ + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } + + MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); +} + +static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) +{ + int ret = 0; + monitor_interface* mon_if; + + mon_if = ndev_to_monif(ndev); + if (mon_if == NULL || mon_if->real_ndev == NULL) { + MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } + + MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); + return ret; +} + +/** + * Global function definitions (declared in dhd_linux_mon.h) + */ + +int dhd_add_monitor(char *name, struct net_device **new_ndev) +{ + int idx; + int ret = 0; + struct net_device* ndev = NULL; + dhd_linux_monitor_t **dhd_mon; + + mutex_lock(&g_monitor.lock); + + MON_TRACE("enter, if name: %s\n", name); + if (!name || !new_ndev) { + MON_PRINT("invalid parameters\n"); + ret = -EINVAL; + goto out; + } + + if (g_monitor.count >= DHD_MAX_IFS) { + MON_PRINT("exceeds maximum interfaces\n"); + ret = -EFAULT; + goto out; + } + + ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*)); + if (!ndev) { + MON_PRINT("failed to allocate memory\n"); + ret = -ENOMEM; + goto out; + } + + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(ndev->name, name, IFNAMSIZ); + ndev->name[IFNAMSIZ - 1] = 0; + ndev->netdev_ops = &dhd_mon_if_ops; + + ret = register_netdevice(ndev); + if (ret) { + MON_PRINT(" register_netdevice failed (%d)\n", ret); + goto out; + } + + *new_ndev = ndev; + idx = g_monitor.count; + g_monitor.mon_if[idx].radiotap_enabled = TRUE; + g_monitor.mon_if[idx].mon_ndev = ndev; + g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name); + g_monitor.count++; + dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev); + *dhd_mon = &g_monitor; + + MON_PRINT("net device returned: 0x%p\n", ndev); + MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name); + +out: + if (ret && ndev) + free_netdev(ndev); + + mutex_unlock(&g_monitor.lock); + return ret; + +} + +int dhd_monitor_init(void *dhd_pub) +{ + g_monitor.dhd_pub = dhd_pub; + mutex_init(&g_monitor.lock); + return 0; +} + +int dhd_monitor_uninit(void) +{ + int i; + struct net_device *ndev; + + mutex_lock(&g_monitor.lock); + + for (i = 0; i < DHD_MAX_IFS; i++) { + ndev = g_monitor.mon_if[i].mon_ndev; + if (ndev) { + unregister_netdev(ndev); + free_netdev(ndev); + g_monitor.mon_if[i].real_ndev = NULL; + g_monitor.mon_if[i].mon_ndev = NULL; + g_monitor.count--; + } + } + + mutex_unlock(&g_monitor.lock); + return 0; +} diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index ce9d26b90cf9..2dbb8027569e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -392,6 +392,11 @@ static bool dhd_readahead; /* To check if there's window offered */ #define DATAOK(bus) \ + (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ + (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) + +/* To check if there's window offered for ctrl frame*/ +#define TXCTLOK(bus) \ (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) @@ -1364,7 +1369,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - if (!DATAOK(bus)) { + if (!TXCTLOK(bus)) { DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", __FUNCTION__, bus->tx_max, bus->tx_seq)); bus->ctrl_frame_stat = TRUE; @@ -2602,46 +2607,44 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch break; #ifdef SOFTAP - case IOV_GVAL(IOV_FWPATH): - { - uint32 fw_path_len; - - fw_path_len = strlen(bus->fw_path); - - DHD_INFO(("[softap] get fwpath, l=%d\n", len)); - - if ( fw_path_len > len-1 ) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - if ( fw_path_len ) - bcopy(bus->fw_path, arg, fw_path_len); - - ((uchar*)arg)[fw_path_len] = 0; - } - break; - - case IOV_SVAL(IOV_FWPATH): - { - DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val)); - - switch(int_val) { - case 1: - bus->fw_path = fw_path; /* ordinary one */ - break; - case 2: - bus->fw_path = fw_path2; - break; - default: - bcmerror = BCME_BADARG; - return bcmerror; - } - - DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0]?bus->fw_path:"NULL"))); - } - break; -#endif + case IOV_GVAL(IOV_FWPATH): + { + uint32 fw_path_len; + + fw_path_len = strlen(bus->fw_path); + DHD_INFO(("[softap] get fwpath, l=%d\n", len)); + + if (fw_path_len > len-1) { + bcmerror = BCME_BUFTOOSHORT; + break; + } + + if (fw_path_len) { + bcopy(bus->fw_path, arg, fw_path_len); + ((uchar*)arg)[fw_path_len] = 0; + } + break; + } + + case IOV_SVAL(IOV_FWPATH): + DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val)); + + switch (int_val) { + case 1: + bus->fw_path = fw_path; /* ordinary one */ + break; + case 2: + bus->fw_path = fw_path2; + break; + default: + bcmerror = BCME_BADARG; + break; + } + + DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL"))); + break; + +#endif /* SOFTAP */ case IOV_GVAL(IOV_DEVRESET): DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); @@ -4386,6 +4389,12 @@ dhdsdio_dpc(dhd_bus_t *bus) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); + bus->intstatus = 0; + return 0; + } + /* Start with leftover status bits */ intstatus = bus->intstatus; @@ -4544,7 +4553,7 @@ clkwait: bcmsdh_intr_enable(sdh); } - if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { + if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { int ret, i; ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, @@ -4589,6 +4598,9 @@ clkwait: framecnt = dhdsdio_sendfromq(bus, framecnt); txlimit -= framecnt; } + /* Resched the DPC if ctrl cmd is pending on bus credit*/ + if (bus->ctrl_frame_stat) + resched = TRUE; /* Resched if events or tx frames are pending, else await next interrupt */ /* On failed register access, all bets are off: no resched or interrupts */ @@ -5176,7 +5188,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, sd1idle = TRUE; dhd_readahead = TRUE; retrydata = FALSE; - dhd_doflow = TRUE; + dhd_doflow = FALSE; dhd_dongle_memsize = 0; dhd_txminmax = DHD_TXMINMAX; @@ -5291,15 +5303,20 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, goto fail; } - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); - bcmsdh_intr_disable(sdh); - if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { - DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", - __FUNCTION__, ret)); - goto fail; + if (bus->intr) { + /* Register interrupt callback, but mask it (not operational yet). */ + DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); + bcmsdh_intr_disable(sdh); + if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { + DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", + __FUNCTION__, ret)); + goto fail; + } + DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); + } else { + DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", + __FUNCTION__)); } - DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); DHD_INFO(("%s: completed!!\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 432e2539ab05..fa6e305f45b8 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -65,6 +65,7 @@ #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" #define CMD_BTCOEXMODE "BTCOEXMODE" #define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" #define CMD_SETFWPATH "SETFWPATH" #define CMD_SETBAND "SETBAND" #define CMD_GETBAND "GETBAND" @@ -105,6 +106,7 @@ typedef struct android_wifi_priv_cmd { void dhd_customer_gpio_wlan_ctrl(int onoff); uint dhd_dev_reset(struct net_device *dev, uint8 flag); void dhd_dev_init_ioctl(struct net_device *dev); +int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); extern bool ap_fw_loaded; #ifdef CUSTOMER_HW2 @@ -276,6 +278,18 @@ exit_proc: } #endif +static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) +{ + int ret; + int bytes_written = 0; + + ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command); + if (ret) + return 0; + bytes_written = sizeof(struct ether_addr); + return bytes_written; +} + /** * Global function definitions (declared in wl_android.h) */ @@ -439,8 +453,8 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { char *country_code = command + strlen(CMD_COUNTRY) + 1; bytes_written = wldev_set_country(net, country_code); -#ifdef PNO_SUPPORT } +#ifdef PNO_SUPPORT else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { bytes_written = dhd_dev_pno_reset(net); } @@ -450,7 +464,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) { uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0'; bytes_written = dhd_dev_pno_enable(net, pfn_enabled); + } #endif + else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { + bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd->total_len); } else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 22b636d9cafb..69180b56b42f 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -29,6 +29,11 @@ #include #include +/* + * sys proc file will be REMOVED in next release + */ +#undef CONFIG_SYSCTL + #ifdef CONFIG_SYSCTL #include #endif @@ -189,6 +194,7 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa); static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); +static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted); /* * event & event Q handlers for cfg80211 interfaces */ @@ -331,6 +337,7 @@ 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); static void wl_init_conf(struct wl_conf *conf); +static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); static s32 wl_dongle_eventmsg(struct net_device *ndev); /* @@ -353,6 +360,8 @@ static s32 wl_pattern_atoh(s8 *src, s8 *dst); static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); static s32 wl_update_wiphybands(struct wl_priv *wl); #endif /* !EMBEDDED_PLATFORM */ +static __used void wl_dongle_poweron(struct wl_priv *wl); +static __used void wl_dongle_poweroff(struct wl_priv *wl); static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock); /* @@ -404,6 +413,12 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl); static int wl_setup_rfkill(struct wl_priv *wl); static int wl_rfkill_set(void *data, bool blocked); +/* + * Some external functions, TODO: move them to dhd_linux.h + */ +int dhd_add_monitor(char *name, struct net_device **new_ndev); +int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); + #define WL_PRIV_GET() \ ({ \ struct wl_iface *ci = NULL; \ @@ -418,13 +433,17 @@ static int wl_rfkill_set(void *data, bool blocked); #define CHECK_SYS_UP() \ do { \ struct wl_priv *wl = WL_PRIV_GET(); \ - if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \ + if (unlikely(!wl_get_drv_status(wl, READY))) { \ WL_INFO(("device is not ready : status (%d)\n", \ (int)wl->status)); \ return -EIO; \ } \ } while (0) +#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ + (akm) == RSN_AKM_UNSPECIFIED || \ + (akm) == RSN_AKM_PSK) + extern int dhd_wait_pend8021x(struct net_device *dev); #if (WL_DBG_LEVEL > 0) @@ -773,6 +792,16 @@ wl_dbg_dump_wps_ie(char *wps_ie) } } +static struct net_device* wl_cfg80211_add_monitor_if(char *name) +{ + int ret = 0; + struct net_device* ndev = NULL; + + ret = dhd_add_monitor(name, &ndev); + WL_ERR(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); + return ndev; +} + static struct net_device * wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, enum nl80211_iftype type, u32 *flags, @@ -780,7 +809,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, { s32 err; s32 timeout = -1; - s32 wlif_type; + s32 wlif_type = -1; s32 index = 0; s32 mode = 0; chanspec_t chspec; @@ -798,7 +827,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, mode = WL_MODE_IBSS; return NULL; case NL80211_IFTYPE_MONITOR: - return wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); + return wl_cfg80211_add_monitor_if(name); case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: wlif_type = WL_P2P_IF_CLIENT; @@ -819,35 +848,37 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, WL_ERR(("name is NULL\n")); return NULL; } + if (wl->p2p_supported && (wlif_type != -1)) { + if (wl_get_p2p_status(wl, IF_DELETING) == 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, + (wl_get_p2p_status(wl, IF_DELETING) == false), + msecs_to_jiffies(MAX_WAIT_TIME)); - if (wl_get_p2p_status(wl, IF_DELETING) == 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, - (wl_get_p2p_status(wl, IF_DELETING) == 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")); + /* 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); + } else { + WL_ERR(("%s: timeount < 0, return -EAGAIN\n", __func__)); + return ERR_PTR(-EAGAIN); + } + } + if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + p2p_on(wl) = true; + wl_cfgp2p_set_firm_p2p(wl); + wl_cfgp2p_init_discovery(wl); } - } - if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { - p2p_on(wl) = true; - wl_cfgp2p_init_discovery(wl); - } - memset(wl->p2p.vir_ifname, 0, IFNAMSIZ); - strncpy(wl->p2p.vir_ifname, name, IFNAMSIZ - 1); - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr); + memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); + strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Temporary use channel 11, in case GO will be changed with set_channel API */ chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); @@ -856,13 +887,13 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, * bss: "wl p2p_ifadd" */ wl_set_p2p_status(wl, IF_ADD); - err = wl_cfgp2p_ifadd(wl, &wl->p2p.int_addr, htod32(wlif_type), chspec); + 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, - (wl_get_p2p_status(wl, IF_ADD) == FALSE), + (wl_get_p2p_status(wl, IF_ADD) == false), msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) { @@ -873,7 +904,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-ENOMEM); } vwdev->wiphy = wl->wdev->wiphy; - WL_INFO((" virtual interface(%s) is created \n", wl->p2p.vir_ifname)); + WL_INFO((" virtual interface(%s) is created \n", wl->p2p->vir_ifname)); index = alloc_idx_vwdev(wl); wl->vwdev[index] = vwdev; vwdev->iftype = @@ -883,20 +914,19 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, _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; + wl_set_drv_status(wl, READY); + wl->p2p->vif_created = true; set_mode_by_netdev(wl, _ndev, mode); wl = wdev_to_wl(vwdev); return _ndev; } else { wl_clr_p2p_status(wl, IF_ADD); - WL_ERR((" virtual interface(%s) is not created timeout=%d\n", - wl->p2p.vir_ifname, timeout)); - memset(wl->p2p.vir_ifname, '\0', IFNAMSIZ); - wl->p2p.vif_created = FALSE; + WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname)); + memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); + wl->p2p->vif_created = false; + } } - return ERR_PTR(-ENODEV); } @@ -906,19 +936,31 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) { struct ether_addr p2p_mac; struct wl_priv *wl = WL_PRIV_GET(); - memcpy(p2p_mac.octet, wl->p2p.int_addr.octet, ETHER_ADDR_LEN); - if (wl->p2p.vif_created) { - if (test_bit(WL_STATUS_SCANNING, &wl->status)) { - 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..")); - wl_set_p2p_status(wl, IF_DELETING); + s32 timeout = -1; + + if (wl->p2p_supported) { + memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); + if (wl->p2p->vif_created) { + if (wl_get_drv_status(wl, SCANNING)) { + wl_cfg80211_scan_abort(wl, dev); + } + wl_cfgp2p_ifdel(wl, &p2p_mac); + wl_set_p2p_status(wl, IF_DELETING); + + /* Wait for any pending scan req to get aborted from the sysioc context */ + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (wl->scan_request == false), + msecs_to_jiffies(MAX_WAIT_TIME)); + + if (timeout > 0 && (!wl->scan_request)) { + WL_DBG(("IFDEL Operations Done")); + } else { + WL_ERR(("IFDEL didn't complete properly")); + } + } } - WL_DBG(("Done\n")); return 0; } @@ -935,7 +977,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, s32 mode = 0; chanspec_t chspec; struct wl_priv *wl = WL_PRIV_GET(); - CHECK_SYS_UP(); + WL_DBG(("Enter \n")); switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: @@ -963,21 +1005,36 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, } - if (ap && wl->p2p.vif_created) { - WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p.vif_created, - p2p_on(wl))); - chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); - wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT; - WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type)); - wl_set_p2p_status(wl, IF_CHANGING); - wl_clr_p2p_status(wl, IF_CHANGED); - err = wl_cfgp2p_ifchange(wl, &wl->p2p.int_addr, htod32(wlif_type), chspec); - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, - (wl_get_p2p_status(wl, IF_CHANGED) == TRUE), - msecs_to_jiffies(MAX_WAIT_TIME)); + if (ap) { set_mode_by_netdev(wl, ndev, mode); - wl_clr_p2p_status(wl, IF_CHANGING); - wl_clr_p2p_status(wl, IF_CHANGED); + if (wl->p2p_supported && wl->p2p->vif_created) { + WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, + p2p_on(wl))); + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT; + WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", + ndev->name, ap, infra, type)); + wl_set_p2p_status(wl, IF_CHANGING); + wl_clr_p2p_status(wl, IF_CHANGED); + err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); + timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + (wl_get_p2p_status(wl, IF_CHANGED) == true), + msecs_to_jiffies(MAX_WAIT_TIME)); + set_mode_by_netdev(wl, ndev, mode); + wl_clr_p2p_status(wl, IF_CHANGING); + wl_clr_p2p_status(wl, IF_CHANGED); + } else if (ndev == wl_to_prmry_ndev(wl) && + !wl_get_drv_status(wl, AP_CREATED)) { + wl_set_drv_status(wl, AP_CREATING); + if (!wl->ap_info && + !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { + WL_ERR(("struct ap_saved_ie allocation failed\n")); + return -ENOMEM; + } + } else { + WL_ERR(("Cannot change the interface for GO or SOFTAP\n")); + return -EINVAL; + } } ndev->ieee80211_ptr->iftype = type; @@ -993,20 +1050,22 @@ wl_cfg80211_notify_ifadd(struct net_device *net) WL_ERR(("net is NULL\n")); return 0; } - - WL_DBG(("IF_ADD event called from dongle, old interface name: %s, new name: %s\n", - 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; - wl_clr_p2p_status(wl, IF_ADD); - wake_up_interruptible(&wl->dongle_event_wait); + if (wl->p2p_supported) { + WL_DBG(("IF_ADD event called from dongle, old interface name: %s," + "new name: %s\n", 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; + wl_clr_p2p_status(wl, IF_ADD); + wake_up_interruptible(&wl->dongle_event_wait); + } return ret; } s32 -wl_cfg80211_notify_ifdel(struct net_device *net) +wl_cfg80211_ifdel_ops(struct net_device *net) { struct wl_priv *wl = WL_PRIV_GET(); @@ -1015,15 +1074,39 @@ wl_cfg80211_notify_ifdel(struct net_device *net) return 0; } - WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n", - net->name, wl->p2p.vir_ifname)); - if (wl->p2p.vif_created) { + if ((wl->p2p->vif_created) && (wl->scan_request)) { + + /* Abort any pending scan requests */ + wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; + rtnl_lock(); + WL_INFO(("ESCAN COMPLETED\n")); + wl_notify_escan_complete(wl, true); + rtnl_unlock(); + } + + /* Wake up any waiting thread */ + wake_up_interruptible(&wl->dongle_event_wait); + + return 0; +} + +s32 +wl_cfg80211_notify_ifdel(struct net_device *net) +{ + struct wl_priv *wl = WL_PRIV_GET(); + + + if (wl->p2p->vif_created) { s32 index = 0; - memset(wl->p2p.vir_ifname, '\0', IFNAMSIZ); + + WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n", + net->name, wl->p2p->vir_ifname)); + + memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); index = wl_cfgp2p_find_idx(wl, net); wl_to_p2p_bss_ndev(wl, index) = NULL; wl_to_p2p_bss_bssidx(wl, index) = 0; - wl->p2p.vif_created = FALSE; + wl->p2p->vif_created = false; set_mode_by_netdev(wl, net, -1); wl_cfgp2p_clear_management_ie(wl, index); @@ -1032,12 +1115,13 @@ 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.. */ + } + wl_clr_p2p_status(wl, IF_DELETING); - WL_ERR(("Cleared IF_DELETING status bit\n")); + + /* Wake up any waiting thread */ wake_up_interruptible(&wl->dongle_event_wait); - WL_ERR(("Cleared IF_DELETING status bit DONE WAKEUP Interruptible\n")); - } + return 0; } @@ -1144,7 +1228,7 @@ static s32 wl_do_iscan(struct wl_priv *wl) passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), FALSE); + &passive_scan, sizeof(passive_scan), false); if (unlikely(err)) { WL_DBG(("error (%d)\n", err)); return err; @@ -1171,8 +1255,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint WL_DBG(("Enter \n")); - if ((ndev == wl_to_prmry_ndev(wl)) && - !p2p_scan(wl)) { + if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) && + !p2p_scan(wl))) { /* LEGACY SCAN TRIGGER */ WL_DBG(("LEGACY SCAN START\n")); if (ssid && ssid->SSID_len) { @@ -1255,7 +1339,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), FALSE); + &passive_scan, sizeof(passive_scan), false); if (unlikely(err)) { WL_DBG(("error (%d)\n", err)); return err; @@ -1284,11 +1368,11 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, bool spec_scan; s32 err = 0; - if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) { + if (unlikely(wl_get_drv_status(wl, SCANNING))) { WL_ERR(("Scanning already : status (%d)\n", (int)wl->status)); return -EAGAIN; } - if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) { + if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) { WL_ERR(("Scanning being aborted : status (%d)\n", (int)wl->status)); return -EAGAIN; @@ -1305,33 +1389,37 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } else if (wl->escan_on) { escan_req = true; if (ssids->ssid_len && IS_P2P_SSID(ssids->ssid)) { - /* p2p scan trigger */ - if (p2p_on(wl) == false) { - /* p2p on at the first time */ - p2p_on(wl) = true; - wl_cfgp2p_set_firm_p2p(wl); + if (wl->p2p_supported) { + /* p2p scan trigger */ + if (p2p_on(wl) == false) { + /* p2p on at the first time */ + p2p_on(wl) = true; + wl_cfgp2p_set_firm_p2p(wl); + } + p2p_scan(wl) = true; } - p2p_scan(wl) = true; - } else { /* legacy scan trigger * So, we have to disable p2p discovery if p2p discovery is on */ - p2p_scan(wl) = false; - /* If Netdevice is not equals to primary and p2p is on - * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. - */ - if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl))) - p2p_scan(wl) = true; + if (wl->p2p_supported) { + p2p_scan(wl) = false; + /* If Netdevice is not equals to primary and p2p is on + * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE. + */ + if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl))) + p2p_scan(wl) = true; + + if (p2p_scan(wl) == false) { + if (wl_get_p2p_status(wl, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(wl, + false); + if (unlikely(err)) { + goto scan_out; + } - if (p2p_scan(wl) == false) { - if (wl_get_p2p_status(wl, DISCOVERY_ON)) { - err = wl_cfgp2p_discover_enable_search(wl, FALSE); - if (unlikely(err)) { - goto scan_out; } - } } } @@ -1341,7 +1429,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ssids = this_ssid; } wl->scan_request = request; - set_bit(WL_STATUS_SCANNING, &wl->status); + wl_set_drv_status(wl, SCANNING); if (iscan_req) { err = wl_do_iscan(wl); if (likely(!err)) @@ -1354,13 +1442,15 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, memcpy(ssid_info.SSID, ssids->ssid, ssids->ssid_len); ssid_info.SSID_len = ssids->ssid_len; + if (wl->p2p_supported) { + if (p2p_on(wl) && p2p_scan(wl)) { - if (p2p_on(wl) && p2p_scan(wl)) { - - err = wl_cfgp2p_enable_discovery(wl, ndev, request->ie, request->ie_len); + err = wl_cfgp2p_enable_discovery(wl, ndev, + request->ie, request->ie_len); - if (unlikely(err)) { - goto scan_out; + if (unlikely(err)) { + goto scan_out; + } } } err = wl_do_escan(wl, wiphy, ndev, &ssid_info); @@ -1386,13 +1476,13 @@ __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 = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, - &passive_scan, sizeof(passive_scan), FALSE); + &passive_scan, sizeof(passive_scan), false); if (unlikely(err)) { WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); goto scan_out; } err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, - sizeof(sr->ssid), FALSE); + sizeof(sr->ssid), false); if (err) { if (err == -EBUSY) { WL_INFO(("system busy : scan for \"%s\" " @@ -1407,7 +1497,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return 0; scan_out: - clear_bit(WL_STATUS_SCANNING, &wl->status); + wl_clr_drv_status(wl, SCANNING); wl->scan_request = NULL; return err; } @@ -1439,7 +1529,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 = wldev_ioctl(dev, WLC_SET_VAR, buf, len, FALSE); + err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -1461,7 +1551,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 = wldev_ioctl(dev, WLC_GET_VAR, &var, len, FALSE); + err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -1500,7 +1590,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 = wldev_ioctl(dev, cmd, &retry, sizeof(retry), FALSE); + err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false); if (unlikely(err)) { WL_ERR(("cmd (%d) , error (%d)\n", cmd, err)); return err; @@ -1612,7 +1702,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN); err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, - sizeof(join_params), FALSE); + sizeof(join_params), false); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -1985,12 +2075,12 @@ 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 = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, FALSE); + err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; } - set_bit(WL_STATUS_CONNECTING, &wl->status); + wl_set_drv_status(wl, CONNECTING); return err; } @@ -2012,7 +2102,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), FALSE); + sizeof(scb_val_t), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -2053,7 +2143,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 = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), FALSE); + 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; @@ -2116,7 +2206,7 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, index = (u32) key_idx; index = htod32(index); err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index, - sizeof(index), FALSE); + sizeof(index), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); } @@ -2132,7 +2222,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, struct wl_wsec_key key; s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - + s32 mode = get_mode_by_netdev(wl, dev); memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -2155,11 +2245,11 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("Invalid key length (%d)\n", key.len)); return -EINVAL; } - WL_DBG(("Setting the key index %d\n", key.index)); memcpy(key.data, params->key, key.len); - if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { + if ((mode == WL_MODE_BSS) && + (params->cipher == WLAN_CIPHER_SUITE_TKIP)) { u8 keybuf[8]; memcpy(keybuf, &key.data[24], sizeof(keybuf)); memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); @@ -2225,10 +2315,10 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, s32 val = 0; s32 wsec = 0; s32 err = 0; - uint8 keybuf[8]; + u8 keybuf[8]; s32 bssidx = 0; struct wl_priv *wl = WL_PRIV_GET(); - + s32 mode = get_mode_by_netdev(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); CHECK_SYS_UP(); @@ -2264,10 +2354,12 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, case WLAN_CIPHER_SUITE_TKIP: key.algo = CRYPTO_ALGO_TKIP; val = TKIP_ENABLED; - /* wpa_supplicant switches the third and fourth quarters of the TKIP key, linm */ - bcopy(&key.data[24], keybuf, sizeof(keybuf)); - bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); - bcopy(keybuf, &key.data[16], sizeof(keybuf)); + /* wpa_supplicant switches the third and fourth quarters of the TKIP key */ + if (mode == WL_MODE_BSS) { + bcopy(&key.data[24], keybuf, sizeof(keybuf)); + bcopy(&key.data[16], &key.data[24], sizeof(keybuf)); + bcopy(keybuf, &key.data[16], sizeof(keybuf)); + } WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); break; case WLAN_CIPHER_SUITE_AES_CMAC: @@ -2312,7 +2404,7 @@ exit: /* TODO: Removed in P2P, check later --lm */ val = 1; /* assume shared key. otherwise 0 */ val = htod32(val); - err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE); + 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; @@ -2359,7 +2451,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, /* TODO: Removed in P2P twig, check later --lin */ val = 0; /* assume open key. otherwise 1 */ val = htod32(val); - err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE); + 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; @@ -2395,28 +2487,28 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); return err; } - switch (wsec) { - case WEP_ENABLED: - sec = wl_read_prof(wl, WL_PROF_SEC); - if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { - params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { - params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); - } - break; - case TKIP_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_TKIP; - WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); - break; - case AES_ENABLED: - params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; - WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); - break; - default: - WL_ERR(("Invalid algo (0x%x)\n", wsec)); - return -EINVAL; + switch (wsec & ~SES_OW_ENABLED) { + case WEP_ENABLED: + sec = wl_read_prof(wl, WL_PROF_SEC); + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); + break; + default: + WL_ERR(("Invalid algo (0x%x)\n", wsec)); + return -EINVAL; } callback(cookie, ¶ms); @@ -2450,7 +2542,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), FALSE); + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); if (err) { WL_ERR(("Could not get rate (%d)\n", err)); } else { @@ -2460,11 +2552,11 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("Rate %d Mbps\n", (rate / 2))); } - if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { + if (wl_get_drv_status(wl, CONNECTED)) { memset(&scb_val, 0, sizeof(scb_val)); scb_val.val = 0; err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), FALSE); + sizeof(scb_val_t), false); if (unlikely(err)) { WL_ERR(("Could not get rssi (%d)\n", err)); return err; @@ -2476,7 +2568,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, } #if defined(ANDROID_WIRELESS_PATCH) - err = wldev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed), FALSE); + 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; @@ -2498,7 +2590,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 = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE); + 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")); @@ -2553,7 +2645,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, /* addr param is always NULL. ignore it */ /* Get current rateset */ err = wldev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, - sizeof(rateset), FALSE); + sizeof(rateset), false); if (unlikely(err)) { WL_ERR(("could not get current rateset (%d)\n", err)); return err; @@ -2623,14 +2715,14 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) return 0; } - set_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + wl_set_drv_status(wl, SCAN_ABORTING); wl_term_iscan(wl); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - clear_bit(WL_STATUS_SCANNING, &wl->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCAN_ABORTING); return err; } @@ -2640,6 +2732,18 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, s32 err) { int i, j; + struct wl_priv *wl = WL_PRIV_GET(); + struct net_device *primary_dev = wl_to_prmry_ndev(wl); + + /* Firmware is supporting pmk list only for STA interface i.e. primary interface + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + * Do we really need to support PMK cache in P2P in firmware? + */ + if (primary_dev != dev) { + WL_ERR(("Not supporting Flushing pmklist on virtual" + " interfaces than primary interface\n")); + return err; + } WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid)); for (i = 0; i < pmk_list->pmkids.npmkid; i++) { @@ -2745,7 +2849,6 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) { struct wl_priv *wl = WL_PRIV_GET(); s32 err = 0; - CHECK_SYS_UP(); memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); err = wl_update_pmklist(dev, wl->pmk_list, err); @@ -2806,20 +2909,11 @@ 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 = wldev_ioctl(ndev, WLC_SCAN, params, params_size, FALSE); + err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, false); if (err < 0) { WL_ERR(("scan abort failed \n")); } - /* Report the scan abort to CFG driver too - * We will report it from the thread context, not from this context. - */ - { - 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); - } return err; } static s32 @@ -2834,7 +2928,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, struct wl_priv *wl = WL_PRIV_GET(); dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); - if (likely(test_bit(WL_STATUS_SCANNING, &wl->status))) { + if (likely(wl_get_drv_status(wl, SCANNING))) { wl_cfg80211_scan_abort(wl, dev); } @@ -2845,7 +2939,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, cfg80211_ready_on_channel(dev, *cookie, channel, channel_type, duration, GFP_KERNEL); if (!p2p_on(wl)) { - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr); + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* In case of p2p_listen command, supplicant send remain_on_channel * without turning on P2P @@ -2867,13 +2961,11 @@ exit: } static s32 -wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, u64 cookie) +wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, + u64 cookie) { - s32 err = 0; WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); - - return err; } @@ -2896,7 +2988,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, u32 p2pie_len = 0; u32 wpsie_len = 0; u16 fc; - bool ack = FALSE; + bool ack = false; WL_DBG(("Enter \n")); /* find bssidx based on ndev */ bssidx = wl_cfgp2p_find_idx(wl, dev); @@ -2909,24 +3001,20 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, return -ENODEV; } if (p2p_on(wl)) { - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr); - + wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Suspend P2P discovery search-listen to prevent it from changing the * 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); + if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) { + WL_ERR(("Can not disable discovery mode\n")); + return -EFAULT; + } } + mgmt = (const struct ieee80211_mgmt *) buf; fc = mgmt->frame_control; if (fc != IEEE80211_STYPE_ACTION) { - if (p2p_on(wl) && (fc == IEEE80211_STYPE_PROBE_RESP)) { + if (fc == IEEE80211_STYPE_PROBE_RESP) { s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; s32 ie_len = len - ie_offset; if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len)) @@ -2953,12 +3041,23 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_PRBRSP_FLAG, (u8 *)wps_ie, wpsie_len + p2pie_len); - + /* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD + * from responding many probe request + */ + wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false); } } cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL); goto exit; + } else { + /* 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); } af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); @@ -2993,7 +3092,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); - if (wl->p2p.vif_created) { + if (wl->p2p->vif_created) { wifi_p2p_pub_act_frame_t *act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); /* @@ -3017,7 +3116,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } } - ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? FALSE : TRUE; + 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); @@ -3077,28 +3176,31 @@ 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)); - wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), FALSE); + wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), false); return err; } static s32 -wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) +wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) { - s32 len = wpa2ie->len; + s32 len = 0; s32 err = BCME_OK; u16 auth = 0; /* d11 open authentication */ - u16 wpa_auth = 0; u16 count; u32 wsec; u32 pval = 0; u32 gval = 0; + u32 wpa_auth = 0; u8* tmp; wpa_suite_mcast_t *mcast; wpa_suite_ucast_t *ucast; wpa_suite_auth_key_mgmt_t *mgmt; if (wpa2ie == NULL) goto exit; + + WL_DBG(("Enter \n")); + len = wpa2ie->len; /* check the mcast cipher */ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN]; tmp = mcast->oui; @@ -3141,7 +3243,6 @@ wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) break; default: WL_ERR(("No Security Info\n")); - break; } /* FOR WPS , set SEC_OW_ENABLED */ wsec = (pval | gval | SES_OW_ENABLED); @@ -3161,33 +3262,171 @@ wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) break; default: WL_ERR(("No Key Mgmt Info\n")); - break; } /* set auth */ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); if (err < 0) { WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; } /* set wsec */ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); if (err < 0) { WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; } /* set upper-layer auth */ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); if (err < 0) { WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; } exit: return 0; } static s32 -wl_check_wpaie(struct net_device *dev, bcm_tlv_t *wpaie, s32 bssidx) +wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) { + wpa_suite_mcast_t *mcast; + wpa_suite_ucast_t *ucast; + wpa_suite_auth_key_mgmt_t *mgmt; + u16 auth = 0; /* d11 open authentication */ + u16 count; + s32 err = BCME_OK; + s32 len = 0; + u32 i; + u32 wsec; + u32 pval = 0; + u32 gval = 0; + u32 wpa_auth = 0; + u32 tmp = 0; + if (wpaie == NULL) goto exit; + WL_DBG(("Enter \n")); + len = wpaie->length; /* value length */ + len -= WPA_IE_TAG_FIXED_LEN; + /* check for multicast cipher suite */ + if (len < WPA_SUITE_LEN) { + WL_INFO(("no multicast cipher suite\n")); + goto exit; + } + /* pick up multicast cipher */ + mcast = (wpa_suite_mcast_t *)&wpaie[1]; + len -= WPA_SUITE_LEN; + if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(mcast->type)) { + tmp = 0; + switch (mcast->type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + gval |= tmp; + } + } + /* Check for unicast suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFO(("no unicast suite\n")); + goto exit; + } + /* walk thru unicast cipher list and pick up what we recognize */ + ucast = (wpa_suite_ucast_t *)&mcast[1]; + count = ltoh16_ua(&ucast->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_CIPHER(ucast->list[i].type)) { + tmp = 0; + switch (ucast->list[i].type) { + case WPA_CIPHER_NONE: + tmp = 0; + break; + case WPA_CIPHER_WEP_40: + case WPA_CIPHER_WEP_104: + tmp = WEP_ENABLED; + break; + case WPA_CIPHER_TKIP: + tmp = TKIP_ENABLED; + break; + case WPA_CIPHER_AES_CCM: + tmp = AES_ENABLED; + break; + default: + WL_ERR(("No Security Info\n")); + } + pval |= tmp; + } + } + } + len -= (count - i) * WPA_SUITE_LEN; + /* Check for auth key management suite(s) */ + if (len < WPA_IE_SUITE_COUNT_LEN) { + WL_INFO((" no auth key mgmt suite\n")); + goto exit; + } + /* walk thru auth management suite list and pick up what we recognize */ + mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count]; + count = ltoh16_ua(&mgmt->count); + len -= WPA_IE_SUITE_COUNT_LEN; + for (i = 0; i < count && len >= WPA_SUITE_LEN; + i++, len -= WPA_SUITE_LEN) { + if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) { + if (IS_WPA_AKM(mgmt->list[i].type)) { + tmp = 0; + switch (mgmt->list[i].type) { + case RSN_AKM_NONE: + tmp = WPA_AUTH_NONE; + break; + case RSN_AKM_UNSPECIFIED: + tmp = WPA_AUTH_UNSPECIFIED; + break; + case RSN_AKM_PSK: + tmp = WPA_AUTH_PSK; + break; + default: + WL_ERR(("No Key Mgmt Info\n")); + } + wpa_auth |= tmp; + } + } + + } + /* FOR WPS , set SEC_OW_ENABLED */ + wsec = (pval | gval | SES_OW_ENABLED); + /* set auth */ + err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx); + if (err < 0) { + WL_ERR(("auth error %d\n", err)); + return BCME_ERROR; + } + /* set wsec */ + err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx); + if (err < 0) { + WL_ERR(("wsec error %d\n", err)); + return BCME_ERROR; + } + /* set upper-layer auth */ + err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx); + if (err < 0) { + WL_ERR(("wpa_auth error %d\n", err)); + return BCME_ERROR; + } exit: return 0; } @@ -3198,27 +3437,29 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, { s32 err = BCME_OK; bcm_tlv_t *ssid_ie; + wlc_ssid_t ssid; + struct wl_priv *wl = WL_PRIV_GET(); + struct wl_join_params join_params; wpa_ie_fixed_t *wps_ie; wpa_ie_fixed_t *wpa_ie; bcm_tlv_t *wpa2_ie; wifi_p2p_ie_t *p2p_ie; - struct wl_priv *wl = WL_PRIV_GET(); bool is_bssup = false; + bool update_bss = false; u16 wpsie_len = 0; u16 p2pie_len = 0; u8 beacon_ie[IE_MAX_LEN]; s32 ie_offset = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); s32 infra = 1; - - memset(beacon_ie, 0, sizeof(beacon_ie)); - + s32 join_params_size = 0; + s32 ap = 0; 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)); - - - if (p2p_on(wl) && (bssidx >= wl_to_p2p_bss_bssidx(wl, + if (wl->p2p_supported && p2p_on(wl) && + (bssidx >= wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { + memset(beacon_ie, 0, sizeof(beacon_ie)); /* 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 @@ -3228,8 +3469,8 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, 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; + 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 { @@ -3238,7 +3479,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, /* 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); + wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; /* * Should be compared with saved ie before saving it */ @@ -3269,10 +3510,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, beacon_ie, wpsie_len + p2pie_len); wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG, 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) { @@ -3280,19 +3518,209 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, } is_bssup = wl_cfgp2p_bss_isup(dev, bssidx); - if (!is_bssup && (wpa_ie != NULL || wpa2_ie != NULL)) { - wl_check_wpa2ie(dev, wpa2_ie, bssidx); - wl_check_wpaie(dev, (bcm_tlv_t *)wpa_ie, bssidx); - - err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), FALSE); + if (!is_bssup && (wpa2_ie != NULL)) { + if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) { + WL_ERR(("WPA2 IE parsing error")); + return BCME_ERROR; + } + err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false); if (err < 0) { WL_ERR(("SET INFRA error %d\n", err)); + return err; } - - err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p.ssid, - sizeof(wl->p2p.ssid), ioctlbuf, sizeof(ioctlbuf), bssidx); - - wl_cfgp2p_bss(dev, bssidx, 1); + err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, + sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx); + if (err < 0) { + WL_ERR(("GO SSID setting error %d\n", err)); + return err; + } + if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) { + WL_ERR(("GO Bring up error %d\n", err)); + return err; + } + } + } else if (wl_get_drv_status(wl, AP_CREATING)) { + ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; + ap = 1; + /* find the SSID */ + if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset], + info->head_len - ie_offset, + DOT11_MNG_SSID_ID)) != NULL) { + memset(&ssid, 0, sizeof(wlc_ssid_t)); + memcpy(ssid.SSID, ssid_ie->data, ssid_ie->len); + WL_DBG(("SSID is (%s) in Head \n", ssid.SSID)); + ssid.SSID_len = ssid_ie->len; + wldev_iovar_setint(dev, "mpc", 0); + wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), false); + wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false); + wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false); + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* 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")); + } + if ((wpa_ie != NULL || wpa2_ie != NULL)) { + if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) { + wl->ap_info->security_mode = false; + return BCME_ERROR; + } + wl->ap_info->security_mode = true; + kfree(wl->ap_info->rsn_ie); + kfree(wl->ap_info->wpa_ie); + kfree(wl->ap_info->wps_ie); + if (wpa_ie != NULL) { + /* WPAIE */ + wl->ap_info->rsn_ie = NULL; + wl->ap_info->wpa_ie = kmemdup(wpa_ie, + wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else { + /* RSNIE */ + wl->ap_info->wpa_ie = NULL; + wl->ap_info->rsn_ie = kmemdup(wpa2_ie, + wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + } else + wl->ap_info->security_mode = false; + /* find the WPSIE */ + if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, + info->tail_len)) != NULL) { + wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN; + /* + * 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); + wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, + beacon_ie, wpsie_len); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ + wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } else { + WL_ERR(("No WPSIE in beacon \n")); + } + wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false); + + memset(&join_params, 0, sizeof(join_params)); + /* join parameters starts with ssid */ + join_params_size = sizeof(join_params.ssid); + memcpy(join_params.ssid.SSID, ssid.SSID, ssid.SSID_len); + join_params.ssid.SSID_len = htod32(ssid.SSID_len); + /* create softap */ + if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, + join_params_size, false)) == 0) { + wl_clr_drv_status(wl, AP_CREATING); + wl_set_drv_status(wl, AP_CREATED); + } + } + } else if (wl_get_drv_status(wl, AP_CREATED)) { + ap = 1; + /* find the WPSIE */ + if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { + wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN; + /* + * 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); + wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, + beacon_ie, wpsie_len); + if (wl->ap_info->wps_ie && + memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { + WL_DBG((" WPS IE is changed\n")); + kfree(wl->ap_info->wps_ie); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ + wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } else if (wl->ap_info->wps_ie == NULL) { + WL_DBG((" WPS IE is added\n")); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ + wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true); + } + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* 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")); + } + if ((wpa_ie != NULL || wpa2_ie != NULL)) { + if (!wl->ap_info->security_mode) { + /* change from open mode to security mode */ + update_bss = true; + if (wpa_ie != NULL) { + wl->ap_info->wpa_ie = kmemdup(wpa_ie, + wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else { + wl->ap_info->rsn_ie = kmemdup(wpa2_ie, + wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } + } else if (wl->ap_info->wpa_ie) { + /* change from WPA mode to WPA2 mode */ + if (wpa2_ie != NULL) { + update_bss = true; + kfree(wl->ap_info->wpa_ie); + wl->ap_info->rsn_ie = kmemdup(wpa2_ie, + wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + wl->ap_info->wpa_ie = NULL; + } + else if (memcmp(wl->ap_info->wpa_ie, + wpa_ie, wpa_ie->length + + WPA_RSN_IE_TAG_FIXED_LEN)) { + kfree(wl->ap_info->wpa_ie); + update_bss = true; + wl->ap_info->wpa_ie = kmemdup(wpa_ie, + wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + wl->ap_info->rsn_ie = NULL; + } + } else { + /* change from WPA2 mode to WPA mode */ + if (wpa_ie != NULL) { + update_bss = true; + kfree(wl->ap_info->rsn_ie); + wl->ap_info->rsn_ie = NULL; + wl->ap_info->wpa_ie = kmemdup(wpa_ie, + wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + } else if (memcmp(wl->ap_info->rsn_ie, + wpa2_ie, wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) { + update_bss = true; + kfree(wl->ap_info->rsn_ie); + wl->ap_info->rsn_ie = kmemdup(wpa2_ie, + wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN, + GFP_KERNEL); + wl->ap_info->wpa_ie = NULL; + } + } + if (update_bss) { + wl->ap_info->security_mode = true; + wl_cfgp2p_bss(dev, bssidx, 0); + if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 || + wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) { + return BCME_ERROR; + } + wl_cfgp2p_bss(dev, bssidx, 1); + } + } + } else { + WL_ERR(("No WPSIE in beacon \n")); } } return 0; @@ -3400,7 +3828,8 @@ 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_STATION) | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; @@ -3455,6 +3884,7 @@ static void wl_free_wdev(struct wl_priv *wl) wiphy_unregister(wdev->wiphy); wiphy_free(wdev->wiphy); kfree(wdev); + wl_to_wdev(wl) = NULL; } static s32 wl_inform_bss(struct wl_priv *wl) @@ -3465,13 +3895,11 @@ static s32 wl_inform_bss(struct wl_priv *wl) s32 i; bss_list = wl->bss_list; - /* if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) { - WL_ERR(("Version %d != %d\n", - bss_list->version, WL_BSS_INFO_VERSION)); + WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version)); return -EOPNOTSUPP; } - */ WL_DBG(("scanned AP count (%d)\n", bss_list->count)); bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { @@ -3618,7 +4046,7 @@ 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; + bool isfree = false; s32 err = 0; s32 freq; s32 channel; @@ -3642,7 +4070,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, 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); + wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); switch (event) { case WLC_E_ASSOC_IND: fc = FC_ASSOC_REQ; @@ -3663,7 +4091,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, fc = 0; goto exit; } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), FALSE))) + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) return err; channel = dtoh32(ci.hw_channel); @@ -3682,14 +4110,14 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, &mgmt_frame, &len, body); if (err < 0) goto exit; - isfree = TRUE; + isfree = true; if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + cfg80211_send_rx_assoc(ndev, mgmt_frame, len); } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + cfg80211_send_disassoc(ndev, mgmt_frame, len); } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + cfg80211_send_deauth(ndev, mgmt_frame, len); } } else { @@ -3712,16 +4140,16 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, act = true; wl_update_prof(wl, e, &act, WL_PROF_ACT); } else if (wl_is_linkdown(wl, e)) { - if (test_bit(WL_STATUS_CONNECTED, &wl->status)) { + if (wl_get_drv_status(wl, CONNECTED)) { printk("link down, call cfg80211_disconnected "); cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl_clr_drv_status(wl, CONNECTED); wl_link_down(wl); wl_init_prof(wl->profile); } } else if (wl_is_nonetwork(wl, e)) { printk("connect failed e->status 0x%x", (int)ntoh32(e->status)); - if (test_bit(WL_STATUS_CONNECTING, &wl->status)) + if (wl_get_drv_status(wl, CONNECTING)) wl_bss_connect_done(wl, ndev, e, data, false); } else { printk("%s nothing\n", __FUNCTION__); @@ -3758,7 +4186,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 wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, FALSE); + return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, false); } static s32 @@ -3772,7 +4200,7 @@ 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 = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, - WL_IOCTL_LEN_MAX, FALSE); + WL_IOCTL_LEN_MAX, false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -3897,7 +4325,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) WL_DBG(("Could not find the AP\n")); *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO, - wl->extra_buf, WL_EXTRA_BUF_MAX, FALSE); + 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; @@ -3932,7 +4360,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) * so we speficially query dtim information to dongle. */ err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), FALSE); + &dtim_period, sizeof(dtim_period), false); if (unlikely(err)) { WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err)); goto update_bss_info_out; @@ -3966,7 +4394,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); WL_DBG(("Report roaming result\n")); - set_bit(WL_STATUS_CONNECTED, &wl->status); + wl_set_drv_status(wl, CONNECTED); return err; } @@ -3982,7 +4410,8 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_get_assoc_ies(wl, ndev); memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); wl_update_bss_info(wl, ndev); - if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) { + if (wl_get_drv_status(wl, CONNECTING)) { + wl_clr_drv_status(wl, CONNECTING); cfg80211_connect_result(ndev, (u8 *)&wl->bssid, conn_info->req_ie, @@ -3994,6 +4423,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, WL_DBG(("Report connect result - connection %s\n", completed ? "succeeded" : "failed")); } else { + wl_clr_drv_status(wl, CONNECTING); cfg80211_roamed(ndev, #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) NULL, @@ -4004,7 +4434,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, GFP_KERNEL); WL_DBG(("Report roaming result\n")); } - set_bit(WL_STATUS_CONNECTED, &wl->status); + wl_set_drv_status(wl, CONNECTED); return err; } @@ -4038,20 +4468,21 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, u32 len = WL_SCAN_BUF_MAX; s32 err = 0; - WL_DBG(("Enter \n")); if (wl->iscan_on && wl->iscan_kickstart) return wl_wakeup_iscan(wl_to_iscan(wl)); - if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + if (unlikely(!wl_get_drv_status(wl, SCANNING))) { + wl_clr_drv_status(wl, SCANNING); WL_DBG(("Scan complete while device not scanning\n")); return -EINVAL; } + wl_clr_drv_status(wl, SCANNING); if (unlikely(!wl->scan_request)) { } rtnl_lock(); err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, - sizeof(channel_inform), FALSE); + sizeof(channel_inform), false); if (unlikely(err)) { WL_ERR(("scan busy (%d)\n", err)); goto scan_done_out; @@ -4066,7 +4497,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 = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, FALSE); + 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; @@ -4138,7 +4569,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, struct wiphy *wiphy = wl_to_wiphy(wl); struct ether_addr da; struct ether_addr bssid; - bool isfree = FALSE; + bool isfree = false; s32 err = 0; s32 freq; wl_event_rx_frame_data_t *rxframe = @@ -4152,6 +4583,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, band = wiphy->bands[IEEE80211_BAND_2GHZ]; else band = wiphy->bands[IEEE80211_BAND_5GHZ]; + #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) freq = ieee80211_channel_to_frequency(channel); #else @@ -4160,7 +4592,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, 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); + 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)); @@ -4169,7 +4601,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, __func__, mgmt_frame_len, channel, freq)); goto exit; } - isfree = TRUE; + isfree = true; } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); } @@ -4221,6 +4653,7 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; + wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; @@ -4320,6 +4753,13 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) wl->fw = NULL; kfree(wl->pmk_list); wl->pmk_list = NULL; + if (wl->ap_info) { + kfree(wl->ap_info->wpa_ie); + kfree(wl->ap_info->rsn_ie); + kfree(wl->ap_info->wps_ie); + kfree(wl->ap_info); + wl->ap_info = NULL; + } } static s32 wl_create_event_handler(struct wl_priv *wl) @@ -4352,7 +4792,7 @@ static void wl_term_iscan(struct wl_priv *wl) iscan->state = WL_ISCAN_STATE_IDLE; WL_INFO(("SIGTERM\n")); send_sig(SIGTERM, iscan->tsk, 1); - printk("kthread_stop\n"); + WL_DBG(("kthread_stop\n")); kthread_stop(iscan->tsk); iscan->tsk = NULL; } @@ -4363,10 +4803,12 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) struct wl_priv *wl = iscan_to_wl(iscan); WL_DBG(("Enter \n")); - if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + if (unlikely(!wl_get_drv_status(wl, SCANNING))) { + wl_clr_drv_status(wl, SCANNING); WL_ERR(("Scan complete while device not scanning\n")); return; } + wl_clr_drv_status(wl, SCANNING); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; @@ -4556,11 +4998,13 @@ static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted) { WL_DBG(("Enter \n")); - if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) { + if (unlikely(!wl_get_drv_status(wl, SCANNING))) { + wl_clr_drv_status(wl, SCANNING); WL_ERR(("Scan complete while device not scanning\n")); return; } - if (p2p_on(wl)) + wl_clr_drv_status(wl, SCANNING); + if (wl->p2p_supported && p2p_on(wl)) wl_clr_p2p_status(wl, SCANNING); if (likely(wl->scan_request)) { @@ -4584,7 +5028,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); if (!wl->escan_on && - !test_bit(WL_STATUS_SCANNING, &wl->status)) { + !wl_get_drv_status(wl, SCANNING)) { WL_ERR(("escan is not ready \n")); return err; } @@ -4733,7 +5177,6 @@ static s32 wl_init_priv(struct wl_priv *wl) wl_init_conf(wl->conf); wl_init_prof(wl->profile); wl_link_down(wl); - wl_cfgp2p_init_priv(wl); return err; } @@ -4757,10 +5200,10 @@ s32 wl_cfg80211_sysctl_export_devaddr(void *data) 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); + 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)); + 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; } @@ -4776,18 +5219,24 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) return -ENODEV; } wl = WL_PRIV_GET(); - if (wl && !test_bit(WL_STATUS_READY, &wl->status)) { + if (wl && !wl_get_drv_status(wl, READY)) { if (wl->wdev && wl_cfgp2p_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)); + if ((err = wl_cfgp2p_init_priv(wl)) != 0) + goto fail; +#ifdef CONFIG_SYSCTL + wl_cfg80211_sysctl_export_devaddr(wl->pub); +#endif + wl->p2p_supported = true; } } else return -ENODEV; - set_bit(WL_STATUS_READY, &wl->status); + wl_set_drv_status(wl, READY); +fail: return err; } s32 wl_cfg80211_attach(struct net_device *ndev, void *data) @@ -4864,7 +5313,8 @@ void wl_cfg80211_detach(void) #endif rfkill_unregister(wl->rfkill); rfkill_destroy(wl->rfkill); - + if (wl->p2p_supported) + wl_cfgp2p_deinit_priv(wl); wl_deinit_priv(wl); wl_free_wdev(wl); wl_set_drvdata(wl_cfg80211_dev, NULL); @@ -5001,9 +5451,6 @@ static void wl_put_event(struct wl_event_q *e) kfree(e); } -/* TODO: this has been changed to wl_cfg80211_set_sdio_func in FALCON - * Keep is as-is in P2P Twig - */ void wl_cfg80211_set_sdio_func(void *func) { cfg80211_sdio_func = (struct sdio_func *)func; @@ -5035,16 +5482,22 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp mode = WL_MODE_IBSS; break; case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: mode = WL_MODE_BSS; infra = 1; break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + mode = WL_MODE_AP; + infra = 1; + break; default: err = -EINVAL; WL_ERR(("invalid type (%d)\n", iftype)); return err; } infra = htod32(infra); - err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), FALSE); + 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; @@ -5054,6 +5507,39 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp return 0; } +static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s8 eventmask[WL_EVENTING_MASK_LEN]; + s32 err = 0; + + /* Setup event_msgs */ + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, 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; + } + memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); + if (add) { + setbit(eventmask, event); + } else { + clrbit(eventmask, event); + } + bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, 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; + } + +dongle_eventmsg_out: + return err; + +} static s32 wl_dongle_eventmsg(struct net_device *ndev) { @@ -5065,7 +5551,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 = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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; @@ -5099,7 +5585,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) setbit(eventmask, WLC_E_ESCAN_RESULT); bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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; @@ -5122,7 +5608,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) { s32 err = 0; - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), FALSE); + err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), false); if (unlikely(err)) { WL_ERR(("WLC_UP error (%d)\n", err)); } @@ -5134,7 +5620,7 @@ static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) s32 err = 0; WL_TRACE(("In\n")); - err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), FALSE); + 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)); } @@ -5151,14 +5637,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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; @@ -5178,7 +5664,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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; @@ -5186,7 +5672,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + 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; @@ -5202,7 +5688,7 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 err = 0; err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, - sizeof(scan_assoc_time), FALSE); + sizeof(scan_assoc_time), false); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("Scan assoc time is not supported\n")); @@ -5212,7 +5698,7 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, goto dongle_scantime_out; } err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, - sizeof(scan_unassoc_time), FALSE); + sizeof(scan_unassoc_time), false); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("Scan unassoc time is not supported\n")); @@ -5236,7 +5722,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false); if (err) { if (err == -EOPNOTSUPP) WL_INFO(("arpoe is not supported\n")); @@ -5246,7 +5732,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false); if (err) { if (err == -EOPNOTSUPP) WL_INFO(("arp_ol is not supported\n")); @@ -5345,7 +5831,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 = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, FALSE); + err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, false); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter not supported\n")); @@ -5358,7 +5844,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 = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter_mode not supported\n")); @@ -5445,7 +5931,7 @@ static s32 wl_update_wiphybands(struct wl_priv *wl) s32 err = 0; err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list, - sizeof(phy_list), FALSE); + sizeof(phy_list), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -5473,7 +5959,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) return err; wl_invoke_iscan(wl); - set_bit(WL_STATUS_READY, &wl->status); + wl_set_drv_status(wl, READY); return err; } @@ -5483,25 +5969,32 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) WL_TRACE(("In\n")); /* Check if cfg80211 interface is already down */ - if (!test_bit(WL_STATUS_READY, &wl->status)) + if (!wl_get_drv_status(wl, READY)) return err; /* it is even not ready */ - set_bit(WL_STATUS_SCAN_ABORTING, &wl->status); + wl_set_drv_status(wl, SCAN_ABORTING); + wl_term_iscan(wl); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); - wl->scan_request = NULL; } - clear_bit(WL_STATUS_READY, &wl->status); - clear_bit(WL_STATUS_SCANNING, &wl->status); - clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); - clear_bit(WL_STATUS_CONNECTED, &wl->status); - + wl_clr_drv_status(wl, READY); + wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCAN_ABORTING); + wl_clr_drv_status(wl, CONNECTED); + if (wl_get_drv_status(wl, AP_CREATED)) { + wl_clr_drv_status(wl, AP_CREATED); + wl_clr_drv_status(wl, AP_CREATING); + wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = + NL80211_IFTYPE_STATION; + } wl->dongle_up = false; wl_flush_eq(wl); wl_link_down(wl); - wl_cfgp2p_down(wl); + if (wl->p2p_supported) + wl_cfgp2p_down(wl); + wl_debugfs_remove_netdev(wl); return err; @@ -5833,6 +6326,47 @@ s8 *wl_cfg80211_get_nvramname(void) return wl->fw->nvram_name; } +s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) +{ + struct wl_priv *wl; + dhd_pub_t *dhd_pub; + struct ether_addr p2pif_addr; + + wl = WL_PRIV_GET(); + dhd_pub = (dhd_pub_t *)wl->pub; + wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr); + + return 0; +} + +static __used void wl_dongle_poweron(struct wl_priv *wl) +{ + + WL_DBG(("Enter \n")); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); + +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 0); +#endif +#if defined(BCMLXSDMMC) + sdioh_start(NULL, 1); +#endif + wl_cfg80211_resume(wl_to_wiphy(wl)); +} + +static __used void wl_dongle_poweroff(struct wl_priv *wl) +{ + + + WL_DBG(("Enter \n")); + wl_cfg80211_suspend(wl_to_wiphy(wl)); + +#if defined(BCMLXSDMMC) + sdioh_stop(NULL); +#endif + /* clean up dtim_skip setting */ + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); +} static int wl_debugfs_add_netdev_params(struct wl_priv *wl) { char buf[10+IFNAMSIZ]; @@ -5872,6 +6406,13 @@ static const struct rfkill_ops wl_rfkill_ops = { static int wl_rfkill_set(void *data, bool blocked) { + struct wl_priv *wl = (struct wl_priv *)data; + + WL_DBG(("Enter \n")); + WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); + + wl->rf_blocked = blocked; + return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 4c05987ce2a8..f9de60f0ca3e 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -114,12 +114,6 @@ do { \ */ #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 { @@ -127,7 +121,9 @@ enum wl_status { WL_STATUS_SCANNING, WL_STATUS_SCAN_ABORTING, WL_STATUS_CONNECTING, - WL_STATUS_CONNECTED + WL_STATUS_CONNECTED, + WL_STATUS_AP_CREATING, + WL_STATUS_AP_CREATED }; /* wi-fi mode */ @@ -315,6 +311,17 @@ struct escan_info { struct wiphy *wiphy; }; +struct ap_info { +/* Structure to hold WPS, WPA IEs for a AP */ + u8 probe_res_ie[IE_MAX_LEN]; + u8 beacon_ie[IE_MAX_LEN]; + u32 probe_res_ie_len; + u32 beacon_ie_len; + u8 *wpa_ie; + u8 *rsn_ie; + u8 *wps_ie; + bool security_mode; +}; /* dongle private data of cfg80211 interface */ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ @@ -373,12 +380,13 @@ struct wl_priv { struct dentry *debugfsdir; struct rfkill *rfkill; bool rf_blocked; - struct ieee80211_channel remain_on_chan; enum nl80211_channel_type remain_on_chan_type; u64 cache_cookie; wait_queue_head_t dongle_event_wait; - struct p2p_info p2p; + struct ap_info *ap_info; + struct p2p_info *p2p; + bool p2p_supported; s8 last_eventmask[WL_EVENTING_MASK_LEN]; u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); }; @@ -398,6 +406,10 @@ struct wl_priv { #define wl_to_iscan(w) (w->iscan) #define wl_to_conn(w) (&w->conn_info) #define wiphy_from_scan(w) (w->escan_info.wiphy) +#define wl_get_drv_status(wl, stat) (test_bit(WL_STATUS_ ## stat, &(wl)->status)) +#define wl_set_drv_status(wl, stat) (set_bit(WL_STATUS_ ## stat, &(wl)->status)) +#define wl_clr_drv_status(wl, stat) (clear_bit(WL_STATUS_ ## stat, &(wl)->status)) +#define wl_chg_drv_status(wl, stat) (change_bit(WL_STATUS_ ## stat, &(wl)->status)) static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) { @@ -488,6 +500,7 @@ extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function i 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_ifdel_ops(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); @@ -499,6 +512,7 @@ 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); +extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); #ifdef CONFIG_SYSCTL extern s32 wl_cfg80211_sysctl_export_devaddr(void *data); #endif diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 0a5a8a8f1097..fa88d4b4cf81 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -65,14 +65,13 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, * Initialize variables related to P2P * */ -void +s32 wl_cfgp2p_init_priv(struct wl_priv *wl) { - wl->p2p.on = 0; - wl->p2p.scan = 0; /* by default , legacy scan */ - wl->p2p.status = 0; - wl->p2p.listen_timer = NULL; - + if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) { + CFGP2P_ERR(("struct p2p_info allocation failed\n")); + return -ENOMEM; + } #define INIT_IE(IE_TYPE, BSS_TYPE) \ do { \ memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \ @@ -103,17 +102,38 @@ wl_cfgp2p_init_priv(struct wl_priv *wl) wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL; wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0; -} + return BCME_OK; +} +/* + * Deinitialize variables related to P2P + * + */ +void +wl_cfgp2p_deinit_priv(struct wl_priv *wl) +{ + if (wl->p2p) { + kfree(wl->p2p); + } + wl->p2p_supported = 0; +} /* * Set P2P functions into firmware */ s32 wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) { + struct net_device *ndev = wl_to_prmry_ndev(wl); s32 ret = BCME_OK; - - /* TODO : Do we have to check whether APSTA is enabled or not ? */ + s32 val = 0; + /* Do we have to check whether APSTA is enabled or not ? */ + wldev_iovar_getint(ndev, "apsta", &val); + if (val == 0) { + val = 1; + wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), false); + wldev_iovar_setint(ndev, "apsta", val); + wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), false); + } return ret; } @@ -130,7 +150,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; - struct net_device *netdev = wl_to_prmry_ndev(wl); + struct net_device *ndev = wl_to_prmry_ndev(wl); ifreq.type = if_type; ifreq.chspec = chspec; @@ -142,7 +162,7 @@ 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 = wldev_iovar_setbuf(netdev, "p2p_ifadd", &ifreq, sizeof(ifreq), + err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), ioctlbuf, sizeof(ioctlbuf)); return err; } @@ -571,21 +591,21 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, /* 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 +/* Delete and Set a management vndr ie to firmware * Parameters: * @wl : wl_private data * @ndev : net device for bssidx * @bssidx : bssidx for BSS * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG, * VNDR_IE_ASSOCREQ_FLAG) - * @ie : probe request ie (WPS IE + P2P IE) - * @ie_len : probe request ie length + * @ie : VNDR IE (such as P2P IE , WPS IE) + * @ie_len : VNDR IE Length * Returns 0 if success. */ s32 wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len) + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len) { /* Vendor-specific Information Element ID */ #define VNDR_SPEC_ELEMENT_ID 0xdd @@ -601,50 +621,70 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi #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) { - case VNDR_IE_PRBREQ_FLAG : - mgmt_ie_buf = IE_TYPE(probe_req, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); - break; - case VNDR_IE_PRBRSP_FLAG : - mgmt_ie_buf = IE_TYPE(probe_res, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); - break; - case VNDR_IE_ASSOCREQ_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); - break; - case VNDR_IE_ASSOCRSP_FLAG : - mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); - break; - case VNDR_IE_BEACON_FLAG : - mgmt_ie_buf = IE_TYPE(beacon, bssidx); - mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); - mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); - break; - default: - mgmt_ie_buf = NULL; - mgmt_ie_len = NULL; - CFGP2P_ERR(("not suitable type\n")); - return -1; + if (wl->p2p_supported && p2p_on(wl)) { + if (bssidx == P2PAPI_BSSCFG_PRIMARY) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + switch (pktflag) { + case VNDR_IE_PRBREQ_FLAG : + mgmt_ie_buf = IE_TYPE(probe_req, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx)); + break; + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = IE_TYPE(probe_res, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx)); + break; + case VNDR_IE_ASSOCREQ_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_req, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx)); + break; + case VNDR_IE_ASSOCRSP_FLAG : + mgmt_ie_buf = IE_TYPE(assoc_res, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx)); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = IE_TYPE(beacon, bssidx); + mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx); + mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx)); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return -1; + } + } else { + switch (pktflag) { + case VNDR_IE_PRBRSP_FLAG : + mgmt_ie_buf = wl->ap_info->probe_res_ie; + mgmt_ie_len = &wl->ap_info->probe_res_ie_len; + mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie); + break; + case VNDR_IE_BEACON_FLAG : + mgmt_ie_buf = wl->ap_info->beacon_ie; + mgmt_ie_len = &wl->ap_info->beacon_ie_len; + mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie); + break; + default: + mgmt_ie_buf = NULL; + mgmt_ie_len = NULL; + CFGP2P_ERR(("not suitable type\n")); + return -1; + } } /* Add if there is any extra IE */ - if (p2p_ie && p2p_ie_len) { - CFGP2P_INFO(("Request has extra IE")); - if (p2p_ie_len > mgmt_ie_buf_len) { + if (vndr_ie && vndr_ie_len) { + CFGP2P_ERR(("Request has extra IE")); + if (vndr_ie_len > mgmt_ie_buf_len) { CFGP2P_ERR(("extra IE size too big\n")); ret = -ENOMEM; } else { if (mgmt_ie_buf != NULL) { - if ((p2p_ie_len == *mgmt_ie_len) && - (memcmp(mgmt_ie_buf, p2p_ie, p2p_ie_len) == 0)) { + if ((vndr_ie_len == *mgmt_ie_len) && + (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) { CFGP2P_INFO(("Previous mgmt IE is equals to current IE")); goto exit; } @@ -666,12 +706,12 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi } /* save the current IE in wl struct */ - memcpy(mgmt_ie_buf, p2p_ie, p2p_ie_len); - *mgmt_ie_len = p2p_ie_len; + memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len); + *mgmt_ie_len = vndr_ie_len; pos = 0; - ie_buf = (u8 *) p2p_ie; + ie_buf = (u8 *) vndr_ie; delete = 0; - while (pos < p2p_ie_len) { + while (pos < vndr_ie_len) { ie_id = ie_buf[pos++]; ie_len = ie_buf[pos++]; if ((ie_id == DOT11_MNG_VS_ID) && @@ -719,8 +759,6 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx) INIT_IE(assoc_req, bssidx); INIT_IE(assoc_res, bssidx); INIT_IE(beacon, bssidx); - - return BCME_OK; } @@ -749,6 +787,7 @@ wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u return FALSE; } + wpa_ie_fixed_t * wl_cfgp2p_find_wpaie(u8 *parse, u32 len) { @@ -855,12 +894,17 @@ wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev) CFGP2P_ERR((" ndev is NULL\n")); goto exit; } + if (!wl->p2p_supported) { + return P2PAPI_BSSCFG_PRIMARY; + } for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) { if (ndev == wl_to_p2p_bss_ndev(wl, i)) { index = wl_to_p2p_bss_bssidx(wl, i); break; } } + if (index == -1) + return P2PAPI_BSSCFG_PRIMARY; exit: return index; } @@ -874,12 +918,11 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, s32 ret = BCME_OK; CFGP2P_DBG((" Enter\n")); - /* TODO : have to acquire bottom half lock ? */ if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) { wl_set_p2p_status(wl, LISTEN_EXPIRED); - if (wl->p2p.listen_timer) - del_timer_sync(wl->p2p.listen_timer); + if (wl->p2p->listen_timer) + del_timer_sync(wl->p2p->listen_timer); cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); @@ -944,12 +987,12 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); - if (wl->p2p.listen_timer) - del_timer_sync(wl->p2p.listen_timer); + if (wl->p2p->listen_timer) + del_timer_sync(wl->p2p->listen_timer); - wl->p2p.listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); + wl->p2p->listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL); - if (wl->p2p.listen_timer == NULL) { + if (wl->p2p->listen_timer == NULL) { CFGP2P_ERR(("listen_timer allocation failed\n")); return -ENOMEM; } @@ -957,7 +1000,7 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , * otherwise we will wait up to duration_ms + 10ms */ - INIT_TIMER(wl->p2p.listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20); + INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20); #undef INIT_TIMER exit: @@ -986,7 +1029,7 @@ wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable) */ if (!enable) { wl_clr_p2p_status(wl, SCANNING); - (void) wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, + ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE)); } @@ -1214,16 +1257,19 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) CFGP2P_ERR(("wl p2p error %d\n", ret)); return 0; } - if (p2p_supported) + if (p2p_supported == 1) { CFGP2P_INFO(("p2p is supported\n")); - + } else { + CFGP2P_INFO(("p2p is unsupported\n")); + p2p_supported = 0; + } return p2p_supported; } /* Cleanup P2P resources */ s32 wl_cfgp2p_down(struct wl_priv *wl) { - if (wl->p2p.listen_timer) - del_timer_sync(wl->p2p.listen_timer); + if (wl->p2p->listen_timer) + del_timer_sync(wl->p2p->listen_timer); return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 27aef59201a4..1b28fa9b80ac 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -91,16 +91,20 @@ enum wl_cfgp2p_status { }; -#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p.bss_idx[type].dev) -#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p.bss_idx[type].bssidx) -#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p.bss_idx[type].saved_ie) -#define wl_to_p2p_bss(wl, type) ((wl)->p2p.bss_idx[type]) -#define wl_get_p2p_status(wl, stat) (test_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status)) -#define wl_set_p2p_status(wl, stat) (set_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status)) -#define wl_clr_p2p_status(wl, stat) (clear_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status)) -#define wl_chg_p2p_status(wl, stat) (change_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status)) -#define p2p_on(wl) ((wl)->p2p.on) -#define p2p_scan(wl) ((wl)->p2p.scan) +#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev) +#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx) +#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie) +#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) +#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ + &(wl)->p2p->status)) +#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \ + &(wl)->p2p->status)) +#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \ + &(wl)->p2p->status)) +#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \ + &(wl)->p2p->status)) +#define p2p_on(wl) ((wl)->p2p->on) +#define p2p_scan(wl) ((wl)->p2p->scan) /* dword align allocation */ @@ -131,8 +135,10 @@ enum wl_cfgp2p_status { } while (0) -extern void +extern s32 wl_cfgp2p_init_priv(struct wl_priv *wl); +extern void +wl_cfgp2p_deinit_priv(struct wl_priv *wl); extern s32 wl_cfgp2p_set_firm_p2p(struct wl_priv *wl); extern s32 @@ -171,7 +177,7 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len); extern s32 wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, - s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len); + s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len); extern s32 wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx); @@ -220,5 +226,7 @@ wl_cfgp2p_down(struct wl_priv *wl); #define SOCIAL_CHAN_3 11 #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 IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) #endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index 1f811a90ae56..75022a4b0170 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1889,6 +1889,12 @@ iwpriv_set_ap_config(struct net_device *dev, info->cmd, info->flags, wrqu->data.pointer, wrqu->data.length)); + if (!ap_fw_loaded) { + WL_ERROR(("Can't execute %s(), SOFTAP fw is not Loaded\n", + __FUNCTION__)); + return -1; + } + if (wrqu->data.length != 0) { char *str_ptr; @@ -1955,13 +1961,14 @@ static int iwpriv_get_assoc_list(struct net_device *dev, iw = *(wl_iw_t **)netdev_priv(dev); - MUTEX_LOCK_SOFTAP_SET(iw->pub); - DHD_OS_WAKE_LOCK(iw->pub); + net_os_wake_lock(dev); + DHD_OS_MUTEX_LOCK(&wl_softap_lock); WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d," "iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags)); + memset(sta_maclist, 0, sizeof(mac_buf)); sta_maclist->count = 8; @@ -2028,8 +2035,9 @@ static int iwpriv_get_assoc_list(struct net_device *dev, } func_exit: - DHD_OS_WAKE_UNLOCK(iw->pub); - MUTEX_UNLOCK_SOFTAP_SET(iw->pub); + + DHD_OS_MUTEX_UNLOCK(&wl_softap_lock); + net_os_wake_unlock(dev); WL_SOFTAP(("%s: Exited\n", __FUNCTION__)); return ret; @@ -4320,6 +4328,10 @@ wl_iw_iscan_get_scan( WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); + + if (!dwrq->length) + return -EAGAIN; + return 0; } #endif @@ -6266,7 +6278,7 @@ thr_wait_for_2nd_eth_dev(void *data) } DHD_OS_WAKE_LOCK(iw->pub); complete(&tsk_ctl->completed); - if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(5000)) != 0) { + if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) { #else if (down_interruptible(&tsk_ctl->sema) != 0) { #endif @@ -6289,7 +6301,7 @@ thr_wait_for_2nd_eth_dev(void *data) goto fail; } - WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n", + WL_SOFTAP(("\n>%s: Thread:'softap ethdev IF:%s is detected!'\n\n", __FUNCTION__, ap_net_dev->name)); ap_cfg_running = TRUE; @@ -6304,7 +6316,7 @@ fail: DHD_OS_WAKE_UNLOCK(iw->pub); - WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__)); + WL_SOFTAP(("\n>%s, thread completed\n", __FUNCTION__)); complete_and_exit(&tsk_ctl->completed, 0); return ret; -- 2.34.1