wifi: fix wifi close issue and ap62x8 open fail issue
authorRongjun Chen <rongjun.chen@amlogic.com>
Mon, 8 Oct 2018 11:47:16 +0000 (19:47 +0800)
committerRongjun Chen <rongjun.chen@amlogic.com>
Mon, 8 Oct 2018 11:56:26 +0000 (19:56 +0800)
PD# 174173

root cause: interrupt not enabled when ctrl cmd comming in some conner case
solution: enable the interrupt when ctrl command is comming

Change-Id: Ief804d124150cbfe9ec1134c527bdb536b8375a0
Signed-off-by: Rongjun Chen <rongjun.chen@amlogic.com>
12 files changed:
bcmdhd.1.579.77.41.1.cn/Makefile [changed mode: 0755->0644]
bcmdhd.1.579.77.41.1.cn/dbus.c
bcmdhd.1.579.77.41.1.cn/dhd_config.c
bcmdhd.1.579.77.41.1.cn/dhd_config.h
bcmdhd.1.579.77.41.1.cn/dhd_gpio.c
bcmdhd.1.579.77.41.1.cn/dhd_ip.c
bcmdhd.1.579.77.41.1.cn/dhd_linux.c
bcmdhd.1.579.77.41.1.cn/dhd_sdio.c
bcmdhd.1.579.77.41.1.cn/dhd_static_buf.c
bcmdhd.1.579.77.41.1.cn/wl_android_ext.c
bcmdhd.1.579.77.41.1.cn/wl_cfg80211.c
bcmdhd.1.579.77.41.1.cn/wl_cfg80211.h

old mode 100755 (executable)
new mode 100644 (file)
index cea6c7f1c87d589714c9becb49975ec2d93c96c6..1f040e72669c31da7b0dcc6dea42af8dfd4e8fd3 100644 (file)
@@ -1442,7 +1442,7 @@ dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub,
 
        dhd_bus = MALLOC(osh, sizeof(dhd_bus_t));
        if (dhd_bus == NULL) {
-               DBUSERR(("%s: malloc failed %d\n", __FUNCTION__, (int)sizeof(dhd_bus_t)));
+               DBUSERR(("%s: malloc failed %zu\n", __FUNCTION__, sizeof(dhd_bus_t)));
                return NULL;
        }
 
index 798fc6b0b3e3286dfd561b1d3042194222dc02fa..27d0e9db91426349084d7808c40db69a8e3feec8 100644 (file)
@@ -1215,6 +1215,39 @@ dhd_conf_set_ap_in_suspend(dhd_pub_t *dhd, int suspend)
        return mode;\r
 }\r
 \r
+void\r
+dhd_conf_set_eapol_status(dhd_pub_t *dhd, char *ifname, char *dump_data)\r
+{\r
+       unsigned char type;\r
+       int pair, ack, mic, kerr, req, sec, install;\r
+       unsigned short us_tmp;\r
+\r
+       if (!(dhd->conf->in4way&DONT_DELETE_GC_AFTER_WPS) || strncmp(ifname, "p2p", 3)) {\r
+               return;\r
+       }\r
+\r
+       type = dump_data[15];\r
+       if ((type == 0) && (dump_data[22] == 254) && (dump_data[30] == 5)) {\r
+               dhd->conf->eapol_status = EAPOL_STATUS_WPS_DONE;\r
+               CONFIG_TRACE(("EAP Packet, WSC Done\n"));\r
+       } else if (type == 3 && dump_data[18] == 2) {\r
+               us_tmp = (dump_data[19] << 8) | dump_data[20];\r
+               pair =  0 != (us_tmp & 0x08);\r
+               ack = 0  != (us_tmp & 0x80);\r
+               mic = 0  != (us_tmp & 0x100);\r
+               kerr =  0 != (us_tmp & 0x400);\r
+               req = 0  != (us_tmp & 0x800);\r
+               sec = 0  != (us_tmp & 0x200);\r
+               install  = 0 != (us_tmp & 0x40);\r
+               if (pair && !install && !ack && mic && sec && !req && !kerr) {\r
+                       dhd->conf->eapol_status = EAPOL_STATUS_M4;\r
+                       CONFIG_TRACE(("EAPOL Packet, 4-way handshake, M4\n"));\r
+               }\r
+       }\r
+\r
+       return;\r
+}\r
+\r
 #ifdef PROP_TXSTATUS\r
 int\r
 dhd_conf_get_disable_proptx(dhd_pub_t *dhd)\r
@@ -1974,6 +2007,7 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->sd_f2_blocksize = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: sd_f2_blocksize = %d\n", __FUNCTION__, conf->sd_f2_blocksize);\r
        }\r
+#if defined(HW_OOB)\r
        else if (!strncmp("oob_enabled_later=", full_param, len_param)) {\r
                if (!strncmp(data, "0", 1))\r
                        conf->oob_enabled_later = FALSE;\r
@@ -1981,6 +2015,7 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                        conf->oob_enabled_later = TRUE;\r
                printf("%s: oob_enabled_later = %d\n", __FUNCTION__, conf->oob_enabled_later);\r
        }\r
+#endif\r
        else if (!strncmp("dpc_cpucore=", full_param, len_param)) {\r
                conf->dpc_cpucore = (int)simple_strtol(data, NULL, 10);\r
                printf("%s: dpc_cpucore = %d\n", __FUNCTION__, conf->dpc_cpucore);\r
@@ -2027,7 +2062,7 @@ dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param)
                printf("%s: deferred_tx_len = %d\n", __FUNCTION__, conf->deferred_tx_len);\r
        }\r
        else if (!strncmp("txctl_tmo_fix=", full_param, len_param)) {\r
-               conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 10);\r
+               conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 0);\r
                printf("%s: txctl_tmo_fix = %d\n", __FUNCTION__, conf->txctl_tmo_fix);\r
        }\r
        else if (!strncmp("tx_max_offset=", full_param, len_param)) {\r
@@ -2268,6 +2303,10 @@ dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param)
                conf->in4way = (int)simple_strtol(data, NULL, 0);\r
                printf("%s: in4way = 0x%x\n", __FUNCTION__, conf->in4way);\r
        }\r
