]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
NAN: USD in hostapd
authorJouni Malinen <quic_jouni@quicinc.com>
Thu, 15 Feb 2024 15:41:05 +0000 (17:41 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 15 Feb 2024 17:54:17 +0000 (19:54 +0200)
Add hostapd support for interacting with the NAN discovery engine to
allow single-channel (i.e., the AP's operating channel) USD as Publisher
or Subscriber.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
13 files changed:
hostapd/Android.mk
hostapd/Makefile
hostapd/android.config
hostapd/ctrl_iface.c
hostapd/defconfig
src/ap/drv_callbacks.c
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_11.c
src/ap/nan_usd_ap.c [new file with mode: 0644]
src/ap/nan_usd_ap.h [new file with mode: 0644]
wpa_supplicant/Android.mk
wpa_supplicant/Makefile

index 3cc2b51b890b163a8c66534cc3c0e18dd3abf350..29579c526b60e41882e36404151894830066a7fd 100644 (file)
@@ -581,6 +581,12 @@ L_CFLAGS += -DCONFIG_DPP3
 endif
 endif
 
+ifdef CONFIG_NAN_USD
+OBJS += src/common/nan_de.c
+OBJS += src/ap/nan_usd_ap.c
+L_CFLAGS += -DCONFIG_NAN_USD
+endif
+
 ifdef CONFIG_PASN
 L_CFLAGS += -DCONFIG_PASN
 L_CFLAGS += -DCONFIG_PTKSA_CACHE
index bfafe73b751488a3cf40bc0bef0b85580aed5b79..94421d43bdd7d375eb845c6aa1aa951cca6ddc6f 100644 (file)
@@ -607,6 +607,12 @@ CFLAGS += -DCONFIG_DPP3
 endif
 endif
 
+ifdef CONFIG_NAN_USD
+OBJS += ../src/common/nan_de.o
+OBJS += ../src/ap/nan_usd_ap.o
+CFLAGS += -DCONFIG_NAN_USD
+endif
+
 ifdef CONFIG_PASN
 CFLAGS += -DCONFIG_PASN
 CFLAGS += -DCONFIG_PTKSA_CACHE
index c8b3afabef8ddb8fce6c794a49acaddfa1512398..34cc125c1b4176202de0b33d970486087abe4e94 100644 (file)
@@ -212,3 +212,6 @@ CONFIG_NO_RANDOM_POOL=y
 # release under this optional build parameter. This functionality is subject to
 # be completely removed in a future release.
 CONFIG_WEP=y
+
+# Wi-Fi Aware unsynchronized service discovery (NAN USD)
+#CONFIG_NAN_USD=y
index 015a67aea22195d142fa4e7471906b74945e8339..5552cce6d406deda263afc71b6fcfe008c61da0c 100644 (file)
@@ -39,6 +39,7 @@
 #include "common/wpa_ctrl.h"
 #include "common/ptksa_cache.h"
 #include "common/hw_features_common.h"
+#include "common/nan_de.h"
 #include "crypto/tls.h"
 #include "drivers/driver.h"
 #include "eapol_auth/eapol_auth_sm.h"
@@ -63,6 +64,7 @@
 #include "ap/rrm.h"
 #include "ap/dpp_hostapd.h"
 #include "ap/dfs.h"
+#include "ap/nan_usd_ap.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "fst/fst_ctrl_iface.h"
@@ -3580,6 +3582,292 @@ static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
 #endif /* CONFIG_IEEE80211BE */
 
 
+#ifdef CONFIG_NAN_USD
+
+static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd,
+                                   char *buf, size_t buflen)
+{
+       char *token, *context = NULL;
+       int publish_id;
+       struct nan_publish_params params;
+       const char *service_name = NULL;
+       struct wpabuf *ssi = NULL;
+       int ret = -1;
+       enum nan_service_protocol_type srv_proto_type = 0;
+
+       os_memset(&params, 0, sizeof(params));
+       /* USD shall use both solicited and unsolicited transmissions */
+       params.unsolicited = true;
+       params.solicited = true;
+       /* USD shall require FSD without GAS */
+       params.fsd = true;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (os_strncmp(token, "service_name=", 13) == 0) {
+                       service_name = token + 13;
+                       continue;
+               }
+
+               if (os_strncmp(token, "ttl=", 4) == 0) {
+                       params.ttl = atoi(token + 4);
+                       continue;
+               }
+
+               if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
+                       srv_proto_type = atoi(token + 15);
+                       continue;
+               }
+
+               if (os_strncmp(token, "ssi=", 4) == 0) {
+                       if (ssi)
+                               goto fail;
+                       ssi = wpabuf_parse_bin(token + 4);
+                       if (!ssi)
+                               goto fail;
+                       continue;
+               }
+
+               if (os_strcmp(token, "solicited=0") == 0) {
+                       params.solicited = false;
+                       continue;
+               }
+
+               if (os_strcmp(token, "unsolicited=0") == 0) {
+                       params.unsolicited = false;
+                       continue;
+               }
+
+               if (os_strcmp(token, "fsd=0") == 0) {
+                       params.fsd = false;
+                       continue;
+               }
+
+               wpa_printf(MSG_INFO, "CTRL: Invalid NAN_PUBLISH parameter: %s",
+                          token);
+               goto fail;
+       }
+
+       publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type,
+                                            ssi, &params);
+       if (publish_id > 0)
+               ret = os_snprintf(buf, buflen, "%d", publish_id);
+fail:
+       wpabuf_free(ssi);
+       return ret;
+}
+
+
+static int hostapd_ctrl_nan_cancel_publish(struct hostapd_data *hapd,
+                                          char *cmd)
+{
+       char *token, *context = NULL;
+       int publish_id = 0;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (sscanf(token, "publish_id=%i", &publish_id) == 1)
+                       continue;
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid NAN_CANCEL_PUBLISH parameter: %s",
+                          token);
+               return -1;
+       }
+
+       if (publish_id <= 0) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid or missing NAN_CANCEL_PUBLISH publish_id");
+               return -1;
+       }
+
+       hostapd_nan_usd_cancel_publish(hapd, publish_id);
+       return 0;
+}
+
+
+static int hostapd_ctrl_nan_update_publish(struct hostapd_data *hapd,
+                                          char *cmd)
+{
+       char *token, *context = NULL;
+       int publish_id = 0;
+       struct wpabuf *ssi = NULL;
+       int ret = -1;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (sscanf(token, "publish_id=%i", &publish_id) == 1)
+                       continue;
+               if (os_strncmp(token, "ssi=", 4) == 0) {
+                       if (ssi)
+                               goto fail;
+                       ssi = wpabuf_parse_bin(token + 4);
+                       if (!ssi)
+                               goto fail;
+                       continue;
+               }
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid NAN_UPDATE_PUBLISH parameter: %s",
+                          token);
+               goto fail;
+       }
+
+       if (publish_id <= 0) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid or missing NAN_UPDATE_PUBLISH publish_id");
+               goto fail;
+       }
+
+       ret = hostapd_nan_usd_update_publish(hapd, publish_id, ssi);
+fail:
+       wpabuf_free(ssi);
+       return ret;
+}
+
+
+static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd,
+                                     char *buf, size_t buflen)
+{
+       char *token, *context = NULL;
+       int subscribe_id;
+       struct nan_subscribe_params params;
+       const char *service_name = NULL;
+       struct wpabuf *ssi = NULL;
+       int ret = -1;
+       enum nan_service_protocol_type srv_proto_type = 0;
+
+       os_memset(&params, 0, sizeof(params));
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (os_strncmp(token, "service_name=", 13) == 0) {
+                       service_name = token + 13;
+                       continue;
+               }
+
+               if (os_strcmp(token, "active=1") == 0) {
+                       params.active = true;
+                       continue;
+               }
+
+               if (os_strncmp(token, "ttl=", 4) == 0) {
+                       params.ttl = atoi(token + 4);
+                       continue;
+               }
+
+               if (os_strncmp(token, "srv_proto_type=", 15) == 0) {
+                       srv_proto_type = atoi(token + 15);
+                       continue;
+               }
+
+               if (os_strncmp(token, "ssi=", 4) == 0) {
+                       if (ssi)
+                               goto fail;
+                       ssi = wpabuf_parse_bin(token + 4);
+                       if (!ssi)
+                               goto fail;
+                       continue;
+               }
+
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
+                          token);
+               goto fail;
+       }
+
+       subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name,
+                                                srv_proto_type, ssi,
+                                                &params);
+       if (subscribe_id > 0)
+               ret = os_snprintf(buf, buflen, "%d", subscribe_id);
+fail:
+       wpabuf_free(ssi);
+       return ret;
+}
+
+
+static int hostapd_ctrl_nan_cancel_subscribe(struct hostapd_data *hapd,
+                                            char *cmd)
+{
+       char *token, *context = NULL;
+       int subscribe_id = 0;
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (sscanf(token, "subscribe_id=%i", &subscribe_id) == 1)
+                       continue;
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid NAN_CANCEL_SUBSCRIBE parameter: %s",
+                          token);
+               return -1;
+       }
+
+       if (subscribe_id <= 0) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid or missing NAN_CANCEL_SUBSCRIBE subscribe_id");
+               return -1;
+       }
+
+       hostapd_nan_usd_cancel_subscribe(hapd, subscribe_id);
+       return 0;
+}
+
+
+static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
+{
+       char *token, *context = NULL;
+       int handle = 0;
+       int req_instance_id = 0;
+       struct wpabuf *ssi = NULL;
+       u8 peer_addr[ETH_ALEN];
+       int ret = -1;
+
+       os_memset(peer_addr, 0, ETH_ALEN);
+
+       while ((token = str_token(cmd, " ", &context))) {
+               if (sscanf(token, "handle=%i", &handle) == 1)
+                       continue;
+
+               if (sscanf(token, "req_instance_id=%i", &req_instance_id) == 1)
+                       continue;
+
+               if (os_strncmp(token, "address=", 8) == 0) {
+                       if (hwaddr_aton(token + 8, peer_addr) < 0)
+                               return -1;
+                       continue;
+               }
+
+               if (os_strncmp(token, "ssi=", 4) == 0) {
+                       if (ssi)
+                               goto fail;
+                       ssi = wpabuf_parse_bin(token + 4);
+                       if (!ssi)
+                               goto fail;
+                       continue;
+               }
+
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid NAN_TRANSMIT parameter: %s",
+                          token);
+               goto fail;
+       }
+
+       if (handle <= 0) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid or missing NAN_TRANSMIT handle");
+               goto fail;
+       }
+
+       if (is_zero_ether_addr(peer_addr)) {
+               wpa_printf(MSG_INFO,
+                          "CTRL: Invalid or missing NAN_TRANSMIT address");
+               goto fail;
+       }
+
+       ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr,
+                                   req_instance_id);
+fail:
+       wpabuf_free(ssi);
+       return ret;
+}
+
+#endif /* CONFIG_NAN_USD */
+
+
 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                                              char *buf, char *reply,
                                              int reply_size,
