wlan: HDD and SME support for DISA

1. HDD accepts DISA request through iwpriv command "encryptMsg".
2. Parses the buffer and populates the fields required to give to
   the firmware for encryption.
3. Registers a HDD callback to receive the response from the
   firmware.

Change-Id: I69299f0ca677c5afbda36a08c818035aa4918b38
CRs-Fixed: 765234
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 14fc6ad..23d9bcd 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -190,6 +190,7 @@
 #endif
 #define WE_SET_AP_WPS_IE     4  //This is called in station mode to set probe rsp ie.
 #define WE_SET_CONFIG        5
+#define WE_SET_ENCRYPT_MSG   6
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_THREE_INT_GET_NONE   (SIOCIWFIRSTPRIV + 4)
@@ -3110,6 +3111,206 @@
     return ret;
 }
 
+static uint8 chartohex(char c)
+{
+    uint8 val = 0;
+    if (c >= '0' && c <= '9')
+        val = c - '0';
+    else if (c >= 'a' && c <= 'f')
+        val = c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+        val = c - 'A' + 10;
+    else
+        hddLog(VOS_TRACE_LEVEL_ERROR, "Not a valid hex char");
+
+    return val;
+}
+
+uint8 getByte(char **buf)
+{
+    uint8 byte = 0;
+    char *temp = *buf;
+    byte = chartohex(*temp) * 16;
+    temp++;
+    byte += chartohex(*temp);
+    temp++;
+    *buf = temp;
+    return byte;
+}
+
+static void parse_Bufferforpkt(tSirpkt80211 *pkt, u8 *pBuffer, u16 len)
+{
+    tSir80211Header *macHeader;
+    int i = 0, j = 0, length = 0;
+    uint8 byte = 0;
+    char *temp = pBuffer;
+    uint16 fragNum = 0;
+
+    macHeader = &pkt->macHeader;
+
+    pkt->encParams.keyParams.key[0].keyId = *temp - '0';
+
+    temp++;
+
+    hddLog(VOS_TRACE_LEVEL_ERROR, "Input Message to encrypt");
+    hddLog(VOS_TRACE_LEVEL_ERROR, "Key Id : %d",
+            pkt->encParams.keyParams.key[0].keyId);
+
+    for (i = 0; i< 16; i++) {
+        pkt->encParams.keyParams.key[0].key[i]
+            = getByte(&temp);
+    }
+
+    print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1,
+            &pkt->encParams.keyParams.key[0].key[0], 16, 0);
+
+    for (i = 0; i< 6; i++) {
+        pkt->encParams.pn[i]
+            = getByte(&temp);
+    }
+
+    print_hex_dump(KERN_INFO, "PN : ", DUMP_PREFIX_NONE, 16, 1,
+            &pkt->encParams.pn[0], 6, 0);
+
+    for (i = 0, j= 5; i< 3; i++, j--) {
+        byte = pkt->encParams.pn[i];
+        pkt->encParams.pn[i] = pkt->encParams.pn[j];
+        pkt->encParams.pn[j] = byte;
+    }
+
+    length = getByte(&temp);
+
+    byte = getByte(&temp);
+
+    macHeader->frameCtrl.protVer  = byte & 0x3;
+    macHeader->frameCtrl.type     = (byte >> 2) & 0x3;
+    macHeader->frameCtrl.subType  = (byte >> 4) & 0xF;
+
+    byte = getByte(&temp);
+    macHeader->frameCtrl.toDS     = (byte) & 0x1;
+    macHeader->frameCtrl.fromDS   = (byte >> 1) & 0x1;
+    macHeader->frameCtrl.moreFrag = (byte >> 2) & 0x1;
+    macHeader->frameCtrl.retry    = (byte >> 3) & 0x1;
+    macHeader->frameCtrl.powerMgmt = (byte >> 4) & 0x1;
+    macHeader->frameCtrl.moreData = (byte >> 5) & 0x1;
+    macHeader->frameCtrl.wep      = (byte >> 6) & 0x1;
+    macHeader->frameCtrl.order    = (byte >> 7) & 0x1;
+
+    hddLog(VOS_TRACE_LEVEL_INFO, "macHeader->frameCtrl.protVer    : %x "
+            "macHeader->frameCtrl.type       : %x "
+            "macHeader->frameCtrl.subType    : %x "
+            "macHeader->frameCtrl.toDS       : %x "
+            "macHeader->frameCtrl.fromDS     : %x "
+            "macHeader->frameCtrl.moreFrag   : %x "
+            "macHeader->frameCtrl.retry      : %x "
+            "macHeader->frameCtrl.powerMgmt  : %x "
+            "macHeader->frameCtrl.MoreData   : %x "
+            "macHeader->frameCtrl.wep        : %x "
+            "macHeader->frameCtrl.order      : %x "
+            , macHeader->frameCtrl.protVer
+            , macHeader->frameCtrl.type
+            , macHeader->frameCtrl.subType
+            , macHeader->frameCtrl.toDS
+            , macHeader->frameCtrl.fromDS
+            , macHeader->frameCtrl.moreFrag
+            , macHeader->frameCtrl.retry
+            , macHeader->frameCtrl.powerMgmt
+            , macHeader->frameCtrl.moreData
+            , macHeader->frameCtrl.wep
+            , macHeader->frameCtrl.order);
+
+
+    macHeader->usDurationId = getByte(&temp);
+    macHeader->usDurationId += getByte(&temp) << 8;
+
+    macHeader->vA1[0]       = getByte(&temp);
+    macHeader->vA1[1]       = getByte(&temp);
+    macHeader->vA1[2]       = getByte(&temp);
+    macHeader->vA1[3]       = getByte(&temp);
+    macHeader->vA1[4]       = getByte(&temp);
+    macHeader->vA1[5]       = getByte(&temp);
+
+    macHeader->vA2[0]       = getByte(&temp);
+    macHeader->vA2[1]       = getByte(&temp);
+    macHeader->vA2[2]       = getByte(&temp);
+    macHeader->vA2[3]       = getByte(&temp);
+    macHeader->vA2[4]       = getByte(&temp);
+    macHeader->vA2[5]       = getByte(&temp);
+
+    macHeader->vA3[0]       = getByte(&temp);
+    macHeader->vA3[1]       = getByte(&temp);
+    macHeader->vA3[2]       = getByte(&temp);
+    macHeader->vA3[3]       = getByte(&temp);
+    macHeader->vA3[4]       = getByte(&temp);
+    macHeader->vA3[5]       = getByte(&temp);
+
+    macHeader->sSeqCtrl = getByte(&temp);
+    fragNum = macHeader->sSeqCtrl & 0xF;
+    macHeader->sSeqCtrl >>= 4;
+
+    macHeader->sSeqCtrl += getByte(&temp) << 4;
+
+    macHeader->sSeqCtrl |= fragNum << 12;
+
+    if (length == 30 || length == 32) {
+        macHeader->optvA4[0]       = getByte(&temp);
+        macHeader->optvA4[1]       = getByte(&temp);
+        macHeader->optvA4[2]       = getByte(&temp);
+        macHeader->optvA4[3]       = getByte(&temp);
+        macHeader->optvA4[4]       = getByte(&temp);
+        macHeader->optvA4[5]       = getByte(&temp);
+    }
+
+    if (length == 26 || length == 32) {
+        macHeader->usQosCtrl = getByte(&temp);
+        macHeader->usQosCtrl += getByte(&temp) << 8;
+    }
+
+    print_hex_dump(KERN_INFO, "Header : ", DUMP_PREFIX_NONE, 16, 1,
+            (char *)&pkt->macHeader, sizeof(tSir80211Header), 0);
+
+    //parse payload
+    length = getByte(&temp);
+    length += getByte(&temp) << 8;
+    hddLog(VOS_TRACE_LEVEL_INFO,"Payload length : %d", length);
+
+    pkt->data.length = length;
+
+    for (i = 0; i< length; i++) {
+        pkt->data.data[i] = getByte(&temp);
+    }
+
+    print_hex_dump(KERN_INFO, "Data : ", DUMP_PREFIX_NONE, 16, 1,
+            &pkt->data.data[0], pkt->data.length, 0);
+}
+
+/**---------------------------------------------------------------------------
+
+  \brief hdd_encrypt_msg_cb() - Callback function for DISA
+  encrypt message request
+  This is an asynchronous callback function from SME when the encrypted data
+  is received
+
+  \pEncInfoRsp -> Encrypted data info
+
+  \return - 0 for success non-zero for failure
+  --------------------------------------------------------------------------*/
+static void
+hdd_encrypt_msg_cb(v_VOID_t *pUserData, v_VOID_t *pEncInfoRsp)
+{
+    tpSetEncryptedDataRspParams   pEncryptedDataRsp;
+
+    pEncryptedDataRsp = (tpSetEncryptedDataRspParams)pEncInfoRsp;
+
+    hddLog(VOS_TRACE_LEVEL_ERROR, "Encrypted Message");
+    hddLog(VOS_TRACE_LEVEL_ERROR, "Length : %d",
+            pEncryptedDataRsp->encryptedPayload.length);
+    hddLog(VOS_TRACE_LEVEL_ERROR, " Encrypted Data: ");
+    print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
+            pEncryptedDataRsp->encryptedPayload.data,
+            pEncryptedDataRsp->encryptedPayload.length, 0);
+}
+
 VOS_STATUS  wlan_hdd_enter_bmps(hdd_adapter_t *pAdapter, int mode)
 {
    struct statsContext context;
@@ -4860,6 +5061,7 @@
     hdd_config_t  *pConfig = pHddCtx->cfg_ini;
 #endif /* WLAN_FEATURE_VOWIFI */
     struct iw_point s_priv_data;
+    tSirpkt80211 *pkt;
 
     if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
     {
@@ -4947,6 +5149,38 @@
              ret = -EINVAL;
           }
           break;
+       case WE_SET_ENCRYPT_MSG:
+          pkt = vos_mem_malloc(sizeof(tSirpkt80211));
+          if (NULL == pkt)
+          {
+              hddLog(VOS_TRACE_LEVEL_ERROR,
+                      "%s: vos_mem_alloc failed", __func__);
+              return -ENOMEM;
+          }
+
+          memset(pkt, 0, sizeof(tSirpkt80211));
+
+          if (FALSE == sme_IsFeatureSupportedByFW(DISA)) {
+              hddLog(VOS_TRACE_LEVEL_ERROR,
+                      FL("Firmware is not DISA capable"));
+              ret = -EINVAL;
+              vos_mem_free(pkt);
+              break;
+          }
+
+          parse_Bufferforpkt(pkt, pBuffer, wrqu->data.length);
+
+          ret = sme_Encryptmsgsend(pHddCtx->hHal, (u8 *)pkt,
+                  sizeof(tSirpkt80211), hdd_encrypt_msg_cb);
+          if (eHAL_STATUS_SUCCESS != ret) {
+              hddLog(VOS_TRACE_LEVEL_ERROR,
+                      FL("SENDEncryptMSG: fail to post WDA cmd"));
+              ret = -EINVAL;
+          }
+          vos_mem_free(pkt);
+
+          break;
+
        default:
        {
            hddLog(LOGE, "%s: Invalid sub command %d",__func__, sub_cmd);
@@ -8733,6 +8967,12 @@
         0,
         "setConfig" },
 
+    {   WE_SET_ENCRYPT_MSG,
+        IW_PRIV_TYPE_CHAR| 512,
+        0,
+        "encryptMsg" },
+
+
     /* handlers for main ioctl */
     {   WLAN_PRIV_SET_THREE_INT_GET_NONE,
         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,