OSDN Git Service

net: wireless: bcmdhd: Update to version 5.90.195.75
authorDmitry Shmidt <dimitrysh@google.com>
Thu, 31 May 2012 21:06:50 +0000 (14:06 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Thu, 31 May 2012 21:22:22 +0000 (14:22 -0700)
- Fix false PCB-OVERLAP issue
- Fix simultanious connect request on two P2P devices

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
13 files changed:
drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/include/bcmdevs.h
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/include/hndpmu.h
drivers/net/wireless/bcmdhd/include/sbchipc.h
drivers/net/wireless/bcmdhd/include/siutils.h
drivers/net/wireless/bcmdhd/include/wlioctl.h
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.h

index 0470b33..3b4dc7a 100644 (file)
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd.h 328934 2012-04-23 05:15:42Z $
+ * $Id: dhd.h 333052 2012-05-12 02:09:28Z $
  */
 
 /****************
@@ -51,6 +51,7 @@
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
 #include <linux/wakelock.h>
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
+
 /* The kernel threading is sdio-specific */
 struct task_struct;
 struct sched_param;
@@ -436,10 +437,14 @@ extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
 extern int dhd_pno_clean(dhd_pub_t *dhd);
 extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
                        ushort  scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_pno_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid,
+                               ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
 extern int dhd_pno_get_status(dhd_pub_t *dhd);
 extern int dhd_dev_pno_reset(struct net_device *dev);
 extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
                            int nssid, ushort  scan_fr, int pno_repeat, int pno_freq_expo_max);
+extern int dhd_dev_pno_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
+                               ushort  pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
 extern int dhd_dev_pno_enable(struct net_device *dev,  int pfn_enabled);
 extern int dhd_dev_get_pno_status(struct net_device *dev);
 #endif /* PNO_SUPPORT */
index 60e1449..d5af27f 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_common.c 329682 2012-04-26 09:20:38Z $
+ * $Id: dhd_common.c 331276 2012-05-04 08:05:57Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -1763,7 +1763,6 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
        }
 }
 
-
 /* Function to estimate possible DTIM_SKIP value */
 int
 dhd_get_dtim_skip(dhd_pub_t *dhd)
@@ -1885,12 +1884,13 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
                return ret;
        }
 
-       if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
-               return (ret);
 
        memset(iovbuf, 0, sizeof(iovbuf));
 
 #ifndef WL_SCHED_SCAN
+       if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
+               return (ret);
+
        if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) {
                DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
                return ret;
@@ -1934,9 +1934,10 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
                err = -1;
                return err;
        }
-
+#ifndef WL_SCHED_SCAN
        if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
                return (err);
+#endif /* !WL_SCHED_SCAN */
 
        /* Check for broadcast ssid */
        for (k = 0; k < nssid; k++) {
@@ -2030,6 +2031,123 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
 }
 
 int
+dhd_pno_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid, ushort pno_interval,
+       int pno_repeat, int pno_expo_max, int pno_lost_time)
+{
+       int err = -1;
+       char iovbuf[128];
+       int k, i;
+       wl_pfn_param_t pfn_param;
+       wl_pfn_t        pfn_element;
+       uint len = 0;
+
+       DHD_TRACE(("%s nssid=%d pno_interval=%d\n", __FUNCTION__, nssid, pno_interval));
+
+       if ((!dhd) && (!ssidnet)) {
+               DHD_ERROR(("%s error exit\n", __FUNCTION__));
+               err = -1;
+               return err;
+       }
+
+       if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
+               return (err);
+
+       /* Check for broadcast ssid */
+       for (k = 0; k < nssid; k++) {
+               if (!ssidnet[k].ssid.SSID_len) {
+                       DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
+                       return err;
+               }
+       }
+/* #define  PNO_DUMP 1 */
+#ifdef PNO_DUMP
+       {
+               int j;
+               for (j = 0; j < nssid; j++) {
+                       DHD_ERROR(("%d: scan  for  %s size =%d\n", j,
+                               ssidnet[j].ssid.SSID, ssidnet[j].ssid.SSID_len));
+               }
+       }
+#endif /* PNO_DUMP */
+
+       /* clean up everything */
+       if  ((err = dhd_pno_clean(dhd)) < 0) {
+               DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
+               return err;
+       }
+       memset(iovbuf, 0, sizeof(iovbuf));
+       memset(&pfn_param, 0, sizeof(pfn_param));
+       memset(&pfn_element, 0, sizeof(pfn_element));
+
+       /* set pfn parameters */
+       pfn_param.version = htod32(PFN_VERSION);
+       pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
+
+       /* check and set extra pno params */
+       if ((pno_repeat != 0) || (pno_expo_max != 0)) {
+               pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
+               pfn_param.repeat = (uchar) (pno_repeat);
+               pfn_param.exp = (uchar) (pno_expo_max);
+       }
+
+       /* set up pno scan fr */
+       if (pno_interval  != 0)
+               pfn_param.scan_freq = htod32(pno_interval);
+
+       if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
+               DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
+               return err;
+       }
+       if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
+               DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
+               return err;
+       }
+
+       /* network lost time */
+       pfn_param.lost_network_timeout = htod32(pno_lost_time);
+
+       len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
+       if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
+                               DHD_ERROR(("%s pfn_set failed for error=%d\n",
+                                       __FUNCTION__, err));
+                               return err;
+       } else {
+               DHD_TRACE(("%s pfn_set OK with PNO time=%d repeat=%d max_adjust=%d\n",
+                       __FUNCTION__, pfn_param.scan_freq,
+                       pfn_param.repeat, pfn_param.exp));
+       }
+
+       /* set all pfn ssid */
+       for (i = 0; i < nssid; i++) {
+               pfn_element.flags = htod32(ssidnet[i].flags);
+               pfn_element.infra = htod32(ssidnet[i].infra);
+               pfn_element.auth = htod32(ssidnet[i].auth);
+               pfn_element.wpa_auth = htod32(ssidnet[i].wpa_auth);
+               pfn_element.wsec = htod32(ssidnet[i].wsec);
+
+               memcpy((char *)pfn_element.ssid.SSID, ssidnet[i].ssid.SSID, ssidnet[i].ssid.SSID_len);
+               pfn_element.ssid.SSID_len = htod32(ssidnet[i].ssid.SSID_len);
+
+               if ((len =
+                       bcm_mkiovar("pfn_add", (char *)&pfn_element,
+                       sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
+                       if ((err =
+                               dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
+                               DHD_ERROR(("%s pfn_add failed with ssidnet[%d] error=%d\n",
+                                       __FUNCTION__, i, err));
+                               return err;
+                       } else {
+                               DHD_TRACE(("%s pfn_add OK with ssidnet[%d]\n", __FUNCTION__, i));
+                       }
+               } else {
+                       DHD_ERROR(("%s bcm_mkiovar failed with ssidnet[%d]\n", __FUNCTION__, i));
+               }
+       }
+
+       return err;
+}
+
+int
 dhd_pno_get_status(dhd_pub_t *dhd)
 {
        int ret = -1;
index d85ee03..d8c1c1b 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $
+ * $Id: dhd_linux.c 333885 2012-05-18 00:39:03Z $
  */
 
 #include <typedefs.h>
@@ -1525,9 +1525,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                                tout_ctrl = DHD_PACKET_TIMEOUT_MS;
                        if (event.event_type == WLC_E_BTA_HCI_EVENT) {
                                dhd_bta_doevt(dhdp, data, event.datalen);
-                       } else if (event.event_type == WLC_E_PFN_NET_FOUND) {
+                       }
+#ifdef PNO_SUPPORT
+                       if (event.event_type == WLC_E_PFN_NET_FOUND) {
                                tout_ctrl *= 2;
                        }
+#endif /* PNO_SUPPORT */
                } else {
                        tout_rx = DHD_PACKET_TIMEOUT_MS;
                }
@@ -1562,6 +1565,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
                }
        }
