]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
proc_coord: Testing and example use of process coordination
authorJouni Malinen <jouni.malinen@oss.qualcomm.com>
Thu, 11 Dec 2025 18:39:37 +0000 (20:39 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 15 Dec 2025 15:58:49 +0000 (17:58 +0200)
Add hwsim testing for proc_coord to enable automated testing of this
functionality. In addition, this shows a simple example on how the
defined proc_coord API can be used.

Signed-off-by: Jouni Malinen <jouni.malinen@oss.qualcomm.com>
hostapd/ctrl_iface.c
src/common/proc_coord.h
tests/hwsim/example-hostapd.config
tests/hwsim/example-wpa_supplicant.config
tests/hwsim/test_proc_coord.py [new file with mode: 0644]

index 4fa824b4a66d75afc8e07ef59247247de6bf5581..67e84b6b2a2e6a01c316304dcaa95f694533be7a 100644 (file)
@@ -40,6 +40,7 @@
 #include "common/wpa_ctrl.h"
 #include "common/ptksa_cache.h"
 #include "common/nan_de.h"
+#include "common/proc_coord.h"
 #include "crypto/tls.h"
 #include "drivers/driver.h"
 #include "eapol_auth/eapol_auth_sm.h"
@@ -3873,6 +3874,69 @@ static int hostapd_ctrl_iface_sae_password_bind(struct hostapd_data *hapd,
 #endif /* CONFIG_SAE */
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_PROCESS_COORDINATION
+
+static bool hapd_ctrl_proc_coord_cb(void *ctx, int src,
+                                   enum proc_coord_message_types msg_type,
+                                   enum proc_coord_commands cmd,
+                                   u32 seq, const struct wpabuf *msg)
+{
+       struct hostapd_data *hapd = ctx;
+
+       if (cmd != PROC_COORD_CMD_TEST)
+               return false;
+
+       wpa_msg(hapd->msg_ctx, MSG_INFO,
+               "PROC-COORD-TEST RX src=%u msg_type=%d seq=%u msg_len=%zu",
+               src, msg_type, seq, wpabuf_len(msg));
+
+       if (msg_type == PROC_COORD_MSG_REQUEST)
+               proc_coord_send_response(hapd->iface->interfaces->pc,
+                                        src, cmd, seq, msg);
+       return false;
+}
+
+
+static void hapd_ctrl_proc_coord_test_cb(void *ctx, int pid,
+                                        const struct wpabuf *msg)
+{
+       struct hostapd_data *hapd = ctx;
+
+       wpa_msg(hapd->msg_ctx, MSG_INFO,
+               "PROC-COORD-TEST RX-RESP src=%u msg_len=%d",
+               pid, msg ? (int) wpabuf_len(msg) : -1);
+
+}
+
+
+static int hostapd_ctrl_iface_proc_coord_test(struct hostapd_data *hapd,
+                                             const char *cmd)
+{
+       int res, dst;
+       struct wpabuf *msg;
+
+       if (!hapd->iface->interfaces->pc)
+               return -1;
+
+       dst = atoi(cmd);
+
+       msg = wpabuf_alloc(1);
+       if (!msg)
+               return -1;
+       wpabuf_put_u8(msg, 123);
+
+       res = proc_coord_send_request(hapd->iface->interfaces->pc,
+                                     dst, PROC_COORD_CMD_TEST, msg, 1000,
+                                     hapd_ctrl_proc_coord_test_cb, hapd);
+       wpabuf_free(msg);
+       return res < 0 ? -1 : 0;
+}
+
+#endif /* CONFIG_PROCESS_COORDINATION */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                                              char *buf, char *reply,
                                              int reply_size,
@@ -4486,6 +4550,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                if (hostapd_ctrl_iface_sae_password_bind(hapd, buf + 18))
                        reply_len = -1;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_PROCESS_COORDINATION
+       } else if (os_strncmp(buf, "PROC_COORD_TEST ", 16) == 0) {
+               if (hostapd_ctrl_iface_proc_coord_test(hapd, buf + 16))
+                       reply_len = -1;
+#endif /* CONFIG_PROCESS_COORDINATION */
+#endif /* CONFIG_TESTING_OPTIONS */
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
                reply_len = 16;
@@ -5198,6 +5269,14 @@ fail:
        hapd->msg_ctx = hapd;
        wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_PROCESS_COORDINATION
+       if (hapd->iface->interfaces->pc)
+               proc_coord_register_handler(hapd->iface->interfaces->pc,
+                                           hapd_ctrl_proc_coord_cb, hapd);
+#endif /* CONFIG_PROCESS_COORDINATION */
+#endif /* CONFIG_TESTING_OPTIONS */
+
        return 0;
 
 fail:
@@ -5253,6 +5332,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
 #ifdef CONFIG_TESTING_OPTIONS
        l2_packet_deinit(hapd->l2_test);
        hapd->l2_test = NULL;
+#ifdef CONFIG_PROCESS_COORDINATION
+       if (hapd->iface->interfaces->pc) {
+               proc_coord_unregister_handler(hapd->iface->interfaces->pc,
+                                             hapd_ctrl_proc_coord_cb, hapd);
+               proc_coord_cancel_wait(hapd->iface->interfaces->pc,
+                                      hapd_ctrl_proc_coord_test_cb, hapd);
+       }
+#endif /* CONFIG_PROCESS_COORDINATION */
 #endif /* CONFIG_TESTING_OPTIONS */
 }
 
index 47b09c40b52f936c64252d5ad776fd8ee16b52f5..8eae443444f24a7d3925efa43e02831ca2d0e744 100644 (file)
@@ -21,6 +21,7 @@ enum proc_coord_commands {
        PROC_COORD_CMD_STARTING = 0,
        PROC_COORD_CMD_STOPPING = 1,
        PROC_COORD_CMD_PING = 2,
+       PROC_COORD_CMD_TEST = 3,
 };
 
 /**
index c75395c00a5763097f01f3bbdba6fb7927cbbee7..65e6d7e5ee2b159dbb5b07172755e6a6b3a6b5b1 100644 (file)
@@ -124,3 +124,4 @@ CONFIG_PASN=y
 CONFIG_AIRTIME_POLICY=y
 CONFIG_IEEE80211BE=y
 CONFIG_NAN_USD=y
+CONFIG_PROCESS_COORDINATION=y
index a43bdc5ce00c4315cfc68b3560d8cd66be6796da..d9b26464c1d21a37f58a2d9b125ba0011025832e 100644 (file)
@@ -169,3 +169,4 @@ CONFIG_PASN=y
 CONFIG_NAN_USD=y
 
 CONFIG_IEEE80211BE=y
+CONFIG_PROCESS_COORDINATION=y
diff --git a/tests/hwsim/test_proc_coord.py b/tests/hwsim/test_proc_coord.py
new file mode 100644 (file)
index 0000000..beda15a
--- /dev/null
@@ -0,0 +1,96 @@
+# Test cases for process coordination
+# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import stat
+import subprocess
+import tempfile
+
+from hwsim import HWSimRadio
+from utils import *
+
+def test_proc_coord_hostapd(dev, apdev, params):
+    """Process coordination in hostapd"""
+    dir = "/tmp/hostapd-proc-coord"
+    os.mkdir(dir)
+    os.chmod(dir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
+
+    with HWSimRadio(use_mlo=True, n_channels=2) as (hapd_radio, hapd_iface):
+        hapd_iface2 = hapd_iface + '-2'
+        cmd = ['iw', 'phy' + str(hapd_radio), 'interface', 'add',
+               hapd_iface2, 'type', '__ap']
+        proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT,
+                                stdout=subprocess.PIPE, shell=False)
+        out, err = proc.communicate()
+        logger.debug("iw output: " + out.decode())
+
+        fd, fname = tempfile.mkstemp(dir='/tmp', prefix='hostapd-cfg-')
+        f = os.fdopen(fd, 'w')
+        f.write("driver=nl80211\n")
+        f.write("ctrl_interface=/var/run/hostapd\n")
+        f.write("hw_mode=g\n")
+        f.write("channel=1\n")
+        f.write("ieee80211n=1\n")
+        f.write("ssid=foo\n")
+        f.close()
+
+        pid1 = params['prefix'] + ".hostapd.pid-1"
+        cmd = ['../../hostapd/hostapd', '-ddKtB', '-P', pid1, '-f',
+               params['prefix'] + ".hostapd-log-1",
+               '-i', hapd_iface,
+               '-z', dir,
+               fname]
+        res = subprocess.check_call(cmd)
+        if res != 0:
+            raise Exception("Could not start hostapd: %s" % str(res))
+
+        pid2 = params['prefix'] + ".hostapd.pid-2"
+        cmd = ['../../hostapd/hostapd', '-ddKtB', '-P', pid2, '-f',
+               params['prefix'] + ".hostapd-log-2",
+               '-i', hapd_iface2,
+               '-z', dir,
+               fname]
+        res = subprocess.check_call(cmd)
+        if res != 0:
+            raise Exception("Could not start hostapd: %s" % str(res))
+
+        time.sleep(2)
+        for i in range(20):
+            if os.path.exists(pid1) and os.path.exists(pid2):
+                break
+            time.sleep(0.2)
+
+        if not (os.path.exists(pid1) and os.path.exists(pid2)):
+            raise Exception("hostapd did not create PID file.")
+
+        hapd1 = hostapd.Hostapd(hapd_iface)
+        hapd1.ping()
+
+        hapd2 = hostapd.Hostapd(hapd_iface2)
+        hapd2.ping()
+
+        if "OK" not in hapd1.request("PROC_COORD_TEST 0"):
+            raise Exception("PROC_COORD_TEST failed")
+
+        ev = hapd1.wait_event(["PROC-COORD-TEST"], timeout=5)
+        if ev is None:
+            raise Exception("hapd1 did not report PROC-COORD-TEST")
+        if " RX-RESP " not in ev:
+            raise Exception("Unexpected hapd1 PROC-COORD-TEST contents")
+        if " msg_len=1" not in ev:
+            raise Exception("Unexpected hapd1 PROC-COORD-TEST msg_len")
+
+        ev = hapd2.wait_event(["PROC-COORD-TEST"], timeout=5)
+        if ev is None:
+            raise Exception("hapd2 did not report PROC-COORD-TEST")
+        if " RX " not in ev:
+            raise Exception("Unexpected hapd2 PROC-COORD-TEST contents")
+
+        hapd1.request("TERMINATE")
+        hapd2.request("TERMINATE")
+        time.sleep(1)
+
+    os.rmdir(dir)