+       else if (!strncmp("max_wait_gc_time=", full_param, len_param)) {\r
+               conf->max_wait_gc_time = (int)simple_strtol(data, NULL, 0);\r
+               printf("%s: max_wait_gc_time = %d\n", __FUNCTION__, conf->max_wait_gc_time);\r
+       }\r
        else if (!strncmp("wl_preinit=", full_param, len_param)) {\r
                if (!(conf->wl_preinit = kmalloc(len_param+1, GFP_KERNEL))) {\r
                        CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));\r
@@ -2530,8 +2569,8 @@ dhd_conf_set_wl_preinit(dhd_pub_t *dhd, char *data)
        char name[32], *pch, *pick_tmp, *pick_tmp2;\r
 \r
        /* Process wl_preinit:\r
-        * wl_preinit=[cmd]/[val], [cmd]/[val] \\r
-        * Ex: wl_preinit=86/0, mpc/0\r
+        * wl_preinit=[cmd]=[val], [cmd]=[val]\r
+        * Ex: wl_preinit=86=0, mpc=0\r
         */\r
        pick_tmp = data;\r
        while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ",", 0)) != NULL) {\r
@@ -2701,13 +2740,15 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->txglom_ext = FALSE;\r
        conf->tx_max_offset = 0;\r
        conf->txglomsize = SDPCM_DEFGLOM_SIZE;\r
-       conf->txctl_tmo_fix = 300;\r
+       conf->txctl_tmo_fix = -1;\r
        conf->txglom_mode = SDPCM_TXGLOM_CPY;\r
        conf->deferred_tx_len = 0;\r
        conf->dhd_txminmax = 1;\r
        conf->txinrx_thres = -1;\r
        conf->sd_f2_blocksize = 0;\r
+#if defined(HW_OOB)\r
        conf->oob_enabled_later = FALSE;\r
+#endif\r
        conf->orphan_move = 0;\r
 #endif\r
 #ifdef BCMPCIE\r
@@ -2747,6 +2788,7 @@ dhd_conf_preinit(dhd_pub_t *dhd)
        conf->ctrl_resched = 2;\r
        conf->dhd_ioctl_timeout_msec = 0;\r
        conf->in4way = NO_SCAN_IN4WAY;\r
+       conf->max_wait_gc_time = 300;\r
 #ifdef ISAM_PREINIT\r
        memset(conf->isam_init, 0, sizeof(conf->isam_init));\r
        memset(conf->isam_config, 0, sizeof(conf->isam_config));\r
@@ -2758,9 +2800,11 @@ dhd_conf_preinit(dhd_pub_t *dhd)
 #ifdef CUSTOMER_HW_AMLOGIC\r
        dhd_slpauto = FALSE;\r
 #endif\r
-       if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||\r
-                       conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID ||\r
-                       conf->chip == BCM4359_CHIP_ID || conf->chip == BCM4362_CHIP_ID) {\r
+       if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||\r
+                       conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||\r
+                       conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||\r
+                       conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID ||\r
+                       conf->chip == BCM4362_CHIP_ID) {\r
 #ifdef DHDTCPACK_SUPPRESS\r
 #ifdef BCMSDIO\r
                conf->tcpack_sup_mode = TCPACK_SUP_REPLACE;\r
@@ -2776,7 +2820,6 @@ dhd_conf_preinit(dhd_pub_t *dhd)
                conf->dhd_txminmax = -1;\r
                conf->txinrx_thres = 128;\r
                conf->sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;\r
-               conf->oob_enabled_later = TRUE;\r
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))\r
                conf->orphan_move = 1;\r
 #else\r
index 8d592ff8b89205c5f603e49fe7e0c791bd81155f..ad472715007e99341b1a7df0fc360aca090e0564 100644 (file)
@@ -103,7 +103,14 @@ typedef struct mchan_params {
 
 enum in4way_flags {
        NO_SCAN_IN4WAY  = (1 << (0)),
-       NO_BTC_IN4WAY   = (1 << (1))
+       NO_BTC_IN4WAY   = (1 << (1)),
+       DONT_DELETE_GC_AFTER_WPS        = (1 << (2))
+};
+
+enum eapol_status {
+       EAPOL_STATUS_NONE = 0,
+       EAPOL_STATUS_WPS_DONE,
+       EAPOL_STATUS_M4
 };
 
 typedef struct dhd_conf {
@@ -204,7 +211,9 @@ typedef struct dhd_conf {
        struct mchan_params mchan[MCHAN_MAX_NUM];
        char *wl_preinit;
        int tsq;
+       uint eapol_status;
        uint in4way;
+       uint max_wait_gc_time;
 } dhd_conf_t;
 
 #ifdef BCMSDIO
@@ -243,6 +252,9 @@ int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev);
 uint dhd_conf_get_chip(void *context);
 uint dhd_conf_get_chiprev(void *context);
 int dhd_conf_get_pm(dhd_pub_t *dhd);
+void dhd_conf_set_eapol_status(dhd_pub_t *dhd, char *ifname,
+       char *dump_data);
+
 #ifdef PROP_TXSTATUS
 int dhd_conf_get_disable_proptx(dhd_pub_t *dhd);
 #endif
index 525a4b91ecaaa3c714c18f05d6bdb46fd9335e06..d2b53b18008b23b0a677852840a835b5383e5426 100644 (file)
@@ -335,9 +335,10 @@ int dhd_wlan_init_gpio(void)
 
        dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq;
        dhd_wlan_resources[0].flags = host_oob_irq_flags;
-       printf("%s: WL_REG_ON=%d, WL_HOST_WAKE=%d\n", __FUNCTION__, gpio_wl_reg_on, gpio_wl_host_wake);
-       printf("%s: oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__, host_oob_irq, host_oob_irq_flags);
+       printf("%s: WL_HOST_WAKE=%d, oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__,
+               gpio_wl_host_wake, host_oob_irq, host_oob_irq_flags);
 #endif /* CUSTOMER_OOB */
+       printf("%s: WL_REG_ON=%d\n", __FUNCTION__, gpio_wl_reg_on);
 
        return 0;
 }
index d8be26cd8cef804d60a96ee8034dc68d454c3cd9..47cfe8ac72ffffb266114b000e5ccfe7fd053cd7 100644 (file)
@@ -378,8 +378,8 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
                goto exit;
        }
 
