NAN: Update A3 for USD to use NAN Network ID or NAN Cluster ID in A3

Wi-Fi Aware spec v4.0 was not clear on all cases and used a bit unclear
definition of A3 use in Table 5 (Address field definiton for NAN SDF
frames in USD). That resulted in the initial implementation using
Wildcard BSSID to comply with the IEEE 802.11 rules on Public Action
frame addressing.

For USD to have chances of working with synchronized NNA devices, A3
needs to be set to the NAN Cluster ID when replying to a frame received
from a synchronized NAN device. While there is no cluster ID for USD,
this can be done by copying the A3 from the received frame. For the
cases where sending out an unsolicited multicast frame, the NAN Network
ID should be used instead of the Wildcard BSSID.

While this behavior is not strictly speaking compliant with the IEEE
802.11 standard, this is the expected behavior for NAN devices, so
update the USD implementation to match.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2024-09-13 21:58:51 +03:00 committed by Jouni Malinen
parent e0496580a4
commit fbbc9cb9e2
13 changed files with 88 additions and 58 deletions

View file

@ -3976,10 +3976,12 @@ static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
int handle = 0;
int req_instance_id = 0;
struct wpabuf *ssi = NULL;
u8 peer_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN], a3[ETH_ALEN];
int ret = -1;
bool a3_set = false;
os_memset(peer_addr, 0, ETH_ALEN);
os_memset(a3, 0, ETH_ALEN);
while ((token = str_token(cmd, " ", &context))) {
if (sscanf(token, "handle=%i", &handle) == 1)
@ -3994,6 +3996,13 @@ static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
continue;
}
if (os_strncmp(token, "a3=", 3) == 0) {
if (hwaddr_aton(token + 3, a3) < 0)
return -1;
a3_set = true;
continue;
}
if (os_strncmp(token, "ssi=", 4) == 0) {
if (ssi)
goto fail;
@ -4022,7 +4031,7 @@ static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd)
}
ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr,
req_instance_id);
a3_set ? a3 : NULL, req_instance_id);
fail:
wpabuf_free(ssi);
return ret;

View file

@ -1788,8 +1788,8 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
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);
hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, mgmt->bssid,
drv_mgmt->freq, pos, end - pos);
return;
}
#endif /* CONFIG_NAN_USD */

View file

@ -6149,8 +6149,8 @@ static int handle_action(struct hostapd_data *hapd,
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);
hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, mgmt->bssid,
freq, pos, end - pos);
return 1;
}
#endif /* CONFIG_NAN_USD */

View file

@ -29,8 +29,10 @@ static int hostapd_nan_de_tx(void *ctx, unsigned int freq,
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));
return hostapd_drv_send_action_forced_addr3(hapd, hapd->iface->freq, 0,
dst, bssid,
wpabuf_head(buf),
wpabuf_len(buf));
}
@ -127,7 +129,7 @@ static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
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)
const u8 *peer_addr, const u8 *a3)
{
struct hostapd_data *hapd = ctx;
char *ssi_hex;
@ -138,8 +140,9 @@ static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id,
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);
"id=%d peer_instance_id=%d address=" MACSTR " a3=" MACSTR
" ssi=%s",
id, peer_instance_id, MAC2STR(peer_addr), MAC2STR(a3), ssi_hex);
os_free(ssi_hex);
}
@ -173,11 +176,12 @@ 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)
const u8 *a3, 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);
nan_de_rx_sdf(hapd->nan_de, src, a3, freq, buf, len);
}
@ -258,10 +262,11 @@ void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
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)
const u8 *peer_addr, const u8 *a3,
u8 req_instance_id)
{
if (!hapd->nan_de)
return -1;
return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr,
return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr, a3,
req_instance_id);
}

View file

@ -16,6 +16,7 @@ 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,
const u8 *a3,
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,
@ -35,7 +36,8 @@ void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
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);
const u8 *peer_addr, const u8 *a3,
u8 req_instance_id);
void hostapd_nan_usd_remain_on_channel_cb(struct hostapd_data *hapd,
unsigned int freq,
unsigned int duration);

View file

