wlan: Add PMF (802.11w) support for station mode

These changes add Protected Management Frames (802.11w) support for
the device in station mode.

Change-Id: I2cdc60c4a9ed3ab40303de11ca3b679a9fe1d455
CRs-Fixed: 452422, 452831, 455139, 450564, 452558
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 668b4ae..8a7c095 100755
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -109,6 +109,9 @@
 #ifdef FEATURE_WLAN_CCX
 v_U8_t ccpRSNOui06[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x40, 0x96, 0x00 }; // CCKM
 #endif /* FEATURE_WLAN_CCX */
+#ifdef WLAN_FEATURE_11W
+v_U8_t ccpRSNOui07[ HDD_RSN_OUI_SIZE ] = { 0x00, 0x0F, 0xAC, 0x06 }; // RSN-PSK-SHA256
+#endif
 
 #if defined(WLAN_FEATURE_VOWIFI_11R) 
 // Offset where the EID-Len-IE, start.
@@ -120,6 +123,13 @@
 
 void hdd_ResetCountryCodeAfterDisAssoc(hdd_adapter_t *pAdapter);
 
+#ifdef WLAN_FEATURE_11W
+void hdd_indicateUnprotMgmtFrame(hdd_adapter_t *pAdapter,
+                            tANI_U32 nFrameLength,
+                            tANI_U8* pbFrames,
+                            tANI_U8 frameType );
+#endif
+
 v_VOID_t hdd_connSetConnectionState( hdd_station_ctx_t *pHddStaCtx,
                                         eConnectionState connState )
 {
@@ -1329,7 +1339,10 @@
                     "Cannot register STA with TL.  Failed with vosStatus = %d [%08lX]",
                     vosStatus, vosStatus );
         }
-
+#ifdef WLAN_FEATURE_11W
+        vos_mem_zero( &pAdapter->hdd_stats.hddPmfStats,
+                      sizeof(pAdapter->hdd_stats.hddPmfStats) );
+#endif
         // Start the Queue
         netif_tx_wake_all_queues(dev);
     }  
@@ -2320,6 +2333,13 @@
             wlan_hdd_tdls_mgmt_completion_callback(pAdapter, pRoamInfo->reasonCode);
             break;
 #endif
+#ifdef WLAN_FEATURE_11W
+       case eCSR_ROAM_UNPROT_MGMT_FRAME_IND:
+            hdd_indicateUnprotMgmtFrame(pAdapter, pRoamInfo->nFrameLength,
+                                         pRoamInfo->pbFrames,
+                                         pRoamInfo->frameType);
+            break;
+#endif
         default:
             break;
     }
@@ -2355,6 +2375,12 @@
         auth_type = eCSR_AUTH_TYPE_CCKM_RSN;
     } else
 #endif /* FEATURE_WLAN_CCX */
+#ifdef WLAN_FEATURE_11W
+    if (memcmp(auth_suite , ccpRSNOui07, 4) == 0)
+    {
+        auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256;
+    } else
+#endif
     { 
         auth_type = eCSR_AUTH_TYPE_UNKNOWN;
     }
@@ -2470,6 +2496,10 @@
                 eCsrEncryptionType *pEncryptType, 
                 eCsrEncryptionType *mcEncryptType, 
                 eCsrAuthType *pAuthType, 
+#ifdef WLAN_FEATURE_11W
+                u_int8_t *pMfpRequired,
+                u_int8_t *pMfpCapable,
+#endif
                 u_int16_t gen_ie_len, 
                 u_int8_t *gen_ie) 
 {
@@ -2522,6 +2552,10 @@
         *pEncryptType = hdd_TranslateRSNToCsrEncryptionType(dot11RSNIE.pwise_cipher_suites[0]);                     
         //dot11RSNIE.gp_cipher_suite_count 
         *mcEncryptType = hdd_TranslateRSNToCsrEncryptionType(dot11RSNIE.gp_cipher_suite);                     
+#ifdef WLAN_FEATURE_11W
+        *pMfpRequired = (dot11RSNIE.RSN_Cap[0] >> 6) & 0x1 ;
+        *pMfpCapable = (dot11RSNIE.RSN_Cap[0] >> 7) & 0x1 ;
+#endif
         // Set the PMKSA ID Cache for this interface
         for (i=0; i<dot11RSNIE.pmkid_count; i++) 
         {
@@ -2590,6 +2624,10 @@
     v_U32_t status = 0;
     eCsrEncryptionType RSNEncryptType;
     eCsrEncryptionType mcRSNEncryptType;
+#ifdef WLAN_FEATURE_11W
+    u_int8_t RSNMfpRequired;
+    u_int8_t RSNMfpCapable;
+#endif
     struct ether_addr   bSsid;   // MAC address of assoc peer
     // MAC address of assoc peer
     // But, this routine is only called when we are NOT associated.
@@ -2611,6 +2649,10 @@
             &RSNEncryptType,
             &mcRSNEncryptType,
             RSNAuthType,
+#ifdef WLAN_FEATURE_11W
+            &RSNMfpRequired,
+            &RSNMfpCapable,
+#endif
             pWextState->WPARSNIE[1]+2,
             pWextState->WPARSNIE);
     if (status == 0)
@@ -2621,6 +2663,11 @@
         
         pWextState->roamProfile.EncryptionType.encryptionType[0] = RSNEncryptType; // Use the cipher type in the RSN IE
         pWextState->roamProfile.mcEncryptionType.encryptionType[0] = mcRSNEncryptType;
+
+#ifdef WLAN_FEATURE_11W
+        pWextState->roamProfile.MFPRequired = RSNMfpRequired;
+        pWextState->roamProfile.MFPCapable = RSNMfpCapable;
+#endif
         hddLog( LOG1, "%s: CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", __func__, *RSNAuthType, RSNEncryptType, mcRSNEncryptType);
     }
     return 0;