+
        DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
        DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
 }
@@ -2939,16 +2943,20 @@ dhd_concurrent_fw(dhd_pub_t *dhd)
                bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
                if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
                        FALSE, 0)) < 0) {
-                       DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+                       DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
                } else if (buf[0] == 1) {
                        DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
                        return 1;
                }
        }
-       return 0;
+       return ret;
 }
 #endif 
 
+/*
+ *   dhd_preinit_ioctls makes special pre-setting in the firmware before radio turns on
+ *   returns : 0 if all settings passed or negative value if anything failed
+*/
 int
 dhd_preinit_ioctls(dhd_pub_t *dhd)
 {
@@ -2957,7 +2965,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
 #if !defined(WL_CFG80211)
        uint up = 0;
-#endif
+#endif /* defined(WL_CFG80211) */
        uint power_mode = PM_FAST;
        uint32 dongle_align = DHD_SDALIGN;
        uint32 glom = 0;
@@ -3041,19 +3049,31 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif /* SET_RANDOM_MAC_SOFTAP */
 
        DHD_TRACE(("Firmware = %s\n", fw_path));
+
 #if !defined(AP)  && defined(WLP2P)
        /* Check if firmware with WFD support used */
+#if defined(WL_ENABLE_P2P_IF)
+       if ((ret = dhd_concurrent_fw(dhd)) < 0) {
+               DHD_ERROR(("%s error : firmware can't support p2p mode\n", __FUNCTION__));
+               goto done;
+       }
+#endif /* (WL_ENABLE_P2P_IF) */
+
        if ((!op_mode && strstr(fw_path, "_p2p") != NULL)
 #if defined(WL_ENABLE_P2P_IF)
-                       || (op_mode == 0x04) ||(dhd_concurrent_fw(dhd))
+                       || (op_mode == WFD_MASK) || (dhd_concurrent_fw(dhd) == 1)
 #endif
                ) {
                bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
                if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
                        iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
-                       DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
+                       DHD_ERROR(("%s APSTA setting failed ret= %d\n", __FUNCTION__, ret));
                } else {
                        dhd->op_mode |= WFD_MASK;
+#if !defined(WL_ENABLE_P2P_IF)
+                       /* ICS back capability : disable any packet filtering for p2p only mode */
+                       dhd_pkt_filter_enable = FALSE;
+#endif /*!defined(WL_ENABLE_P2P_IF) */
                }
        }
 #endif
@@ -3098,16 +3118,20 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #if defined(ARP_OFFLOAD_SUPPORT)
                                arpoe = 0;
 #endif /* (ARP_OFFLOAD_SUPPORT) */
+                               /* disable any filtering for SoftAP mode */
                                dhd_pkt_filter_enable = FALSE;
                        }
        }
 #endif
 
+#if !defined(WL_ENABLE_P2P_IF)
+       /* ICS mode setting for sta */
        if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
                /* STA only operation mode */
                dhd->op_mode |= STA_MASK;
                dhd_pkt_filter_enable = TRUE;
        }
+#endif /* !defined(WL_ENABLE_P2P_IF) */
 
        DHD_ERROR(("Firmware up: op_mode=%d, "
                        "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
@@ -3260,6 +3284,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        dhd->pktfilter[1] = NULL;
        dhd->pktfilter[2] = NULL;
        dhd->pktfilter[3] = NULL;
+       /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
        dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
 #if defined(SOFTAP)
        if (ap_fw_loaded) {
@@ -4446,6 +4471,17 @@ dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
        return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
 }
 
+/* Linux wrapper to call common dhd_pno_set_ex */
+int
+dhd_dev_pno_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
+       ushort  pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time)
+{
+       dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+       return (dhd_pno_set_ex(&dhd->pub, ssidnet, nssid,
+                                       pno_interval, pno_repeat, pno_expo_max, pno_lost_time));
+}
+
 /* Linux wrapper to get  pno status */
 int
 dhd_dev_get_pno_status(struct net_device *dev)
index 287f1c6..cdfc5fe 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmdevs.h 295140 2011-11-09 17:22:01Z $
+ * $Id: bcmdevs.h 332966 2012-05-11 22:40:21Z $
  */
 
 
 #define BFL2_EXTLNA_TX         0x08000000  
                                                
 #define BFL2_4313_RADIOREG     0x10000000
+#define BFL2_SECI_LOPWR_DIS    0x20000000  
                                                                           
 
 
index 3bff73e..5df25c1 100644 (file)
@@ -23,6 +23,7 @@
  *
 */
 
+
 #ifndef _epivers_h_
 #define _epivers_h_
 
 
 #define        EPI_RC_NUMBER           195
 
-#define        EPI_INCREMENTAL_NUMBER  61
+#define        EPI_INCREMENTAL_NUMBER  75
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             5, 90, 195, 61
+#define        EPI_VERSION             5, 90, 195, 75
 
-#define        EPI_VERSION_NUM         0x055ac33d
+#define        EPI_VERSION_NUM         0x055ac34b
 
 #define EPI_VERSION_DEV                5.90.195
 
 
-#define        EPI_VERSION_STR         "5.90.195.61"
+#define        EPI_VERSION_STR         "5.90.195.75"
 
 #endif 
index 69a834c..9bfc8c9 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: hndpmu.h 277737 2011-08-16 17:54:59Z $
+ * $Id: hndpmu.h 335486 2012-05-28 09:47:55Z $
  */
 
 #ifndef _hndpmu_h_
@@ -31,4 +31,7 @@
 extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on);
 extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength);
 