-       DHD_TRACE(("%s: TCP ACK Suppress mode %d -> mode %d\n",
-               __FUNCTION__, dhdp->tcpack_sup_mode, mode));
+       printf("%s: TCP ACK Suppress mode %d -> mode %d\n",
+               __FUNCTION__, dhdp->tcpack_sup_mode, mode);
 
        /* Pre-process routines to change a new mode as per previous mode */
        switch (prev_mode) {
index cde26666db637ed528cf88f60d150471e68ac05a..0264224a271d97adaa6f9abb028368d5fe141140 100644 (file)
@@ -4696,38 +4696,25 @@ static const char *_get_packet_type_str(uint16 type)
 
        return packet_type_info[n].str;
 }
-#endif /* DHD_RX_DUMP || DHD_TX_DUMP */
 
-#if defined(DHD_TX_DUMP)
 void
-dhd_tx_dump(struct net_device *ndev, osl_t *osh, void *pkt)
+dhd_trx_dump(struct net_device *ndev, uint8 *dump_data, uint datalen, bool tx)
 {
-       uint8 *dump_data;
        uint16 protocol;
        char *ifname;
 
-       dump_data = PKTDATA(osh, pkt);
        protocol = (dump_data[12] << 8) | dump_data[13];
        ifname = ndev ? ndev->name : "N/A";
 
-       DHD_ERROR(("TX DUMP[%s] - %s\n", ifname, _get_packet_type_str(protocol)));
-
-#if defined(DHD_TX_FULL_DUMP)
-       {
-               int i;
-               uint datalen;
-               datalen = PKTLEN(osh, pkt);
-
-               for (i = 0; i < datalen; i++) {
-                       printk("%02X ", dump_data[i]);
-                       if ((i & 15) == 15)
-                               printk("\n");
-               }
-               printk("\n");
+       if (protocol != ETHER_TYPE_BRCM) {
+               DHD_ERROR(("%s DUMP[%s] - %s\n", tx?"Tx":"Rx", ifname,
+                       _get_packet_type_str(protocol)));
+#if defined(DHD_TX_FULL_DUMP) || defined(DHD_RX_FULL_DUMP)
+               prhex("Data", dump_data, datalen);
+#endif /* DHD_TX_FULL_DUMP || DHD_RX_FULL_DUMP */
        }
-#endif /* DHD_TX_FULL_DUMP */
 }
-#endif /* DHD_TX_DUMP */
+#endif /* DHD_TX_DUMP || DHD_RX_DUMP */
 
 /*  This routine do not support Packet chain feature, Currently tested for
  *  proxy arp feature
@@ -4890,6 +4877,7 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 #if defined(DHD_8021X_DUMP)
                        dhd_dump_eapol_4way_message(dhd_ifname(dhdp, ifidx), pktdata, TRUE);
 #endif /* DHD_8021X_DUMP */
+                       dhd_conf_set_eapol_status(dhdp, dhd_ifname(dhdp, ifidx), pktdata);
                }
 
                if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
@@ -4942,7 +4930,8 @@ __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
 #endif
 
 #if defined(DHD_TX_DUMP)
-       dhd_tx_dump(dhd_idx2net(dhdp, ifidx), dhdp->osh, pktbuf);
+       dhd_trx_dump(dhd_idx2net(dhdp, ifidx), PKTDATA(dhdp->osh, pktbuf),
+               PKTLEN(dhdp->osh, pktbuf), TRUE);
 #endif
        /* terence 20150901: Micky add to ajust the 802.1X priority */
        /* Set the 802.1X packet with the highest priority 7 */
@@ -5717,10 +5706,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
        void *skbhead = NULL;
        void *skbprev = NULL;
        uint16 protocol;
-#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) || \
-       defined(DHD_ICMP_DUMP) || defined(DHD_WAKE_STATUS)
        unsigned char *dump_data;
-#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP || DHD_ICMP_DUMP || DHD_WAKE_STATUS */
 #ifdef DHD_MCAST_REGEN
        uint8 interface_role;
        if_flow_lkup_t *if_flow_lkup;
@@ -5951,10 +5937,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                eth = skb->data;
                len = skb->len;
 
-#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) || \
-       defined(DHD_ICMP_DUMP) || defined(DHD_WAKE_STATUS)
                dump_data = skb->data;
-#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP || DHD_ICMP_DUMP || DHD_WAKE_STATUS */
 
                protocol = (skb->data[12] << 8) | skb->data[13];
                if (protocol == ETHER_TYPE_802_1X) {
@@ -5962,6 +5945,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 #ifdef DHD_8021X_DUMP
                        dhd_dump_eapol_4way_message(dhd_ifname(dhdp, ifidx), dump_data, FALSE);
 #endif /* DHD_8021X_DUMP */
+                       dhd_conf_set_eapol_status(dhdp, dhd_ifname(dhdp, ifidx), dump_data);
                }
 
                if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) {
@@ -5973,33 +5957,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 #endif /* DHD_ICMP_DUMP */
                }
 #ifdef DHD_RX_DUMP