@@ -2698,6 +2745,12 @@
             } else
 #endif
 
+#ifdef WLAN_FEATURE_11W
+            if (RSNAuthType == eCSR_AUTH_TYPE_RSN_PSK_SHA256) {
+                pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_RSN_PSK_SHA256;
+            } else
+#endif
+
             if( (pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) 
                     == IW_AUTH_KEY_MGMT_802_1X) {
                pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_RSN;   
@@ -3222,6 +3275,9 @@
          case eCSR_AUTH_TYPE_FT_RSN_PSK:
 #endif
          case eCSR_AUTH_TYPE_RSN_PSK:
+#ifdef WLAN_FEATURE_11W
+         case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
+#endif
              hddLog(LOG1,"%s called with unknown auth type", __func__);
              wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM;
              return -EIO;
@@ -3415,3 +3471,77 @@
     }
 }
 
+#ifdef WLAN_FEATURE_11W
+/**---------------------------------------------------------------------------
+
+  \brief hdd_indicateUnprotMgmtFrame -
+  This function forwards the unprotected management frame to the supplicant
+  \param  - pAdapter - Pointer to HDD adapter
+          - nFrameLength - Length of the unprotected frame being passed
+          - pbFrames - Pointer to the frame buffer
+          - frameType - 802.11 frame type
+  \return - nothing
+
+  --------------------------------------------------------------------------*/
+void hdd_indicateUnprotMgmtFrame( hdd_adapter_t *pAdapter,
+                            tANI_U32 nFrameLength,
+                            tANI_U8* pbFrames,
+                            tANI_U8 frameType )
+{
+    tANI_U8 type = 0;
+    tANI_U8 subType = 0;
+
+    hddLog(VOS_TRACE_LEVEL_INFO, "%s: Frame Type = %d Frame Length = %d",
+            __func__, frameType, nFrameLength);
+
+    /* Sanity Checks */
+    if (NULL == pAdapter)
+    {
+        hddLog( LOGE, FL("pAdapter is NULL"));
+        return;
+    }
+
+    if (NULL == pAdapter->dev)
+    {
+        hddLog( LOGE, FL("pAdapter->dev is NULL"));
+        return;
+    }
+
+    if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
+    {
+        hddLog( LOGE, FL("pAdapter has invalid magic"));
+        return;
+    }
+
+    if( !nFrameLength )
+    {
+        hddLog( LOGE, FL("Frame Length is Invalid ZERO"));
+        return;
+    }
+
+    if (NULL == pbFrames) {
+        hddLog( LOGE, FL("pbFrames is NULL"));
+        return;
+    }
+
+    type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]);
+    subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]);
+
+    /* Get pAdapter from Destination mac address of the frame */
+    if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DISASSOC)
+    {
+        cfg80211_send_unprot_disassoc(pAdapter->dev, pbFrames, nFrameLength);
+        pAdapter->hdd_stats.hddPmfStats.numUnprotDisassocRx++;
+    }
+    else if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DEAUTH)
+    {
+        cfg80211_send_unprot_deauth(pAdapter->dev, pbFrames, nFrameLength);
+        pAdapter->hdd_stats.hddPmfStats.numUnprotDeauthRx++;
+    }
+    else
+    {
+        hddLog( LOGE, FL("Frame type %d and subtype %d are not valid"), type, subType);
+        return;
+    }
+}
+#endif
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 5fa9cce..58fffeb 100755
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -164,6 +164,9 @@
 #ifdef FEATURE_WLAN_WAPI
     WLAN_CIPHER_SUITE_SMS4,
 #endif