@ -18,8 +18,6 @@
static const u8 nan_network_id[ETH_ALEN] =
{ 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
static const u8 wildcard_bssid[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
enum nan_de_service_type {
NAN_DE_PUBLISH,
@ -212,7 +210,7 @@ static int nan_de_tx(struct nan_de *de, unsigned int freq,
static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv,
unsigned int wait_time,
enum nan_service_control_type type,
const u8 *dst, u8 req_instance_id,
const u8 *dst, const u8 *a3, u8 req_instance_id,
const struct wpabuf *ssi)
{
struct wpabuf *buf;
@ -274,10 +272,7 @@ static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv,
wpabuf_put_buf(buf, srv->elems);
}
/* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD,
* but there is no synchronization in USD as as such, no NAN Cluster
* either. Use Wildcard BSSID instead. */
nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, wildcard_bssid, buf);
nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, a3, buf);
wpabuf_free(buf);
}
@ -358,7 +353,7 @@ static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv,
return;
}
nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id,
nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, nan_network_id,
req_instance_id, srv->ssi);
os_get_reltime(&srv->last_multicast);
}
@ -812,7 +807,7 @@ static void nan_de_process_elem_container(struct nan_de *de, const u8 *buf,
static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
const u8 *peer_addr, u8 instance_id,
const u8 *peer_addr, const u8 *a3, u8 instance_id,
u8 req_instance_id, u16 sdea_control,
enum nan_service_protocol_type srv_proto_type,
const u8 *ssi, size_t ssi_len)
@ -834,7 +829,7 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
/* Passive subscriber replies with a Follow-up message without
* Service Specific Info field if it received a matching
* unsolicited Publish message. */
nan_de_transmit(de, srv->id, NULL, NULL, peer_addr,
nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, a3,
instance_id);
}
@ -883,7 +878,8 @@ static bool nan_de_filter_match(struct nan_de_service *srv,
static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
const u8 *peer_addr, u8 instance_id,
const u8 *peer_addr, const u8 *a3,
u8 instance_id,
const u8 *matching_filter,
size_t matching_filter_len,
enum nan_service_protocol_type srv_proto_type,
@ -969,12 +965,12 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
wpabuf_put_buf(buf, srv->elems);
}
/* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD,
* but there is no synchronization in USD as as such, no NAN Cluster
* either. Use Wildcard BSSID instead. */
if (srv->publish.solicited_multicast || !a3)
a3 = nan_network_id;
nan_de_tx(de, srv->freq, 100,
srv->publish.solicited_multicast ? nan_network_id : peer_addr,
de->nmi, wildcard_bssid, buf);
de->nmi, a3, buf);
wpabuf_free(buf);
nan_de_pause_state(srv, peer_addr, instance_id);
@ -987,8 +983,8 @@ offload:
static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
const u8 *peer_addr, u8 instance_id,
const u8 *ssi, size_t ssi_len)
const u8 *peer_addr, const u8 *a3,
u8 instance_id, const u8 *ssi, size_t ssi_len)
{
/* Follow-up function processing of a receive Follow-up message for a
* Subscribe or Publish instance */
@ -1010,11 +1006,11 @@ static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
if (de->cb.receive)
de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len,
peer_addr);
peer_addr, a3);
}
static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
unsigned int freq, const u8 *buf, size_t len,
const u8 *sda, size_t sda_len)
{
@ -1141,20 +1137,20 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
switch (type) {
case NAN_SRV_CTRL_PUBLISH:
nan_de_rx_publish(de, srv, peer_addr, instance_id,
nan_de_rx_publish(de, srv, peer_addr, a3, instance_id,
req_instance_id,
sdea_control, srv_proto_type,
ssi, ssi_len);
break;
case NAN_SRV_CTRL_SUBSCRIBE:
nan_de_rx_subscribe(de, srv, peer_addr, instance_id,
nan_de_rx_subscribe(de, srv, peer_addr, a3, instance_id,
matching_filter,
matching_filter_len,
srv_proto_type,
ssi, ssi_len);
break;
case NAN_SRV_CTRL_FOLLOW_UP:
nan_de_rx_follow_up(de, srv, peer_addr, instance_id,
nan_de_rx_follow_up(de, srv, peer_addr, a3, instance_id,
ssi, ssi_len);
break;
}
@ -1162,8 +1158,8 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
}
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
const u8 *buf, size_t len)
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
unsigned int freq, const u8 *buf, size_t len)
{
const u8 *sda;
u16 sda_len;
@ -1185,7 +1181,7 @@ void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
sda++;
sda_len = WPA_GET_LE16(sda);
sda += 2;
nan_de_rx_sda(de, peer_addr, freq, buf, len, sda, sda_len);
nan_de_rx_sda(de, peer_addr, a3, freq, buf, len, sda, sda_len);
}
}
@ -1445,7 +1441,7 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id)
int nan_de_transmit(struct nan_de *de, int handle,
const struct wpabuf *ssi, const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id)
const u8 *peer_addr, const u8 *a3, u8 req_instance_id)
{
struct nan_de_service *srv;
@ -1456,8 +1452,10 @@ int nan_de_transmit(struct nan_de *de, int handle,
if (!srv)
return -1;
if (!a3)
a3 = nan_network_id;
nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP,
peer_addr, req_instance_id, ssi);
peer_addr, a3, req_instance_id, ssi);
os_get_reltime(&srv->last_followup);
return 0;

View file

@ -52,7 +52,7 @@ struct nan_callbacks {
void (*receive)(void *ctx, int id, int peer_instance_id,
const u8 *ssi, size_t ssi_len,
const u8 *peer_addr);
const u8 *peer_addr, const u8 *a3);
void (*process_p2p_usd_elems)(void *ctx, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
@ -71,8 +71,8 @@ void nan_de_listen_ended(struct nan_de *de, unsigned int freq);
void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst);
void nan_de_tx_wait_ended(struct nan_de *de);
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
const u8 *buf, size_t len);
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
unsigned int freq, const u8 *buf, size_t len);
const u8 * nan_de_get_service_id(struct nan_de *de, int id);
struct nan_publish_params {
@ -149,6 +149,6 @@ void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id);
* req_instance_id = peer publish_id or subscribe_id */
int nan_de_transmit(struct nan_de *de, int handle,
const struct wpabuf *ssi, const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id);
const u8 *peer_addr, const u8 *a3, u8 req_instance_id);
#endif /* NAN_DE_H */