@@ -4124,6 +4412,26 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                        reply_len = -1;
 #endif /* CONFIG_DPP3 */
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_NAN_USD
+       } else if (os_strncmp(buf, "NAN_PUBLISH ", 12) == 0) {
+               reply_len = hostapd_ctrl_nan_publish(hapd, buf + 12, reply,
+                                                    reply_size);
+       } else if (os_strncmp(buf, "NAN_CANCEL_PUBLISH ", 19) == 0) {
+               if (hostapd_ctrl_nan_cancel_publish(hapd, buf + 19) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) {
+               if (hostapd_ctrl_nan_update_publish(hapd, buf + 19) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) {
+               reply_len = hostapd_ctrl_nan_subscribe(hapd, buf + 14, reply,
+                                                      reply_size);
+       } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) {
+               if (hostapd_ctrl_nan_cancel_subscribe(hapd, buf + 21) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) {
+               if (hostapd_ctrl_nan_transmit(hapd, buf + 13) < 0)
+                       reply_len = -1;
+#endif /* CONFIG_NAN_USD */
 #ifdef RADIUS_SERVER
        } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
                if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
index 36c147682759b70fea4e0ac1492dd5fcac224478..2f5f3f6d047109fdd5e2a646c5fab39a2945e51f 100644 (file)
@@ -419,3 +419,6 @@ CONFIG_DPP2=y
 # DPP version 3 support (experimental and still changing; do not enable for
 # production use)
 #CONFIG_DPP3=y
+
+# Wi-Fi Aware unsynchronized service discovery (NAN USD)
+#CONFIG_NAN_USD=y
index 504e0f8bf4ee6bc9b2aabae5d2ca1d1648a97055..35522d2d1210dd21239b64c43067c959c933d59d 100644 (file)
@@ -42,6 +42,7 @@
 #include "dpp_hostapd.h"
 #include "fils_hlp.h"
 #include "neighbor_db.h"
+#include "nan_usd_ap.h"
 
 
 #ifdef CONFIG_FILS
@@ -1622,6 +1623,23 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
                return;
        }
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_NAN_USD
+       if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && plen >= 5 &&
+           mgmt->u.action.u.vs_public_action.action ==
+           WLAN_PA_VENDOR_SPECIFIC &&
+           WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
+           OUI_WFA &&
+           mgmt->u.action.u.vs_public_action.variable[0] == NAN_OUI_TYPE) {
+               const u8 *pos, *end;
+
+               pos = mgmt->u.action.u.vs_public_action.variable;
+               end = drv_mgmt->frame + drv_mgmt->frame_len;
+               pos++;
+               hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, drv_mgmt->freq,
+                                      pos, end - pos);
+               return;
+       }
+#endif /* CONFIG_NAN_USD */
 }
 #endif /* NEED_AP_MLME */
 