+extern void si_pmu_set_otp_wr_volts(si_t *sih);
+extern void si_pmu_set_otp_rd_volts(si_t *sih);
+
 #endif /* _hndpmu_h_ */
index 8f75750..aa4df44 100644 (file)
@@ -5,7 +5,7 @@
  * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
  * GPIO interface, extbus, and support for serial and parallel flashes.
  *
- * $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $
+ * $Id: sbchipc.h 333924 2012-05-18 04:48:52Z $
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
  * 
@@ -1441,17 +1441,17 @@ typedef volatile struct {
 #define CCTRL4331_EXT_LNA_G            (1<<2)  
 #define CCTRL4331_SPROM_GPIO13_15       (1<<3)  
 #define CCTRL4331_EXTPA_EN             (1<<4)  
-#define CCTRL4331_GPIOCLK_ON_SPROMCS   <1<<5)  
+#define CCTRL4331_GPIOCLK_ON_SPROMCS   (1<<5)  
 #define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6)  
 #define CCTRL4331_EXTPA_ON_GPIO2_5     (1<<7)  
 #define CCTRL4331_OVR_PIPEAUXCLKEN     (1<<8)  
 #define CCTRL4331_OVR_PIPEAUXPWRDOWN   (1<<9)  
-#define CCTRL4331_PCIE_AUXCLKEN                <1<<10) 
-#define CCTRL4331_PCIE_PIPE_PLLDOWN    <1<<11) 
+#define CCTRL4331_PCIE_AUXCLKEN                (1<<10) 
+#define CCTRL4331_PCIE_PIPE_PLLDOWN    (1<<11) 
 #define CCTRL4331_EXTPA_EN2            (1<<12) 
 #define CCTRL4331_EXT_LNA_A            (1<<13) 
-#define CCTRL4331_BT_SHD0_ON_GPIO4     <1<<16) 
-#define CCTRL4331_BT_SHD1_ON_GPIO5     <1<<17) 
+#define CCTRL4331_BT_SHD0_ON_GPIO4     (1<<16) 
+#define CCTRL4331_BT_SHD1_ON_GPIO5     (1<<17) 
 #define CCTRL4331_EXTPA_ANA_EN         (1<<24) 
 
 
index 6a7b93c..4e7aeb7 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: siutils.h 285387 2011-09-21 18:38:37Z $
+ * $Id: siutils.h 335486 2012-05-28 09:47:55Z $
  */
 
 
@@ -222,6 +222,8 @@ static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
 extern bool si_is_otp_disabled(si_t *sih);
 extern bool si_is_otp_powered(si_t *sih);
 extern void si_otp_power(si_t *sih, bool on);
+extern void si_set_otp_wr_volts(si_t *sih);
+extern void si_set_otp_rd_volts(si_t *sih);
 
 
 extern bool si_is_sprom_available(si_t *sih);
index 91274a0..891d15c 100644 (file)
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $
+ * $Id: wlioctl.h 331292 2012-05-04 09:04:23Z $
  */
 
 
@@ -1460,6 +1460,14 @@ typedef struct wl_sampledata {
 } wl_sampledata_t;
 
 
+#define WL_CHAN_VALID_HW    (1 << 0)    
+#define WL_CHAN_VALID_SW    (1 << 1)    
+#define WL_CHAN_BAND_5G     (1 << 2)    
+#define WL_CHAN_RADAR       (1 << 3)    
+#define WL_CHAN_INACTIVE    (1 << 4)    
+#define WL_CHAN_PASSIVE     (1 << 5)    
+#define WL_CHAN_RESTRICTED  (1 << 6)    
+
 
 #define WL_ERROR_VAL        0x00000001
 #define WL_TRACE_VAL        0x00000002
index 5b2ad9c..bee7d55 100644 (file)
@@ -231,6 +231,8 @@ static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
 static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data, bool completed);
+static s32 wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data, bool completed);
 static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
 static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
@@ -296,6 +298,7 @@ static void wl_free_wdev(struct wl_priv *wl);
 
 static s32 wl_inform_bss(struct wl_priv *wl);
 static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
+static s32 wl_inform_ibss(struct wl_priv *wl, const u8 *bssid);
 static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
 
@@ -335,7 +338,6 @@ static void wl_link_up(struct wl_priv *wl);
 static void wl_link_down(struct wl_priv *wl);
 static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
 static void wl_init_conf(struct wl_conf *conf);
-static s32 wl_update_wiphybands(struct wl_priv *wl);
 
 /*
  * iscan handler
@@ -704,7 +706,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
 
                *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
                if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
-                       sizeof(WL_EXTRA_BUF_MAX), false))) {
+                       WL_EXTRA_BUF_MAX, false))) {
                                WL_ERR(("Failed to get associated bss info, use temp channel \n"));
                                chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
                }
@@ -925,6 +927,11 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
 
        if (wl->p2p_supported) {
                memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
+
+               /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
+                */
+               WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
+               wl_clr_p2p_status(wl, GO_NEG_PHASE);
                if (wl->p2p->vif_created) {
                        if (wl_get_drv_status(wl, SCANNING, dev)) {
                                wl_notify_escan_complete(wl, dev, true, true);
@@ -1004,6 +1011,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
        default:
                return -EINVAL;
        }
+       WL_DBG(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type));
 
        if (ap) {
                wl_set_mode_by_netdev(wl, ndev, mode);
@@ -1019,7 +1027,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                         */
                        chspec = wl_cfg80211_get_shared_freq(wiphy);
 
-                       wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
+                       wlif_type = WL_P2P_IF_GO;
                        WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
                                ndev->name, ap, infra, type));
                        wl_set_p2p_status(wl, IF_CHANGING);