View file

@ -12514,10 +12514,12 @@ static int wpas_ctrl_nan_transmit(struct wpa_supplicant *wpa_s, char *cmd)
int handle = 0;
int req_instance_id = 0;
struct wpabuf *ssi = NULL;
u8 peer_addr[ETH_ALEN];
u8 peer_addr[ETH_ALEN], a3[ETH_ALEN];
int ret = -1;
bool a3_set = false;
os_memset(peer_addr, 0, ETH_ALEN);
os_memset(a3, 0, ETH_ALEN);
while ((token = str_token(cmd, " ", &context))) {
if (sscanf(token, "handle=%i", &handle) == 1)
@ -12532,6 +12534,13 @@ static int wpas_ctrl_nan_transmit(struct wpa_supplicant *wpa_s, char *cmd)
continue;
}
if (os_strncmp(token, "a3=", 3) == 0) {
if (hwaddr_aton(token + 3, a3) < 0)
return -1;
a3_set = true;
continue;
}
if (os_strncmp(token, "ssi=", 4) == 0) {
if (ssi)
goto fail;
@ -12560,7 +12569,7 @@ static int wpas_ctrl_nan_transmit(struct wpa_supplicant *wpa_s, char *cmd)
}
ret = wpas_nan_usd_transmit(wpa_s, handle, ssi, NULL, peer_addr,
req_instance_id);
a3_set ? a3 : NULL, req_instance_id);
fail:
wpabuf_free(ssi);
return ret;

View file

@ -5540,7 +5540,8 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
WPA_GET_BE32(&payload[1]) == NAN_SDF_VENDOR_TYPE) {
payload += 5;
plen -= 5;
wpas_nan_usd_rx_sdf(wpa_s, mgmt->sa, freq, payload, plen);
wpas_nan_usd_rx_sdf(wpa_s, mgmt->sa, mgmt->bssid, freq,
payload, plen);
return;
}
#endif /* CONFIG_NAN_USD */

View file

@ -282,11 +282,11 @@ static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id,
static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id,
const u8 *ssi, size_t ssi_len,
const u8 *peer_addr)
const u8 *peer_addr, const u8 *a3)
{
struct wpa_supplicant *wpa_s = ctx;
wpas_notify_nan_receive(wpa_s, id, peer_instance_id, peer_addr,
wpas_notify_nan_receive(wpa_s, id, peer_instance_id, peer_addr, a3,
ssi, ssi_len);
}
@ -336,11 +336,12 @@ void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s)
void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *a3,
unsigned int freq, const u8 *buf, size_t len)
{
if (!wpa_s->nan_de)
return;
nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len);
nan_de_rx_sdf(wpa_s->nan_de, src, a3, freq, buf, len);
}
@ -466,11 +467,11 @@ void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s,
int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle,
const struct wpabuf *ssi, const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id)
const u8 *peer_addr, const u8 *a3, u8 req_instance_id)
{
if (!wpa_s->nan_de)
return -1;
return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr,
return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr, a3,
req_instance_id);
}

View file

@ -16,6 +16,7 @@ enum nan_service_protocol_type;
int wpas_nan_usd_init(struct wpa_supplicant *wpa_s);
void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s);
void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *a3,
unsigned int freq, const u8 *buf, size_t len);
void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s);
int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name,
@ -34,7 +35,8 @@ void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s,
int subscribe_id);
int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle,
const struct wpabuf *ssi, const struct wpabuf *elems,
const u8 *peer_addr, u8 req_instance_id);
const u8 *peer_addr, const u8 *a3,
u8 req_instance_id);
void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq,
unsigned int duration);

View file

@ -1121,6 +1121,7 @@ void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s,
void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id,
int peer_instance_id, const u8 *peer_addr,
const u8 *a3,
const u8 *ssi, size_t ssi_len)
{
char *ssi_hex;
@ -1131,8 +1132,9 @@ void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id,
if (ssi)
wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len);
wpa_msg(wpa_s, MSG_INFO, NAN_RECEIVE
"id=%d peer_instance_id=%d address=" MACSTR " ssi=%s",
id, peer_instance_id, MAC2STR(peer_addr), ssi_hex);
"id=%d peer_instance_id=%d address=" MACSTR " a3=" MACSTR
" ssi=%s",
id, peer_instance_id, MAC2STR(peer_addr), MAC2STR(a3), ssi_hex);
os_free(ssi_hex);
}

View file

@ -192,6 +192,7 @@ void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s,
const u8 *ssi, size_t ssi_len);
void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id,
int peer_instance_id, const u8 *peer_addr,
const u8 *a3,
const u8 *ssi, size_t ssi_len);
void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s,
int publish_id,