index cb464f67012b2e5bf9ecc00e93d0048ccd79ace4..ddbcabc49328e57dac55d0d65c2b4d37829bf339 100644 (file)
@@ -35,6 +35,7 @@
 #include "wpa_auth.h"
 #include "wps_hostapd.h"
 #include "dpp_hostapd.h"
+#include "nan_usd_ap.h"
 #include "gas_query_ap.h"
 #include "hw_features.h"
 #include "wpa_auth_glue.h"
@@ -528,6 +529,9 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
        gas_query_ap_deinit(hapd->gas);
        hapd->gas = NULL;
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_NAN_USD
+       hostapd_nan_usd_deinit(hapd);
+#endif /* CONFIG_NAN_USD */
 
        authsrv_deinit(hapd);
 
@@ -1516,6 +1520,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
                return -1;
 #endif /* CONFIG_DPP */
 
+#ifdef CONFIG_NAN_USD
+       if (hostapd_nan_usd_init(hapd) < 0)
+               return -1;
+#endif /* CONFIG_NAN_USD */
+
        if (authsrv_init(hapd) < 0)
                return -1;
 
index 3dba121c6cb8973bb0790c2ef37b84216d3c6388..3339554865e3ef875971106cd984ca4374b8242b 100644 (file)
@@ -475,6 +475,10 @@ struct hostapd_data {
        u8 eht_mld_link_removal_count;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_IEEE80211BE */
+
+#ifdef CONFIG_NAN_USD
+       struct nan_de *nan_de;
+#endif /* CONFIG_NAN_USD */
 };
 
 
