prima: NAN - HDD and SME changes to support NAN

Changes required in HDD and SME layers to support NAN
control path.
1. Receive NAN vendor command in HDD and pass the it to SME.
2. Register a NAN callback which to be called by SME when a
   NAN event is received from WDA/WDI.
3. Send the NAN events to wifihal using NAN vendor event

Change-Id: I8244e14706ef91ec0d17c51fee37fdd9e9ebdc26
CRs-Fixed: 797391
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index b8fd5b4..df82845 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -192,6 +192,7 @@
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX,
     /*EXT TDLS*/
     QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX,
+    QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX,
 };
 
 enum qca_wlan_vendor_attr
@@ -976,4 +977,6 @@
                                       void *pMsg);
 #endif /* WLAN_FEATURE_EXTSCAN */
 
+void wlan_hdd_cfg80211_nan_init(hdd_context_t *pHddCtx);
+
 #endif
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index b33f943..8ee9b31 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -641,6 +641,147 @@
 }
 #endif /* FEATURE_WLAN_CH_AVOID */
 
+/*
+ * FUNCTION: __wlan_hdd_cfg80211_nan_request
+ * This is called when wlan driver needs to send vendor specific
+ * nan request event.
+ */
+static int __wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         const void *data, int data_len)
+{
+    tNanRequestReq nan_req;
+    VOS_STATUS status;
+    int ret_val = -1;
+    hdd_context_t *pHddCtx = wiphy_priv(wiphy);
+
+    if (0 == data_len)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+                FL("NAN - Invalid Request, length = 0"));
+        return ret_val;
+    }
+
+    if (NULL == data)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+                FL("NAN - Invalid Request, data is NULL"));
+        return ret_val;
+    }
+
+    status = wlan_hdd_validate_context(pHddCtx);
+    if (0 != status)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("HDD context is not valid"));
+        return -EINVAL;
+    }
+
+    hddLog(LOG1, FL("Received NAN command"));
+    vos_trace_hex_dump( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+        (tANI_U8 *)data, data_len);
+
+    /* check the NAN Capability */
+    if (TRUE != sme_IsFeatureSupportedByFW(NAN))
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("NAN is not supported by Firmware"));
+        return -EINVAL;
+    }
+
+    nan_req.request_data_len = data_len;
+    nan_req.request_data = data;
+
+    status = sme_NanRequest(&nan_req);
+    if (VOS_STATUS_SUCCESS == status)
+    {
+        ret_val = 0;
+    }
+    return ret_val;
+}
+
+/*
+ * FUNCTION: wlan_hdd_cfg80211_nan_request
+ * Wrapper to protect the nan vendor command from ssr
+ */
+static int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         const void *data, int data_len)
+{
+    int ret;
+
+    vos_ssr_protect(__func__);
+    ret = __wlan_hdd_cfg80211_nan_request(wiphy, wdev, data, data_len);
+    vos_ssr_unprotect(__func__);
+
+    return ret;
+}
+
+/*
+ * FUNCTION: wlan_hdd_cfg80211_nan_callback
+ * This is a callback function and it gets called
+ * when we need to report nan response event to
+ * upper layers.
+ */
+static void wlan_hdd_cfg80211_nan_callback(void* ctx, tSirNanEvent* msg)
+{
+    hdd_context_t *pHddCtx = (hdd_context_t *)ctx;
+    struct sk_buff *vendor_event;
+    int status;
+    tSirNanEvent *data;
+
+    ENTER();
+    if (NULL == msg)
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   FL(" msg received here is null"));
+        return;
+    }
+    data = msg;
+
+    status = wlan_hdd_validate_context(pHddCtx);
+
+    if (0 != status)
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   FL("HDD context is not valid"));
+        return;
+    }
+
+    vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
+                                   data->event_data_len +
+                                   NLMSG_HDRLEN,
+                                   QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX,
+                                   GFP_KERNEL);
+
+    if (!vendor_event)
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   FL("cfg80211_vendor_event_alloc failed"));
+        return;
+    }
+    if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NAN,
+                data->event_data_len, data->event_data))
+    {
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   FL("QCA_WLAN_VENDOR_ATTR_NAN put fail"));
+        kfree_skb(vendor_event);
+        return;
+    }
+    cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+    EXIT();
+}
+
+/*
+ * FUNCTION: wlan_hdd_cfg80211_nan_init
+ * This function is called to register the callback to sme layer
+ */
+inline void wlan_hdd_cfg80211_nan_init(hdd_context_t *pHddCtx)
+{
+    sme_NanRegisterCallback(pHddCtx->hHal, wlan_hdd_cfg80211_nan_callback);
+}
+
+
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 
 static v_BOOL_t put_wifi_rate_stat( tpSirWifiRateStat stats,
@@ -4846,12 +4987,10 @@
     }
 #endif
 