-               DHD_ERROR(("RX DUMP[%s] - %s\n",
-                       dhd_ifname(dhdp, ifidx), _get_packet_type_str(protocol)));
-               if (protocol != ETHER_TYPE_BRCM) {
-                       if (dump_data[0] == 0xFF) {
-                               DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
-
-                               if ((dump_data[12] == 8) &&
-                                       (dump_data[13] == 6)) {
-                                       DHD_ERROR(("%s: ARP %d\n",
-                                               __FUNCTION__, dump_data[0x15]));
-                               }
-                       } else if (dump_data[0] & 1) {
-                               DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
-                                       __FUNCTION__, MAC2STRDBG(dump_data)));
-                       }
-#ifdef DHD_RX_FULL_DUMP
-                       {
-                               int k;
-                               for (k = 0; k < skb->len; k++) {
-                                       printk("%02X ", dump_data[k]);
-                                       if ((k & 15) == 15)
-                                               printk("\n");
-                               }
-                               printk("\n");
-                       }
-#endif /* DHD_RX_FULL_DUMP */
-               }
+               dhd_trx_dump(dhd_idx2net(dhdp, ifidx), dump_data, skb->len, FALSE);
 #endif /* DHD_RX_DUMP */
 #if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP)
                if (pkt_wake) {
@@ -7791,12 +7749,12 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
                        goto done;
                }
        }
-
+/*
        if (!capable(CAP_NET_ADMIN)) {
                bcmerror = BCME_EPERM;
                goto done;
        }
-
+*/
        /* Take backup of ioc.buf and restore later */
        ioc_buf_user = ioc.buf;
 
@@ -10996,7 +10954,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        DHD_TRACE(("Enter %s\n", __FUNCTION__));
 
 #ifdef DHDTCPACK_SUPPRESS
-       printf("%s: Set tcpack_sup_mode %d\n", __FUNCTION__, dhd->conf->tcpack_sup_mode);
        dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode);
 #endif
        dhd->op_mode = 0;
index ea32a6b89ea286efec965ceca048317884458ee3..fb6150facbd2b41779b120cccee09bfaf5dda1ab 100644 (file)
@@ -437,7 +437,7 @@ typedef struct dhd_bus {
 #endif /* defined (BT_OVER_SDIO) */
        uint            txglomframes;   /* Number of tx glom frames (superframes) */
        uint            txglompkts;             /* Number of packets from tx glom frames */
-       uint8           *membuf;                /* Buffer for receiving big glom packet */
+       uint8           *membuf;                /* Buffer for dhdsdio_membytes */
 } dhd_bus_t;
 
 
@@ -2762,13 +2762,15 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
 
 
        /* Need to lock here to protect txseq and SDIO tx calls */
+       dhd_os_sdlock(bus->dhd);
        if (bus->dhd->conf->txctl_tmo_fix > 0 && !TXCTLOK(bus)) {
                bus->ctrl_wait = TRUE;
+               dhd_os_sdunlock(bus->dhd);
                wait_event_interruptible_timeout(bus->ctrl_tx_wait, TXCTLOK(bus),
                        msecs_to_jiffies(bus->dhd->conf->txctl_tmo_fix));
+               dhd_os_sdlock(bus->dhd);
                bus->ctrl_wait = FALSE;
        }
-       dhd_os_sdlock(bus->dhd);
 
        BUS_WAKE(bus);
 
@@ -3361,6 +3363,7 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s
        int bcmerror = 0;
        uint32 sdaddr;
        uint dsize;
+       uint8 *pdata;
 
        /* In remap mode, adjust address beyond socram and redirect
         * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
@@ -3377,10 +3380,6 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s
                dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
        else
                dsize = size;
-       if (dsize > MAX_MEM_BUF) {
-               DHD_ERROR(("%s: dsize %d > %d\n", __FUNCTION__, dsize, MAX_MEM_BUF));
-               goto xfer_done;
-       }
 
        /* Set the backplane window to include the start address */
        if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
@@ -3393,14 +3392,20 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s
                DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
                          __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
                          (address & SBSDIO_SBWINDOW_MASK)));
-               if (write)
-                       memcpy(bus->membuf, data, dsize);
-               if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, bus->membuf, dsize))) {
+               if (dsize <= MAX_MEM_BUF) {
+                       pdata = bus->membuf;
+                       if (write)
+                               memcpy(bus->membuf, data, dsize);
+               } else {
+                       pdata = data;
+               }
+               if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, pdata, dsize))) {
                        DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
                        break;
                }
