bcmdhd_88: add cfg80211 vendor command support
Om Prakash Singh [Wed, 23 Sep 2015 12:18:53 +0000 (17:18 +0530)]
add change to support vendor command:
 ANDR_WIFI_SET_COUNTRY
 GSCAN_SUBCMD_GET_CHANNEL_LIST
 WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
 WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
 BRCM_VENDOR_SCMD_PRIV_STR

This code is copied from below source
https://android.googlesource.com/kernel/common
branch: bcmdhd-3.10

Bug 200141562
Change-Id: I732df79fc68cee849d97823e6aca518ed77bbef3
Signed-off-by: Ecco Park <eccopark@broadcom.com>
Signed-off-by: Ashwin <ashwin.bhat@broadcom.com>
Signed-off-by: Om Prakash Singh <omp@nvidia.com>
Reviewed-on: http://git-master/r/805711
GVS: Gerrit_Virtual_Submit
Reviewed-by: Kasturi Raghavender <kraghavender@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

drivers/net/wireless/bcmdhd_88/Makefile
drivers/net/wireless/bcmdhd_88/dhd.h
drivers/net/wireless/bcmdhd_88/dhd_linux.c
drivers/net/wireless/bcmdhd_88/dhd_pno.c
drivers/net/wireless/bcmdhd_88/dhd_pno.h
drivers/net/wireless/bcmdhd_88/wl_cfg80211.c
drivers/net/wireless/bcmdhd_88/wl_cfgvendor.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd_88/wl_cfgvendor.h [new file with mode: 0644]

index 62ebe30..7763c49 100644 (file)
@@ -18,6 +18,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER                 \
        -Idrivers/net/wireless/bcmdhd_88/include
 
 DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT
+DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT
 # for < K3.8
 #DHDCFLAGS += -DWL_ENABLE_P2P_IF -DWL_IFACE_COMB_NUM_CHANNELS
 # for >= K3.8
@@ -117,7 +118,7 @@ DHDOFILES = bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \
        dhd_linux.o dhd_linux_sched.o dhd_pno.o dhd_sdio.o dhd_wlfc.o       \
        aiutils.o bcmevent.o bcmutils.o bcmwifi_channels.o hndpmu.o         \
        linux_osl.o sbutils.o siutils.o wldev_common.o wl_android.o         \
-       wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
+       wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfgvendor.o
 
 ifneq ($(findstring QMONITOR, $(DHDCFLAGS)),)
  DHDOFILES += dhd_qmon.o
index a19e2cd..00283ca 100644 (file)
@@ -597,6 +597,12 @@ extern int dhd_set_packet_filter_ports(struct net_device *dev, char *command);
 extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
 extern bool dhd_support_sta_mode(dhd_pub_t *dhd);
 
+#if defined(KEEP_ALIVE)
+extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt,
+       u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec);
+extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id);
+#endif /* defined(KEEP_ALIVE) */
+
 #ifdef DHD_DEBUG
 extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
 #endif /* DHD_DEBUG */
index e11a681..6f01d74 100644 (file)
@@ -5981,8 +5981,250 @@ dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
        return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
 }
+
+/* Linux wrapper to call common dhd_pno_get_gscan */
+void *
+dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type,
+       void *info, uint32 *len)
+{
+       dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+       return (dhd_pno_get_gscan(&dhd->pub, type, info, len));
+}
 #endif /* PNO_SUPPORT */
 