index 7fb49a4b429e9edfaf54740dc16bac51cb95256f..8b8c1f09584050263f11841cae9bde472b095793 100644 (file)
@@ -56,6 +56,7 @@
 #include "dpp_hostapd.h"
 #include "gas_query_ap.h"
 #include "comeback_token.h"
+#include "nan_usd_ap.h"
 #include "pasn/pasn_common.h"
 
 
@@ -6034,6 +6035,25 @@ static int handle_action(struct hostapd_data *hapd,
                                return 1;
                }
 #endif /* CONFIG_DPP */
+#ifdef CONFIG_NAN_USD
+               if (mgmt->u.action.category == WLAN_ACTION_PUBLIC &&
+                   len >= IEEE80211_HDRLEN + 5 &&
+                   mgmt->u.action.u.vs_public_action.action ==
+                   WLAN_PA_VENDOR_SPECIFIC &&
+                   WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
+                   OUI_WFA &&
+                   mgmt->u.action.u.vs_public_action.variable[0] ==
+                   NAN_OUI_TYPE) {
+                       const u8 *pos, *end;
+
+                       pos = mgmt->u.action.u.vs_public_action.variable;
+                       end = ((const u8 *) mgmt) + len;
+                       pos++;
+                       hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq,
+                                              pos, end - pos);
+                       return 1;
+               }
+#endif /* CONFIG_NAN_USD */
                if (hapd->public_action_cb) {
                        hapd->public_action_cb(hapd->public_action_cb_ctx,
                                               (u8 *) mgmt, len, freq);
@@ -6141,6 +6161,10 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
        int ret = 0;
        unsigned int freq;
        int ssi_signal = fi ? fi->ssi_signal : 0;
+#ifdef CONFIG_NAN_USD
+       static const u8 nan_network_id[ETH_ALEN] =
+               { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
+#endif /* CONFIG_NAN_USD */
 
        if (len < 24)
                return 0;
@@ -6207,6 +6231,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
            !(hapd->conf->mld_ap &&
              ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
 #endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_NAN_USD
+           !ether_addr_equal(mgmt->da, nan_network_id) &&
+#endif /* CONFIG_NAN_USD */
            !ether_addr_equal(mgmt->da, hapd->own_addr)) {
                hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_DEBUG,
diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c
new file mode 100644 (file)
index 0000000..52a967a
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * NAN unsynchronized service discovery (USD)
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "common/nan_de.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "nan_usd_ap.h"
+
+
+static int hostapd_nan_de_tx(void *ctx, unsigned int freq,
+                            unsigned int wait_time,
+                            const u8 *dst, const u8 *src, const u8 *bssid,
+                            const struct wpabuf *buf)
+{
+       struct hostapd_data *hapd = ctx;
+
+       wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR
+                  " A3=" MACSTR " len=%zu",
+                  MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+                  wpabuf_len(buf));
+
+       /* TODO: Force use of OFDM */
+       return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+                                      wpabuf_head(buf), wpabuf_len(buf));
+}
+
+
+static int hostapd_nan_de_listen(void *ctx, unsigned int freq,
+                             unsigned int duration)
+{
+       return 0;
+}
+
+
+static void
+hostapd_nan_de_discovery_result(void *ctx, int subscribe_id,
+                               enum nan_service_protocol_type srv_proto_type,
+                               const u8 *ssi, size_t ssi_len,
+                               int peer_publish_id, const u8 *peer_addr,
+                               bool fsd, bool fsd_gas)
+{
+       struct hostapd_data *hapd = ctx;
+       char *ssi_hex;
+
+       ssi_hex = os_zalloc(2 * ssi_len + 1);
+       if (!ssi_hex)
+               return;
+       if (ssi)
+               wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
+       wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_DISCOVERY_RESULT
+               "subscribe_id=%d publish_id=%d address=" MACSTR
+               " fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s",
+               subscribe_id, peer_publish_id, MAC2STR(peer_addr),
+               fsd, fsd_gas, srv_proto_type, ssi_hex);
+       os_free(ssi_hex);
+}
+
+
+static void
+hostapd_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr,
+                      int peer_subscribe_id,
+                      enum nan_service_protocol_type srv_proto_type,
+                      const u8 *ssi, size_t ssi_len)
+{
+       struct hostapd_data *hapd = ctx;
+       char *ssi_hex;
+
+       ssi_hex = os_zalloc(2 * ssi_len + 1);
+       if (!ssi_hex)
+               return;
+       if (ssi)
+               wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
+       wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_REPLIED
+               "publish_id=%d address=" MACSTR
+               " subscribe_id=%d srv_proto_type=%u ssi=%s",
+               publish_id, MAC2STR(peer_addr), peer_subscribe_id,
+               srv_proto_type, ssi_hex);
+       os_free(ssi_hex);
+}
+
+
+static const char * nan_reason_txt(enum nan_de_reason reason)
+{
+       switch (reason) {
+       case NAN_DE_REASON_TIMEOUT:
+               return "timeout";
+       case NAN_DE_REASON_USER_REQUEST:
+               return "user-request";
+       case NAN_DE_REASON_FAILURE:
+               return "failure";
+       }
+
+       return "unknown";
+}
+
+
+static void hostapd_nan_de_publish_terminated(void *ctx, int publish_id,
+                                             enum nan_de_reason reason)
+{
+       struct hostapd_data *hapd = ctx;
+
+       wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_PUBLISH_TERMINATED
+               "publish_id=%d reason=%s",
+               publish_id, nan_reason_txt(reason));
+}
+
+
+static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
+                                               enum nan_de_reason reason)
+{
+       struct hostapd_data *hapd = ctx;
+
+       wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
+               "subscribe_id=%d reason=%s",
+               subscribe_id, nan_reason_txt(reason));
+}
+
+
+static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id,
+                                  const u8 *ssi, size_t ssi_len,
+                                  const u8 *peer_addr)
+{
+       struct hostapd_data *hapd = ctx;
+       char *ssi_hex;
+
+       ssi_hex = os_zalloc(2 * ssi_len + 1);
+       if (!ssi_hex)
+               return;
+       if (ssi)
+               wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
+       wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_RECEIVE
+               "id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
+               id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
+       os_free(ssi_hex);
+}
+
+
+int hostapd_nan_usd_init(struct hostapd_data *hapd)
+{
+       struct nan_callbacks cb;
+
+       os_memset(&cb, 0, sizeof(cb));
+       cb.ctx = hapd;
+       cb.tx = hostapd_nan_de_tx;
+       cb.listen = hostapd_nan_de_listen;
+       cb.discovery_result = hostapd_nan_de_discovery_result;
+       cb.replied = hostapd_nan_de_replied;
+       cb.publish_terminated = hostapd_nan_de_publish_terminated;
+       cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated;
+       cb.receive = hostapd_nan_de_receive;
+
+       hapd->nan_de = nan_de_init(hapd->own_addr, true, &cb);
+       if (!hapd->nan_de)
+               return -1;
+       return 0;
+}
+
+
+void hostapd_nan_usd_deinit(struct hostapd_data *hapd)
+{
+       nan_de_deinit(hapd->nan_de);
+       hapd->nan_de = NULL;
+}
+
+
+void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
+                           unsigned int freq, const u8 *buf, size_t len)
+{
+       if (!hapd->nan_de)
+               return;
+       nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len);
+}
+
+
+void hostapd_nan_usd_flush(struct hostapd_data *hapd)
+{
+       if (!hapd->nan_de)
+               return;
+       nan_de_flush(hapd->nan_de);
+}
+
+
+int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
+                           enum nan_service_protocol_type srv_proto_type,
+                           const struct wpabuf *ssi,
+                           struct nan_publish_params *params)
+{
+       int publish_id;
+       struct wpabuf *elems = NULL;
+
+       if (!hapd->nan_de)
+               return -1;
+
+       publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
+                                   ssi, elems, params);
+       wpabuf_free(elems);
+       return publish_id;
+}
+
+
+void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id)
+{
+       if (!hapd->nan_de)
+               return;
+       nan_de_cancel_publish(hapd->nan_de, publish_id);
+}
+
+
+int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
+                                  const struct wpabuf *ssi)
+{
+       int ret;
+
+       if (!hapd->nan_de)
+               return -1;
+       ret = nan_de_update_publish(hapd->nan_de, publish_id, ssi);
+       return ret;
+}
+
+
+int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
+                             const char *service_name,
+                             enum nan_service_protocol_type srv_proto_type,
+                             const struct wpabuf *ssi,
+                             struct nan_subscribe_params *params)
+{
+       int subscribe_id;
+       struct wpabuf *elems = NULL;
+
+       if (!hapd->nan_de)
+               return -1;
+
+       subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
+                                       srv_proto_type, ssi, elems, params);
+       wpabuf_free(elems);
+       return subscribe_id;
+}
+
+
+void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
+                                     int subscribe_id)
+{
+       if (!hapd->nan_de)
+               return;
+       nan_de_cancel_subscribe(hapd->nan_de, subscribe_id);
+}
+
+
+int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
+                            const struct wpabuf *ssi,
+                            const struct wpabuf *elems,
+                            const u8 *peer_addr, u8 req_instance_id)
+{
+       if (!hapd->nan_de)
+               return -1;
+       return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr,
+                              req_instance_id);
+}
diff --git a/src/ap/nan_usd_ap.h b/src/ap/nan_usd_ap.h
new file mode 100644 (file)
index 0000000..58ff5fc
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * NAN unsynchronized service discovery (USD)
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NAN_USD_AP_H
+#define NAN_USD_AP_H
+
+struct nan_subscribe_params;
+struct nan_publish_params;
+enum nan_service_protocol_type;
+
+int hostapd_nan_usd_init(struct hostapd_data *hapd);
+void hostapd_nan_usd_deinit(struct hostapd_data *hapd);
+void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
+                           unsigned int freq, const u8 *buf, size_t len);
+void hostapd_nan_usd_flush(struct hostapd_data *hapd);
+int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
+                           enum nan_service_protocol_type srv_proto_type,
+                           const struct wpabuf *ssi,
+                           struct nan_publish_params *params);
+void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id);
+int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id,
+                                  const struct wpabuf *ssi);
+int hostapd_nan_usd_subscribe(struct hostapd_data *hapd,
+                             const char *service_name,
+                             enum nan_service_protocol_type srv_proto_type,
+                             const struct wpabuf *ssi,
+                             struct nan_subscribe_params *params);
+void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
+                                     int subscribe_id);
+int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
+                            const struct wpabuf *ssi,
+                            const struct wpabuf *elems,
+                            const u8 *peer_addr, u8 req_instance_id);
+void hostapd_nan_usd_remain_on_channel_cb(struct hostapd_data *hapd,
+                                         unsigned int freq,
+                                         unsigned int duration);
+void hostapd_nan_usd_cancel_remain_on_channel_cb(struct hostapd_data *hapd,
+                                                unsigned int freq);
+void hostapd_nan_usd_tx_wait_expire(struct hostapd_data *hapd);
+
+#endif /* NAN_USD_AP_H */
index b6fcebd69581702541d3c4bce144f7795f08cf28..307e18952d2b902f800d0cc7db5bb788d8ba0f33 100644 (file)
@@ -994,6 +994,9 @@ OBJS += src/ap/dpp_hostapd.c
 OBJS += src/ap/gas_query_ap.c
 NEED_AP_GAS_SERV=y
 endif
+ifdef CONFIG_NAN_USD
+OBJS += src/ap/nan_usd_ap.c
+endif
 ifdef CONFIG_INTERWORKING
 NEED_AP_GAS_SERV=y
 endif
index 288f8553601ae07348daa26d3a2fa32c93a2d3a7..976da5962a014a3853eaa46f9697f3553eb5fbc1 100644 (file)
@@ -1068,6 +1068,9 @@ OBJS += ../src/ap/dpp_hostapd.o
 OBJS += ../src/ap/gas_query_ap.o
 NEED_AP_GAS_SERV=y
 endif
+ifdef CONFIG_NAN_USD
+OBJS += ../src/ap/nan_usd_ap.o
+endif
 ifdef CONFIG_INTERWORKING
 NEED_AP_GAS_SERV=y
 endif