Merge "Snap for 9204358 from c5abec4c0b596d3c6ee0e8699e80a95709776905 to gki13-boot-release" into gki13-boot-release
diff --git a/wifi/mac80211_create_radios/main.cpp b/wifi/mac80211_create_radios/main.cpp
index 879cae9..2dfebc5 100644
--- a/wifi/mac80211_create_radios/main.cpp
+++ b/wifi/mac80211_create_radios/main.cpp
@@ -22,6 +22,7 @@
 #include <netlink/genl/genl.h>
 #include <netlink/netlink.h>
 #include <net/ethernet.h>
+#include <linux/nl80211.h>
 
 enum {
     HWSIM_CMD_UNSPEC,
@@ -59,6 +60,8 @@
     HWSIM_ATTR_PERM_ADDR,
     HWSIM_ATTR_IFTYPE_SUPPORT,
     HWSIM_ATTR_CIPHER_SUPPORT,
+    HWSIM_ATTR_MLO_SUPPORT,
+    HWSIM_ATTR_PMSR_SUPPORT,
 };
 
 struct nl_sock_deleter {
@@ -71,7 +74,29 @@
 
 constexpr char kHwSimFamilyName[] = "MAC80211_HWSIM";
 constexpr int kHwSimVersion = 1;
-constexpr int kChannels = 2;
+constexpr uint32_t kChannels = 2;
+constexpr uint32_t kPmsrMaxPeers = 10;
+constexpr uint32_t kFtmAllPreables = NL80211_PREAMBLE_LEGACY
+        | NL80211_PREAMBLE_HT
+        | NL80211_PREAMBLE_VHT
+        | NL80211_PREAMBLE_DMG
+        | NL80211_PREAMBLE_HE;
+constexpr uint32_t kFtmAllBandwidths = NL80211_CHAN_WIDTH_20_NOHT
+        | NL80211_CHAN_WIDTH_20
+        | NL80211_CHAN_WIDTH_40
+        | NL80211_CHAN_WIDTH_80
+        | NL80211_CHAN_WIDTH_80P80
+        | NL80211_CHAN_WIDTH_160
+        | NL80211_CHAN_WIDTH_5
+        | NL80211_CHAN_WIDTH_10
+        | NL80211_CHAN_WIDTH_1
+        | NL80211_CHAN_WIDTH_2
+        | NL80211_CHAN_WIDTH_4
+        | NL80211_CHAN_WIDTH_8
+        | NL80211_CHAN_WIDTH_16
+        | NL80211_CHAN_WIDTH_320;
+constexpr uint8_t kFtmMaxBurstsExponent = 15;
+constexpr uint8_t kFtmMaxFtmsPerBurst = 31;
 
 const char* nlErrStr(const int e) { return (e < 0) ? nl_geterror(e) : ""; }
 
@@ -102,27 +127,82 @@
     RETURN(msg);
 }
 