@@ -1043,6 +1051,14 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                        WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
                        return -EINVAL;
                }
+       } else {
+               infra = htod32(infra);
+               err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+               if (err) {
+                       WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+                       return -EAGAIN;
+               }
+               wl_set_mode_by_netdev(wl, ndev, mode);
        }
 
        ndev->ieee80211_ptr->iftype = type;
@@ -1587,6 +1603,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                                wl_cfgp2p_generate_bss_mac(&primary_mac,
                                                        &wl->p2p->dev_addr, &wl->p2p->int_addr);
                                        }
+                                       wl_clr_p2p_status(wl, GO_NEG_PHASE);
+                                       WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
                                        p2p_scan(wl) = true;
                                }
                        } else {
@@ -1625,10 +1643,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                                } else {
                                                        wpsie_len = 0;
                                                }
-                                               err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
-                                                       VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
-                                               if (unlikely(err)) {
-                                                       goto scan_out;
+                                               if (wpsie_len > 0) {
+                                                       err = wl_cfgp2p_set_management_ie(wl,
+                                                               ndev, -1, VNDR_IE_PRBREQ_FLAG,
+                                                               wpsie, wpsie_len);
+                                                       if (unlikely(err)) {
+                                                               goto scan_out;
+                                                       }
                                                }
                                        }
                                }
@@ -1808,86 +1829,192 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        struct cfg80211_ibss_params *params)
 {
        struct wl_priv *wl = wiphy_priv(wiphy);
-       struct cfg80211_bss *bss;
-       struct ieee80211_channel *chan;
        struct wl_join_params join_params;
-       struct cfg80211_ssid ssid;
-       s32 scan_retry = 0;
+       struct wlc_ssid ssid;
+       struct ether_addr bssid;
+       size_t join_params_size = 0;
+       s32 wsec = 0;
+       s32 bcnprd;
        s32 err = 0;
-       bool rollback_lock = false;
 
        WL_TRACE(("In\n"));
        CHECK_SYS_UP(wl);
-       if (params->bssid) {
-               WL_ERR(("Invalid bssid\n"));
-               return -EOPNOTSUPP;
-       }
-       bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
-       if (!bss) {
-               memcpy(ssid.ssid, params->ssid, params->ssid_len);
-               ssid.ssid_len = params->ssid_len;
-               do {
-                       if (unlikely
-                               (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
-                                -EBUSY)) {
-                               wl_delay(150);
-                       } else {
-                               break;
-                       }
-               } while (++scan_retry < WL_SCAN_RETRY_MAX);
-               /* to allow scan_inform to propagate to cfg80211 plane */
-               if (rtnl_is_locked()) {
-                       rtnl_unlock();
-                       rollback_lock = true;
-               }
-
-               /* wait 4 secons till scan done.... */
-               schedule_timeout_interruptible(4 * HZ);
-               if (rollback_lock)
-                       rtnl_lock();
-               bss = cfg80211_get_ibss(wiphy, NULL,
-                       params->ssid, params->ssid_len);
-       }
-       if (bss) {
-               wl->ibss_starter = false;
-               WL_DBG(("Found IBSS\n"));
-       } else {
-               wl->ibss_starter = true;
-       }
-       chan = params->channel;
-       if (chan)
-               wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+
        /*
-        * Join with specific BSSID and cached SSID
-        * If SSID is zero join based on BSSID only
+        * Cancel ongoing scan to sync up with sme state machine of cfg80211.
         */
-       memset(&join_params, 0, sizeof(join_params));
-       memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
-               params->ssid_len);
-       join_params.ssid.SSID_len = htod32(params->ssid_len);
+       if (wl->scan_request) {
+               wl_notify_escan_complete(wl, dev, true, true);
+       }
+       /* Clean BSSID */
+       bzero(&bssid, sizeof(bssid));
+       wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
+
+       if (params->ssid)
+               WL_INFO(("SSID: %s\n", params->ssid));
+       else {
+               WL_ERR(("SSID: NULL, Not supported\n"));
+               err = -EOPNOTSUPP;
+               goto CleanUp;
+       }
+
        if (params->bssid)
-               memcpy(&join_params.params.bssid, params->bssid,
-                       ETHER_ADDR_LEN);
+               WL_INFO(("BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+                       params->bssid[0], params->bssid[1], params->bssid[2],
+                       params->bssid[3], params->bssid[4], params->bssid[5]));
+
+       if (params->channel)
+               WL_INFO(("channel: %d\n", params->channel->center_freq));
+
+       if (params->channel_fixed)
+               WL_INFO(("fixed channel required\n"));
+
+       if (params->ie && params->ie_len)
+               WL_INFO(("ie len: %d\n", params->ie_len));
+
+       if (params->beacon_interval)
+               WL_INFO(("beacon interval: %d\n", params->beacon_interval));
+
+       if (params->basic_rates)
+               WL_INFO(("basic rates: %08X\n", params->basic_rates));
+
+       if (params->privacy)
+               WL_INFO(("privacy required\n"));
+
+       wl_set_drv_status(wl, CONNECTING, dev);
+
+       /* Configure Privacy for starter */
+       if (params->privacy)
+               wsec |= WEP_ENABLED;
+
+       err = wldev_iovar_setint(dev, "wsec", wsec);
+       if (err) {
+               WL_ERR(("wsec failed (%d)\n", err));
+               goto CleanUp;
+       }
+
+       err = wldev_iovar_setint(dev, "auth", WL_AUTH_OPEN_SYSTEM);
+       if (err) {
+               WL_ERR(("auth failed (%d)\n", err));
+               goto CleanUp;
+       }
+
+       err = wldev_iovar_setint(dev, "wpa_auth", 0);
+       if (err) {
+               WL_ERR(("wpa_auth failed (%d)\n", err));
+               goto CleanUp;
+       }
+
+       /* Configure Beacon Interval for starter */
+       if (params->beacon_interval)
+               bcnprd = params->beacon_interval;
        else
-               memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+               bcnprd = 100;
 