-               if (!write)
+               if (dsize <= MAX_MEM_BUF && !write) {
                        memcpy(data, bus->membuf, dsize);
+               }
 
                /* Adjust for next transfer (if any) */
                if ((size -= dsize)) {
@@ -6605,7 +6610,7 @@ dhdsdio_dpc(dhd_bus_t *bus)
                goto clkwait;
 
        /* Pending interrupt indicates new device status */
-       if (bus->ipend) {
+       if (bus->ipend || (bus->ctrl_frame_stat && bus->dhd->conf->txctl_tmo_fix)) {
                bus->ipend = FALSE;
 #if defined(BT_OVER_SDIO)
        bcmsdh_btsdio_process_f3_intr();
@@ -6728,7 +6733,8 @@ clkwait:
         * or clock availability.  (Allows tx loop to check ipend if desired.)
         * (Unless register access seems hosed, as we may not be able to ACK...)
         */
-       if (!bus->dhd->conf->oob_enabled_later && bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
+       if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
+                       !(bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
                DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
                          __FUNCTION__, rxdone, framecnt));
                bus->intdis = FALSE;
@@ -6786,7 +6792,7 @@ clkwait:
        }
        /* Resched the DPC if ctrl cmd is pending on bus credit */
        if (bus->ctrl_frame_stat) {
-               if (bus->dhd->conf->txctl_tmo_fix > 0) {
+               if (bus->dhd->conf->txctl_tmo_fix) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        if (!kthread_should_stop())
                                schedule_timeout(1);
@@ -6834,7 +6840,8 @@ exit:
                 * or clock availability.  (Allows tx loop to check ipend if desired.)
                 * (Unless register access seems hosed, as we may not be able to ACK...)
                 */
-               if (bus->dhd->conf->oob_enabled_later && bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
+               if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh) &&
+                               (bus->dhd->conf->oob_enabled_later && !bus->ctrl_frame_stat)) {
                        DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
                                          __FUNCTION__, rxdone, framecnt));
                        bus->intdis = FALSE;
index 2bf784c8ae936b877491ef7bc90ea6b797219c2a..a0f0a2a3bbab24166e1c83c2467af3b36f7c226e 100644 (file)
@@ -272,7 +272,6 @@ int bcmdhd_init_wlan_mem(void)
 {\r
        int i;\r
        int j;\r
-\r
        printk(KERN_ERR "%s(): %s\n", __func__, DHD_STATIC_VERSION_STR);\r
 \r
        for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) {\r
index bf901eab419dabd409e195833bc0d0eb34915a20..3159d4c842fe3f2ae00b626c7a879fe552590eea 100644 (file)
@@ -3020,66 +3020,126 @@ wl_ext_dhcpc_dump(struct net_device *dev, char *command, int total_len)
 }
 #endif
 
+static int
+wl_ext_rsdb_mode(struct net_device *dev, char *data, char *command,
+       int total_len)
+{
+       s8 iovar_buf[WLC_IOCTL_SMLEN];
+       wl_config_t rsdb_mode_cfg = {1, 0}, *rsdb_p;
+       int ret = 0;
+
+       ANDROID_TRACE(("%s: Enter\n", __FUNCTION__));
+
+       if (data) {
+               rsdb_mode_cfg.config = (int)simple_strtol(data, NULL, 0);
+               ret = wl_ext_iovar_setbuf(dev, "rsdb_mode", (char *)&rsdb_mode_cfg,
+                       sizeof(rsdb_mode_cfg), iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               printf("%s: rsdb_mode %d\n", __FUNCTION__, rsdb_mode_cfg.config);
+       } else {
+               ret = wl_ext_iovar_getbuf(dev, "rsdb_mode", NULL, 0,
+                       iovar_buf, WLC_IOCTL_SMLEN, NULL);
+               if (!ret) {
+                       rsdb_p = (wl_config_t *) iovar_buf;
+                       ret = snprintf(command, total_len, "%d", rsdb_p->config);
+                       ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
+                               command));
+               }
+       }
+
+       return ret;
+}
+
+typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command,
+       int total_len);
+
+typedef struct wl_ext_iovar_tpl_t {
+       int get;
+       int set;
+       char *name;
+       wl_ext_tpl_parse_t *parse;
+} wl_ext_iovar_tpl_t;
+
+const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = {
+       {WLC_GET_VAR,   WLC_SET_VAR,    "rsdb_mode",    wl_ext_rsdb_mode},
+};
+
 /*
-dhd_priv dhd [string] ==> Not ready
-1. Get dhd val:
-  Ex: dhd_priv dhd bussleep
-2. Set dhd val:
-  Ex: dhd_priv dhd bussleep 1
-
-dhd_priv wl [WLC_GET_PM]  ==> Ready to get int val
-dhd_priv wl [WLC_SET_PM] [int]  ==> Ready to set int val
-dhd_priv wl [string]  ==> Ready to get int val
-dhd_priv wl [string] [int]  ==> Ready to set int val
-Ex: get/set WLC_PM
+Ex: dhd_priv wl [cmd] [val]
   dhd_priv wl 85
   dhd_priv wl 86 1
-Ex: get/set mpc
   dhd_priv wl mpc
   dhd_priv wl mpc 1
 */
 int