+#define PUT_FLAG(MSG, TYPE, R) \
+    do { \
+        (R) = nla_put_flag((MSG).get(), TYPE); \
+        if (R) RETURN_NL_ERROR("nla_put_flag(" #TYPE ")", R, nullptr); \
+    } while (false);
+
+#define PUT_DATA(MSG, TYPE, V, SIZE, R) \
+    do { \
+        (R) = nla_put((MSG).get(), TYPE, SIZE, V); \
+        if (R) RETURN_NL_ERROR("nla_put(" #TYPE ")", R, nullptr); \
+    } while (false);
+
+#define PUT_VALUE(MSG, TYPE, V, R) PUT_DATA(MSG, TYPE, &(V), sizeof(V), (R))
+
+#define NEST_START(MSG, TYPE, ATTR) \
+    do { \
+        (ATTR) = nla_nest_start((MSG).get(), TYPE); \
+        if (!(ATTR)) RETURN_ERROR("nla_nest_start(" #TYPE ")", nullptr); \
+    } while (false);
+
+#define NEST_END(MSG, START, R) \
+    do { \
+        (R) = nla_nest_end((MSG).get(), START); \
+        if (R) RETURN_NL_ERROR("nla_nest_end(" #START ")", R, nullptr); \
+    } while (false);
+
 std::unique_ptr<struct nl_msg, nl_msg_deleter>
-buildCreateRadioMessage(const int family, const uint8_t mac[ETH_ALEN]) {
+buildCreateRadioMessage(const int family, const uint8_t mac[ETH_ALEN],
+                        const bool enablePmsr) {
     std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
         createNlMessage(family, HWSIM_CMD_NEW_RADIO);
     if (!msg) { RETURN(nullptr); }
 
     int ret;
-    ret = nla_put(msg.get(), HWSIM_ATTR_PERM_ADDR, ETH_ALEN, mac);
-    if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_PERM_ADDR)", ret, nullptr); }
+    PUT_DATA(msg, HWSIM_ATTR_PERM_ADDR, mac, ETH_ALEN, ret);
+    PUT_FLAG(msg, HWSIM_ATTR_SUPPORT_P2P_DEVICE, ret);
+    PUT_VALUE(msg, HWSIM_ATTR_CHANNELS, kChannels, ret);
 
-    ret = nla_put_flag(msg.get(), HWSIM_ATTR_SUPPORT_P2P_DEVICE);
-    if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_SUPPORT_P2P_DEVICE)", ret, nullptr); }
+    if (enablePmsr) {
+        struct nlattr* pmsr;
+        NEST_START(msg, HWSIM_ATTR_PMSR_SUPPORT, pmsr);
 
-    ret = nla_put_u32(msg.get(), HWSIM_ATTR_CHANNELS, kChannels);
-    if (ret) { RETURN_NL_ERROR("nla_put(HWSIM_ATTR_CHANNELS)", ret, nullptr); }
+        PUT_VALUE(msg, NL80211_PMSR_ATTR_MAX_PEERS, kPmsrMaxPeers, ret);
+
+        struct nlattr* pmsrType;
+        NEST_START(msg, NL80211_PMSR_ATTR_TYPE_CAPA, pmsrType);
+
+        struct nlattr* ftm;
+        NEST_START(msg, NL80211_PMSR_TYPE_FTM, ftm);
+
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP, ret);
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP, ret);
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI, ret);
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC, ret);
+        PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
+                     kFtmAllPreables, ret);
+        PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
+                     kFtmAllBandwidths, ret);
+        PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
+                     kFtmMaxBurstsExponent, ret);
+        PUT_VALUE(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+                     kFtmMaxFtmsPerBurst, ret);
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, ret);
+        PUT_FLAG(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, ret);
+
+        NEST_END(msg, ftm, ret);
+        NEST_END(msg, pmsrType, ret);
+        NEST_END(msg, pmsr, ret);
+    }
 
     RETURN(msg);
 }
 
 int createRadios(struct nl_sock* socket, const int netlinkFamily,
-                 const int nRadios, const int macPrefix) {
+                 const int nRadios, const int macPrefix,
+                 const bool enablePmsr) {
     uint8_t mac[ETH_ALEN] = {};
     mac[0] = 0x02;
     mac[1] = (macPrefix >> CHAR_BIT) & 0xFF;
@@ -132,7 +212,7 @@
         mac[4] = idx;
 
         std::unique_ptr<struct nl_msg, nl_msg_deleter> msg =
-            buildCreateRadioMessage(netlinkFamily, mac);
+            buildCreateRadioMessage(netlinkFamily, mac, enablePmsr);
         if (msg) {
             int ret = nl_send_auto(socket, msg.get());
             if (ret < 0) { RETURN_NL_ERROR("nl_send_auto", ret, 1); }
@@ -144,7 +224,8 @@
     RETURN(0);
 }
 
-int manageRadios(const int nRadios, const int macPrefix) {
+int manageRadios(const int nRadios, const int macPrefix,
+                 const bool enablePmsr) {
     std::unique_ptr<struct nl_sock, nl_sock_deleter> socket(nl_socket_alloc());
     if (!socket) { RETURN_ERROR("nl_socket_alloc", 1); }
 
@@ -155,7 +236,8 @@
     const int netlinkFamily = genl_ctrl_resolve(socket.get(), kHwSimFamilyName);
     if (netlinkFamily < 0) { RETURN_NL_ERROR("genl_ctrl_resolve", ret, 1); }
 
-    ret = createRadios(socket.get(), netlinkFamily, nRadios, macPrefix);
+    ret = createRadios(socket.get(), netlinkFamily, nRadios, macPrefix,
+                       enablePmsr);
     if (ret) { RETURN(ret); }
 
     RETURN(0);
@@ -164,29 +246,38 @@
 int printUsage(FILE* dst, const int ret) {
     fprintf(dst, "%s",
     "Usage:\n"
-    "   mac80211_create_radios n_radios mac_prefix\n"
+    "   mac80211_create_radios [options] n_radios mac_prefix\n"
     "   where\n"
     "       n_radios - int, [1,100], e.g. 2;\n"
     "       mac_prefix - int, [0, 65535], e.g. 5555.\n\n"
     "   mac80211_create_radios will create n_radios with MAC addresses\n"
     "   02:pp:pp:00:nn:00, where nn is incremented (from zero)\n"
-    "   and pp:pp is the mac_prefix specified.\n");
+    "   and pp:pp is the mac_prefix specified.\n"
+    "\n"
+    "   options:\n"
+    "       --enable-pmsr: enable peer measurement for RTT support.\n");
 
     return ret;
 }
 
 int main(int argc, char* argv[]) {
-    if (argc != 3) { return printUsage(stdout, 0); }
+    if (argc != 4 && argc != 3) { return printUsage(stdout, 0); }
 
+    int argIndex = 1;
+    bool enablePmsr = false;
+    if (!strcmp(argv[argIndex], "--enable-pmsr")) {
+      enablePmsr = true;
+      argIndex++;
+    }
     int nRadios;
-    if (!parseInt(argv[1], &nRadios)) { return printUsage(stderr, 1); }
+    if (!parseInt(argv[argIndex++], &nRadios)) { return printUsage(stderr, 1); }
     if (nRadios < 1) { return printUsage(stderr, 1); }
     if (nRadios > 100) { return printUsage(stderr, 1); }
 
     int macPrefix;
-    if (!parseInt(argv[2], &macPrefix)) { return printUsage(stderr, 1); }
+    if (!parseInt(argv[argIndex], &macPrefix)) { return printUsage(stderr, 1); }
     if (macPrefix < 0) { return printUsage(stderr, 1); }
     if (macPrefix > UINT16_MAX) { return printUsage(stderr, 1); }
 
-    return manageRadios(nRadios, macPrefix);
+    return manageRadios(nRadios, macPrefix, enablePmsr);
 }