-       err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
-               sizeof(join_params), false);
-       if (unlikely(err)) {
-               WL_ERR(("Error (%d)\n", err));
-               return err;
+       bcnprd = htod32(bcnprd);
+       err = wldev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd), true);
+       if (err) {
+               WL_ERR(("WLC_SET_BCNPRD failed (%d)\n", err));
+               goto CleanUp;
+       }
+
+       /* Configure required join parameter */
+       memset(&join_params, 0, sizeof(struct wl_join_params));
+
+       /* SSID */
+       memset(&ssid, 0, sizeof(struct wlc_ssid));
+       ssid.SSID_len = MIN(params->ssid_len, 32);
+       join_params.ssid.SSID_len = htod32(ssid.SSID_len);
+       memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
+       memcpy(join_params.ssid.SSID, params->ssid, ssid.SSID_len);
+       join_params_size = sizeof(join_params.ssid);
+
+       wl_update_prof(wl, dev, NULL, &ssid, WL_PROF_SSID);
+
+       /* BSSID */
+       if (params->bssid) {
+               memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
+               join_params_size = sizeof(join_params.ssid) +
+                       WL_ASSOC_PARAMS_FIXED_SIZE;
+
+               wl_update_prof(wl, dev, NULL, params->bssid, WL_PROF_BSSID);
+       } else {
+               memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
        }
+
+       /* Channel */
+       if (params->channel) {
+               u32 target_channel;
+
+               target_channel = ieee80211_frequency_to_channel(
+                                                       params->channel->center_freq);
+               if (params->channel_fixed) {
+                       /* adding chanspec */
+                       wl_ch_to_chanspec(target_channel,
+                               &join_params, &join_params_size);
+               }
+
+               /* set channel for starter */
+               target_channel = htod32(target_channel);
+               err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+                       &target_channel, sizeof(target_channel), true);
+               if (err) {
+                       WL_ERR(("WLC_SET_CHANNEL failed (%d)\n", err));
+                       goto CleanUp;
+               }
+       }
+
+       wl->ibss_starter = false;
+
+       err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
+       if (err) {
+               WL_ERR(("WLC_SET_SSID failed (%d)\n", err));
+               goto CleanUp;
+       }
+
+CleanUp:
+
+       if (err)
+               wl_clr_drv_status(wl, CONNECTING, dev);
+
+       WL_TRACE(("Exit\n"));
        return err;
 }
 
 static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 {
        struct wl_priv *wl = wiphy_priv(wiphy);
+       scb_val_t scbval;
+       bool act = false;
        s32 err = 0;
+       u8 *curbssid;
+
+       WL_TRACE(("Enter\n"));
 
        CHECK_SYS_UP(wl);
-       wl_link_down(wl);
+       act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT);
+       curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID);
+       if (act) {
+               /*
+               * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+               */
+               if (wl->scan_request) {
+                       wl_notify_escan_complete(wl, dev, true, true);
+               }
+               wl_set_drv_status(wl, DISCONNECTING, dev);
+               scbval.val = DOT11_RC_DISASSOC_LEAVING;
+               memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+               scbval.val = htod32(scbval.val);
+               err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+                               sizeof(scb_val_t), true);
+               if (unlikely(err)) {
+                       wl_clr_drv_status(wl, DISCONNECTING, dev);
+                       WL_ERR(("error (%d)\n", err));
+                       return err;
+               }
+       }
 
+       WL_TRACE(("Exit\n"));
        return err;
 }
 
@@ -3436,8 +3563,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                        WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
                                bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
                                scb_val.val));
-                       /* Wait for the deauth event to come, supplicant will do the delete iface immediately
-                        * and we will have problem in sending deauth frame if we delete the bss in firmware
+                       /* Wait for the deauth event to come, supplicant will do the
+                        * delete iface immediately and we will have problem in sending
+                        * deauth frame if we delete the bss in firmware
                         */
                        wl_delay(400);
                        cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
@@ -3506,6 +3634,36 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n",
                        action_frame->len, af_params->channel,
                        act_frm->category, act_frm->subtype));
+               if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
+                 (act_frm->subtype == P2P_PAF_GON_RSP) ||
+                 (act_frm->subtype == P2P_PAF_GON_CONF) ||
+                 (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
+                       wldev_iovar_setint(dev, "mpc", 0);
+               }
+
+               if (act_frm->subtype == P2P_PAF_GON_REQ) {
+                       WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
+                       wl_set_p2p_status(wl, GO_NEG_PHASE);
+               } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
+                       /* If we reached till GO Neg confirmation
+                        * reset the filter
+                        */
+                       WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+                       wl_clr_p2p_status(wl, GO_NEG_PHASE);
+               }
+
+               if (act_frm->subtype == P2P_PAF_GON_RSP)
+                       retry_cnt = 1;
+               else retry_cnt = WL_ACT_FRAME_RETRY;
+
+               if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+                       af_params->dwell_time = WL_LONG_DWELL_TIME;
+               } else if (act_frm &&
+                       (act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
+                       act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
+                       act_frm->subtype == P2P_PAF_GON_RSP)) {
+                       af_params->dwell_time = WL_MED_DWELL_TIME;
+               }
        } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) {
                p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data);
                WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n",
@@ -3522,26 +3680,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        /*
         * To make sure to send successfully action frame, we have to turn off mpc
         */
-
-       if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
-         (act_frm->subtype == P2P_PAF_GON_RSP) ||
-         (act_frm->subtype == P2P_PAF_GON_CONF) ||
-         (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
-               wldev_iovar_setint(dev, "mpc", 0);
-       }
-       if (act_frm->subtype == P2P_PAF_GON_RSP)
-               retry_cnt = 1;
-       else retry_cnt = WL_ACT_FRAME_RETRY;
-
-       if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
-               af_params->dwell_time = WL_LONG_DWELL_TIME;
-       } else if (act_frm &&
-               (act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
-               act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
-               act_frm->subtype == P2P_PAF_GON_RSP)) {
-               af_params->dwell_time = WL_MED_DWELL_TIME;
-       }
-
        if (IS_P2P_SOCIAL(af_params->channel) &&
                (IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) ||
                IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
@@ -4245,7 +4383,7 @@ exit:
 #ifdef WL_SCHED_SCAN
 #define PNO_TIME       30
 #define PNO_REPEAT     4
-#define PNO_FREQ_EXPO_MAX      3
+#define PNO_FREQ_EXPO_MAX      2
 int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
                              struct net_device *dev,
                              struct cfg80211_sched_scan_request *request)