+#ifdef WLAN_FEATURE_11W
+    WLAN_CIPHER_SUITE_AES_CMAC,
+#endif
 };
 
 static inline int is_broadcast_ether_addr(const u8 *addr)
@@ -704,6 +707,13 @@
     sme_RegisterMgmtFrame(hHal, pAdapter->sessionId, type,
                          (v_U8_t*)P2P_ACTION_FRAME,
                                   P2P_ACTION_FRAME_SIZE );
+
+#ifdef WLAN_FEATURE_11W
+    /* SA Query Response Action Frame */
+    sme_RegisterMgmtFrame(hHal, pAdapter->sessionId, type,
+                         (v_U8_t*)SA_QUERY_FRAME_RSP,
+                                  SA_QUERY_FRAME_RSP_SIZE );
+#endif /* WLAN_FEATURE_11W */
 }
 
 void wlan_hdd_cfg80211_pre_voss_stop(hdd_adapter_t* pAdapter)
@@ -743,6 +753,13 @@
     sme_DeregisterMgmtFrame(hHal, pAdapter->sessionId, type,
                          (v_U8_t*)P2P_ACTION_FRAME,
                                   P2P_ACTION_FRAME_SIZE );
+
+#ifdef WLAN_FEATURE_11W
+    /* SA Query Response Action Frame */
+    sme_DeregisterMgmtFrame(hHal, pAdapter->sessionId, type,
+                         (v_U8_t*)SA_QUERY_FRAME_RSP,
+                                  SA_QUERY_FRAME_RSP_SIZE );
+#endif /* WLAN_FEATURE_11W */
 }
 
 #ifdef FEATURE_WLAN_WAPI
@@ -3111,11 +3128,23 @@
                 return 0;
             }
 #endif
+
 #ifdef FEATURE_WLAN_CCX
         case WLAN_CIPHER_SUITE_KRK:
             setKey.encType = eCSR_ENCRYPT_TYPE_KRK;
             break;
 #endif
+
+#ifdef WLAN_FEATURE_11W
+        case WLAN_CIPHER_SUITE_AES_CMAC:
+            setKey.encType = eCSR_ENCRYPT_TYPE_AES_CMAC;
+            /* Temporarily we will ignore the setting of the IGTK.  Once the Riva
+               firmware is modified to handle the IGTK, then we will proceeed normally.
+               For now, we just return success. */
+            return 0;
+            /* break; */
+#endif
+
         default:
             hddLog(VOS_TRACE_LEVEL_ERROR, "%s: unsupported cipher type %lu",
                     __func__, params->cipher);
@@ -4811,6 +4840,11 @@
            pRoamProfile->ChannelInfo.ChannelList = &operatingChannel;
            pRoamProfile->ChannelInfo.numOfChannels = 1;
         }
+        else
+        {
+            pRoamProfile->ChannelInfo.ChannelList = NULL;
+            pRoamProfile->ChannelInfo.numOfChannels = 0;
+        }
 
         /* change conn_state to connecting before sme_RoamConnect(), because sme_RoamConnect()
          * has a direct path to call hdd_smeRoamCallback(), which will change the conn_state
@@ -5365,6 +5399,10 @@
         return status;
     }
 
+#ifdef WLAN_FEATURE_11W
+    pWextState->roamProfile.MFPEnabled = (req->mfp == NL80211_MFP_REQUIRED);
+#endif
+
     /*parse WPA/RSN IE, and set the correspoing fileds in Roam profile*/
     if (req->ie_len)
     {
diff --git a/CORE/HDD/src/wlan_hdd_p2p.c b/CORE/HDD/src/wlan_hdd_p2p.c
index 806c716..0b751c7 100644
--- a/CORE/HDD/src/wlan_hdd_p2p.c
+++ b/CORE/HDD/src/wlan_hdd_p2p.c
@@ -554,6 +554,9 @@
     tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]);
     tActionFrmType actionFrmType;
     bool noack = 0;
+#ifdef WLAN_FEATURE_11W
+    tANI_U8 *pTxFrmBuf = (tANI_U8 *) buf; // For SA Query, we have to set protect bit
+#endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
     hdd_adapter_t *goAdapter;
@@ -785,7 +788,17 @@
                 hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__);
             }
         }
