]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
NAN USD: Allow services to disable listen operation during SDF exchange
authorJouni Malinen <jouni.malinen@oss.qualcomm.com>
Fri, 24 Oct 2025 13:31:55 +0000 (16:31 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 24 Oct 2025 17:00:22 +0000 (20:00 +0300)
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 <jouni.malinen@oss.qualcomm.com>
doc/dbus.doxygen
src/common/nan_de.c
src/common/nan_de.h
wpa_supplicant/README-NAN-USD
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/dbus/dbus_new_handlers.h
wpa_supplicant/nan_usd.c
wpa_supplicant/nan_usd.h

index 68c3cb7840d06a86acdc46223338dbfc5308c31a..fa73e8a1b7d1ff5f655328ab02fe05c87c0da641 100644 (file)
@@ -805,6 +805,20 @@ fi.w1.wpa_supplicant1.CreateInterface.
          <dd>Needed memory was not possible to get allocated.</dd>
        </dl>
       </li>
+      <li>
+       <h3>NANPublishStopListen ( u : publish_id ) --> nothing</h3>
+       <p>Stop listen operation for a previously added NAN USD publisher service.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>u : publish_id</dt>
+         <dd>Publish ID from NANPublish().</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
       <li>
        <h3>NANSubscribe ( a{sv} : args ) --> u : subscribe_id</h3>
        <p>Subscribe to a NAN USD service.</p>
@@ -847,6 +861,20 @@ fi.w1.wpa_supplicant1.CreateInterface.
          <dd>Invalid entries were found in the passed argument.</dd>
        </dl>
       </li>
+      <li>
+       <h3>NANSubscribeStopListen ( u : subscribe_id ) --> nothing</h3>
+       <p>Stop listen operation for a previously started NAN USD subscription.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>u : subscribe_id</dt>
+         <dd>Subscription ID from NANSubscribe().</dd>
+       </dl>
+       <h4>Possible errors</h4>
+       <dl>
+         <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+         <dd>Invalid entries were found in the passed argument.</dd>
+       </dl>
+      </li>
       <li>
        <h3>NANTransmit ( a{sv} : args ) --> nothing</h3>
        <p>Send a follow-up message for NAN USD service discovery.</p>
index 69175224ded624908f856dc20ad950ac43a327bf..e4e20f3cb82a08fbbac981ebccfe8a322420a378 100644 (file)
@@ -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;
 }
index b423544649db4f81a94a175a428e28237c2e0e09..e4bdbaeab1366f2df5bbba38d6f86740fcb5a59a 100644 (file)
@@ -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 */
index 72c379fc976af15143580c7266ca01ac6cb414a8..b006819b25ddf43262960ab557e04672f2982e92 100644 (file)
@@ -56,6 +56,14 @@ NAN_UPDATE_PUBLISH publish_id=<id from NAN_PUBLISH> [ssi=<service specific infor
 This command maps to the UpdatePublish() method in the NAN Discovery
 Engine.
 
+NAN_PUBLISH_STOP_LISTEN publish_id=<id from NAN_PUBLISH>
+
+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=<name> [active=1] [ttl=<time-to-live-in-sec>] [freq=<in MHz>] [srv_proto_type=<type>] [ssi=<service specific information (hexdump)>]
 
 If ttl=0 or the parameter is not included, operation is terminated once
@@ -75,6 +83,14 @@ NAN_CANCEL_SUBSCRIBE subscribe_id=<id from NAN_SUBSCRIBE>
 
 This command maps to the CancelSubscribe() method in the NAN Discovery Engine.
 
+NAN_SUBSCRIBE_STOP_LISTEN subscribe_id=<id from NAN_SUBSCRIBE>
+
+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=<id from NAN_PUBLISH or NAN_SUBSCRIBE> req_instance_id=<peer's id> address=<peer's MAC address> [ssi=<service specific information (hexdump)>]
 
 This command maps to the Transmit() method in the NAN Discovery Engine.
index 688d2034b22dd9c50e187bfdedf0b614be074b1e..050ed1624086b40015f86bc9e4fb955c921baa27 100644 (file)
@@ -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;
index 2d623fe8dcb508fa4365c18a3569d21909ef7e64..6ae6fa74ffb51579a633291d532e7ec126033c05 100644 (file)
@@ -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,
          {
index 5df941f9d1d16c8a40eece24adbb21f725d77ee8..76a9297eba30a3d6e730b2c18032ab3ba6eb6bfa 100644 (file)
@@ -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
index a5260907a2f341e64e766f7869dea111c0a41501..24ee678e1712759e306b4834f6730f8a8b6f8bd7 100644 (file)
@@ -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);
 
index b8eb4c41b7738b78c066bfffbaa925a66615c005..8d170f2ee48dc485d5ddfa00724dfdae83b2ab9b 100644 (file)
@@ -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)
index 6a43fb24174f8ea6f74f88084682622e09c4523f..5ae65304f49ccbd8632686707e47bcf5f29fdab5 100644 (file)
@@ -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);