From ff7eeec86ccffae169b1c49dd38e8fb006473a57 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Oct 2025 16:31:55 +0300 Subject: [PATCH] NAN USD: Allow services to disable listen operation during SDF exchange The new stop-listen commands (through wpa_supplicant control interface or D-Bus) can be used by an upper layer service implementation to stop a listen operation (i.e., wait for a response SDF from the peer) in the driver to free up the radio for other parallel operations at points in the SDF exchange when the service knows the peer is not expected to send any further SDFs before an SDF is sent to it. This can be used, e.g., to optimize radio use during provisioning exchange where the SDF exchange is stopped in the middle during the connection attempt and the result of that connection attempt is reporting later within that same SDF exchange. Signed-off-by: Jouni Malinen --- doc/dbus.doxygen | 28 ++++++++++ src/common/nan_de.c | 28 ++++++++++ src/common/nan_de.h | 2 + wpa_supplicant/README-NAN-USD | 16 ++++++ wpa_supplicant/ctrl_iface.c | 56 ++++++++++++++++++++ wpa_supplicant/dbus/dbus_new.c | 14 +++++ wpa_supplicant/dbus/dbus_new_handlers.c | 68 +++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new_handlers.h | 5 ++ wpa_supplicant/nan_usd.c | 48 +++++++++++++++++ wpa_supplicant/nan_usd.h | 4 ++ 10 files changed, 269 insertions(+) diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen index 68c3cb784..fa73e8a1b 100644 --- a/doc/dbus.doxygen +++ b/doc/dbus.doxygen @@ -805,6 +805,20 @@ fi.w1.wpa_supplicant1.CreateInterface.
Needed memory was not possible to get allocated.
+
  • +

    NANPublishStopListen ( u : publish_id ) --> nothing

    +

    Stop listen operation for a previously added NAN USD publisher service.

    +

    Arguments

    +
    +
    u : publish_id
    +
    Publish ID from NANPublish().
    +
    +

    Possible errors

    +
    +
    fi.w1.wpa_supplicant1.InvalidArgs
    +
    Invalid entries were found in the passed argument.
    +
    +
  • NANSubscribe ( a{sv} : args ) --> u : subscribe_id

    Subscribe to a NAN USD service.

    @@ -847,6 +861,20 @@ fi.w1.wpa_supplicant1.CreateInterface.
    Invalid entries were found in the passed argument.
  • +
  • +

    NANSubscribeStopListen ( u : subscribe_id ) --> nothing

    +

    Stop listen operation for a previously started NAN USD subscription.

    +

    Arguments

    +
    +
    u : subscribe_id
    +
    Subscription ID from NANSubscribe().
    +
    +

    Possible errors

    +
    +
    fi.w1.wpa_supplicant1.InvalidArgs
    +
    Invalid entries were found in the passed argument.
    +
    +
  • NANTransmit ( a{sv} : args ) --> nothing

    Send a follow-up message for NAN USD service discovery.

    diff --git a/src/common/nan_de.c b/src/common/nan_de.c index 69175224d..e4e20f3cb 100644 --- a/src/common/nan_de.c +++ b/src/common/nan_de.c @@ -65,6 +65,7 @@ struct nan_de_service { unsigned int next_publish_duration; bool is_p2p; bool is_pr; + bool listen_stopped; }; struct nan_de { @@ -641,6 +642,11 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) duration = os_reltime_in_ms(&diff); if (duration < 0) continue; + if (srv->listen_stopped) { + wpa_printf(MSG_DEBUG, + "NAN: Publisher listen stopped temporarily - do not start driver listen operation"); + continue; + } if ((unsigned int) duration > de->max_listen) duration = de->max_listen; if (de->cb.listen(de->cb.ctx, srv->freq, duration) == @@ -670,6 +676,12 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) !srv->subscribe.active))) { int duration = 1000; + if (srv->listen_stopped) { + wpa_printf(MSG_DEBUG, + "NAN: Listen stopped temporarily - do not start driver listen operation"); + continue; + } + if (srv->type == NAN_DE_PUBLISH) { nan_de_check_chan_change(srv); duration = nan_de_time_to_next_chan_change(srv); @@ -1604,5 +1616,21 @@ int nan_de_transmit(struct nan_de *de, int handle, nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, peer_addr, a3, req_instance_id, ssi); + srv->listen_stopped = false; + return 0; +} + + +int nan_de_stop_listen(struct nan_de *de, int handle) +{ + struct nan_de_service *srv; + + if (handle < 1 || handle > NAN_DE_MAX_SERVICE) + return -1; + + srv = de->service[handle - 1]; + if (!srv) + return -1; + srv->listen_stopped = true; return 0; } diff --git a/src/common/nan_de.h b/src/common/nan_de.h index b42354464..e4bdbaeab 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -170,4 +170,6 @@ 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); +int nan_de_stop_listen(struct nan_de *de, int handle); + #endif /* NAN_DE_H */ diff --git a/wpa_supplicant/README-NAN-USD b/wpa_supplicant/README-NAN-USD index 72c379fc9..b006819b2 100644 --- a/wpa_supplicant/README-NAN-USD +++ b/wpa_supplicant/README-NAN-USD @@ -56,6 +56,14 @@ NAN_UPDATE_PUBLISH publish_id= [ssi= + +This command is an implementation specific mechanism to allow a service +to stop driver listen operation during an ongoing SDF exchange, e.g., to +allow optimized radio use for parallel operations during provisioning +sequence when no SDF is expected to be received from the peer during the +other operations. NAN_TRANSMIT can used to re-enable listen operations. + NAN_SUBSCRIBE service_name= [active=1] [ttl=] [freq=] [srv_proto_type=] [ssi=] If ttl=0 or the parameter is not included, operation is terminated once @@ -75,6 +83,14 @@ NAN_CANCEL_SUBSCRIBE subscribe_id= This command maps to the CancelSubscribe() method in the NAN Discovery Engine. +NAN_SUBSCRIBE_STOP_LISTEN subscribe_id= + +This command is an implementation specific mechanism to allow a service +to stop driver listen operation during an ongoing SDF exchange, e.g., to +allow optimized radio use for parallel operations during provisioning +sequence when no SDF is expected to be received from the peer during the +other operations. NAN_TRANSMIT can used to re-enable listen operations. + NAN_TRANSMIT handle= req_instance_id= address= [ssi=] This command maps to the Transmit() method in the NAN Discovery Engine. diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 688d2034b..050ed1624 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12863,6 +12863,31 @@ fail: } +static int wpas_ctrl_nan_publish_stop_listen(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *token, *context = NULL; + int publish_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "id=%i", &publish_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_PUBLISH_STOP_LISTEN parameter: %s", + token); + return -1; + } + + if (publish_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_PUBLISH_STOP_LISTEN publish_id"); + return -1; + } + + return wpas_nan_usd_publish_stop_listen(wpa_s, publish_id); +} + + static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -12989,6 +13014,31 @@ static int wpas_ctrl_nan_cancel_subscribe(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_nan_subscribe_stop_listen(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *token, *context = NULL; + int subscribe_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "id=%i", &subscribe_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_SUBSCRIBE_STOP_LISTEN parameter: %s", + token); + return -1; + } + + if (subscribe_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_SUBSCRIBE_STOP_LISTEN subscribe_id"); + return -1; + } + + return wpas_nan_usd_subscribe_stop_listen(wpa_s, subscribe_id); +} + + static int wpas_ctrl_nan_transmit(struct wpa_supplicant *wpa_s, char *cmd) { char *token, *context = NULL; @@ -14112,12 +14162,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) { if (wpas_ctrl_nan_update_publish(wpa_s, buf + 19) < 0) reply_len = -1; + } else if (os_strncmp(buf, "NAN_PUBLISH_STOP_LISTEN ", 24) == 0) { + if (wpas_ctrl_nan_publish_stop_listen(wpa_s, buf + 24) < 0) + reply_len = -1; } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) { reply_len = wpas_ctrl_nan_subscribe(wpa_s, buf + 14, reply, reply_size); } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) { if (wpas_ctrl_nan_cancel_subscribe(wpa_s, buf + 21) < 0) reply_len = -1; + } else if (os_strncmp(buf, "NAN_SUBSCRIBE_STOP_LISTEN ", 26) == 0) { + if (wpas_ctrl_nan_subscribe_stop_listen(wpa_s, buf + 26) < 0) + reply_len = -1; } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) { if (wpas_ctrl_nan_transmit(wpa_s, buf + 13) < 0) reply_len = -1; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 2d623fe8d..6ae6fa74f 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -3869,6 +3869,13 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, + { "NANPublishStopListen", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_publish_stop_listen, + { + { "publish_id", "u", ARG_IN }, + END_ARGS + } + }, { "NANSubscribe", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_nan_subscribe, { @@ -3884,6 +3891,13 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, + { "NANSubscribeStopListen", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_subscribe_stop_listen, + { + { "subscribe_id", "u", ARG_IN }, + END_ARGS + } + }, { "NANTransmit", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_nan_transmit, { diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 5df941f9d..76a9297eb 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -6737,6 +6737,39 @@ fail: } +/* + * wpas_dbus_handler_nan_publish_stop_listen - Stop listen for a NAN publish + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "NANPublishStopListen" method call of network interface. + */ +DBusMessage * +wpas_dbus_handler_nan_publish_stop_listen(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t publish_id; + + if (!wpa_s->nan_de) + return NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_UINT32, &publish_id, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_DEBUG, + "dbus: NANPublishStopListen failed to get args"); + return wpas_dbus_error_invalid_args(message, NULL); + } + + wpa_printf(MSG_DEBUG, "dbus: NANPublishStopListen: id=%u", publish_id); + if (wpas_nan_usd_publish_stop_listen(wpa_s, publish_id) < 0) + return wpas_dbus_error_unknown_error( + message, "error stopping listen"); + return NULL; +} + + /* * wpas_dbus_handler_nan_subscribe - Send out NAN USD subscribe messages * @message: Pointer to incoming dbus message @@ -6893,6 +6926,41 @@ wpas_dbus_handler_nan_cancel_subscribe(DBusMessage *message, } +/* + * wpas_dbus_handler_nan_subscribe_stop_listen - Stop listen for a NAN subscription + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL indicating success or DBus error message on failure + * + * Handler function for "NANSubscribeStopListen" method call of network + * interface. + */ +DBusMessage * +wpas_dbus_handler_nan_subscribe_stop_listen(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t subscribe_id; + + if (!wpa_s->nan_de) + return NULL; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_UINT32, &subscribe_id, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_DEBUG, + "dbus: NANSubscribeStopListen failed to get args"); + return wpas_dbus_error_invalid_args(message, NULL); + } + + wpa_printf(MSG_DEBUG, "dbus: NANSubscribeStopListen: id=%u", + subscribe_id); + if (wpas_nan_usd_subscribe_stop_listen(wpa_s, subscribe_id) < 0) + return wpas_dbus_error_unknown_error( + message, "error stopping listen"); + return NULL; +} + + /* * wpas_dbus_handler_nan_transmit - Send out NAN followup frames * @message: Pointer to incoming dbus message diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index a5260907a..24ee678e1 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -296,11 +296,16 @@ DBusMessage * wpas_dbus_handler_nan_cancel_publish( DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_nan_update_publish( DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_nan_publish_stop_listen( + DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_nan_subscribe(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_nan_cancel_subscribe(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * +wpas_dbus_handler_nan_subscribe_stop_listen(DBusMessage *message, + struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_nan_transmit(DBusMessage *message, struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c index b8eb4c41b..8d170f2ee 100644 --- a/wpa_supplicant/nan_usd.c +++ b/wpa_supplicant/nan_usd.c @@ -490,6 +490,42 @@ int wpas_nan_usd_unpause_publish(struct wpa_supplicant *wpa_s, int publish_id, } +static int wpas_nan_stop_listen(struct wpa_supplicant *wpa_s, int id) +{ + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) + return 0; + + if (nan_de_stop_listen(wpa_s->nan_de, id) < 0) + return -1; + + if (wpa_s->nan_usd_listen_work) { + wpa_printf(MSG_DEBUG, "NAN: Stop listen operation"); + wpa_drv_cancel_remain_on_channel(wpa_s); + wpas_nan_usd_listen_work_done(wpa_s); + } + + if (wpa_s->nan_usd_tx_work) { + wpa_printf(MSG_DEBUG, "NAN: Stop TX wait operation"); + offchannel_send_action_done(wpa_s); + wpas_nan_usd_tx_work_done(wpa_s); + } + + return 0; +} + + +int wpas_nan_usd_publish_stop_listen(struct wpa_supplicant *wpa_s, + int publish_id) +{ + if (!wpa_s->nan_de) + return -1; + + wpa_printf(MSG_DEBUG, "NAN: Request to stop listen for publish_id=%d", + publish_id); + return wpas_nan_stop_listen(wpa_s, publish_id); +} + + int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, @@ -547,6 +583,18 @@ void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, } +int wpas_nan_usd_subscribe_stop_listen(struct wpa_supplicant *wpa_s, + int subscribe_id) +{ + if (!wpa_s->nan_de) + return -1; + + wpa_printf(MSG_DEBUG, "NAN: Request to stop listen for subscribe_id=%d", + subscribe_id); + return wpas_nan_stop_listen(wpa_s, 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) diff --git a/wpa_supplicant/nan_usd.h b/wpa_supplicant/nan_usd.h index 6a43fb241..5ae65304f 100644 --- a/wpa_supplicant/nan_usd.h +++ b/wpa_supplicant/nan_usd.h @@ -28,6 +28,8 @@ int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, const struct wpabuf *ssi); int wpas_nan_usd_unpause_publish(struct wpa_supplicant *wpa_s, int publish_id, u8 peer_instance_id, const u8 *peer_addr); +int wpas_nan_usd_publish_stop_listen(struct wpa_supplicant *wpa_s, + int publish_id); int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, @@ -35,6 +37,8 @@ int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, struct nan_subscribe_params *params, bool p2p); void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, int subscribe_id); +int wpas_nan_usd_subscribe_stop_listen(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); -- 2.47.3