@@ -4589,8 +4727,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
                        kfree(notif_bss_info);
                        return err;
                }
+               else if( wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO) == NULL)
+               {
+                       WL_DBG(("Couldn't find P2P_SEID_DEV_INFO in probe response/beacon\n"));
+                       kfree(notif_bss_info);
+                       return err;
+               }
        }
-
        if (!mgmt->u.probe_resp.timestamp) {
                struct timeval tv;
 
@@ -4613,6 +4756,114 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
        return err;
 }
 
+static s32 wl_inform_ibss(struct wl_priv *wl, const u8 *bssid)
+{
+       struct net_device *ndev = wl_to_prmry_ndev(wl);
+       struct wiphy *wiphy = wl_to_wiphy(wl);
+       struct wl_bss_info *bi = NULL;
+       struct ieee80211_channel *notify_channel;
+       struct ieee80211_supported_band *band;
+       struct cfg80211_bss *bss;
+       s32 err = 0;
+       u16 channel;
+       u32 freq;
+       u32 wsec = 0;
+       u16 notify_capability;
+       u16 notify_interval;
+       u8 *notify_ie;
+       size_t notify_ielen;
+       s32 notify_signal;
+
+       WL_TRACE(("Enter\n"));
+
+       if (wl->scan_request) {
+               wl_notify_escan_complete(wl, ndev, true, true);
+       }
+
+       mutex_lock(&wl->usr_sync);
+
+       *(u32 *)wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+       err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, wl->extra_buf,
+                                       WL_EXTRA_BUF_MAX, false);
+       if (err) {
+               WL_ERR(("Failed to get bss info for IBSS\n"));
+               err = -EIO;
+               goto CleanUp;
+       }
+       bi = (struct wl_bss_info *)(wl->extra_buf + 4);
+
+       if (memcmp(bssid, &bi->BSSID, ETHER_ADDR_LEN)) {
+               WL_ERR(("BSSID mismatch: Inform %02x:%02x:%02x:%02x:%02x:%02x,"
+                                       "%02x:%02x:%02x:%02x:%02x:%02x\n",
+                                       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
+                                       bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+                                       bi->BSSID.octet[3], bi->BSSID.octet[4],
+                                       bi->BSSID.octet[5]));
+               err = -EINVAL;
+               goto CleanUp;
+       }
+
+       err = wldev_iovar_getint(ndev, "wsec", &wsec);
+       if (err) {
+               WL_ERR(("wsec failed: %d\n", err));
+               err = -EIO;
+               goto CleanUp;
+       }
+
+       channel = bi->ctl_ch ? bi->ctl_ch :
+                               CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+       if (channel <= CH_MAX_2G_CHANNEL)
+               band = wiphy->bands[IEEE80211_BAND_2GHZ];
+       else
+               band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+       freq = ieee80211_channel_to_frequency(channel);
+       (void)band->band;
+#else
+       freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+       notify_channel = ieee80211_get_channel(wiphy, freq);
+
+       notify_capability = dtoh16(bi->capability);
+       notify_interval = dtoh16(bi->beacon_period);
+       notify_ie = (u8 *)bi + dtoh16(bi->ie_offset);
+       notify_ielen = dtoh32(bi->ie_length);
+       notify_signal = (int16)dtoh16(bi->RSSI) * 100;
+
+       if (wl->p2p_supported) {
+               notify_capability |= DOT11_CAP_IBSS;
+               if (wsec)
+                       notify_capability |= DOT11_CAP_PRIVACY;
+       }
+
+       WL_DBG(("BSSID %02x:%02x:%02x:%02x:%02x:%02x",
+                       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]));
+       WL_INFO(("channel: %d(%d)\n", channel, freq));
+       WL_INFO(("capability: %X\n", notify_capability));
+       WL_INFO(("beacon interval: %d ms\n", notify_interval));
+       WL_INFO(("signal: %d dBm\n", notify_signal));
+       WL_INFO(("ie_len: %d\n", notify_ielen));
+       bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, 0,
+                               notify_capability, notify_interval,
+                               notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+       if (!bss) {
+               WL_ERR(("cfg80211_inform_bss() Failed\n"));
+               err = -ENOMEM;
+               goto CleanUp;
+       }
+
+       cfg80211_put_bss(bss);
+       err = 0;
+
+CleanUp:
+
+       mutex_unlock(&wl->usr_sync);
+
+       WL_TRACE(("Exit\n"));
+       return err;
+}
+
 static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
 {
        u32 event = ntoh32(e->event_type);
@@ -4622,12 +4873,12 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
        WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
        if (event == WLC_E_SET_SSID) {
                if (status == WLC_E_STATUS_SUCCESS) {
-                       if (!wl_is_ibssmode(wl, ndev))
-                               return true;
+                       return true;
                }
        } else if (event == WLC_E_LINK) {
                if (flags & WLC_EVENT_MSG_LINK)
-                       return true;
+                       if (!wl_is_ibssmode(wl, ndev))
+                               return true;
        }
 
        WL_DBG(("wl_is_linkup false\n"));
@@ -4808,7 +5059,9 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) {
                        reason = ntoh32(e->reason);
                        wl->deauth_reason = reason;
-                       WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
+                       WL_ERR(("Received %s event with reason code: %d\n",
+                       (event == WLC_E_DEAUTH_IND)?
+                       "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
                }
                if (wl_is_linkup(wl, e, ndev)) {
                        wl_link_up(wl);
@@ -4817,10 +5070,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                        wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
                        wl->deauth_reason = 0;
                        if (wl_is_ibssmode(wl, ndev)) {
-                               printk("cfg80211_ibss_joined\n");
-                               cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
-                                       GFP_KERNEL);
-                               WL_DBG(("joined in IBSS network\n"));
+                               wl_ibss_join_done(wl, ndev, e, data, true);
+                               WL_DBG(("wl_ibss_join_done succeeded\n"));
                        } else {
                                if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
                                        printk("wl_bss_connect_done succeeded\n");
@@ -4830,7 +5081,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                                         wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
                                }
                        }
-
                } else if (wl_is_linkdown(wl, e)) {
                        if (wl->scan_request) {
                                if (wl->escan_on) {
@@ -4854,15 +5104,21 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                                        scbval.val = htod32(scbval.val);
                                        wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
                                                sizeof(scb_val_t), true);
-                                       WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason));
-                                       cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL);
+                                       WL_ERR(("link down, calling cfg80211_disconnected"
+                                       " with deauth_reason:%d\n", wl->deauth_reason));
+                                       if (!wl_is_ibssmode(wl, ndev))
+                                               cfg80211_disconnected(ndev, wl->deauth_reason,
+                                                       NULL, 0, GFP_KERNEL);
                                        wl_link_down(wl);
                                        wl_init_prof(wl, ndev);
                                }
                        }
                        else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
                                printk("link down, during connecting\n");
