wlan: HDD: Add mac spoofing support based on random mac OUI

This is done as per need to spoof scans. Only FW initialted
scans will use spoofed mac addr after this.

Add a way to pass first 3 bytes (OUI bytes) of mac addr from
cfg80211 and randomly generate last three bytes in driver
and send them to FW. Disable spoof scanning by set first 3 bytes
of mac addr to 00:00:00.

Change-Id: If862a2e28dccd7c9dc4d1ab6b6105148fc78cb0e
CRs-Fixed: 731655
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index f61f5ee..8304b39 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -2253,6 +2253,11 @@
 #define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX              (1)
 #define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT          (0)
 
+#define CFG_ENABLE_MAC_ADDR_SPOOFING                         "gEnableMacAddrSpoof"
+#define CFG_ENABLE_MAC_ADDR_SPOOFING_MIN                     (0)
+#define CFG_ENABLE_MAC_ADDR_SPOOFING_MAX                     (1)
+#define CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT                 (0)
+
 #define CFG_ENABLE_CH_AVOID                                  "gEnableChannelAvoidance"
 #define CFG_ENABLE_CH_AVOID_MIN                              ( 0 )
 #define CFG_ENABLE_CH_AVOID_MAX                              ( 1 )
@@ -2819,6 +2824,7 @@
 #endif
    v_U32_t                     deferImpsTime;
    v_BOOL_t                    sendDeauthBeforeCon;
+   v_BOOL_t                    enableMacSpoofing;
    v_BOOL_t                    fenableCHAvoidance;
    v_U8_t                      gMaxConcurrentActiveSessions;
 
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index bf65898..a0c9486 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -154,6 +154,7 @@
     QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35,
     QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36,
     QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37,
+    QCA_NL80211_VENDOR_SUBCMD_MAC_OUI = 39
 };
 
 enum qca_nl80211_vendor_subcmds_index {
@@ -779,6 +780,14 @@
 };
 
 #endif /* WLAN_FEATURE_EXTSCAN */
+enum qca_wlan_vendor_attr_set_scanning_mac_oui{
+    QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_INVALID = 0,
+    QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI = 1,
+    /* keep last */
+    QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST,
+    QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX =
+        QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST - 1,
+};
 
 /* Vendor id to be used in vendor specific command and events
  * to user space. Use QCA OUI 00:13:74 to match with define in
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 8295885..7f2688d 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1119,6 +1119,11 @@
    tANI_U32 magic;
 }bcnMissRateContext_t;
 
+typedef struct
+{
+   v_MACADDR_t randomMacAddr;
+}macAddrSpoof_t;
+
 /** Adapter stucture definition */
 
 struct hdd_context_s
@@ -1324,6 +1329,7 @@
 
     v_BOOL_t btCoexModeSet;
     v_BOOL_t isPnoEnable;
+    macAddrSpoof_t spoofMacAddr;
 };
 
 
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 828a930..846b211 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -3091,6 +3091,13 @@
                 CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN,
                 CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX),
 
+   REG_VARIABLE(CFG_ENABLE_MAC_ADDR_SPOOFING, WLAN_PARAM_Integer,
+                hdd_config_t, enableMacSpoofing,
+                VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT,
+                CFG_ENABLE_MAC_ADDR_SPOOFING_MIN,
+                CFG_ENABLE_MAC_ADDR_SPOOFING_MAX),
+
    REG_VARIABLE(CFG_ENABLE_CH_AVOID, WLAN_PARAM_Integer,
                  hdd_config_t, fenableCHAvoidance,
                  VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index b0918c1..1c3d228 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -3972,6 +3972,72 @@
     [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON] = {.type = NLA_S32 },
 
 };