-wl_ext_iovar(struct net_device *dev, char *command, int total_len)
+wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len)
 {
-       int ret = 0;
-       char wl[3]="\0", arg[20]="\0", cmd_str[20]="\0", val_str[20]="\0";
-       int cmd=-1, val=0;
+       int cmd, val, ret = -1, i;
+       char name[32], *pch, *pick_tmp, *data;
        int bytes_written=-1;
+       const wl_ext_iovar_tpl_t *tpl = wl_ext_iovar_tpl_list;
+       int tpl_count = ARRAY_SIZE(wl_ext_iovar_tpl_list);
 
        ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
+       pick_tmp = command;
 
-       sscanf(command, "%s %d %s", wl, &cmd, arg);
-       if (cmd < 0)
-               sscanf(command, "%s %s %s", wl, cmd_str, val_str);
-
-       if (!strcmp(wl, "wl")) {
-               if (cmd>=0 && cmd!=WLC_GET_VAR && cmd!=WLC_SET_VAR) {
-                       ret = sscanf(arg, "%d", &val);
-                       if (ret > 0) { // set
-                               ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
-                       } else { // get
-                               ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
-                               if (!ret) {
-                                       bytes_written = snprintf(command, total_len, "%d", val);
-                                       ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-                                       ret = bytes_written;
-                               }
+       pch = bcmstrtok(&pick_tmp, " ", 0); // pick wl
+       if (!pch || strncmp(pch, "wl", 2))
+               goto exit;
+
+       pch = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
+       if (!pch)
+               goto exit;
+
+       memset(name, 0 , sizeof (name));
+       cmd = (int)simple_strtol(pch, NULL, 0);
+       if (cmd == 0) {
+               strcpy(name, pch);
+       }
+       data = bcmstrtok(&pick_tmp, " ", 0); // pick data
+       if (data && cmd == 0) {
+               cmd = WLC_SET_VAR;
+       } else if (cmd == 0) {
+               cmd = WLC_GET_VAR;
+       }
+
+       /* look for a matching code in the table */
+       for (i = 0; i < tpl_count; i++, tpl++) {
+               if ((tpl->get == cmd || tpl->set == cmd) && !strcmp(tpl->name, name))
+                       break;
+       }
+       if (i < tpl_count && tpl->parse) {
+               ret = tpl->parse(dev, data, command, total_len);
+       } else {
+               if (cmd == WLC_SET_VAR) {
+                       val = (int)simple_strtol(data, NULL, 0);
+                       ANDROID_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val));
+                       ret = wl_ext_iovar_setint(dev, name, val);
+               } else if (cmd == WLC_GET_VAR) {
+                       ANDROID_TRACE(("%s: get %s\n", __FUNCTION__, name));
+                       ret = wl_ext_iovar_getint(dev, name, &val);
+                       if (!ret) {
+                               bytes_written = snprintf(command, total_len, "%d", val);
+                               ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
+                                       command));
+                               ret = bytes_written;
                        }
-               } else if (strlen(cmd_str)) {
-                       ret = sscanf(val_str, "%d", &val);
-                       if (ret > 0) { // set
-                               ret = wl_ext_iovar_setint(dev, cmd_str, val);
-                       } else { // get
-                               ret = wl_ext_iovar_getint(dev, cmd_str, &val);
-                               if (!ret) {
-                                       bytes_written = snprintf(command, total_len, "%d", val);
-                                       ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
-                                       ret = bytes_written;
-                               }
+               } else if (data) {
+                       val = (int)simple_strtol(data, NULL, 0);
+                       ANDROID_TRACE(("%s: set %d %d\n", __FUNCTION__, cmd, val));
+                       ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
+               } else {
+                       ANDROID_TRACE(("%s: get %d\n", __FUNCTION__, cmd));
+                       ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
+                       if (!ret) {
+                               bytes_written = snprintf(command, total_len, "%d", val);
+                               ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__,
+                                       command));
+                               ret = bytes_written;
                        }
                }
        }
 
+exit:
        return ret;
 }
 
@@ -3159,7 +3219,7 @@ int wl_android_ext_priv_cmd(struct net_device *net, char *command,
        }
 #endif
        else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
-               *bytes_written = wl_ext_iovar(net, command, total_len);
+               *bytes_written = wl_ext_wl_iovar(net, command, total_len);
        }
        else
                ret = -1;
index eb4e338d138eab070ff7254970bcadd21f608787..777ac49df7ff89d6e3933b9414b42645e284b099 100644 (file)
@@ -912,6 +912,8 @@ extern int dhd_wait_pend8021x(struct net_device *dev);
 #ifdef PROP_TXSTATUS_VSDB
 extern int disable_proptx;
 #endif /* PROP_TXSTATUS_VSDB */
+static int wl_cfg80211_check_in4way(struct bcm_cfg80211 *cfg,
+       struct net_device *dev, uint action, enum wl_ext_status status, void *context);
 
 
 extern int passive_channel_skip;
@@ -3323,53 +3325,6 @@ scan_out:
        return err;
 }
 
-void
-wl_cfg80211_4way_start(struct bcm_cfg80211 *cfg, struct net_device *dev)
-{
-       dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
-       struct wl_security *sec;
-       s32 bssidx = -1;
-
-       bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
-
-       sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
-       if ((sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
-                       bssidx == 0 && dhdp->conf->in4way) {
-               WL_DBG(("Enter in4way=0x%x\n", dhdp->conf->in4way));
-               cfg->handshaking = 1;
-               if (dhdp->conf->in4way & NO_BTC_IN4WAY)
-                       wldev_iovar_setint(dev, "btc_mode", 0);
-       }
-}
-
-void
-wl_cfg80211_4way_exit(struct bcm_cfg80211 *cfg, struct net_device *dev)
-{
-       dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
-
-       if (cfg->handshaking) {
-               WL_DBG(("Enter in4way=0x%x\n", dhdp->conf->in4way));
-               if (dhdp->conf->in4way & NO_BTC_IN4WAY)
-                       wldev_iovar_setint(dev, "btc_mode", 1);
-               cfg->handshaking = 0;
-       }
-}
-
-s32
-wl_cfg80211_4way_check(struct bcm_cfg80211 *cfg, uint mode)
-{
-       dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
-
-       if (cfg->handshaking && (dhdp->conf->in4way & mode)) {
-               if (mode & NO_SCAN_IN4WAY && cfg->handshaking <= 3) {
-                       WL_ERR(("%s: return -EBUSY cnt %d\n", __FUNCTION__, cfg->handshaking));
-                       cfg->handshaking++;
-                       return -EBUSY;
-               }
-       }
-       return 0;
-}
-
 static s32
 #if defined(WL_CFG80211_P2P_DEV_IF)
 wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
@@ -3401,7 +3356,8 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                         return -ENODEV;
                }
        }
-       err = wl_cfg80211_4way_check(cfg, NO_SCAN_IN4WAY);
+       err = wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+               WL_EXT_STATUS_SCAN, NULL);
        if (err)
                return err;
 
@@ -5763,7 +5719,8 @@ exit:
                wl_clr_drv_status(cfg, CONNECTING, dev);
        }
        if (!err)
-               wl_cfg80211_4way_start(cfg, dev);
+               wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+               WL_EXT_STATUS_CONNECTING, NULL);
 
 #ifdef WLTDLS
        /* disable TDLS if number of connected interfaces is >= 1 */
@@ -6216,7 +6173,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
                return BCME_ERROR;
        }