-#ifdef WLAN_FEATURE_NAN
     if (sme_IsFeatureSupportedByFW(NAN)) {
         hddLog(LOG1, FL("NAN is supported by firmware"));
         fset |= WIFI_FEATURE_NAN;
     }
-#endif
 
     /* D2D RTT is not supported currently by default */
     if (sme_IsFeatureSupportedByFW(RTT)) {
@@ -5189,6 +5328,16 @@
                  WIPHY_VENDOR_CMD_NEED_RUNNING,
         .doit = wlan_hdd_cfg80211_firmware_roaming
     },
+
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV |
+                 WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_nan_request
+    },
+
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
     {
         .info.vendor_id = QCA_NL80211_VENDOR_ID,
@@ -5445,6 +5594,12 @@
         .vendor_id = QCA_NL80211_VENDOR_ID,
         .subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE
     },
+
+    {
+        .vendor_id = QCA_NL80211_VENDOR_ID,
+        .subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN
+    },
+
 };
 
 /*
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 975d6ce..aaa3581 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -9863,6 +9863,8 @@
                      hdd_tx_rx_pkt_cnt_stat_timer_handler,
                      (void *)pHddCtx);
    }
+   wlan_hdd_cfg80211_nan_init(pHddCtx);
+
 #ifdef WLAN_FEATURE_EXTSCAN
     sme_EXTScanRegisterCallback(pHddCtx->hHal,
             wlan_hdd_cfg80211_extscan_callback,
diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h
index 34dcd60..824395f 100644
--- a/CORE/MAC/inc/wniApi.h
+++ b/CORE/MAC/inc/wniApi.h
@@ -390,6 +390,7 @@
     eWNI_SME_MAC_SPOOF_ADDR_IND,
     eWNI_SME_ENCRYPT_MSG_RSP,
     eWNI_SME_UPDATE_MAX_RATE_IND,
+    eWNI_SME_NAN_EVENT,
     eWNI_SME_MSG_TYPES_END
 };
 
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index bb57992..0c0ea66 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -104,9 +104,7 @@
    UPDATE_CHANNEL_LIST    = 35,
    WLAN_MCADDR_FLT        = 36,
    WLAN_CH144             = 37,
-#ifdef WLAN_FEATURE_NAN
    NAN = 38,
-#endif
 #ifdef FEATURE_WLAN_TDLS
    TDLS_SCAN_COEXISTENCE  = 39,
 #endif
@@ -707,6 +705,8 @@
 #define SIR_HAL_MGMT_LOGGING_INIT_REQ         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 265)
 #define SIR_HAL_GET_FRAME_LOG_REQ             (SIR_HAL_ITC_MSG_TYPES_BEGIN + 266)
 
+#define SIR_HAL_NAN_REQUEST                   (SIR_HAL_ITC_MSG_TYPES_BEGIN + 267)
+
 #define SIR_HAL_MSG_TYPES_END              (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 // CFG message types
 #define SIR_CFG_MSG_TYPES_BEGIN        (SIR_CFG_MODULE_ID << 8)
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index a4f221f..b988bcc 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -64,6 +64,7 @@
 #if defined WLAN_FEATURE_VOWIFI
 #include "smeRrmInternal.h"
 #endif
+#include "nan_Api.h"
 
 /*-------------------------------------------------------------------------- 
   Preprocessor definitions and constants
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 69fe764..d632b31 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -2502,6 +2502,20 @@
               }
               break;
 
+          case eWNI_SME_NAN_EVENT:
+              if (pMsg->bodyptr)
+              {
+                  sme_NanEvent(hHal, pMsg->bodyptr);
+                  vos_mem_free(pMsg->bodyptr);
+              }
+              else
+              {
+                  smsLog(pMac, LOGE,
+                          "Empty message for (eWNI_SME_NAN_EVENT),"
+                          " nothing to process");
+              }
+              break;
+
           default:
 
              if ( ( pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN )
diff --git a/CORE/WDA/inc/legacy/halMsgApi.h b/CORE/WDA/inc/legacy/halMsgApi.h
index 2eaaaf1..2711451 100644
--- a/CORE/WDA/inc/legacy/halMsgApi.h
+++ b/CORE/WDA/inc/legacy/halMsgApi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1411,5 +1411,11 @@
     tANI_U8  ucRemIeId[1];
 }  __ani_attr_packed tRemBeaconFilterMsg, *tpRemBeaconFilterMsg;
 
+typedef struct sNanRequest
+{
+    tANI_U16 request_data_len;
+    tANI_U8  request_data[1];
+} tNanRequest, *tpNanRequest;
+
 #endif /* _HALMSGAPI_H_ */
 
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 6329b81..e71ea6d 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1195,6 +1195,8 @@
 #define WDA_GET_ROAM_RSSI_REQ      SIR_HAL_GET_ROAM_RSSI_REQ
 #define WDA_GET_ROAM_RSSI_RSP      SIR_HAL_GET_ROAM_RSSI_RSP
 
