NAN: USD in hostapd
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>
This commit is contained in:
parent
e3f9ab3c3a
commit
3a5d1a7e6d
13 changed files with 703 additions and 0 deletions
|
@ -581,6 +581,12 @@ L_CFLAGS += -DCONFIG_DPP3
|
||||||
endif
|
endif
|
||||||
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
|
ifdef CONFIG_PASN
|
||||||
L_CFLAGS += -DCONFIG_PASN
|
L_CFLAGS += -DCONFIG_PASN
|
||||||
L_CFLAGS += -DCONFIG_PTKSA_CACHE
|
L_CFLAGS += -DCONFIG_PTKSA_CACHE
|
||||||
|
|
|
@ -607,6 +607,12 @@ CFLAGS += -DCONFIG_DPP3
|
||||||
endif
|
endif
|
||||||
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
|
ifdef CONFIG_PASN
|
||||||
CFLAGS += -DCONFIG_PASN
|
CFLAGS += -DCONFIG_PASN
|
||||||
CFLAGS += -DCONFIG_PTKSA_CACHE
|
CFLAGS += -DCONFIG_PTKSA_CACHE
|
||||||
|
|
|
@ -212,3 +212,6 @@ CONFIG_NO_RANDOM_POOL=y
|
||||||
# release under this optional build parameter. This functionality is subject to
|
# release under this optional build parameter. This functionality is subject to
|
||||||
# be completely removed in a future release.
|
# be completely removed in a future release.
|
||||||
CONFIG_WEP=y
|
CONFIG_WEP=y
|
||||||
|
|
||||||
|
# Wi-Fi Aware unsynchronized service discovery (NAN USD)
|
||||||
|
#CONFIG_NAN_USD=y
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "common/wpa_ctrl.h"
|
#include "common/wpa_ctrl.h"
|
||||||
#include "common/ptksa_cache.h"
|
#include "common/ptksa_cache.h"
|
||||||
#include "common/hw_features_common.h"
|
#include "common/hw_features_common.h"
|
||||||
|
#include "common/nan_de.h"
|
||||||
#include "crypto/tls.h"
|
#include "crypto/tls.h"
|
||||||
#include "drivers/driver.h"
|
#include "drivers/driver.h"
|
||||||
#include "eapol_auth/eapol_auth_sm.h"
|
#include "eapol_auth/eapol_auth_sm.h"
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
#include "ap/rrm.h"
|
#include "ap/rrm.h"
|
||||||
#include "ap/dpp_hostapd.h"
|
#include "ap/dpp_hostapd.h"
|
||||||
#include "ap/dfs.h"
|
#include "ap/dfs.h"
|
||||||
|
#include "ap/nan_usd_ap.h"
|
||||||
#include "wps/wps_defs.h"
|
#include "wps/wps_defs.h"
|
||||||
#include "wps/wps.h"
|
#include "wps/wps.h"
|
||||||
#include "fst/fst_ctrl_iface.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 */
|
#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,
|
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||||
char *buf, char *reply,
|
char *buf, char *reply,
|
||||||
int reply_size,
|
int reply_size,
|
||||||
|
@ -4124,6 +4412,26 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
#endif /* CONFIG_DPP3 */
|
#endif /* CONFIG_DPP3 */
|
||||||
#endif /* CONFIG_DPP */
|
#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
|
#ifdef RADIUS_SERVER
|
||||||
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
|
} else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) {
|
||||||
if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
|
if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0)
|
||||||
|
|
|
@ -419,3 +419,6 @@ CONFIG_DPP2=y
|
||||||
# DPP version 3 support (experimental and still changing; do not enable for
|
# DPP version 3 support (experimental and still changing; do not enable for
|
||||||
# production use)
|
# production use)
|
||||||
#CONFIG_DPP3=y
|
#CONFIG_DPP3=y
|
||||||
|
|
||||||
|
# Wi-Fi Aware unsynchronized service discovery (NAN USD)
|
||||||
|
#CONFIG_NAN_USD=y
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "dpp_hostapd.h"
|
#include "dpp_hostapd.h"
|
||||||
#include "fils_hlp.h"
|
#include "fils_hlp.h"
|
||||||
#include "neighbor_db.h"
|
#include "neighbor_db.h"
|
||||||
|
#include "nan_usd_ap.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_FILS
|
#ifdef CONFIG_FILS
|
||||||
|
@ -1622,6 +1623,23 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_DPP */
|
#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 */
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "wpa_auth.h"
|
#include "wpa_auth.h"
|
||||||
#include "wps_hostapd.h"
|
#include "wps_hostapd.h"
|
||||||
#include "dpp_hostapd.h"
|
#include "dpp_hostapd.h"
|
||||||
|
#include "nan_usd_ap.h"
|
||||||
#include "gas_query_ap.h"
|
#include "gas_query_ap.h"
|
||||||
#include "hw_features.h"
|
#include "hw_features.h"
|
||||||
#include "wpa_auth_glue.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);
|
gas_query_ap_deinit(hapd->gas);
|
||||||
hapd->gas = NULL;
|
hapd->gas = NULL;
|
||||||
#endif /* CONFIG_DPP */
|
#endif /* CONFIG_DPP */
|
||||||
|
#ifdef CONFIG_NAN_USD
|
||||||
|
hostapd_nan_usd_deinit(hapd);
|
||||||
|
#endif /* CONFIG_NAN_USD */
|
||||||
|
|
||||||
authsrv_deinit(hapd);
|
authsrv_deinit(hapd);
|
||||||
|
|
||||||
|
@ -1516,6 +1520,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first,
|
||||||
return -1;
|
return -1;
|
||||||
#endif /* CONFIG_DPP */
|
#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)
|
if (authsrv_init(hapd) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -475,6 +475,10 @@ struct hostapd_data {
|
||||||
u8 eht_mld_link_removal_count;
|
u8 eht_mld_link_removal_count;
|
||||||
#endif /* CONFIG_TESTING_OPTIONS */
|
#endif /* CONFIG_TESTING_OPTIONS */
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NAN_USD
|
||||||
|
struct nan_de *nan_de;
|
||||||
|
#endif /* CONFIG_NAN_USD */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "dpp_hostapd.h"
|
#include "dpp_hostapd.h"
|
||||||
#include "gas_query_ap.h"
|
#include "gas_query_ap.h"
|
||||||
#include "comeback_token.h"
|
#include "comeback_token.h"
|
||||||
|
#include "nan_usd_ap.h"
|
||||||
#include "pasn/pasn_common.h"
|
#include "pasn/pasn_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -6034,6 +6035,25 @@ static int handle_action(struct hostapd_data *hapd,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_DPP */
|
#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) {
|
if (hapd->public_action_cb) {
|
||||||
hapd->public_action_cb(hapd->public_action_cb_ctx,
|
hapd->public_action_cb(hapd->public_action_cb_ctx,
|
||||||
(u8 *) mgmt, len, freq);
|
(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;
|
int ret = 0;
|
||||||
unsigned int freq;
|
unsigned int freq;
|
||||||
int ssi_signal = fi ? fi->ssi_signal : 0;
|
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)
|
if (len < 24)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -6207,6 +6231,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||||
!(hapd->conf->mld_ap &&
|
!(hapd->conf->mld_ap &&
|
||||||
ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
|
ether_addr_equal(hapd->mld_addr, mgmt->bssid)) &&
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#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)) {
|
!ether_addr_equal(mgmt->da, hapd->own_addr)) {
|
||||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||||
HOSTAPD_LEVEL_DEBUG,
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
|
267
src/ap/nan_usd_ap.c
Normal file
267
src/ap/nan_usd_ap.c
Normal file
|
@ -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);
|
||||||
|
}
|
46
src/ap/nan_usd_ap.h
Normal file
46
src/ap/nan_usd_ap.h
Normal file
|
@ -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 */
|
|
@ -994,6 +994,9 @@ OBJS += src/ap/dpp_hostapd.c
|
||||||
OBJS += src/ap/gas_query_ap.c
|
OBJS += src/ap/gas_query_ap.c
|
||||||
NEED_AP_GAS_SERV=y
|
NEED_AP_GAS_SERV=y
|
||||||
endif
|
endif
|
||||||
|
ifdef CONFIG_NAN_USD
|
||||||
|
OBJS += src/ap/nan_usd_ap.c
|
||||||
|
endif
|
||||||
ifdef CONFIG_INTERWORKING
|
ifdef CONFIG_INTERWORKING
|
||||||
NEED_AP_GAS_SERV=y
|
NEED_AP_GAS_SERV=y
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1068,6 +1068,9 @@ OBJS += ../src/ap/dpp_hostapd.o
|
||||||
OBJS += ../src/ap/gas_query_ap.o
|
OBJS += ../src/ap/gas_query_ap.o
|
||||||
NEED_AP_GAS_SERV=y
|
NEED_AP_GAS_SERV=y
|
||||||
endif
|
endif
|
||||||
|
ifdef CONFIG_NAN_USD
|
||||||
|
OBJS += ../src/ap/nan_usd_ap.o
|
||||||
|
endif
|
||||||
ifdef CONFIG_INTERWORKING
|
ifdef CONFIG_INTERWORKING
|
||||||
NEED_AP_GAS_SERV=y
|
NEED_AP_GAS_SERV=y
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in a new issue