-
+#ifdef WLAN_FEATURE_11W
+        if ((type == SIR_MAC_MGMT_FRAME) &&
+                (subType == SIR_MAC_MGMT_ACTION) &&
+                (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_SA_QUERY_ACTION_FRAME))
+        {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                     "%s: Calling sme_sendAction. For Category %s", __func__, "SA Query");
+            // Since this is an SA Query Action Frame, we have to protect it
+            WLAN_HDD_SET_WEP_FRM_FC(pTxFrmBuf[1]);
+        }
+#endif
         if (eHAL_STATUS_SUCCESS !=
                sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter),
                                sessionId, buf, len, extendedWait, noack))
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 74b4bcc..50ce53c 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -208,6 +208,9 @@
 #ifdef FEATURE_WLAN_TDLS
 #define WE_GET_TDLS_PEERS    8
 #endif
+#ifdef WLAN_FEATURE_11W
+#define WE_GET_11W_INFO      9
+#endif
 
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_NONE   (SIOCIWFIRSTPRIV + 6)
@@ -533,6 +536,9 @@
         case eCSR_AUTH_TYPE_FT_RSN_PSK:
 #endif
         case eCSR_AUTH_TYPE_RSN_PSK:
+#ifdef WLAN_FEATURE_11W
+        case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
+#endif
             rsnType = eANI_BOOLEAN_TRUE;
             break;
         //case eCSR_AUTH_TYPE_FAILED:
@@ -904,6 +910,11 @@
    pWextState->roamProfile.nRSNReqIELength = 0;
    pWextState->roamProfile.pRSNReqIE = (tANI_U8 *)NULL;
 
+#ifdef FEATURE_WLAN_WAPI
+   pWextState->roamProfile.nWAPIReqIELength = 0;
+   pWextState->roamProfile.pWAPIReqIE = (tANI_U8 *)NULL;
+#endif
+
    pWextState->roamProfile.bWPSAssociation = VOS_FALSE;
    pWextState->roamProfile.pAddIEScan = (tANI_U8 *)NULL;
    pWextState->roamProfile.nAddIEScanLength = 0;
@@ -921,6 +932,12 @@
    pWextState->roamProfile.AuthType.numEntries = 1;
    pWextState->roamProfile.AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM;
 
+#ifdef WLAN_FEATURE_11W
+   pWextState->roamProfile.MFPEnabled = eANI_BOOLEAN_FALSE;
+   pWextState->roamProfile.MFPRequired = 0;
+   pWextState->roamProfile.MFPCapable = 0;
+#endif
+
    pWextState->authKeyMgmt = 0;
 
    for (i=0; i < CSR_MAX_NUM_KEY; i++)
@@ -4043,6 +4060,9 @@
 {
     hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
     int sub_cmd = wrqu->data.flags;
+#ifdef WLAN_FEATURE_11W
+    hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
+#endif
 
     if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
     {
@@ -4255,6 +4275,25 @@
             break;
         }
 #endif
+#ifdef WLAN_FEATURE_11W
+       case WE_GET_11W_INFO:
+       {
+           hddLog(LOGE, "WE_GET_11W_ENABLED = %d",  pWextState->roamProfile.MFPEnabled );
+
+           snprintf(extra, WE_MAX_STR_LEN,
+                    "\n BSSID %02X:%02X:%02X:%02X:%02X:%02X, Is PMF Assoc? %d"
+                    "\n Number of Unprotected Disassocs %d"
+                    "\n Number of Unprotected Deauths %d",
+                    (*pWextState->roamProfile.BSSIDs.bssid)[0], (*pWextState->roamProfile.BSSIDs.bssid)[1],
+                    (*pWextState->roamProfile.BSSIDs.bssid)[2], (*pWextState->roamProfile.BSSIDs.bssid)[3],
+                    (*pWextState->roamProfile.BSSIDs.bssid)[4], (*pWextState->roamProfile.BSSIDs.bssid)[5],
+                    pWextState->roamProfile.MFPEnabled, pAdapter->hdd_stats.hddPmfStats.numUnprotDisassocRx,
+                    pAdapter->hdd_stats.hddPmfStats.numUnprotDeauthRx);
+
+           wrqu->data.length = strlen(extra)+1;
+           break;
+       }
+#endif
         default:  
         {
             hddLog(LOGE, "Invalid IOCTL command %d  \n",  sub_cmd );
@@ -6623,6 +6662,13 @@
         IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN,
         "getTdlsPeers" },
 #endif
+#ifdef WLAN_FEATURE_11W
+    {
+        WE_GET_11W_INFO,
+        0,
+        IW_PRIV_TYPE_CHAR| WE_MAX_STR_LEN,
+        "getPMFInfo" },
+#endif
     /* handlers for main ioctl */
     {   WLAN_PRIV_SET_NONE_GET_NONE,
         0,