-                               wl_bss_connect_done(wl, ndev, e, data, false);
+                               if (wl_is_ibssmode(wl, ndev))
+                                       wl_ibss_join_done(wl, ndev, e, data, false);
+                               else
+                                       wl_bss_connect_done(wl, ndev, e, data, false);
                        }
                        wl_clr_drv_status(wl, DISCONNECTING, ndev);
 
@@ -5158,6 +5414,35 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
 }
 
 static s32
+wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data, bool completed)
+{
+       s32 err = 0;
+
+       WL_TRACE(("Enter\n"));
+
+       if (wl->scan_request) {
+               wl_notify_escan_complete(wl, ndev, true, true);
+       }
+       if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+               wl_clr_drv_status(wl, CONNECTING, ndev);
+               if (completed) {
+                       err = wl_inform_ibss(wl, (u8 *)&e->addr);
+                       if (err) {
+                               WL_ERR(("wl_inform_ibss() failed: %d\n", err));
+                       }
+                       wl_set_drv_status(wl, CONNECTED, ndev);
+
+                       cfg80211_ibss_joined(ndev, (u8 *)&e->addr, GFP_KERNEL);
+                       WL_DBG(("cfg80211_ibss_joined() called with valid BSSID\n"));
+               }
+       }
+
+       WL_TRACE(("Exit\n"));
+       return err;
+}
+
+static s32
 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data)
 {
@@ -5339,6 +5624,13 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
                WL_ERR(("No valid band"));
                return -EINVAL;
        }
+
+       if ((event == WLC_E_P2P_PROBREQ_MSG) &&
+               wl->p2p && wl_get_p2p_status(wl, GO_NEG_PHASE)) {
+               WL_DBG(("Filtering P2P probe_req while being in GO-Neg state\n"));
+               goto exit;
+       }
+
 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
        freq = ieee80211_channel_to_frequency(channel);
 #else
@@ -5383,6 +5675,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
                        (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
                        wldev_iovar_setint(dev, "mpc", 1);
                }
+
+               if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
+                       WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+                       wl_clr_p2p_status(wl, GO_NEG_PHASE);
+               }
        } else {
                mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
        }
@@ -6060,7 +6357,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
 
                if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
                        if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
-                               WL_ERR(("Ignoring IBSS result\n"));
+                               WL_DBG(("Ignoring IBSS result\n"));
                                goto exit;
                        }
                }
@@ -6695,20 +6992,148 @@ eventmsg_out:
 
 }
 
+static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
+{
+       struct net_device *dev = wl_to_prmry_ndev(wl);
+       struct ieee80211_channel *band_chan_arr = NULL;
+       wl_uint32_list_t *list;
+       u32 i, j, index, n_2g, n_5g, band, channel, array_size;
+       u32 *n_cnt = NULL;
+       chanspec_t c = 0;
+       s32 err = BCME_OK;
+       bool update;
+       bool ht40_allowed;
+       u8 *pbuf = NULL;
+
+#define LOCAL_BUF_LEN 1024
+       pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
+       if (pbuf == NULL) {
+               WL_ERR(("failed to allocate local buf\n"));
+               return -ENOMEM;
+       }
+
+       list = (wl_uint32_list_t *)(void *)pbuf;
+       list->count = htod32(WL_NUMCHANSPECS);
+
+       err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+               0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync);
+       if (err != 0) {
+               WL_ERR(("get chanspecs failed with %d\n", err));
+               kfree(pbuf);
+               return err;
+       }
+#undef LOCAL_BUF_LEN
+
+       band = array_size = n_2g = n_5g = 0;
+       for (i = 0; i < dtoh32(list->count); i++) {
+               index = 0;
+               update = FALSE;
+               ht40_allowed = FALSE;
+               c = (chanspec_t)dtoh32(list->element[i]);
+               channel = CHSPEC_CHANNEL(c);
+               if (CHSPEC_IS40(c)) {
+                       if (CHSPEC_SB_UPPER(c))
+                               channel += CH_10MHZ_APART;
+                       else
+                               channel -= CH_10MHZ_APART;
+               }
+
+               if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) {
+                       band_chan_arr = __wl_2ghz_channels;
+                       array_size = ARRAYSIZE(__wl_2ghz_channels);
+                       n_cnt = &n_2g;
+                       band = IEEE80211_BAND_2GHZ;
+                       ht40_allowed = (bw_cap == WLC_N_BW_40ALL) ? TRUE : FALSE;
+               } else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) {
+                       band_chan_arr = __wl_5ghz_a_channels;
+                       array_size = ARRAYSIZE(__wl_5ghz_a_channels);
+                       n_cnt = &n_5g;
+                       band = IEEE80211_BAND_5GHZ;
+                       ht40_allowed = (bw_cap == WLC_N_BW_20ALL) ? FALSE : TRUE;
+               }
+
+               for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+                       if (band_chan_arr[j].hw_value == channel) {
+                               update = TRUE;
+                               break;
+                       }
+               }
+
+               if (update)
+                       index = j;
+               else
+                       index = *n_cnt;
+
+               if (index <  array_size) {
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+                       band_chan_arr[index].center_freq =
+                               ieee80211_channel_to_frequency(channel);
+#else
+                       band_chan_arr[index].center_freq =
+                               ieee80211_channel_to_frequency(channel, band);
+#endif
+                       band_chan_arr[index].hw_value = channel;
+
+                       if (CHSPEC_IS40(c) && ht40_allowed) {
+                               u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
+                               if (CHSPEC_SB_UPPER(c)) {
+                                       if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+                                               band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+                                       band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
+                               } else {
+                                       band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+                                       if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+                                               band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40MINUS;
+                               }
+                       } else {
+                               band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
+                               if (band == IEEE80211_BAND_2GHZ)
+                                       channel |= WL_CHANSPEC_BAND_2G;
+                               else
+                                       channel |= WL_CHANSPEC_BAND_5G;
+                               err = wldev_iovar_getint(dev, "per_chan_info", &channel);
+                               if (!err) {
+                                       if (channel & WL_CHAN_RADAR) {
+                                               band_chan_arr[index].flags |= IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS;
+                                       }
+                                       if (channel & WL_CHAN_PASSIVE) {
+                                               band_chan_arr[index].flags |= IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS;
+                                       }
+                               }
+                       }
+
+                       if (!update)
+                               (*n_cnt)++;
+               }
+       }
+
+       __wl_band_2ghz.n_channels = n_2g;
+       __wl_band_5ghz_a.n_channels = n_5g;
+
+       kfree(pbuf);
+       return err;
+}
+
 s32 wl_update_wiphybands(struct wl_priv *wl)
 {
        struct wiphy *wiphy;
+       struct net_device *dev;
        u32 bandlist[3];
        u32 nband = 0;
        u32 i = 0;
        s32 err = 0;
        int nmode = 0;
-       int bw_40 = 0;
+       int bw_cap = 0;
        int index = 0;
 
        WL_DBG(("Entry"));
+
+       if (wl == NULL)
+               wl = wlcfg_drv_priv;
+       dev = wl_to_prmry_ndev(wl);
+
        memset(bandlist, 0, sizeof(bandlist));
-       err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+       err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
                sizeof(bandlist), false);
        if (unlikely(err)) {
                WL_ERR(("error read bandlist (%d)\n", err));
@@ -6719,13 +7144,12 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
        wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
        wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
 
-       err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode);
+       err = wldev_iovar_getint(dev, "nmode", &nmode);
        if (unlikely(err)) {
                WL_ERR(("error reading nmode (%d)\n", err));
-       }
-       else {
+       } else {
                /* For nmodeonly  check bw cap */
-               err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40);
+               err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
                if (unlikely(err)) {
                        WL_ERR(("error get mimo_bw_cap (%d)\n", err));
                }