+#if defined(KEEP_ALIVE)
+#define TEMP_BUF_SIZE 512
+#define FRAME_SIZE 300
+int
+dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len,
+       u8* src_mac, u8* dst_mac, u32 period_msec)
+{
+       const int               ETHERTYPE_LEN = 2;
+       char                    *pbuf;
+       const char              *str;
+       wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0};
+       wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+       int                     buf_len;
+       int                     str_len;
+       int                     res = BCME_ERROR;
+       int                     len_bytes = 0;
+       int                     i;
+
+       /* ether frame to have both max IP pkt (256 bytes) and ether header */
+       char                    *pmac_frame = NULL;
+       char                    *pmac_frame_begin = NULL;
+
+       /*
+        * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
+        * dongle shall reject a mkeep_alive request.
+        */
+       if (!dhd_support_sta_mode(dhd_pub))
+               return res;
+
+       DHD_TRACE(("%s execution\n", __FUNCTION__));
+
+       if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) {
+               DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE));
+               res = BCME_NOMEM;
+               return res;
+       }
+
+       if ((pmac_frame = kzalloc(FRAME_SIZE, GFP_KERNEL)) == NULL) {
+               DHD_ERROR(("failed to allocate mac_frame with size %d\n", FRAME_SIZE));
+               res = BCME_NOMEM;
+               goto exit;
+       }
+       pmac_frame_begin = pmac_frame;
+
+       /*
+        * Get current mkeep-alive status.
+        */
+       bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id),
+                    pbuf, TEMP_BUF_SIZE);
+
+       if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE,
+                                   FALSE, 0)) < 0) {
+               DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
+               goto exit;
+       } else {
+               /* Check available ID whether it is occupied */
+               mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
+               if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
+                       DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n",
+                               __FUNCTION__, mkeep_alive_id));
+
+                       /* Current occupied ID info */
+                       DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__));
+                       DHD_ERROR(("   Id    : %d\n"
+                                  "   Period: %d msec\n"
+                                  "   Length: %d\n"
+                                  "   Packet: 0x",
+                               mkeep_alive_pktp->keep_alive_id,
+                               dtoh32(mkeep_alive_pktp->period_msec),
+                               dtoh16(mkeep_alive_pktp->len_bytes)));
+
+                       for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
+                               DHD_ERROR(("%02x", mkeep_alive_pktp->data[i]));
+                       }
+                       DHD_ERROR(("\n"));
+
+                       res = BCME_NOTFOUND;
+                       goto exit;
+               }
+       }
+
+       /* Request the specified ID */
+       memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
+       memset(pbuf, 0, TEMP_BUF_SIZE);
+       str = "mkeep_alive";
+       str_len = strlen(str);
+       strncpy(pbuf, str, str_len);
+       pbuf[str_len] = '\0';
+
+       mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1);
+       mkeep_alive_pkt.period_msec = htod32(period_msec);
+       buf_len = str_len + 1;
+       mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
+       mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+
+       /* ID assigned */
+       mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
+
+       buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+
+       /*
+        * Build up Ethernet Frame
+        */
+
+       /* Mapping dest mac addr */
+       memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN);
+       pmac_frame += ETHER_ADDR_LEN;
+
+       /* Mapping src mac addr */
+       memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN);
+       pmac_frame += ETHER_ADDR_LEN;
+
+       /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */
+       *(pmac_frame++) = 0x08;
+       *(pmac_frame++) = 0x00;
+
+       /* Mapping IP pkt */
+       memcpy(pmac_frame, ip_pkt, ip_pkt_len);
+       pmac_frame += ip_pkt_len;
+
+       /*
+        * Length of ether frame (assume to be all hexa bytes)
+        *     = src mac + dst mac + ether type + ip pkt len
+        */
+       len_bytes = ETHER_ADDR_LEN*2 + ETHERTYPE_LEN + ip_pkt_len;
+       memcpy(mkeep_alive_pktp->data, pmac_frame_begin, len_bytes);
+       buf_len += len_bytes;
+       mkeep_alive_pkt.len_bytes = htod16(len_bytes);
+
+       /*
+        * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
+        * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
+        * guarantee that the buffer is properly aligned.
+        */
+       memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
+
+       res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0);
+exit:
+       kfree(pmac_frame_begin);
+       kfree(pbuf);
+       return res;
+}
+
+int
+dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id)
+{
+       char                    *pbuf;
+       const char              *str;
+       wl_mkeep_alive_pkt_t    mkeep_alive_pkt;
+       wl_mkeep_alive_pkt_t    *mkeep_alive_pktp;
+       int                     buf_len;
+       int                     str_len;
+       int                     res = BCME_ERROR;
+       int                     i;
+
+       /*
+        * The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
+        * dongle shall reject a mkeep_alive request.
+        */
+       if (!dhd_support_sta_mode(dhd_pub))
+               return res;
+
+       DHD_TRACE(("%s execution\n", __FUNCTION__));
+
+       /*
+        * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt.
+        */
+       if ((pbuf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) {
+               DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE));
+               return res;
+       }
+
+       bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE);
+
+       if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, FALSE, 0)) < 0) {
+               DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res));
+               goto exit;
+       } else {
+               /* Check occupied ID */
+               mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf;
+               DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__));
+               DHD_INFO(("   Id    : %d\n"
+                         "   Period: %d msec\n"
+                         "   Length: %d\n"
+                         "   Packet: 0x",
+                       mkeep_alive_pktp->keep_alive_id,
+                       dtoh32(mkeep_alive_pktp->period_msec),
+                       dtoh16(mkeep_alive_pktp->len_bytes)));
+
+               for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) {
+                       DHD_INFO(("%02x", mkeep_alive_pktp->data[i]));
+               }
+               DHD_INFO(("\n"));
+       }
+
+       /* Make it stop if available */
+       if (dtoh32(mkeep_alive_pktp->period_msec != 0)) {
+               DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id));
+               memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
+               memset(pbuf, 0, TEMP_BUF_SIZE);
+               str = "mkeep_alive";
+               str_len = strlen(str);
+               strncpy(pbuf, str, str_len);
+               pbuf[str_len] = '\0';
+
+               mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1);
+
+               mkeep_alive_pkt.period_msec = 0;
+               buf_len = str_len + 1;
+               mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
+               mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
+               mkeep_alive_pkt.keep_alive_id = mkeep_alive_id;
+               buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+
+               /*
+                * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
+                * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
+                * guarantee that the buffer is properly aligned.
+                */
+               memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
+
+               res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0);
+       } else {
+               DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id));
+               res = BCME_NOTFOUND;
+       }
+exit:
+       kfree(pbuf);
+       return res;
+}
+#endif /* defined(KEEP_ALIVE) */
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
 static void dhd_hang_process(struct work_struct *work)
 {
index 165df80..47629e0 100644 (file)
@@ -1776,6 +1776,87 @@ exit:
        return err;
 }
 