-       wl_cfg80211_4way_exit(cfg, dev);
+       wl_cfg80211_check_in4way(cfg, dev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+               WL_EXT_STATUS_4WAY_DONE, NULL);
 
        if (mac_addr &&
                ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
@@ -9574,6 +9532,7 @@ wl_cfg80211_del_station(
        u16 rc = params->reason_code;
 #endif /* CUSTOM_BLOCK_DEAUTH_AT_EAP_FAILURE */
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
+
        WL_DBG(("Entry\n"));
        if (mac_addr == NULL) {
                WL_DBG(("mac_addr is NULL ignore it\n"));
@@ -9591,6 +9550,11 @@ wl_cfg80211_del_station(
                        return -EFAULT;
                }
        }
+       err = wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
+               WL_EXT_STATUS_DELETE_GC, (void *)mac_addr);
+       if (err) {
+               return 0;
+       }
 
        assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
        err = wldev_ioctl_get(ndev, WLC_GET_ASSOCLIST,
@@ -11740,13 +11704,19 @@ exit:
                sinfo.assoc_req_ies = data;
                sinfo.assoc_req_ies_len = len;
                printf("%s: connected device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+               wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
+                       WL_EXT_STATUS_GC_CONNECTED, NULL);
                cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
        } else if (event == WLC_E_DISASSOC_IND) {
                printf("%s: disassociated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+               wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
+                       WL_EXT_STATUS_GC_DISCONNECTED, NULL);
                cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
        } else if ((event == WLC_E_DEAUTH_IND) ||
                ((event == WLC_E_DEAUTH) && (reason != DOT11_RC_RESERVED))) {
                printf("%s: deauthenticated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+               wl_cfg80211_check_in4way(cfg, ndev, DONT_DELETE_GC_AFTER_WPS,
+                       WL_EXT_STATUS_GC_DISCONNECTED, NULL);
                cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
        }
 #endif 
@@ -12367,7 +12337,8 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                        "event : %d, reason=%d from " MACDBG "\n",
                                        ndev->name, event, ntoh32(e->reason),
                                        MAC2STRDBG((const u8*)(&e->addr)));
-                               wl_cfg80211_4way_exit(cfg, ndev);
+                               wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+                                       WL_EXT_STATUS_DISCONNECTED, NULL);
 
                                /* roam offload does not sync BSSID always, get it from dongle */
                                if (cfg->roam_offload) {
@@ -12474,7 +12445,8 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                        }
                        else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
                                printf("link down, during connecting\n");
-                               wl_cfg80211_4way_exit(cfg, ndev);
+                               wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+                                       WL_EXT_STATUS_DISCONNECTED, NULL);
                                /* Issue WLC_DISASSOC to prevent FW roam attempts */
                                err = wldev_ioctl_set(ndev, WLC_DISASSOC, NULL, 0);
                                if (err < 0) {
@@ -12505,7 +12477,8 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                } else if (wl_is_nonetwork(cfg, e)) {
                        printf("connect failed event=%d e->status %d e->reason %d \n",
                                event, (int)ntoh32(e->status), (int)ntoh32(e->reason));
-                       wl_cfg80211_4way_exit(cfg, ndev);
+                       wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+                               WL_EXT_STATUS_DISCONNECTED, NULL);
 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
                        if (event == WLC_E_SET_SSID) {
                                wl_get_connect_failed_status(cfg, e);
@@ -13383,7 +13356,8 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                        dhd_conf_set_wme(cfg->pub, 0);
                } else {
                        WL_ERR(("Report connect result - connection failed\n"));
-                       wl_cfg80211_4way_exit(cfg, ndev);
+                       wl_cfg80211_check_in4way(cfg, ndev, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+                               WL_EXT_STATUS_DISCONNECTED, NULL);
                }
        }
 #ifdef CONFIG_TCPACK_FASTTX
@@ -15122,6 +15096,7 @@ exit:
 
 }
 #endif /* WL_DRV_AVOID_SCANCACHE */
+
 static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
        const wl_event_msg_t *e, void *data)
 {
@@ -15275,7 +15250,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                        goto exit;
                                }
 #ifdef ESCAN_BUF_OVERFLOW_MGMT
-                               WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
+                               WL_SCAN(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
                                        bss->SSID, MAC2STRDBG(bss->BSSID.octet),
                                        i, bss->RSSI, list->count));
 
@@ -15405,7 +15380,7 @@ static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                        DBG_EVENT_LOG((dhd_pub_t *)cfg->pub, WIFI_EVENT_DRIVER_SCAN_COMPLETE);
                        cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
                        if (!scan_req_match(cfg)) {
-                               WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
+                               WL_SCAN(("SCAN COMPLETED: scanned AP count=%d\n",
                                        cfg->bss_list->count));
                        }
                        wl_inform_bss(cfg);
@@ -15742,6 +15717,7 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
        spin_lock_init(&cfg->cfgdrv_lock);
        mutex_init(&cfg->ioctl_buf_sync);
        init_waitqueue_head(&cfg->netif_change_event);
+       init_waitqueue_head(&cfg->wps_done_event);
        init_completion(&cfg->send_af_done);
        init_completion(&cfg->iface_disable);
        mutex_init(&cfg->usr_sync);
@@ -15749,6 +15725,7 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
        mutex_init(&cfg->scan_complete);
        mutex_init(&cfg->if_sync);
        mutex_init(&cfg->pm_sync);
+       mutex_init(&cfg->in4way_sync);
 #ifdef WLTDLS
        mutex_init(&cfg->tdls_sync);
 #endif /* WLTDLS */
@@ -17083,7 +17060,8 @@ s32 wl_cfg80211_up(struct net_device *net)
                return BCME_VERSION;
        }
        ioctl_version = val;
-       wl_cfg80211_4way_exit(cfg, net);
+       wl_cfg80211_check_in4way(cfg, net, NO_SCAN_IN4WAY|NO_BTC_IN4WAY,
+               WL_EXT_STATUS_DISCONNECTED, NULL);
        WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
 
        mutex_lock(&cfg->usr_sync);