+
+static const struct nla_policy
+wlan_hdd_mac_config[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX+1] =
+{
+    [QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI] = {.type = NLA_UNSPEC },
+};
+
+static int wlan_hdd_cfg80211_set_spoofed_mac_oui(struct wiphy *wiphy,
+        struct wireless_dev *wdev,
+        void *data,
+        int data_len)
+{
+
+    hdd_context_t *pHddCtx      = wiphy_priv(wiphy);
+    struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX + 1];
+
+    if (0 != wlan_hdd_validate_context(pHddCtx)){
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("hdd Ctx invalid while spoof macAddr"));
+        return -EINVAL;
+    }
+    if (FALSE == pHddCtx->cfg_ini->enableMacSpoofing) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("MAC_SPOOFED_SCAN disabled in ini"));
+        return -ENOTSUPP;
+     }
+    if (TRUE != sme_IsFeatureSupportedByFW(MAC_SPOOFED_SCAN)){
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("MAC_SPOOFED_SCAN not supported by FW"));
+        return -ENOTSUPP;
+    }
+
+    if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX,
+                data, data_len, wlan_hdd_mac_config)) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid ATTR"));
+        return -EINVAL;
+    }
+
+    /* Parse and fetch mac address */
+    if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("attr mac addr failed"));
+        return -EINVAL;
+    }
+
+    memcpy(pHddCtx->spoofMacAddr.randomMacAddr.bytes, nla_data(
+                tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]),
+            VOS_MAC_ADDR_LAST_3_BYTES);
+
+    vos_trace_hex_dump( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,nla_data(
+            tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]),
+            VOS_MAC_ADDR_FIRST_3_BYTES);
+
+    if (VOS_STATUS_SUCCESS != vos_randomize_n_bytes(
+        (void *)(&pHddCtx->spoofMacAddr.randomMacAddr.bytes[3]),
+        VOS_MAC_ADDR_LAST_3_BYTES)) {
+        hddLog(LOGE, FL("Failed to generate random Mac Addr"));
+    }
+    vos_trace_hex_dump( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+        pHddCtx->spoofMacAddr.randomMacAddr.bytes,
+            VOS_MAC_ADDR_SIZE);
+
+    if (eHAL_STATUS_SUCCESS != sme_SpoofMacAddrReq(pHddCtx->hHal,
+                &pHddCtx->spoofMacAddr.randomMacAddr)) {
+        hddLog(LOGE, FL("Failed to send Spoof Mac Addr to FW"));
+    }
+
+    return 0;
+}
+
 static int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy,
                                                 struct wireless_dev *wdev,
                                                 void *data,
@@ -4358,6 +4424,13 @@
         .doit = wlan_hdd_cfg80211_exttdls_get_status
     },
 
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MAC_OUI,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV,
+        .doit = wlan_hdd_cfg80211_set_spoofed_mac_oui
+    },
 };
 
 /* vendor specific events */
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 258c848..3744a8b 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -329,4 +329,6 @@
 
 v_U64_t vos_get_monotonic_boottime(void);
 
+VOS_STATUS vos_randomize_n_bytes(void *mac_addr, tANI_U32 n);
+
 #endif // if !defined __VOS_NVITEM_H
diff --git a/CORE/VOSS/inc/vos_nvitem.h b/CORE/VOSS/inc/vos_nvitem.h
index 815a68e..43d053a 100644
--- a/CORE/VOSS/inc/vos_nvitem.h
+++ b/CORE/VOSS/inc/vos_nvitem.h
@@ -120,6 +120,8 @@
 
 #define VOS_COUNTRY_CODE_LEN  2
 #define VOS_MAC_ADDRESS_LEN   6
+#define VOS_MAC_ADDR_LAST_3_BYTES   3
+#define VOS_MAC_ADDR_FIRST_3_BYTES   3
 #define VOS_NV_FREQUENCY_FOR_1_3V_SUPPLY_3P2MH 0   //3.2 Mhz
 #define VOS_NV_FREQUENCY_FOR_1_3V_SUPPLY_1P6MH 1   //1.6 Mhz
 
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 9df8d14..8535fc1 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -2205,3 +2205,26 @@
     wcnss_get_monotonic_boottime(&ts);
     return (((v_U64_t)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000));
 }
+
+/**---------------------------------------------------------------------------
+
+  \brief vos_randomize_n_bytes() - HDD Random Mac Addr Generator
+
+  This generates the random mac address for WLAN interface
+
+  \param  - mac_addr - pointer to Mac address
+
+  \return -  0 for success, < 0 for failure
+
+  --------------------------------------------------------------------------*/
+
+VOS_STATUS  vos_randomize_n_bytes(void *start_addr, tANI_U32 n)
+{
+
+    if (start_addr == NULL )
+        return VOS_STATUS_E_FAILURE;
+
+    get_random_bytes( start_addr, n);
+
+    return eHAL_STATUS_SUCCESS;
+}