+void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
+                          void *info, uint32 *len)
+{
+       void *ret = NULL;
+       dhd_pno_gscan_capabilities_t *ptr;
+       dhd_epno_params_t *epno_params;
+       dhd_pno_params_t *_params;
+       dhd_pno_status_info_t *_pno_state;
+
+       if (!dhd || !dhd->pno_state) {
+               DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__));
+               return NULL;
+       }
+       _pno_state = PNO_GET_PNOSTATE(dhd);
+       _params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+       if (!len) {
+               DHD_ERROR(("%s: len is NULL\n", __FUNCTION__));
+               return NULL;
+       }
+
+       switch (type) {
+               case DHD_PNO_GET_CHANNEL_LIST:
+                       if (info) {
+                               uint16 ch_list[WL_NUMCHANNELS];
+                               uint32 *ptr, mem_needed, i;
+                               int32 err, nchan = WL_NUMCHANNELS;
+                               uint32 *gscan_band = (uint32 *) info;
+                               uint8 band = 0;
+
+                               /* No band specified?, nothing to do */
+                               if ((*gscan_band & GSCAN_BAND_MASK) == 0) {
+                                       DHD_PNO(("No band specified\n"));
+                                       *len = 0;
+                                       break;
+                               }
+
+                               /* HAL and DHD use different bits for 2.4G and
+                                * 5G in bitmap. Hence translating it here...
+                                */
+                               if (*gscan_band & GSCAN_BG_BAND_MASK)
+                                       band |= WLC_BAND_2G;
+                               if (*gscan_band & GSCAN_A_BAND_MASK)
+                                       band |= WLC_BAND_5G;
+
+                               err = _dhd_pno_get_channels(dhd, ch_list, &nchan,
+                                                         (band & GSCAN_ABG_BAND_MASK),
+                                                         !(*gscan_band & GSCAN_DFS_MASK));
+
+                               if (err < 0) {
+                                       DHD_ERROR(("%s: failed to get valid channel list\n",
+                                               __FUNCTION__));
+                                       *len = 0;
+                               } else {
+                                       mem_needed = sizeof(uint32) * nchan;
+                                       ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL);
+                                       if (!ptr) {
+                                               DHD_ERROR(("%s: Unable to malloc %d bytes\n",
+                                                       __FUNCTION__, mem_needed));
+                                               break;
+                                       }
+                                       for (i = 0; i < nchan; i++) {
+                                               ptr[i] = wf_channel2mhz(ch_list[i],
+                                                       (ch_list[i] <= CH_MAX_2G_CHANNEL?
+                                                       WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+                                       }
+                                       ret = ptr;
+                                       *len = mem_needed;
+                               }
+                       } else {
+                               *len = 0;
+                               DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__));
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       return ret;
+
+}
+
 int
 dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
 {
index 769cdb9..186a5a1 100644 (file)
 #define SCAN_END_MARKER "####\n"
 #define AP_END_MARKER "====\n"
 
+#define GSCAN_MAX_CH_BUCKETS                    8
+#define GSCAN_MAX_CHANNELS_IN_BUCKET    32
+#define GSCAN_MAX_AP_CACHE_PER_SCAN             32
+#define GSCAN_MAX_AP_CACHE                              320
+#define GSCAN_BG_BAND_MASK                        (1 << 0)
+#define GSCAN_A_BAND_MASK                         (1 << 1)
+#define GSCAN_DFS_MASK                            (1 << 2)
+#define GSCAN_ABG_BAND_MASK                       (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK)
+#define GSCAN_BAND_MASK                                   (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK)
+
+#define GSCAN_FLUSH_HOTLIST_CFG                 (1 << 0)
+#define GSCAN_FLUSH_SIGNIFICANT_CFG  (1 << 1)
+#define GSCAN_FLUSH_SCAN_CFG            (1 << 2)
+#define GSCAN_FLUSH_EPNO_CFG            (1 << 3)
+#define GSCAN_FLUSH_ALL_CFG            (GSCAN_FLUSH_SCAN_CFG | \
+                                                                                                                               GSCAN_FLUSH_SIGNIFICANT_CFG | \
+                                                                                                                               GSCAN_FLUSH_HOTLIST_CFG  | \
+                                                                                                                               GSCAN_FLUSH_EPNO_CFG)
+#define DHD_EPNO_HIDDEN_SSID             (1 << 0)
+#define DHD_EPNO_A_BAND_TRIG             (1 << 1)
+#define DHD_EPNO_BG_BAND_TRIG            (1 << 2)
+#define DHD_EPNO_STRICT_MATCH            (1 << 3)
+#define DHD_PNO_USE_SSID                         (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH)
+
+/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */
+#define GSCAN_BATCH_RETRIEVAL_COMPLETE         0
+#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS      1
+#define GSCAN_BATCH_NO_THR_SET                         101
+#define GSCAN_LOST_AP_WINDOW_DEFAULT           4
+#define GSCAN_MIN_BSSID_TIMEOUT                                90
+#define GSCAN_BATCH_GET_MAX_WAIT                       500
+
+#define CHANNEL_BUCKET_EMPTY_INDEX                                             0xFFFF
+#define GSCAN_RETRY_THRESHOLD                     3
+#define MAX_EPNO_SSID_NUM                                      32
+
 enum scan_status {
        /* SCAN ABORT by other scan */
        PNO_STATUS_ABORT,
@@ -81,8 +117,10 @@ enum index_mode {
        INDEX_OF_LEGACY_PARAMS,
        INDEX_OF_BATCH_PARAMS,
        INDEX_OF_HOTLIST_PARAMS,
+       INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS,
        INDEX_MODE_MAX
 };
+
 enum dhd_pno_status {
        DHD_PNO_DISABLED,
        DHD_PNO_ENABLED,
@@ -201,6 +239,43 @@ typedef struct dhd_pno_status_info {
        struct list_head head_list;
 } dhd_pno_status_info_t;
 
+typedef enum dhd_pno_gscan_cmd_cfg {
+       DHD_PNO_BATCH_SCAN_CFG_ID,
+       DHD_PNO_GEOFENCE_SCAN_CFG_ID,
+       DHD_PNO_SIGNIFICANT_SCAN_CFG_ID,
+       DHD_PNO_SCAN_CFG_ID,
+       DHD_PNO_GET_CAPABILITIES,
+       DHD_PNO_GET_BATCH_RESULTS,
+       DHD_PNO_GET_CHANNEL_LIST,
+       DHD_PNO_GET_EPNO_SSID_ELEM,
+       DHD_PNO_EPNO_CFG_ID,
+       DHD_PNO_GET_AUTOJOIN_CAPABILITIES
+} dhd_pno_gscan_cmd_cfg_t;
+
+typedef struct dhd_pno_gscan_capabilities {
+       int max_scan_cache_size;
+       int max_scan_buckets;
+       int max_ap_cache_per_scan;
+       int max_rssi_sample_size;
+       int max_scan_reporting_threshold;
+       int max_hotlist_aps;
+       int max_significant_wifi_change_aps;
+       int max_epno_ssid_crc32;
+       int max_epno_hidden_ssid;
+       int max_white_list_ssid;
+} dhd_pno_gscan_capabilities_t;
+
+typedef struct dhd_epno_params {
+       uint8 ssid[DOT11_MAX_SSID_LEN];
+       uint8 ssid_len;
+       int8 rssi_thresh;
+       uint8 flags;
+       uint8 auth;
+       /* index required only for visble ssid */
+       uint32 index;
+       struct list_head list;
+} dhd_epno_params_t;
+
 /* wrapper functions */
 extern int
 dhd_dev_pno_enable(struct net_device *dev, int enable);
@@ -230,7 +305,7 @@ dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
 extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd);
 extern int dhd_pno_enable(dhd_pub_t *dhd, int enable);
 extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid,
-       uint16  scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan);
+       uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan);
 
 extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params);
 
@@ -243,6 +318,11 @@ extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid,
        struct dhd_pno_hotlist_params *hotlist_params);
 
 extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd);
+extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info,
+                       uint32 *len);
+extern void *
+dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info,
+               uint32 *len);
 
 extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
 extern int dhd_pno_init(dhd_pub_t *dhd);
index 9573ab1..54593f7 100644 (file)
 #include <dhd_wlfc.h>
 #endif
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+#include <wl_cfgvendor.h>
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+
 #ifdef CONFIG_BCMDHD_CUSTOM_SYSFS_TEGRA
 #include "dhd_custom_sysfs_tegra.h"
 #endif
@@ -6811,6 +6815,15 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev
        WL_DBG(("Registering custom regulatory)\n"));
        wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
        wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+       WL_ERR(("Registering Vendor80211\n"));
+       err = wl_cfgvendor_attach(wdev->wiphy, dhd);
+       if (unlikely(err < 0)) {
+               WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
+       }
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+
        /* Now we can register wiphy with cfg80211 module */
        err = wiphy_register(wdev->wiphy);
        if (unlikely(err < 0)) {
@@ -6835,6 +6848,9 @@ static void wl_free_wdev(struct wl_priv *wl)
                return;
        }
        wiphy = wdev->wiphy;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+       wl_cfgvendor_detach(wdev->wiphy);
+#endif /* if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
        wiphy_unregister(wdev->wiphy);
        wdev->wiphy->dev.parent = NULL;
 
diff --git a/drivers/net/wireless/bcmdhd_88/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_88/wl_cfgvendor.c
new file mode 100644 (file)
index 0000000..c34fe1b
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Linux cfg80211 Vendor Extension Code
+ *
+ * Copyright (C) 1999-2014, Broadcom Corporation
+ *
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ *
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfgvendor.c 473890 2014-04-30 01:55:06Z $
+*/
+
+/*
+ * New vendor interface additon to nl80211/cfg80211 to allow vendors
+ * to implement proprietary features over the cfg80211 stack.
+*/
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif /* PNO_SUPPORT */
+#ifdef RTT_SUPPORT
+#include <dhd_rtt.h>
+#endif /* RTT_SUPPORT */
+#include <proto/ethernet.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <linux/vmalloc.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+
+#include <wlioctl.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wl_android.h>
+#include <wl_cfgvendor.h>
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+
+static int wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
+        struct net_device *dev, const void  *data, int len)
+{
+       struct sk_buff *skb;
+
+       /* Alloc the SKB for vendor_event */
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+       if (unlikely(!skb)) {
+               WL_ERR(("skb alloc failed"));
+               return -ENOMEM;
+       }
+
+       /* Push the data to the skb */
+       nla_put_nohdr(skb, len, data);
+
+       return cfg80211_vendor_cmd_reply(skb);
+}
+
+static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       int err = 0, type, band;
+       uint16 *reply = NULL;
+       uint32 reply_len = 0, num_channels, mem_needed;
+       struct sk_buff *skb;
+       struct wl_priv *wl = wiphy_priv(wiphy);
+
+       type = nla_type(data);
+       if (type == GSCAN_ATTRIBUTE_BAND) {
+               band = nla_get_u32(data);
+       } else {
+               return -1;
+       }
+       reply = dhd_dev_pno_get_gscan(wl_to_prmry_ndev(wl),
+          DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
+
+       if (!reply) {
+               WL_ERR(("Could not get channel list\n"));
+               err = -EINVAL;
+               return err;
+       }
+       num_channels =  reply_len/ sizeof(uint32);
+       mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
+
+       /* Alloc the SKB for vendor_event */
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+       if (unlikely(!skb)) {
+               WL_ERR(("skb alloc failed"));
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
+       nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
+
+       err =  cfg80211_vendor_cmd_reply(skb);
+
+       if (unlikely(err))
+               WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+exit:
+       kfree(reply);
+       return err;
+}
+
+static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       struct wl_priv *wl = wiphy_priv(wiphy);
+       int err = 0;
+       int data_len = 0;
+
+       bzero(wl->ioctl_buf, WLC_IOCTL_MAXLEN);
+
+       if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
+               err = wldev_iovar_getbuf(wl_to_prmry_ndev(wl), "cap", NULL, 0,
+                       wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
+               if (unlikely(err)) {
+                       WL_ERR(("error (%d)\n", err));
+                       return err;
+               }
+               data_len = strlen(wl->ioctl_buf);
+               wl->ioctl_buf[data_len] = '\0';
+       }
+
+       err =  wl_cfgvendor_send_cmd_reply(wiphy, wl_to_prmry_ndev(wl),
+               wl->ioctl_buf, data_len+1);
+       if (unlikely(err))
+               WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+       else
+               WL_INFO(("Vendor Command reply sent successfully!\n"));
+
+       return err;
+}
+
+static int wl_cfgvendor_set_country(struct wiphy *wiphy,
+       struct wireless_dev *wdev, const void  *data, int len)
+{
+       int err = BCME_ERROR, rem, type;
+       char country_code[WLC_CNTRY_BUF_SZ] = {0};
+       const struct nlattr *iter;
+       nla_for_each_attr(iter, data, len, rem) {
+               type = nla_type(iter);
+               switch (type) {
+                       case ANDR_WIFI_ATTRIBUTE_COUNTRY:
+                               memcpy(country_code, nla_data(iter),
+                                       MIN(nla_len(iter), WLC_CNTRY_BUF_SZ));
+                               break;
+                       default:
+                               WL_ERR(("Unknown type: %d\n", type));
+                               return err;
+               }
+       }
+
+       err = wldev_set_country(wdev->netdev, country_code, true, true);
+       if (err < 0) {
+               WL_ERR(("Set country failed ret:%d\n", err));
+       }
+
+       return err;
+}
+
+#if defined(KEEP_ALIVE)
+static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+       const void *data, int len)
+{
+       /* max size of IP packet for keep alive */
+       const int MKEEP_ALIVE_IP_PKT_MAX = 256;
+
+       int ret = BCME_OK, rem, type;
+       u8 mkeep_alive_id = 0;
+       u8 *ip_pkt = NULL;
+       u16 ip_pkt_len = 0;
+       u8 src_mac[ETHER_ADDR_LEN];
+       u8 dst_mac[ETHER_ADDR_LEN];
+       u32 period_msec = 0;
+       const struct nlattr *iter;
+       struct wl_priv *wl = wiphy_priv(wiphy);
+       dhd_pub_t *dhd_pub = wl->pub;
+       gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+       nla_for_each_attr(iter, data, len, rem) {
+               type = nla_type(iter);
+               switch (type) {
+                       case MKEEP_ALIVE_ATTRIBUTE_ID:
+                               mkeep_alive_id = nla_get_u8(iter);
+                               break;
+                       case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
+                               ip_pkt_len = nla_get_u16(iter);
+                               if ( ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
+                                       ret = BCME_BADARG;
+                                       goto exit;
+                               }
+                               break;
+                       case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
+                               ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
+                               if (ip_pkt == NULL) {
+                                       ret = BCME_NOMEM;
+                                       WL_ERR(("Failed to allocate mem for ip packet\n"));
+                                       goto exit;
+                               }
+                               memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
+                               break;
+                       case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
+                               memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
+                               break;
+                       case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
+                               memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
+                               break;
+                       case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
+                               period_msec = nla_get_u32(iter);
+                               break;
+                       default:
+                               WL_ERR(("Unknown type: %d\n", type));
+                               ret = BCME_BADARG;
+                               goto exit;
+               }
+       }
+
+       ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
+                                       dst_mac, period_msec);
+       if (ret < 0) {
+               WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
+       }
+
+exit:
+       if (ip_pkt) {
+               kfree(ip_pkt);
+       }
+
+       return ret;
+}
+
+static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+       const void *data, int len)
+{
+       int ret = BCME_OK, rem, type;
+       u8 mkeep_alive_id = 0;
+       const struct nlattr *iter;
+       struct wl_priv *wl = wiphy_priv(wiphy);
+       dhd_pub_t *dhd_pub = wl->pub;
+
+       nla_for_each_attr(iter, data, len, rem) {
+               type = nla_type(iter);
+               switch (type) {
+                       case MKEEP_ALIVE_ATTRIBUTE_ID:
+                               mkeep_alive_id = nla_get_u8(iter);
+                               break;
+                       default:
+                               WL_ERR(("Unknown type: %d\n", type));
+                               ret = BCME_BADARG;
+                               break;
+               }
+       }
+
+       ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
+       if (ret < 0) {
+               WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
+       }
+
+       return ret;
+}
+#endif /* defined(KEEP_ALIVE) */
+
+static const struct wiphy_vendor_command wl_vendor_cmds [] = {
+       {
+               {
+                       .vendor_id = OUI_BRCM,
+                       .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_priv_string_handler
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_gscan_get_channel_list
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = ANDR_WIFI_SET_COUNTRY
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_set_country
+       },
+#ifdef KEEP_ALIVE
+        {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_start_mkeep_alive
+       },
+       {
+               {
+                       .vendor_id = OUI_GOOGLE,
+                       .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
+               },
+               .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = wl_cfgvendor_stop_mkeep_alive
+       },
+#endif /* KEEP_ALIVE */
+};
+
+static const struct  nl80211_vendor_cmd_info wl_vendor_events [] = {
+               { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
+               { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
+               { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
+               { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
+               { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
+               { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
+               { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
+               { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
+               { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
+               { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
+               { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
+               { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
+               { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
+               { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
+               { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }
+};
+
+int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
+{
+
+       WL_INFO(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
+               NL80211_CMD_VENDOR));
+
+       wiphy->vendor_commands  = wl_vendor_cmds;
+       wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
+       wiphy->vendor_events    = wl_vendor_events;
+       wiphy->n_vendor_events  = ARRAY_SIZE(wl_vendor_events);
+
+       return 0;
+}
+
+int wl_cfgvendor_detach(struct wiphy *wiphy)
+{
+       WL_INFO(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
+
+       wiphy->vendor_commands  = NULL;
+       wiphy->vendor_events    = NULL;
+       wiphy->n_vendor_commands = 0;
+       wiphy->n_vendor_events  = 0;
+
+       return 0;
+}
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
diff --git a/drivers/net/wireless/bcmdhd_88/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_88/wl_cfgvendor.h
new file mode 100644 (file)
index 0000000..58077b3
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Linux cfg80211 Vendor Extension Code
+ *
+ * Copyright (C) 1999-2014, Broadcom Corporation
+ *
+ *      Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ *
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfgvendor.h 473890 2014-04-30 01:55:06Z $
+ */
+
+/*
+ * New vendor interface additon to nl80211/cfg80211 to allow vendors
+ * to implement proprietary features over the cfg80211 stack.
+ */
+
+#ifndef _wl_cfgvendor_h_
+#define _wl_cfgvendor_h_
+
+#define OUI_BRCM    0x001018
+#define OUI_GOOGLE  0x001A11
+#define BRCM_VENDOR_SUBCMD_PRIV_STR    1
+#define ATTRIBUTE_U32_LEN                  (NLA_HDRLEN  + 4)
+#define VENDOR_ID_OVERHEAD                 ATTRIBUTE_U32_LEN
+#define VENDOR_SUBCMD_OVERHEAD             ATTRIBUTE_U32_LEN
+#define VENDOR_DATA_OVERHEAD               (NLA_HDRLEN)
+
+#define SCAN_RESULTS_COMPLETE_FLAG_LEN       ATTRIBUTE_U32_LEN
+#define SCAN_INDEX_HDR_LEN                   (NLA_HDRLEN)
+#define SCAN_ID_HDR_LEN                      ATTRIBUTE_U32_LEN
+#define SCAN_FLAGS_HDR_LEN                   ATTRIBUTE_U32_LEN
+#define GSCAN_NUM_RESULTS_HDR_LEN            ATTRIBUTE_U32_LEN
+#define GSCAN_RESULTS_HDR_LEN                (NLA_HDRLEN)
+#define GSCAN_BATCH_RESULT_HDR_LEN  (SCAN_INDEX_HDR_LEN + SCAN_ID_HDR_LEN + \
+                                                                       SCAN_FLAGS_HDR_LEN + \
+                                                               GSCAN_NUM_RESULTS_HDR_LEN + \
+                                                                       GSCAN_RESULTS_HDR_LEN)
+
+#define VENDOR_REPLY_OVERHEAD       (VENDOR_ID_OVERHEAD + \
+                                                                       VENDOR_SUBCMD_OVERHEAD + \
+                                                                       VENDOR_DATA_OVERHEAD)
+typedef enum {
+       /* don't use 0 as a valid subcommand */
+       VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+       /* define all vendor startup commands between 0x0 and 0x0FFF */
+       VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+       VENDOR_NL80211_SUBCMD_RANGE_END   = 0x0FFF,
+
+       /* define all GScan related commands between 0x1000 and 0x10FF */
+       ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+       ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END   = 0x10FF,
+
+
+       /* define all RTT related commands between 0x1100 and 0x11FF */
+       ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+       ANDROID_NL80211_SUBCMD_RTT_RANGE_END   = 0x11FF,
+
+       ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+       ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END   = 0x12FF,
+
+       ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300,
+       ANDROID_NL80211_SUBCMD_TDLS_RANGE_END   = 0x13FF,
+
+       ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
+       ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END  = 0x14FF,
+
+       /* define all NearbyDiscovery related commands between 0x1500 and 0x15FF */
+       ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1500,
+       ANDROID_NL80211_SUBCMD_NBD_RANGE_END   = 0x15FF,
+
+       /* define all wifi calling related commands between 0x1600 and 0x16FF */
+       ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
+       ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END   = 0x16FF,
+
+       /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+enum wl_vendor_subcmd {
+       BRCM_VENDOR_SCMD_UNSPEC,
+       BRCM_VENDOR_SCMD_PRIV_STR,
+       GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+       GSCAN_SUBCMD_SET_CONFIG,
+       GSCAN_SUBCMD_SET_SCAN_CONFIG,
+       GSCAN_SUBCMD_ENABLE_GSCAN,
+       GSCAN_SUBCMD_GET_SCAN_RESULTS,
+       GSCAN_SUBCMD_SCAN_RESULTS,
+       GSCAN_SUBCMD_SET_HOTLIST,
+       GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,
+       GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,
+       GSCAN_SUBCMD_GET_CHANNEL_LIST,
+       ANDR_WIFI_SUBCMD_GET_FEATURE_SET,
+       ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX,
+       ANDR_WIFI_RANDOM_MAC_OUI,
+       ANDR_WIFI_NODFS_CHANNELS,
+       ANDR_WIFI_SET_COUNTRY,
+       GSCAN_SUBCMD_SET_EPNO_SSID,
+       WIFI_SUBCMD_SET_SSID_WHITELIST,
+       WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS,
+       WIFI_SUBCMD_ENABLE_LAZY_ROAM,
+       WIFI_SUBCMD_SET_BSSID_PREF,
+       WIFI_SUBCMD_SET_BSSID_BLACKLIST,
+       GSCAN_SUBCMD_ANQPO_CONFIG,
+       WIFI_SUBCMD_SET_RSSI_MONITOR,
+       RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+       RTT_SUBCMD_CANCEL_CONFIG,
+       RTT_SUBCMD_GETCAPABILITY,
+       LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
+       DEBUG_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
+       DEBUG_TRIGGER_MEM_DUMP,
+       DEBUG_GET_MEM_DUMP,
+       DEBUG_GET_VER,
+       DEBUG_GET_RING_STATUS,
+       DEBUG_GET_RING_DATA,
+       DEBUG_GET_FEATURE,
+       DEBUG_RESET_LOGGING,
+       WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
+       WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE,
+       /* Add more sub commands here */
+    VENDOR_SUBCMD_MAX
+};
+
+enum gscan_attributes {
+    GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+    GSCAN_ATTRIBUTE_BASE_PERIOD,
+    GSCAN_ATTRIBUTE_BUCKETS_BAND,
+    GSCAN_ATTRIBUTE_BUCKET_ID,
+    GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+    GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+    GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+    GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+    GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+    GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+    GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+    GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
+    GSCAN_ATTRIBUTE_FLUSH_FEATURE,
+    GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS,
+    GSCAN_ATTRIBUTE_REPORT_EVENTS,
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+    GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+    GSCAN_ATTRIBUTE_SCAN_RESULTS,                       /* flat array of wifi_scan_result */
+    GSCAN_ATTRIBUTE_SCAN_ID,                            /* indicates scan number */
+    GSCAN_ATTRIBUTE_SCAN_FLAGS,                         /* indicates if scan was aborted */
+    GSCAN_ATTRIBUTE_AP_FLAGS,                           /* flags on significant change event */
+    GSCAN_ATTRIBUTE_NUM_CHANNELS,
+    GSCAN_ATTRIBUTE_CHANNEL_LIST,
+
+       /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_SSID = 40,
+    GSCAN_ATTRIBUTE_BSSID,
+    GSCAN_ATTRIBUTE_CHANNEL,
+    GSCAN_ATTRIBUTE_RSSI,
+    GSCAN_ATTRIBUTE_TIMESTAMP,
+    GSCAN_ATTRIBUTE_RTT,
+    GSCAN_ATTRIBUTE_RTTSD,
+
+    /* remaining reserved for additional attributes */
+
+    GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
+    GSCAN_ATTRIBUTE_RSSI_LOW,
+    GSCAN_ATTRIBUTE_RSSI_HIGH,
+    GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM,
+    GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+
+    /* remaining reserved for additional attributes */
+    GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+    GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+    GSCAN_ATTRIBUTE_MIN_BREACHING,
+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+    GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
+
+    /* EPNO */
+    GSCAN_ATTRIBUTE_EPNO_SSID_LIST = 70,
+    GSCAN_ATTRIBUTE_EPNO_SSID,
+    GSCAN_ATTRIBUTE_EPNO_SSID_LEN,
+    GSCAN_ATTRIBUTE_EPNO_RSSI,
+    GSCAN_ATTRIBUTE_EPNO_FLAGS,
+    GSCAN_ATTRIBUTE_EPNO_AUTH,
+    GSCAN_ATTRIBUTE_EPNO_SSID_NUM,
+    GSCAN_ATTRIBUTE_EPNO_FLUSH,
+
+    /* Roam SSID Whitelist and BSSID pref */
+    GSCAN_ATTRIBUTE_WHITELIST_SSID = 80,
+    GSCAN_ATTRIBUTE_NUM_WL_SSID,
+    GSCAN_ATTRIBUTE_WL_SSID_LEN,
+    GSCAN_ATTRIBUTE_WL_SSID_FLUSH,
+    GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM,
+    GSCAN_ATTRIBUTE_NUM_BSSID,
+    GSCAN_ATTRIBUTE_BSSID_PREF_LIST,
+    GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH,
+    GSCAN_ATTRIBUTE_BSSID_PREF,
+    GSCAN_ATTRIBUTE_RSSI_MODIFIER,
+
+
+    /* Roam cfg */
+    GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD = 90,
+    GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD,
+    GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR,
+    GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR,
+    GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST,
+    GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS,
+    GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER,
+    GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE,
+
+    /* BSSID blacklist */
+    GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH = 100,
+    GSCAN_ATTRIBUTE_BLACKLIST_BSSID,
+
+    GSCAN_ATTRIBUTE_ANQPO_HS_LIST = 110,
+    GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE,
+    GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID,
+    GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM,
+    GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID,
+    GSCAN_ATTRIBUTE_ANQPO_HS_PLMN,
+
+    /* Adaptive scan attributes */
+    GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 120,
+    GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
+
+    GSCAN_ATTRIBUTE_MAX
+};
+
+enum gscan_bucket_attributes {
+       GSCAN_ATTRIBUTE_CH_BUCKET_1,
+       GSCAN_ATTRIBUTE_CH_BUCKET_2,
+       GSCAN_ATTRIBUTE_CH_BUCKET_3,
+       GSCAN_ATTRIBUTE_CH_BUCKET_4,
+       GSCAN_ATTRIBUTE_CH_BUCKET_5,
+       GSCAN_ATTRIBUTE_CH_BUCKET_6,
+       GSCAN_ATTRIBUTE_CH_BUCKET_7
+};
+
+enum gscan_ch_attributes {
+       GSCAN_ATTRIBUTE_CH_ID_1,
+       GSCAN_ATTRIBUTE_CH_ID_2,
+       GSCAN_ATTRIBUTE_CH_ID_3,
+       GSCAN_ATTRIBUTE_CH_ID_4,
+       GSCAN_ATTRIBUTE_CH_ID_5,
+       GSCAN_ATTRIBUTE_CH_ID_6,
+       GSCAN_ATTRIBUTE_CH_ID_7
+};
+
+enum rtt_attributes {
+       RTT_ATTRIBUTE_TARGET_CNT,
+       RTT_ATTRIBUTE_TARGET_INFO,
+       RTT_ATTRIBUTE_TARGET_MAC,
+       RTT_ATTRIBUTE_TARGET_TYPE,
+       RTT_ATTRIBUTE_TARGET_PEER,
+       RTT_ATTRIBUTE_TARGET_CHAN,
+       RTT_ATTRIBUTE_TARGET_PERIOD,
+       RTT_ATTRIBUTE_TARGET_NUM_BURST,
+       RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST,
+       RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM,
+       RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR,
+       RTT_ATTRIBUTE_TARGET_LCI,
+       RTT_ATTRIBUTE_TARGET_LCR,
+       RTT_ATTRIBUTE_TARGET_BURST_DURATION,
+       RTT_ATTRIBUTE_TARGET_PREAMBLE,
+       RTT_ATTRIBUTE_TARGET_BW,
+       RTT_ATTRIBUTE_RESULTS_COMPLETE = 30,
+       RTT_ATTRIBUTE_RESULTS_PER_TARGET,
+       RTT_ATTRIBUTE_RESULT_CNT,
+       RTT_ATTRIBUTE_RESULT
+};
+
+enum debug_attributes {
+       DEBUG_ATTRIBUTE_GET_DRIVER,
+       DEBUG_ATTRIBUTE_GET_FW,
+       DEBUG_ATTRIBUTE_RING_ID,
+       DEBUG_ATTRIBUTE_RING_NAME,
+       DEBUG_ATTRIBUTE_RING_FLAGS,
+       DEBUG_ATTRIBUTE_LOG_LEVEL,
+       DEBUG_ATTRIBUTE_LOG_TIME_INTVAL,
+       DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE,
+       DEBUG_ATTRIBUTE_FW_DUMP_LEN,
+       DEBUG_ATTRIBUTE_FW_DUMP_DATA,
+       DEBUG_ATTRIBUTE_RING_DATA,
+       DEBUG_ATTRIBUTE_RING_STATUS,
+       DEBUG_ATTRIBUTE_RING_NUM
+};
+
+enum mkeep_alive_attributes {
+       MKEEP_ALIVE_ATTRIBUTE_ID,
+       MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
+       MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
+       MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
+       MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
+       MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
+};
+
+enum wifi_rssi_monitor_attr {
+       RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
+       RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
+       RSSI_MONITOR_ATTRIBUTE_START,
+};
+
+typedef enum wl_vendor_event {
+       BRCM_VENDOR_EVENT_UNSPEC,
+       BRCM_VENDOR_EVENT_PRIV_STR,
+       GOOGLE_GSCAN_SIGNIFICANT_EVENT,
+       GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT,
+       GOOGLE_GSCAN_BATCH_SCAN_EVENT,
+       GOOGLE_SCAN_FULL_RESULTS_EVENT,
+       GOOGLE_RTT_COMPLETE_EVENT,
+       GOOGLE_SCAN_COMPLETE_EVENT,
+       GOOGLE_GSCAN_GEOFENCE_LOST_EVENT,
+       GOOGLE_SCAN_EPNO_EVENT,
+       GOOGLE_DEBUG_RING_EVENT,
+       GOOGLE_FW_DUMP_EVENT,
+       GOOGLE_PNO_HOTSPOT_FOUND_EVENT,
+       GOOGLE_RSSI_MONITOR_EVENT,
+       GOOGLE_MKEEP_ALIVE_EVENT
+} wl_vendor_event_t;
+
+enum andr_wifi_attr {
+       ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
+       ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
+       ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI,
+       ANDR_WIFI_ATTRIBUTE_NODFS_SET,
+       ANDR_WIFI_ATTRIBUTE_COUNTRY
+};
+
+typedef enum wl_vendor_gscan_attribute {
+       ATTR_START_GSCAN,
+       ATTR_STOP_GSCAN,
+       ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */
+       ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */
+       ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */
+       ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */
+       ATTR_GET_GSCAN_CAPABILITIES_ID,
+    /* Add more sub commands here */
+    ATTR_GSCAN_MAX
+} wl_vendor_gscan_attribute_t;
+
+typedef enum gscan_batch_attribute {
+       ATTR_GSCAN_BATCH_BESTN,
+       ATTR_GSCAN_BATCH_MSCAN,
+       ATTR_GSCAN_BATCH_BUFFER_THRESHOLD
+} gscan_batch_attribute_t;
+
+typedef enum gscan_geofence_attribute {
+       ATTR_GSCAN_NUM_HOTLIST_BSSID,
+       ATTR_GSCAN_HOTLIST_BSSID
+} gscan_geofence_attribute_t;
+
+typedef enum gscan_complete_event {
+       WIFI_SCAN_BUFFER_FULL,
+       WIFI_SCAN_COMPLETE
+} gscan_complete_event_t;
+
+/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */
+#define BRCM_VENDOR_SCMD_CAPA  "cap"
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+extern int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd);
+extern int wl_cfgvendor_detach(struct wiphy *wiphy);
+extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
+                  struct net_device *dev, int event_id, const void  *data, int len);
+extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
+                struct net_device *dev, void  *data, int len, wl_vendor_event_t event);
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+
+#endif /* _wl_cfgvendor_h_ */