@@ -6751,7 +7175,7 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
                        wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
                }
 
-               if ((index >= 0) && bw_40) {
+               if ((index >= 0) && bw_cap) {
                        wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
                }
        }
@@ -7080,8 +7504,7 @@ static void wl_init_eq_lock(struct wl_priv *wl)
 
 static void wl_delay(u32 ms)
 {
-       if (ms < 1000 / HZ) {
-               cond_resched();
+       if (in_atomic() || ms < 1000 / HZ) {
                mdelay(ms);
        } else {
                msleep(ms);
index fba8531..37c8e58 100644 (file)
@@ -136,6 +136,12 @@ do {                                                                       \
 
 #define WL_INVALID             -1
 
+
+/* Bring down SCB Timeout to 20secs from 60secs default */
+#ifndef WL_SCB_TIMEOUT
+#define WL_SCB_TIMEOUT 20
+#endif
+
 /* driver status */
 enum wl_status {
        WL_STATUS_READY = 0,
@@ -662,5 +668,6 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
 extern s32 wl_mode_to_nl80211_iftype(s32 mode);
 int wl_cfg80211_do_driver_init(struct net_device *net);
 void wl_cfg80211_enable_trace(int level);
+extern s32 wl_update_wiphybands(struct wl_priv *wl);
 extern s32 wl_cfg80211_if_is_group_owner(void);
 #endif                         /* _wl_cfg80211_h_ */
index cfa5ac3..a902666 100644 (file)
@@ -59,6 +59,8 @@ static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
 static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
 static int wl_cfgp2p_if_open(struct net_device *net);
 static int wl_cfgp2p_if_stop(struct net_device *net);
+static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
+       bool notify);
 
 static const struct net_device_ops wl_cfgp2p_if_ops = {
        .ndo_open               = wl_cfgp2p_if_open,
@@ -338,6 +340,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 *ndev = wl_to_prmry_ndev(wl);
+       u32 scb_timeout = WL_SCB_TIMEOUT;
 
        ifreq.type = if_type;
        ifreq.chspec = chspec;
@@ -351,6 +354,15 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
 
        err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
                wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
+
+       if (unlikely(err < 0)) {
+               printk("'wl p2p_ifadd' error %d\n", err);
+       } else if (if_type == WL_P2P_IF_GO) {
+               err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+               if (unlikely(err < 0))
+                       printk("'wl scb_timeout' error %d\n", err);
+       }
+
        return err;
 }
 
@@ -387,6 +399,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
 {
        wl_p2p_if_t ifreq;
        s32 err;
+       u32 scb_timeout = WL_SCB_TIMEOUT;
        struct net_device *netdev =  wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
 
        ifreq.type = if_type;
@@ -404,6 +417,10 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
 
        if (unlikely(err < 0)) {
                printk("'wl p2p_ifupd' error %d\n", err);
+       } else if (if_type == WL_P2P_IF_GO) {
+               err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+               if (unlikely(err < 0))
+                       printk("'wl scb_timeout' error %d\n", err);
        }
        return err;
 }
@@ -1219,7 +1236,7 @@ wl_cfgp2p_listen_expired(unsigned long data)
 /*
  *  Routine for cancelling the P2P LISTEN
  */
-s32
+static s32
 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
                          bool notify)
 {
index be497c3..05323ed 100644 (file)
@@ -42,7 +42,7 @@ typedef enum {
        P2PAPI_BSSCFG_MAX
 } p2p_bsscfg_type_t;
 
-#define IE_MAX_LEN 300
+#define IE_MAX_LEN 512
 /* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
 struct p2p_saved_ie {
        u8  p2p_probe_req_ie[IE_MAX_LEN];
@@ -91,7 +91,8 @@ enum wl_cfgp2p_status {
        WLP2P_STATUS_LISTEN_EXPIRED,
        WLP2P_STATUS_ACTION_TX_COMPLETED,
        WLP2P_STATUS_ACTION_TX_NOACK,
-       WLP2P_STATUS_SCANNING
+       WLP2P_STATUS_SCANNING,
+       WLP2P_STATUS_GO_NEG_PHASE
 };