+#define WDA_NAN_REQUEST            SIR_HAL_NAN_REQUEST
+
 #define WDA_START_SCAN_OFFLOAD_REQ  SIR_HAL_START_SCAN_OFFLOAD_REQ
 #define WDA_START_SCAN_OFFLOAD_RSP  SIR_HAL_START_SCAN_OFFLOAD_RSP
 #define WDA_STOP_SCAN_OFFLOAD_REQ  SIR_HAL_STOP_SCAN_OFFLOAD_REQ
diff --git a/prima/CORE/SME/inc/nan_Api.h b/prima/CORE/SME/inc/nan_Api.h
new file mode 100644
index 0000000..ae140ac
--- /dev/null
+++ b/prima/CORE/SME/inc/nan_Api.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * All Rights Reserved.
+ * Qualcomm Atheros Confidential and Proprietary.
+ *
+ */
+
+/******************************************************************************
+*
+* Name:  nan_Api.h
+*
+* Description: NAN FSM defines.
+*
+******************************************************************************/
+
+#ifndef __NAN_API_H__
+#define __NAN_API_H__
+
+#include "vos_types.h"
+#include "halTypes.h"
+
+typedef struct sNanRequestReq
+{
+    tANI_U16 request_data_len;
+    const tANI_U8* request_data;
+} tNanRequestReq, *tpNanRequestReq;
+
+/******************************************************************************
+ * Function: Pointer NanCallback
+ *
+ * Description:
+ * this function pointer is used hold nan response callback. When ever driver
+ * receives nan response, this callback will be used.
+ *
+ * Args:
+ * first argument to pass hHal pointer and second argument
+ * to pass the nan response data.
+ *
+ * Returns:
+ * void
+******************************************************************************/
+typedef void (*NanCallback)(void*, tSirNanEvent*);
+
+/******************************************************************************
+ * Function: sme_NanRegisterCallback
+ *
+ * Description:
+ * This function gets called when HDD wants register nan rsp callback with
+ * sme layer.
+ *
+ * Args:
+ * hHal and callback which needs to be registered.
+ *
+ * Returns:
+ * void
+******************************************************************************/
+void sme_NanRegisterCallback(tHalHandle hHal, NanCallback callback);
+
+/******************************************************************************
+ * Function: sme_NanRequest
+ *
+ * Description:
+ * This function gets called when HDD receives NAN vendor command
+ * from userspace
+ *
+ * Args:
+ * Nan Request structure ptr
+ *
+ * Returns:
+ * VOS_STATUS
+******************************************************************************/
+VOS_STATUS sme_NanRequest(tpNanRequestReq input);
+
+/******************************************************************************
+  \fn sme_NanEvent
+
+  \brief
+  a callback function called when SME received eWNI_SME_NAN_EVENT
+  event from WDA
+
+  \param hHal - HAL handle for device
+  \param pMsg - Message body passed from WDA; includes NAN header
+
+  \return VOS_STATUS
+******************************************************************************/
+VOS_STATUS sme_NanEvent(tHalHandle hHal, void* pMsg);
+
+#endif /* __NAN_API_H__ */
diff --git a/prima/CORE/SME/src/nan/nan_Api.c b/prima/CORE/SME/src/nan/nan_Api.c
new file mode 100644
index 0000000..b19c84d
--- /dev/null
+++ b/prima/CORE/SME/src/nan/nan_Api.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * All Rights Reserved.
+ * Qualcomm Atheros Confidential and Proprietary.
+ *
+ */
+
+#include "sme_Api.h"
+#include "smsDebug.h"
+#include "csrInsideApi.h"
+#include "smeInside.h"
+#include "limApi.h"
+#include "cfgApi.h"
+
+/******************************************************************************
+ * Function: sme_NanRegisterCallback
+ *
+ * Description:
+ * This function gets called when HDD wants register nan rsp callback with
+ * sme layer.
+ *
+ * Args:
+ * hHal and callback which needs to be registered.
+ *
+ * Returns:
+ * void
+ *****************************************************************************/
+void sme_NanRegisterCallback(tHalHandle hHal, NanCallback callback)
+{
+    tpAniSirGlobal pMac = NULL;
+
+    if (NULL == hHal)
+    {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                FL("hHal is not valid"));
+        return;
+    }
+    pMac = PMAC_STRUCT(hHal);
+    pMac->sme.nanCallback = callback;
+}
+
+/******************************************************************************
+ * Function: sme_NanRequest
+ *
+ * Description:
+ * This function gets called when HDD receives NAN vendor command
+ * from userspace
+ *
+ * Args:
+ * Nan Request structure ptr
+ *
+ * Returns:
+ * VOS_STATUS
+ *****************************************************************************/
+VOS_STATUS sme_NanRequest(tpNanRequestReq input)
+{
+    vos_msg_t msg;
+    tpNanRequest data;
+    size_t data_len;
+
+    data_len = sizeof(tNanRequest) + input->request_data_len;
+    data = vos_mem_malloc(data_len);
+
+    if (data == NULL)
+    {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                FL("Memory allocation failure"));
+        return VOS_STATUS_E_FAULT;
+    }
+
+    vos_mem_zero(data, data_len);
+    data->request_data_len = input->request_data_len;
+    vos_mem_copy(data->request_data,
+            input->request_data, input->request_data_len);
+
+    msg.type = WDA_NAN_REQUEST;
+    msg.reserved = 0;
+    msg.bodyptr = data;
+
+    if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MODULE_ID_WDA, &msg))
+    {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+            FL("Not able to post WDA_NAN_REQUEST message to WDA"));
+        vos_mem_free(data);
+        return VOS_STATUS_E_FAILURE;
+    }
+
+    return VOS_STATUS_SUCCESS;
+}
+
+/******************************************************************************
+ * Function: sme_NanEvent
+ *
+ * Description:
+ * This callback function will be called when SME received eWNI_SME_NAN_EVENT
+ * event from WMA
+ *
+ * Args:
+ * hHal - HAL handle for device
+ * pMsg - Message body passed from WDA; includes NAN header
+ *
+ * Returns:
+ * VOS_STATUS
+******************************************************************************/
+VOS_STATUS sme_NanEvent(tHalHandle hHal, void* pMsg)
+{
+    tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+    VOS_STATUS status = VOS_STATUS_SUCCESS;
+
+    if (NULL == pMsg)
+    {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                FL("msg ptr is NULL"));
+        status = VOS_STATUS_E_FAILURE;
+    }
+    else
+    {
+        VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_MED,
+                FL("SME: Received sme_NanEvent"));
+        if (pMac->sme.nanCallback)
+        {
+            pMac->sme.nanCallback(pMac->hHdd, (tSirNanEvent *)pMsg);
+        }
+        else
+        {
+            VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+                    FL("nanCallback is NULL"));
+        }
+    }
+
+    return status;
+}