@@ -21753,7 +21731,8 @@ wl_set_rssi_logging(struct net_device *dev, void *param)
 }
 #endif /* SUPPORT_RSSI_LOGGING */
 
-s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
+s32
+wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len)
 {
        struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
        int ret = 0;
@@ -21773,3 +21752,105 @@ s32 wl_cfg80211_autochannel(struct net_device *dev, char* command, int total_len
 
        return ret;
 }
+
+static int
+wl_cfg80211_check_in4way(struct bcm_cfg80211 *cfg,
+       struct net_device *dev, uint action, enum wl_ext_status status, void *context)
+{
+       dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+       struct wl_security *sec;
+       s32 bssidx = -1;
+       int ret = 0;
+       int max_wait_gc_time = dhdp->conf->max_wait_gc_time;
+
+       if (!(dhdp->conf->in4way & action))
+               return 0;
+
+       mutex_lock(&cfg->in4way_sync);
+       WL_DBG(("status=%d, action=0x%x\n", status, action));
+
+       switch (status) {
+               case WL_EXT_STATUS_SCAN:
+                       if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
+                               if (cfg->handshaking > 0 && cfg->handshaking <= 3) {
+                                       WL_ERR(("%s: return -EBUSY cnt %d\n",
+                                               __FUNCTION__, cfg->handshaking));
+                                       cfg->handshaking++;
+                                       ret = -EBUSY;
+                                       break;
+                               }
+                       }
+                       break;
+               case WL_EXT_STATUS_CONNECTING:
+                       if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
+                               bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr);
+                               sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+                               if ((sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
+                                               bssidx == 0) {
+                                       cfg->handshaking = 1;
+                                       if (action & NO_BTC_IN4WAY)
+                                               wldev_iovar_setint(dev, "btc_mode", 0);
+                               }
+                       }
+                       break;
+               case WL_EXT_STATUS_DELETE_GC:
+                       if ((action & DONT_DELETE_GC_AFTER_WPS) &&
+                                       (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
+                               u8* mac_addr = context;
+                               if (memcmp(&ether_bcast, mac_addr, ETHER_ADDR_LEN) &&
+                                               dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
+                                       u32 timeout;
+                                       WL_TRACE(("status=%d, wps_done=%d, waiting %dms ...\n",
+                                               status, cfg->wps_done, max_wait_gc_time));
+                                       mutex_unlock(&cfg->in4way_sync);
+                                       timeout = wait_event_interruptible_timeout(cfg->wps_done_event,
+                                               cfg->wps_done, msecs_to_jiffies(max_wait_gc_time));
+                                       mutex_lock(&cfg->in4way_sync);
+                                       WL_TRACE(("status=%d, wps_done=%d, timeout=%d\n",
+                                               status, cfg->wps_done, timeout));
+                                       if (timeout > 0) {
+                                               ret = -1;
+                                               break;
+                                       }
+                               } else {
+                                       WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
+                                       cfg->wps_done = FALSE;
+                                       dhdp->conf->eapol_status = EAPOL_STATUS_NONE;
+                               }
+                       }
+                       break;
+               case WL_EXT_STATUS_GC_DISCONNECTED:
+                       if ((action & DONT_DELETE_GC_AFTER_WPS) &&
+                                       (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
+                                       dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
+                               WL_TRACE(("status=%d, wps_done=%d => 0\n", status, cfg->wps_done));
+                               cfg->wps_done = FALSE;
+                       }
+                       break;
+               case WL_EXT_STATUS_GC_CONNECTED:
+                       if ((action & DONT_DELETE_GC_AFTER_WPS) &&
+                                       (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) &&
+                                       dhdp->conf->eapol_status == EAPOL_STATUS_WPS_DONE) {
+                               WL_TRACE(("status=%d, wps_done=%d => 1\n", status, cfg->wps_done));
+                               cfg->wps_done = TRUE;
+                               wake_up_interruptible(&cfg->wps_done_event);
+                       }
+                       break;
+               case WL_EXT_STATUS_DISCONNECTED:
+               case WL_EXT_STATUS_4WAY_DONE:
+                       if (action & (NO_SCAN_IN4WAY|NO_BTC_IN4WAY)) {
+                               if (cfg->handshaking) {
+                                       if (action & NO_BTC_IN4WAY)
+                                               wldev_iovar_setint(dev, "btc_mode", 1);
+                                       cfg->handshaking = 0;
+                               }
+                       }
+                       break;
+               default:
+                       WL_ERR(("Unknown action=0x%x, status=%d\n", action, status));
+       }
+
+       mutex_unlock(&cfg->in4way_sync);
+
+       return ret;
+}
\ No newline at end of file
index cf9b3fbd2752c8f6291240aa9053453bc7a53d3c..6a6300cba903592b59ddcabd6a9d26c25bc85aee 100644 (file)
@@ -341,6 +341,18 @@ enum wl_status {
        WL_STATUS_NESTED_CONNECT
 };
 
+enum wl_ext_status {
+       WL_EXT_STATUS_DISCONNECTED = 0,
+       WL_EXT_STATUS_SCAN,
+       WL_EXT_STATUS_CONNECTING,
+       WL_EXT_STATUS_CONNECTED,
+       WL_EXT_STATUS_DELETE_GC,
+       WL_EXT_STATUS_GC_DISCONNECTED,
+       WL_EXT_STATUS_GC_CONNECTED,
+       WL_EXT_STATUS_4WAY_START,
+       WL_EXT_STATUS_4WAY_DONE
+};
+
 /* wi-fi mode */
 enum wl_mode {
        WL_MODE_BSS,
@@ -872,6 +884,9 @@ struct bcm_cfg80211 {
        int best_2g_ch;
        int best_5g_ch;
        uint handshaking;
+       bool wps_done;
+       wait_queue_head_t wps_done_event;
+       struct mutex in4way_sync;
 };
 
 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \