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
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
# 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
#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"
#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"
#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(¶ms, 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, ¶ms);
+ 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(¶ms, 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,
+ ¶ms);
+ 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,
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)
# 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
#include "dpp_hostapd.h"
#include "fils_hlp.h"
#include "neighbor_db.h"
+#include "nan_usd_ap.h"
#ifdef CONFIG_FILS
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 */
#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"
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);
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;
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 */
};
#include "dpp_hostapd.h"
#include "gas_query_ap.h"
#include "comeback_token.h"
+#include "nan_usd_ap.h"
#include "pasn/pasn_common.h"
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);
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;
!(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,
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
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
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