From j at w1.fi Thu Aug 1 07:39:41 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 1 Aug 2024 17:39:41 +0300 Subject: [PATCH 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240423053128.129322-2-quic_adisi@quicinc.com> References: <20240423053128.129322-1-quic_adisi@quicinc.com> <20240423053128.129322-2-quic_adisi@quicinc.com> Message-ID: On Tue, Apr 23, 2024 at 11:01:23AM +0530, Aditya Kumar Singh wrote: > Create link based control sockets to access the link based commands > through hostapd_cli. This will create the link interfaces in the name of > wlan_link > > Example: > To fetch link 0 status from wlan0, below command can be used - > $ hostapd_cli -i wlan0 -l 0 status > > On failure of link/interface selection, below error will be observed > $ hostapd_cli -i wlan0 -l 2 status > Failed to connect to hostapd - wpa_ctrl_open: No such file or directory This breaks eht_mld_cohosted_discovery and eht_mlo_color_change test cases: START eht_mld_cohosted_discovery 1/2 Traceback (most recent call last): File "/home/jm/Git/hostap/tests/hwsim/./run-tests.py", line 589, in main t(dev, apdev, params) File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2080, in test_eht_mld_cohosted_discovery eht_mld_cohosted_discovery(dev, apdev, params) File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2050, in eht_mld_cohosted_discovery hapds = get_mld_devs(hapd_iface=hapd_iface, count=2, File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 1959, in get_mld_devs hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 155, in __init__ self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) File "/home/jm/Git/hostap/tests/hwsim/../../wpaspy/wpaspy.py", line 40, in __init__ self.s.connect(self.dest) FileNotFoundError: [Errno 2] No such file or directory Exception: [Errno 2] No such file or directory FAIL eht_mld_cohosted_discovery 2.002865 2024-08-01 14:37:40.010584 START eht_mlo_color_change 2/2 Traceback (most recent call last): File "/home/jm/Git/hostap/tests/hwsim/./run-tests.py", line 591, in main t(dev, apdev) File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2147, in test_eht_mlo_color_change hapd0 = eht_mld_enable_ap(hapd_iface, params) File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 242, in eht_mld_enable_ap hapd = hostapd.add_mld_link(iface, params) File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 752, in add_mld_link hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 155, in __init__ self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) File "/home/jm/Git/hostap/tests/hwsim/../../wpaspy/wpaspy.py", line 40, in __init__ self.s.connect(self.dest) FileNotFoundError: [Errno 2] No such file or directory Exception: [Errno 2] No such file or directory FAIL eht_mlo_color_change 0.000361 2024-08-01 14:37:40.010949 -- Jouni Malinen PGP id EFC895FA From j at w1.fi Thu Aug 1 08:13:46 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 1 Aug 2024 18:13:46 +0300 Subject: [PATCH v2 3/5] bss: don't add hidden OWE transition-networks to scan-list In-Reply-To: <20240428131344.334314-4-mail@david-bauer.net> References: <20240428131344.334314-1-mail@david-bauer.net> <20240428131344.334314-4-mail@david-bauer.net> Message-ID: On Sun, Apr 28, 2024 at 03:13:42PM +0200, David Bauer wrote: > When adding these networks hidden, they get re-added for the same BSSID > when scanning for the transition-SSID. Skip adding the OWE-SSIDs in case > the SSID was not explicitly scanned for. This breaks multiple hwsim test cases for OWE since the expected BSS entry is not available. While I think I understand what this is trying to do, it is not really acceptable to break test cases, so I cannot apply this as-is. At minimum, those test cases would need to be modified, but I'm not really sure this is actually correct behavior since BSSs with a hidden SSID have been added to the scan results in all existing cases for years. > + /* Don't add hidden OWE transition networks with RSN. They are explicitly scanned for. */ > + rsn = wpa_scan_get_ie(res, WLAN_EID_RSN); > + owe = wpa_scan_get_vendor_ie(res, OWE_IE_VENDOR_TYPE); > + if (owe && rsn && (ssid[1] == 0 || ssid[2] == 0)) > + return; And this should likely be within #ifdef CONFIG_OWE even if that were to compile successfully without such conditional check. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Thu Aug 1 08:36:04 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 1 Aug 2024 18:36:04 +0300 Subject: [PATCH v2 0/5] wpa_supplicant: optimize OWE roaming behavior In-Reply-To: <20240428131344.334314-1-mail@david-bauer.net> References: <20240428131344.334314-1-mail@david-bauer.net> Message-ID: On Sun, Apr 28, 2024 at 03:13:39PM +0200, David Bauer wrote: > This patchset aims for improving roaming when connected to an OWE > transition-mode enabled network. > David Bauer (5): > wpa_supplicant: reduce OWE transition network code duplication > ctrl: enable roaming between OWE APs > bss: don't add hidden OWE transition-networks to scan-list > bgscan: add OWE transition SSID to OWE network scan > scan: stored last-seen transition SSID Thanks, I applied patches 1-2 and 4 with some cleanup. Patch 3 has open comments and patch 5 depends on 3. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Thu Aug 1 08:36:26 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 1 Aug 2024 18:36:26 +0300 Subject: [PATCH] hostapd: fix BSS parameters change count on link removal In-Reply-To: <20240724193706.1ee90d20aeed.Ie6d04c0a58c6fc17d44706c18e3b16dd27ab631b@changeid> References: <20240724193706.1ee90d20aeed.Ie6d04c0a58c6fc17d44706c18e3b16dd27ab631b@changeid> Message-ID: On Wed, Jul 24, 2024 at 07:37:07PM +0200, Johannes Berg wrote: > The value currently is simply incremented, but it must not > reach 255 and rather wrap around from 254 to 0, since in > the Reduced Neighbor Report 255 means unknown. Fix that. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From quic_adisi at quicinc.com Thu Aug 1 08:50:25 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 21:20:25 +0530 Subject: [PATCH 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: References: <20240423053128.129322-1-quic_adisi@quicinc.com> <20240423053128.129322-2-quic_adisi@quicinc.com> Message-ID: <79f377b3-9239-4b17-b39f-2f3ae6e9528a@quicinc.com> On 8/1/24 20:09, Jouni Malinen wrote: > On Tue, Apr 23, 2024 at 11:01:23AM +0530, Aditya Kumar Singh wrote: >> Create link based control sockets to access the link based commands >> through hostapd_cli. This will create the link interfaces in the name of >> wlan_link >> >> Example: >> To fetch link 0 status from wlan0, below command can be used - >> $ hostapd_cli -i wlan0 -l 0 status >> >> On failure of link/interface selection, below error will be observed >> $ hostapd_cli -i wlan0 -l 2 status >> Failed to connect to hostapd - wpa_ctrl_open: No such file or directory > > This breaks eht_mld_cohosted_discovery and eht_mlo_color_change test > cases: > > START eht_mld_cohosted_discovery 1/2 > Traceback (most recent call last): > File "/home/jm/Git/hostap/tests/hwsim/./run-tests.py", line 589, in main > t(dev, apdev, params) > File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2080, in test_eht_mld_cohosted_discovery > eht_mld_cohosted_discovery(dev, apdev, params) > File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2050, in eht_mld_cohosted_discovery > hapds = get_mld_devs(hapd_iface=hapd_iface, count=2, > File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 1959, in get_mld_devs > hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], > File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 155, in __init__ > self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) > File "/home/jm/Git/hostap/tests/hwsim/../../wpaspy/wpaspy.py", line 40, in __init__ > self.s.connect(self.dest) > FileNotFoundError: [Errno 2] No such file or directory > Exception: [Errno 2] No such file or directory > FAIL eht_mld_cohosted_discovery 2.002865 2024-08-01 14:37:40.010584 > START eht_mlo_color_change 2/2 > Traceback (most recent call last): > File "/home/jm/Git/hostap/tests/hwsim/./run-tests.py", line 591, in main > t(dev, apdev) > File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 2147, in test_eht_mlo_color_change > hapd0 = eht_mld_enable_ap(hapd_iface, params) > File "/home/jm/Git/hostap/tests/hwsim/test_eht.py", line 242, in eht_mld_enable_ap > hapd = hostapd.add_mld_link(iface, params) > File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 752, in add_mld_link > hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) > File "/home/jm/Git/hostap/tests/hwsim/hostapd.py", line 155, in __init__ > self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) > File "/home/jm/Git/hostap/tests/hwsim/../../wpaspy/wpaspy.py", line 40, in __init__ > self.s.connect(self.dest) > FileNotFoundError: [Errno 2] No such file or directory > Exception: [Errno 2] No such file or directory > FAIL eht_mlo_color_change 0.000361 2024-08-01 14:37:40.010949 > Ah! Right! These test cases got added after the patch was created hence the test cases isn't modified as per the MLO control sockets use case. Let me quickly rebase and send a new version! -- Aditya From quic_adisi at quicinc.com Thu Aug 1 09:34:41 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:41 +0530 Subject: [PATCH v2 0/6] MLO control socket changes Message-ID: <20240801163447.3202440-1-quic_adisi@quicinc.com> From: Aditya Kumar Singh Control socket for each link BSS of MLD currently needs to be in a separate directory since interface name is same for all links in an AP MLD. Hence once the first link comes up, rest of links will not come up if using the same control interface directory. Hence, introduce link level sockets. Each link will use socket with name "_link" under given control interface directory. Also, introduce a MLD level socket with name "" in the same directory. This will help to route the commands to underlying links if required as well as it will keep backwards compatibility with other applications trying to find "" file in the control interface directory. Aditya Kumar Singh (5): ctrl_iface: MLO: introduce MLD level socket hostapd_cli: MLO: pass 'LINKID' in the command hostapd_cli: MLO: add status command for MLD socket tests: MLO: use link ID to access control sockets tests: MLO: add MLD socket connectivity test case Karthikeyan Kathirvel (1): ctrl_iface: create link based hapd control sockets --- v2: * Rebased on ToT. No conflicts in [1-4]. * Fixed newly added EHT MLO and RSN Override sim test cases. [5/6] --- hostapd/ctrl_iface.c | 397 ++++++++++++++++++++++++++++++- hostapd/ctrl_iface.h | 4 + hostapd/hostapd_cli.c | 69 +++++- hostapd/main.c | 5 + src/ap/hostapd.c | 39 +++ src/ap/hostapd.h | 7 + src/common/wpa_ctrl.c | 54 +++++ src/common/wpa_ctrl.h | 7 + tests/hwsim/hostapd.py | 27 ++- tests/hwsim/mld.py | 36 +++ tests/hwsim/test_eht.py | 126 +++++++++- tests/hwsim/test_rsn_override.py | 2 + 12 files changed, 749 insertions(+), 24 deletions(-) create mode 100644 tests/hwsim/mld.py base-commit: 69d18ab9f256360e3a444f45e53840fcf3aa8f19 -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:42 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:42 +0530 Subject: [PATCH v2 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-2-quic_adisi@quicinc.com> From: Karthikeyan Kathirvel Create link based control sockets to access the link based commands through hostapd_cli. This will create the link interfaces in the name of wlan_link Example: To fetch link 0 status from wlan0, below command can be used - $ hostapd_cli -i wlan0 -l 0 status On failure of link/interface selection, below error will be observed $ hostapd_cli -i wlan0 -l 2 status Failed to connect to hostapd - wpa_ctrl_open: No such file or directory Signed-off-by: Karthikeyan Kathirvel Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 16 ++++++++++++++-- hostapd/hostapd_cli.c | 30 ++++++++++++++++++++++++++++-- src/ap/hostapd.c | 28 ++++++++++++++++++++++++++++ src/ap/hostapd.h | 1 + src/common/wpa_ctrl.h | 4 ++++ 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 39b9ef59dc57..3fa33be7a894 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4687,18 +4687,26 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { char *buf; size_t len; + char *ctrl_sock_iface; + +#ifdef CONFIG_IEEE80211BE + ctrl_sock_iface = hapd->ctrl_sock_iface; +#else + ctrl_sock_iface = hapd->conf->iface; +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->ctrl_interface == NULL) return NULL; len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; + os_strlen(ctrl_sock_iface) + 2; + buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); + hapd->conf->ctrl_interface, ctrl_sock_iface); buf[len - 1] = '\0'; return buf; } @@ -4869,7 +4877,11 @@ fail: #endif /* ANDROID */ if (os_strlen(hapd->conf->ctrl_interface) + 1 + +#ifdef CONFIG_IEEE80211BE + os_strlen(hapd->ctrl_sock_iface) >= sizeof(addr.sun_path)) +#else os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) +#endif /* CONFIG_IEEE80211BE */ goto fail; s = socket(PF_UNIX, SOCK_DGRAM, 0); diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index eb8a38350bd1..f05a734fea90 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -54,7 +54,11 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" +#ifdef CONFIG_IEEE80211BE + "usage: hostapd_cli [-p] [-i] [-l] [-hvBr] " +#else "usage: hostapd_cli [-p] [-i] [-hvBr] " +#endif /* CONFIG_IEEE80211BE */ "[-a] \\\n" " [-P] [-G] [command..]\n" "\n" @@ -74,7 +78,12 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n"); + " socket path)\n" +#ifdef CONFIG_IEEE80211BE + " -l Link ID of the interface in case of Multi-Link\n" + " Operation\n" +#endif /* CONFIG_IEEE80211BE */ + "\n"); print_help(stderr, NULL); } @@ -2205,19 +2214,26 @@ static void hostapd_cli_action(struct wpa_ctrl *ctrl) eloop_unregister_read_sock(fd); } - int main(int argc, char *argv[]) { int warning_displayed = 0; int c; int daemonize = 0; int reconnect = 0; +#ifdef CONFIG_IEEE80211BE + int link_id = -1; + char buf[300]; +#endif /* CONFIG_IEEE80211BE */ if (os_program_init()) return -1; for (;;) { +#ifdef CONFIG_IEEE80211BE + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); +#else c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); +#endif /* CONFIG_IEEE80211BE */ if (c < 0) break; switch (c) { @@ -2252,6 +2268,16 @@ int main(int argc, char *argv[]) case 's': client_socket_dir = optarg; break; +#ifdef CONFIG_IEEE80211BE + case 'l': + link_id = atoi(optarg); + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, link_id); + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); + break; +#endif /* CONFIG_IEEE80211BE */ default: usage(); return -1; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a0ac3a857823..49c9d0ddefd7 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1810,12 +1810,37 @@ int hostapd_set_acl(struct hostapd_data *hapd) } +static void hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + + if (hapd->conf->mld_ap) { + char buf[128]; + + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); + } +#endif /* CONFIG_IEEE80211BE */ +} + + static int start_ctrl_iface_bss(struct hostapd_data *hapd) { if (!hapd->iface->interfaces || !hapd->iface->interfaces->ctrl_iface_init) return 0; + hostapd_set_ctrl_sock_iface(hapd); + if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", @@ -1836,6 +1861,9 @@ static int start_ctrl_iface(struct hostapd_iface *iface) for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; + + hostapd_set_ctrl_sock_iface(hapd); + if (iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dcf395ca5ee8..34a665562d35 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -476,6 +476,7 @@ struct hostapd_data { struct hostapd_mld *mld; struct dl_list link; u8 mld_link_id; + char ctrl_sock_iface[IFNAMSIZ + 1]; #ifdef CONFIG_TESTING_OPTIONS u8 eht_mld_link_removal_count; #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f6142501e440..865ac6d91052 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -674,4 +674,8 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); } #endif +#ifdef CONFIG_IEEE80211BE +#define WPA_CTRL_IFACE_LINK_NAME "link" +#endif /* CONFIG_IEEE80211BE */ + #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:43 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:43 +0530 Subject: [PATCH v2 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-3-quic_adisi@quicinc.com> With MLO, each link have socket created with "_link" under the control interface directory. Introduce a MLD level socket - "" as well under the same control interface directory. This socket can be used to pass the command to its partner links directly instead of using the link level socket. Link ID needs to be passed with the command. The structure of the command is - " LINKID " Directory looks something like this - $ ls /var/run/hostapd/ wlan0 wlan0_link0 wlan0_link1 wlan0 here is the MLD level socket. Rest are each link level. This would also help to maintain backwards compatibility with applications which looks for under the control interface directory.` Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 335 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.h | 4 + hostapd/main.c | 5 + src/ap/hostapd.c | 11 ++ src/ap/hostapd.h | 6 + 5 files changed, 361 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 3fa33be7a894..5fe29147fa38 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4682,6 +4682,341 @@ done: } +#ifdef CONFIG_IEEE80211BE +#ifndef CONFIG_CTRL_IFACE_UDP +static int hostapd_mld_ctrl_iface_attach(struct hostapd_mld *mld, + struct sockaddr_storage *from, + socklen_t fromlen, const char *input) +{ + return ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, input); +} + + +static int hostapd_mld_ctrl_iface_detach(struct hostapd_mld *mld, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + return ctrl_iface_detach(&mld->ctrl_dst, from, fromlen); +} + + +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, + char *buf, char *reply, + int reply_size, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct hostapd_data *link_hapd, *link_itr; + int reply_len, link_id = -1; + char *link_cmd; + bool found = false; + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + /* Check if link id is provided in the command or not */ + link_cmd = os_strstr(buf, "LINKID"); + if (link_cmd) { + /* Trim the link id part now */ + *(link_cmd - 1) = '\0'; + + link_cmd += 7; + link_id = atoi(link_cmd); + + if (link_id < 0 || link_id >= 15) { + os_memcpy(reply, "INVALID LINK ID\n", 16); + reply_len = 16; + return reply_len; + } + + link_hapd = mld->fbss; + if (!link_hapd) { + os_memcpy(reply, "NO LINKS ACTIVE\n", 16); + reply_len = 16; + return reply_len; + } + + for_each_mld_link(link_itr, link_hapd) { + if (link_itr->mld_link_id == link_id) { + found = true; + break; + } + } + + if (!found) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + return reply_len; + } + + link_hapd = link_itr; + } else { + link_hapd = mld->fbss; + } + + if (os_strcmp(buf, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); + reply_len = 5; + } else if (os_strcmp(buf, "ATTACH") == 0) { + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, NULL)) + reply_len = -1; + } else if (os_strncmp(buf, "ATTACH ", 7) == 0) { + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, buf + 7)) + reply_len = -1; + } else if (os_strcmp(buf, "DETACH") == 0) { + if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) + reply_len = -1; + } else { + if (link_id == -1) + wpa_printf(MSG_DEBUG, "Link ID not provided, using first link BSS (if available)"); + + if (!link_hapd) + reply_len = -1; + else + reply_len = + hostapd_ctrl_iface_receive_process(link_hapd, buf, + reply, reply_size, + from, fromlen); + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + return reply_len; +} + + +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct hostapd_mld *mld = eloop_ctx; + char buf[4096]; + int res; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + char *reply, *pos = buf; + const int reply_size = 4096; + int reply_len; + int level = MSG_DEBUG; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s", + strerror(errno)); + return; + } + buf[res] = '\0'; + + reply = os_malloc(reply_size); + if (reply == NULL) { + if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + return; + } + + if (os_strcmp(pos, "PING") == 0) + level = MSG_EXCESSIVE; + + wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res); + + reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos, + reply, reply_size, + &from, fromlen); + + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + os_free(reply); +} + + +static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld) +{ + char *buf; + size_t len; + + if (!mld->ctrl_interface) + return NULL; + + len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2; + + buf = os_malloc(len); + if (buf == NULL) + return NULL; + + os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); + buf[len - 1] = '\0'; + return buf; +} +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct sockaddr_un addr; + int s = -1; + char *fname = NULL; + + if (!mld) + return -1; + + if (mld->ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!", + mld->name); + return 0; + } + + dl_list_init(&mld->ctrl_dst); + + if (mld->ctrl_interface == NULL) + return 0; + + if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); + goto fail; + } + } + + if (os_strlen(mld->ctrl_interface) + 1 + + os_strlen(mld->name) >= sizeof(addr.sun_path)) + goto fail; + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ + addr.sun_family = AF_UNIX; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname == NULL) + goto fail; + + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + + wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name); + + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); + goto fail; + } + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < + 0) { + wpa_printf(MSG_ERROR, + "hostapd-ctrl-iface: bind(PF_UNIX): %s", + strerror(errno)); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); + goto fail; + } + os_free(fname); + + mld->ctrl_sock = s; + + if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld, + NULL) < 0) + return -1; + + return 0; + +fail: + if (s >= 0) + close(s); + if (fname) { + unlink(fname); + os_free(fname); + } + return -1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + return 0; +} + + +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct wpa_ctrl_dst *dst, *prev; + + if (mld->ctrl_sock > -1) { + char *fname; + eloop_unregister_read_sock(mld->ctrl_sock); + close(mld->ctrl_sock); + mld->ctrl_sock = -1; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname) + unlink(fname); + os_free(fname); + + if (mld->ctrl_interface && + rmdir(mld->ctrl_interface) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "MLD Control interface " + "directory not empty - leaving it " + "behind"); + } else { + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + mld->ctrl_interface, + strerror(errno)); + } + } + } + + dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst, + list) + os_free(dst); +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + os_free(mld->ctrl_interface); +} +#endif /* CONFIG_IEEE80211BE */ + + #ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h index 3341a66bdc6c..ec5a95be785c 100644 --- a/hostapd/ctrl_iface.h +++ b/hostapd/ctrl_iface.h @@ -14,6 +14,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd); void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); +#ifdef CONFIG_IEEE80211BE +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld); +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld); +#endif /* CONFIG_IEEE80211BE */ #else /* CONFIG_NO_CTRL_IFACE */ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { diff --git a/hostapd/main.c b/hostapd/main.c index 00e02bb034c9..aa1f69812fd8 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -748,6 +748,7 @@ static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) if (!interfaces->mld[i]) continue; + interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]); os_free(interfaces->mld[i]); interfaces->mld[i] = NULL; } @@ -793,6 +794,10 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; +#ifdef CONFIG_IEEE80211BE + interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init; + interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit; +#endif /* CONFIG_IEEE80211BE */ dl_list_init(&interfaces.global_ctrl_dst); #ifdef CONFIG_ETH_P_OUI dl_list_init(&interfaces.eth_p_oui); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 49c9d0ddefd7..2794bb14efdf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3095,9 +3095,18 @@ static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); dl_list_init(&mld->links); + mld->ctrl_sock = -1; + mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface); wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + /* + * Initialize MLD control interfaces early to allow external monitoring of + * link setup operations. + */ + if (interfaces->mld_ctrl_iface_init(mld)) + goto fail; + hapd->mld = mld; hostapd_mld_ref_inc(mld); hostapd_bss_alloc_link_id(hapd); @@ -3157,6 +3166,8 @@ static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) if (!remove && !forced_remove) continue; + interfaces->mld_ctrl_iface_deinit(mld); + wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name, forced_remove ? " (forced)" : ""); os_free(mld); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 34a665562d35..2ef63e5f2383 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -97,6 +97,8 @@ struct hapd_interfaces { #ifdef CONFIG_IEEE80211BE struct hostapd_mld **mld; size_t mld_count; + int (*mld_ctrl_iface_init)(struct hostapd_mld *mld); + void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld); #endif /* CONFIG_IEEE80211BE */ }; @@ -519,6 +521,10 @@ struct hostapd_mld { struct hostapd_data *fbss; struct dl_list links; /* List head of all affiliated links */ + + int ctrl_sock; + struct dl_list ctrl_dst; + char *ctrl_interface; /* directory for UNIX domain sockets */ }; #define HOSTAPD_MLD_MAX_REF_COUNT 0xFF -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:44 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:44 +0530 Subject: [PATCH v2 3/6] hostapd_cli: MLO: pass 'LINKID' in the command In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-4-quic_adisi@quicinc.com> MLD level socket can take 'LINKID '. Add changes to pass this via hostapd_cli. User needs to give "link_id=" in post fix fashion in the command in order to pass this link_id from cli. For example - $ hostapd_cli -i wlan0 status link_id=0 | grep freq= freq=2437 $ hostapd_cli -i wlan0 ... Interactive mode > ping PONG > > status link_id=0 Command for 'LINKID 0' state=ENABLED phy=phy0 freq=2437 Signed-off-by: Aditya Kumar Singh --- hostapd/hostapd_cli.c | 39 +++++++++++++++++++++++++++++++ src/common/wpa_ctrl.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/common/wpa_ctrl.h | 3 +++ 3 files changed, 96 insertions(+) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index f05a734fea90..d695255027ba 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1962,6 +1962,45 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); } else { +#ifdef CONFIG_IEEE80211BE + char *pos, *end; + int i, j, link_id; + bool link_found = false; + + wpa_ctrl_reset_mld_link(ctrl); + i = 0; + + while (i < argc) { + pos = os_strstr(argv[i], "link_id="); + if (!pos) { + i++; + continue; + } + + pos = pos + 8; + link_id = strtol(pos, &end, 10); + + if (link_id < 0 || link_id >= 15) { + printf("Invalid link ID '%d'\n", link_id); + return; + } + + link_found = true; + + /* remove this link_id= from the arguements */ + for (j = i + 1; j < argc; j++) + argv[j - 1] = argv[j]; + + argc--; + i = 0; + } + + if (link_found) { + wpa_ctrl_set_mld_link(ctrl, link_id); + printf("Command for '%s'\n", + wpa_ctrl_get_mld_link(ctrl)); + } +#endif /* CONFIG_IEEE80211BE */ match->handler(ctrl, argc - 1, &argv[1]); } } diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 7e197f094fd1..d0c174c05d48 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -72,6 +72,13 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +#ifdef CONFIG_IEEE80211BE + /* 'LINKID ' - 7 chars including space + * 'XX' - Two chars max for link id + * Total required 10 chars at least + */ + char link_id_str[10]; +#endif /* CONFIG_IEEE80211BE */ }; @@ -488,6 +495,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, fd_set rfds; const char *_cmd; char *cmd_buf = NULL; + char *link_cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP @@ -510,6 +518,28 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, _cmd_len = cmd_len; } +#ifdef CONFIG_IEEE80211BE + if (os_strlen(ctrl->link_id_str)) { + char *pos; + + _cmd_len = _cmd_len + 1 + os_strlen(ctrl->link_id_str); + link_cmd_buf = os_malloc(_cmd_len); + if (link_cmd_buf == NULL) { + if (cmd_buf) + os_free(cmd_buf); + return -1; + } + + pos = link_cmd_buf; + os_strlcpy(pos, _cmd, _cmd_len); + pos += os_strlen(_cmd); + *pos++ = ' '; + os_memcpy(pos, ctrl->link_id_str, os_strlen(ctrl->link_id_str)); + _cmd = link_cmd_buf; + wpa_ctrl_reset_mld_link(ctrl); + } +#endif /* CONFIG_IEEE80211BE */ + errno = 0; started_at.sec = 0; started_at.usec = 0; @@ -535,9 +565,11 @@ retry_send: } send_err: os_free(cmd_buf); + os_free(link_cmd_buf); return -1; } os_free(cmd_buf); + os_free(link_cmd_buf); os_get_reltime(&ending_at); ending_at.sec += 10; @@ -773,4 +805,26 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_IEEE80211BE +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl) +{ + os_memset(ctrl->link_id_str, '\0', sizeof(ctrl->link_id_str)); +} + + +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id) +{ + os_snprintf(ctrl->link_id_str, sizeof(ctrl->link_id_str), + "LINKID %d", link_id); +} + + +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl) +{ + return ctrl->link_id_str; +} +#endif /* CONFIG_IEEE80211BE */ + + #endif /* CONFIG_CTRL_IFACE */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 865ac6d91052..d1ce1dd299f4 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -676,6 +676,9 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); #ifdef CONFIG_IEEE80211BE #define WPA_CTRL_IFACE_LINK_NAME "link" +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl); +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id); +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl); #endif /* CONFIG_IEEE80211BE */ #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:45 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:45 +0530 Subject: [PATCH v2 4/6] hostapd_cli: MLO: add status command for MLD socket In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-5-quic_adisi@quicinc.com> Add MLD level 'status' command. Currently each link level socket has got 'status' command. When the same is passed on MLD level socket without any link id, it routes it to first BSS of the MLD if available. Handle this now properly. If link id is not passed then it will be treated as MLD level status command. $ hostapd_cli -i wlan0 .... Interactive mode > status name=wlan0 mld_address=AA:BB:CC:DD:EE:FF num_links=2 LINK INFORMATION link_id=0 link_addr=AA:BB:CC:DD:EE:EE link_id=1 link_addr=AA:BB:CC:DD:FF:FF Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 5fe29147fa38..a584d370edfe 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4700,6 +4700,49 @@ static int hostapd_mld_ctrl_iface_detach(struct hostapd_mld *mld, } +int hostapd_ctrl_mld_iface_status(struct hostapd_mld *mld, char *buf, + size_t buflen) +{ + struct hostapd_data *link_hapd; + int len = 0, ret; + + ret = os_snprintf(buf + len, buflen - len, + "name=%s\n" + "mld_address=" MACSTR "\n" + "num_links=%d\n", + mld->name, MAC2STR(mld->mld_addr), mld->num_links); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + if (!mld->fbss) { + ret = os_snprintf(buf + len, buflen - len, + "\n No Link information present\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, + "LINK INFORMATION\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + dl_list_for_each(link_hapd, &mld->links, struct hostapd_data, link) { + ret = os_snprintf(buf + len, buflen - len, + "link_id=%d\n" + "link_addr=" MACSTR "\n", + link_hapd->mld_link_id, MAC2STR(link_hapd->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + return len; +} + + static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, char *buf, char *reply, int reply_size, @@ -4766,6 +4809,9 @@ static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, } else if (os_strcmp(buf, "DETACH") == 0) { if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) reply_len = -1; + } else if (os_strcmp(buf, "STATUS") == 0 && link_id == -1){ + reply_len = hostapd_ctrl_mld_iface_status(mld, reply, + reply_size); } else { if (link_id == -1) wpa_printf(MSG_DEBUG, "Link ID not provided, using first link BSS (if available)"); -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:47 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:47 +0530 Subject: [PATCH v2 6/6] tests: MLO: add MLD socket connectivity test case In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-7-quic_adisi@quicinc.com> From: Aditya Kumar Singh Add simple test case to bring up a 2 link MLD and get the status of each link via the MLD level socket. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/mld.py | 36 ++++++++++++++++++++++++++++++++++++ tests/hwsim/test_eht.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/hwsim/mld.py diff --git a/tests/hwsim/mld.py b/tests/hwsim/mld.py new file mode 100644 index 000000000000..af6695e601df --- /dev/null +++ b/tests/hwsim/mld.py @@ -0,0 +1,36 @@ +# Python class for controlling Multi Link Device +# Copyright (c) 2024, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import logging +import wpaspy + +logger = logging.getLogger() +hapd_ctrl = '/var/run/hostapd' + +class Multi_Link_Device: + def __init__(self, ifname, ctrl=hapd_ctrl, port=8877): + self.ifname = ifname + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + + def close_ctrl(self): + self.ctrl.close() + self.ctrl = None + + def request(self, cmd): + logger.debug(self.dbg + ": MLD CTRL: " + cmd) + return self.ctrl.request(cmd) + + def ping(self): + return "PONG" in self.request("PING") + +def get_mld_obj(ifname, ctrl=hapd_ctrl, port=8877): + mld = Multi_Link_Device(ifname, ctrl, port) + if not mld.ping(): + raise Exception("Could not ping MLD %s" % ifname) + + return mld diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index e9543936477c..943ee9809c8d 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -17,6 +17,7 @@ from tshark import run_tshark from test_gas import hs20_ap_params from test_dpp import check_dpp_capab, wait_auth_success from test_rrm import build_beacon_request, run_req_beacon, BeaconReport +import mld def eht_verify_wifi_version(dev): status = dev.get_status() @@ -2258,3 +2259,36 @@ def test_eht_mlo_color_change(dev, apdev): hapd0.dump_monitor() hapd1.dump_monitor() + +def test_eht_mld_socket_connectivity(dev, apdev): + """EHT MLD Socket Connectivity""" + with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \ + HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface): + + ssid = "mld_ap" + link0_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "1", + "link_id": "0"} + link1_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "2", + "link_id": "1"} + + hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) + hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) + + mld_dev = mld.get_mld_obj(hapd_iface) + + # Check status of each link + res = str(mld_dev.request("STATUS LINKID 0")) + if "state" not in res: + raise Exception("Failed to get link 0 status via MLD socket") + + logger.info("LINK 0 STATUS: \n" + res) + + res = mld_dev.request("STATUS LINKID 1") + if "state" not in res: + raise Exception("Failed to get link 1 status via MLD socket") + + logger.info("LINK 1 STATUS: \n" + res) -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:34:46 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:04:46 +0530 Subject: [PATCH v2 5/6] tests: MLO: use link ID to access control sockets In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: <20240801163447.3202440-6-quic_adisi@quicinc.com> With MLO, each BSS will create sockets under the given ctrl_iface directory with the socket name being '_link'. Make necessary changes in MLO related test cases so that it can access the new socket and proceed further as expected. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/hostapd.py | 27 +++++++--- tests/hwsim/test_eht.py | 92 +++++++++++++++++++++++++++----- tests/hwsim/test_rsn_override.py | 2 + 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index ebb2e328af50..4fa19294a99e 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -147,14 +147,20 @@ class HostapdGlobal: class Hostapd: def __init__(self, ifname, bssidx=0, hostname=None, ctrl=hapd_ctrl, - port=8877): + port=8877, link=None): self.hostname = hostname self.host = remotehost.Host(hostname, ifname) self.ifname = ifname if hostname is None: - self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.dbg = ifname + if link is None: + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + else: + ifname = ifname + "_link" + link + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname else: self.ctrl = wpaspy.Ctrl(hostname, port) self.mon = wpaspy.Ctrl(hostname, port) @@ -740,6 +746,13 @@ def add_mld_link(apdev, params): hostname = None port = 8878 + if "link_id" not in params: + raise Exception("Link ID not passed in param") + + link_id = params["link_id"] + # Delete the 'link_id' key from params or else it will be added in config + del params["link_id"] + hapd_global = HostapdGlobal(apdev) confname, ctrl_iface = cfg_mld_link_file(ifname, params) hapd_global.send_file(confname, confname) @@ -749,7 +762,8 @@ def add_mld_link(apdev, params): if str(e) == "Could not add hostapd link": raise utils.HwsimSkip("No MLO support in hostapd") port = hapd_global.get_ctrl_iface_port(ifname) - hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) + hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port, + link=link_id) if not hapd.ping(): raise Exception("Could not ping hostapd") return hapd @@ -1023,9 +1037,6 @@ def cfg_mld_link_file(ifname, params): fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') f = os.fdopen(fd, 'w') - if idx != 0: - ctrl_iface="/var/run/hostapd_%d" % idx - f.write("ctrl_interface=%s\n" % ctrl_iface) f.write("driver=nl80211\n") f.write("ieee80211n=1\n") diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index 00d6adff7190..e9543936477c 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -302,10 +302,12 @@ def test_eht_mld_discovery(dev, apdev): ssid = "mld_ap" link0_params = {"ssid": ssid, "hw_mode": "g", - "channel": "1"} + "channel": "1", + "link_id": "0"} link1_params = {"ssid": ssid, "hw_mode": "g", - "channel": "2"} + "channel": "2", + "link_id": "1"} hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) @@ -387,12 +389,14 @@ def _eht_mld_owe_two_links(dev, apdev, second_link_disabled=False, ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' if second_link_disabled: params['mld_indicate_disabled'] = '1' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) # Check legacy client connection @@ -445,6 +449,7 @@ def test_eht_mld_sae_single_link(dev, apdev): ssid = "mld_ap_sae_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='2') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -470,10 +475,12 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1", params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1', beacon_prot=beacon_prot) + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -560,6 +567,7 @@ def test_eht_mld_sae_ext_one_link(dev, apdev): passphrase = 'qwertyuiop' ssid = "mld_ap_sae_ext_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -583,10 +591,12 @@ def test_eht_mld_sae_ext_two_links(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -606,10 +616,12 @@ def test_eht_mld_sae_legacy_client(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -646,10 +658,12 @@ def test_eht_mld_sae_transition(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -682,10 +696,12 @@ def test_eht_mld_ptk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_ptk_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -722,10 +738,12 @@ def test_eht_mld_gtk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_group_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -762,10 +780,12 @@ def test_eht_ml_probe_req(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -804,10 +824,14 @@ def test_eht_mld_connect_probes(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -849,10 +873,14 @@ def test_eht_tx_link_rejected_connect_other(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -879,10 +907,14 @@ def test_eht_all_links_rejected(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("mld_connect_bssid_pref", "00:11:22:33:44:01") wpas.set("sae_pwe", "1") @@ -922,10 +954,13 @@ def test_eht_connect_invalid_link(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, link_params) # We scan for both APs, then try to connect to link 0, but only the @@ -957,9 +992,12 @@ def test_eht_mld_link_removal(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1009,10 +1047,12 @@ def test_eht_mld_bss_trans_mgmt_link_removal_imminent(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1061,10 +1101,12 @@ def test_eht_ap_mld_proto(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1449,10 +1491,14 @@ def test_eht_mld_gas(dev, apdev): params['venue_group'] = "7" params['venue_type'] = "1" params['venue_name'] = "eng:Example venue" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) bssid0 = hapd0.own_addr() params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) bssid1 = hapd1.own_addr() @@ -1485,9 +1531,13 @@ def test_eht_mld_dpp_responder_while_assoc(dev, apdev): ssid = "owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1513,9 +1563,13 @@ def _eht_mld_disconnect(dev, apdev, disassoc=True): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1570,6 +1624,7 @@ def test_eht_mld_non_pref_chan(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1658,6 +1713,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): params["bss_transition"] = "1" params["mbo"] = "1" params["rrm_beacon_report"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1673,6 +1729,8 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): other_ssid = "other" params = eht_mld_ap_wpa2_params(other_ssid, key_mgmt="OWE", mfp="2") params["channel"] = '6' + params['link_id'] = '0' + hapd1 = eht_mld_enable_ap(hapd1_iface, params) # Issue a beacon request for the second AP @@ -1712,6 +1770,8 @@ def test_eht_mld_legacy_stas(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) for i in range(3): @@ -1751,6 +1811,8 @@ def test_eht_mld_and_mlds(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1816,9 +1878,13 @@ def test_eht_mlo_csa(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1903,7 +1969,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, params['sae_pwe'] = "2" params['group_mgmt_cipher'] = "AES-128-CMAC" params['beacon_prot'] = "1" - params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel) + params["ctrl_interface"] = "/var/run/hostapd/" params["bssid"] = bssid_regex % (i + 1) if rnr: @@ -1911,7 +1977,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, append_bss_conf_to_file(f, ifname, params, first=(i == 0)) - hapds.append([ifname, params["ctrl_interface"], i]) + hapds.append([ifname, i]) f.close() @@ -1956,15 +2022,15 @@ def get_mld_devs(hapd_iface, count, prefix, rnr=False): start_ap(prefix, fname1 + " " + fname2) - hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], - bssidx=hapds1[0][2]) - hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1], - bssidx=hapds2[0][2]) + hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], bssidx=hapds1[0][1], + link="0") + hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], bssidx=hapds2[0][1], + link="1") - hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1], - bssidx=hapds1[1][2]) - hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1], - bssidx=hapds2[1][2]) + hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], bssidx=hapds1[1][1], + link="0") + hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], bssidx=hapds2[1][1], + link="1") if not hapd_mld1_link0.ping(): raise Exception("Could not ping hostapd") @@ -2143,11 +2209,13 @@ def test_eht_mlo_color_change(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') params['he_bss_color'] = '42' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' params['he_bss_color'] = '24' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) diff --git a/tests/hwsim/test_rsn_override.py b/tests/hwsim/test_rsn_override.py index 6733102e7ba4..9ffcad1032d4 100644 --- a/tests/hwsim/test_rsn_override.py +++ b/tests/hwsim/test_rsn_override.py @@ -141,6 +141,7 @@ def run_rsn_override_mld(dev, apdev, mixed): params['sae_groups'] = '19 20' params['sae_require_mfp'] = '1' params['sae_pwe'] = '2' + params['link_id'] = '0' if not mixed: params['rsn_override_key_mgmt'] = 'SAE' params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY' @@ -166,6 +167,7 @@ def run_rsn_override_mld(dev, apdev, mixed): hapd0 = eht_mld_enable_ap(hapd_iface, params) params1['channel'] = '6' + params1['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params1) wpas.set("sae_pwe", "1") -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:11 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:11 +0530 Subject: [PATCH v2 0/6] MLO control socket changes In-Reply-To: <20240801163447.3202440-1-quic_adisi@quicinc.com> References: <20240801163447.3202440-1-quic_adisi@quicinc.com> Message-ID: On 8/1/24 22:04, Aditya Kumar Singh wrote: > From: Aditya Kumar Singh > > Control socket for each link BSS of MLD currently needs to be in a separate > directory since interface name is same for all links in an AP MLD. Hence > once the first link comes up, rest of links will not come up if using the > same control interface directory. > > Hence, introduce link level sockets. Each link will use socket with name > "_link" under given control interface directory. > > Also, introduce a MLD level socket with name "" in the same > directory. This will help to route the commands to underlying links if > required as well as it will keep backwards compatibility with other > applications trying to find "" file in the control interface > directory. > > Aditya Kumar Singh (5): > ctrl_iface: MLO: introduce MLD level socket > hostapd_cli: MLO: pass 'LINKID' in the command > hostapd_cli: MLO: add status command for MLD socket > tests: MLO: use link ID to access control sockets > tests: MLO: add MLD socket connectivity test case > > Karthikeyan Kathirvel (1): > ctrl_iface: create link based hapd control sockets > --- > v2: * Rebased on ToT. No conflicts in [1-4]. > * Fixed newly added EHT MLO and RSN Override sim test cases. [5/6] > --- Kindly ignore this series. v3 is posted now. -- Aditya From quic_adisi at quicinc.com Thu Aug 1 09:51:37 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:37 +0530 Subject: [PATCH v3 0/6] MLO control socket changes Message-ID: <20240801165143.3212598-1-quic_adisi@quicinc.com> Control socket for each link BSS of MLD currently needs to be in a separate directory since interface name is same for all links in an AP MLD. Hence once the first link comes up, rest of links will not come up if using the same control interface directory. Hence, introduce link level sockets. Each link will use socket with name "_link" under given control interface directory. Also, introduce a MLD level socket with name "" in the same directory. This will help to route the commands to underlying links if required as well as it will keep backwards compatibility with other applications trying to find "" file in the control interface directory. Aditya Kumar Singh (5): ctrl_iface: MLO: introduce MLD level socket hostapd_cli: MLO: pass 'LINKID' in the command hostapd_cli: MLO: add status command for MLD socket tests: MLO: use link ID to access control sockets tests: MLO: add MLD socket connectivity test case Karthikeyan Kathirvel (1): ctrl_iface: create link based hapd control sockets --- v3: * Email correction in [0] and [6]. v2: * Rebased on ToT. No conflicts in [1-4]. * Fixed newly added EHT MLO and RSN Override sim test cases. [5/6] --- hostapd/ctrl_iface.c | 397 ++++++++++++++++++++++++++++++- hostapd/ctrl_iface.h | 4 + hostapd/hostapd_cli.c | 69 +++++- hostapd/main.c | 5 + src/ap/hostapd.c | 39 +++ src/ap/hostapd.h | 7 + src/common/wpa_ctrl.c | 54 +++++ src/common/wpa_ctrl.h | 7 + tests/hwsim/hostapd.py | 27 ++- tests/hwsim/mld.py | 36 +++ tests/hwsim/test_eht.py | 126 +++++++++- tests/hwsim/test_rsn_override.py | 2 + 12 files changed, 749 insertions(+), 24 deletions(-) create mode 100644 tests/hwsim/mld.py base-commit: 69d18ab9f256360e3a444f45e53840fcf3aa8f19 -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:38 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:38 +0530 Subject: [PATCH v3 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-2-quic_adisi@quicinc.com> From: Karthikeyan Kathirvel Create link based control sockets to access the link based commands through hostapd_cli. This will create the link interfaces in the name of wlan_link Example: To fetch link 0 status from wlan0, below command can be used - $ hostapd_cli -i wlan0 -l 0 status On failure of link/interface selection, below error will be observed $ hostapd_cli -i wlan0 -l 2 status Failed to connect to hostapd - wpa_ctrl_open: No such file or directory Signed-off-by: Karthikeyan Kathirvel Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 16 ++++++++++++++-- hostapd/hostapd_cli.c | 30 ++++++++++++++++++++++++++++-- src/ap/hostapd.c | 28 ++++++++++++++++++++++++++++ src/ap/hostapd.h | 1 + src/common/wpa_ctrl.h | 4 ++++ 5 files changed, 75 insertions(+), 4 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 39b9ef59dc57..3fa33be7a894 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4687,18 +4687,26 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { char *buf; size_t len; + char *ctrl_sock_iface; + +#ifdef CONFIG_IEEE80211BE + ctrl_sock_iface = hapd->ctrl_sock_iface; +#else + ctrl_sock_iface = hapd->conf->iface; +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->ctrl_interface == NULL) return NULL; len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; + os_strlen(ctrl_sock_iface) + 2; + buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); + hapd->conf->ctrl_interface, ctrl_sock_iface); buf[len - 1] = '\0'; return buf; } @@ -4869,7 +4877,11 @@ fail: #endif /* ANDROID */ if (os_strlen(hapd->conf->ctrl_interface) + 1 + +#ifdef CONFIG_IEEE80211BE + os_strlen(hapd->ctrl_sock_iface) >= sizeof(addr.sun_path)) +#else os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) +#endif /* CONFIG_IEEE80211BE */ goto fail; s = socket(PF_UNIX, SOCK_DGRAM, 0); diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index eb8a38350bd1..f05a734fea90 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -54,7 +54,11 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" +#ifdef CONFIG_IEEE80211BE + "usage: hostapd_cli [-p] [-i] [-l] [-hvBr] " +#else "usage: hostapd_cli [-p] [-i] [-hvBr] " +#endif /* CONFIG_IEEE80211BE */ "[-a] \\\n" " [-P] [-G] [command..]\n" "\n" @@ -74,7 +78,12 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n"); + " socket path)\n" +#ifdef CONFIG_IEEE80211BE + " -l Link ID of the interface in case of Multi-Link\n" + " Operation\n" +#endif /* CONFIG_IEEE80211BE */ + "\n"); print_help(stderr, NULL); } @@ -2205,19 +2214,26 @@ static void hostapd_cli_action(struct wpa_ctrl *ctrl) eloop_unregister_read_sock(fd); } - int main(int argc, char *argv[]) { int warning_displayed = 0; int c; int daemonize = 0; int reconnect = 0; +#ifdef CONFIG_IEEE80211BE + int link_id = -1; + char buf[300]; +#endif /* CONFIG_IEEE80211BE */ if (os_program_init()) return -1; for (;;) { +#ifdef CONFIG_IEEE80211BE + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); +#else c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); +#endif /* CONFIG_IEEE80211BE */ if (c < 0) break; switch (c) { @@ -2252,6 +2268,16 @@ int main(int argc, char *argv[]) case 's': client_socket_dir = optarg; break; +#ifdef CONFIG_IEEE80211BE + case 'l': + link_id = atoi(optarg); + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, link_id); + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); + break; +#endif /* CONFIG_IEEE80211BE */ default: usage(); return -1; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a0ac3a857823..49c9d0ddefd7 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1810,12 +1810,37 @@ int hostapd_set_acl(struct hostapd_data *hapd) } +static void hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + + if (hapd->conf->mld_ap) { + char buf[128]; + + os_memset(buf, '\0', sizeof(buf)); + os_snprintf(buf, sizeof(buf), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + os_memset(hapd->ctrl_sock_iface, '\0', + sizeof(hapd->ctrl_sock_iface)); + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); + } +#endif /* CONFIG_IEEE80211BE */ +} + + static int start_ctrl_iface_bss(struct hostapd_data *hapd) { if (!hapd->iface->interfaces || !hapd->iface->interfaces->ctrl_iface_init) return 0; + hostapd_set_ctrl_sock_iface(hapd); + if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", @@ -1836,6 +1861,9 @@ static int start_ctrl_iface(struct hostapd_iface *iface) for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; + + hostapd_set_ctrl_sock_iface(hapd); + if (iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dcf395ca5ee8..34a665562d35 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -476,6 +476,7 @@ struct hostapd_data { struct hostapd_mld *mld; struct dl_list link; u8 mld_link_id; + char ctrl_sock_iface[IFNAMSIZ + 1]; #ifdef CONFIG_TESTING_OPTIONS u8 eht_mld_link_removal_count; #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f6142501e440..865ac6d91052 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -674,4 +674,8 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); } #endif +#ifdef CONFIG_IEEE80211BE +#define WPA_CTRL_IFACE_LINK_NAME "link" +#endif /* CONFIG_IEEE80211BE */ + #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:39 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:39 +0530 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-3-quic_adisi@quicinc.com> With MLO, each link have socket created with "_link" under the control interface directory. Introduce a MLD level socket - "" as well under the same control interface directory. This socket can be used to pass the command to its partner links directly instead of using the link level socket. Link ID needs to be passed with the command. The structure of the command is - " LINKID " Directory looks something like this - $ ls /var/run/hostapd/ wlan0 wlan0_link0 wlan0_link1 wlan0 here is the MLD level socket. Rest are each link level. This would also help to maintain backwards compatibility with applications which looks for under the control interface directory.` Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 335 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.h | 4 + hostapd/main.c | 5 + src/ap/hostapd.c | 11 ++ src/ap/hostapd.h | 6 + 5 files changed, 361 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 3fa33be7a894..5fe29147fa38 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4682,6 +4682,341 @@ done: } +#ifdef CONFIG_IEEE80211BE +#ifndef CONFIG_CTRL_IFACE_UDP +static int hostapd_mld_ctrl_iface_attach(struct hostapd_mld *mld, + struct sockaddr_storage *from, + socklen_t fromlen, const char *input) +{ + return ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, input); +} + + +static int hostapd_mld_ctrl_iface_detach(struct hostapd_mld *mld, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + return ctrl_iface_detach(&mld->ctrl_dst, from, fromlen); +} + + +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, + char *buf, char *reply, + int reply_size, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct hostapd_data *link_hapd, *link_itr; + int reply_len, link_id = -1; + char *link_cmd; + bool found = false; + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + /* Check if link id is provided in the command or not */ + link_cmd = os_strstr(buf, "LINKID"); + if (link_cmd) { + /* Trim the link id part now */ + *(link_cmd - 1) = '\0'; + + link_cmd += 7; + link_id = atoi(link_cmd); + + if (link_id < 0 || link_id >= 15) { + os_memcpy(reply, "INVALID LINK ID\n", 16); + reply_len = 16; + return reply_len; + } + + link_hapd = mld->fbss; + if (!link_hapd) { + os_memcpy(reply, "NO LINKS ACTIVE\n", 16); + reply_len = 16; + return reply_len; + } + + for_each_mld_link(link_itr, link_hapd) { + if (link_itr->mld_link_id == link_id) { + found = true; + break; + } + } + + if (!found) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + return reply_len; + } + + link_hapd = link_itr; + } else { + link_hapd = mld->fbss; + } + + if (os_strcmp(buf, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); + reply_len = 5; + } else if (os_strcmp(buf, "ATTACH") == 0) { + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, NULL)) + reply_len = -1; + } else if (os_strncmp(buf, "ATTACH ", 7) == 0) { + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, buf + 7)) + reply_len = -1; + } else if (os_strcmp(buf, "DETACH") == 0) { + if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) + reply_len = -1; + } else { + if (link_id == -1) + wpa_printf(MSG_DEBUG, "Link ID not provided, using first link BSS (if available)"); + + if (!link_hapd) + reply_len = -1; + else + reply_len = + hostapd_ctrl_iface_receive_process(link_hapd, buf, + reply, reply_size, + from, fromlen); + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + return reply_len; +} + + +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct hostapd_mld *mld = eloop_ctx; + char buf[4096]; + int res; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + char *reply, *pos = buf; + const int reply_size = 4096; + int reply_len; + int level = MSG_DEBUG; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s", + strerror(errno)); + return; + } + buf[res] = '\0'; + + reply = os_malloc(reply_size); + if (reply == NULL) { + if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + return; + } + + if (os_strcmp(pos, "PING") == 0) + level = MSG_EXCESSIVE; + + wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res); + + reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos, + reply, reply_size, + &from, fromlen); + + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + os_free(reply); +} + + +static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld) +{ + char *buf; + size_t len; + + if (!mld->ctrl_interface) + return NULL; + + len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2; + + buf = os_malloc(len); + if (buf == NULL) + return NULL; + + os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); + buf[len - 1] = '\0'; + return buf; +} +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct sockaddr_un addr; + int s = -1; + char *fname = NULL; + + if (!mld) + return -1; + + if (mld->ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!", + mld->name); + return 0; + } + + dl_list_init(&mld->ctrl_dst); + + if (mld->ctrl_interface == NULL) + return 0; + + if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); + goto fail; + } + } + + if (os_strlen(mld->ctrl_interface) + 1 + + os_strlen(mld->name) >= sizeof(addr.sun_path)) + goto fail; + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ + addr.sun_family = AF_UNIX; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname == NULL) + goto fail; + + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + + wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name); + + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); + goto fail; + } + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < + 0) { + wpa_printf(MSG_ERROR, + "hostapd-ctrl-iface: bind(PF_UNIX): %s", + strerror(errno)); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); + goto fail; + } + os_free(fname); + + mld->ctrl_sock = s; + + if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld, + NULL) < 0) + return -1; + + return 0; + +fail: + if (s >= 0) + close(s); + if (fname) { + unlink(fname); + os_free(fname); + } + return -1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + return 0; +} + + +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct wpa_ctrl_dst *dst, *prev; + + if (mld->ctrl_sock > -1) { + char *fname; + eloop_unregister_read_sock(mld->ctrl_sock); + close(mld->ctrl_sock); + mld->ctrl_sock = -1; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname) + unlink(fname); + os_free(fname); + + if (mld->ctrl_interface && + rmdir(mld->ctrl_interface) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "MLD Control interface " + "directory not empty - leaving it " + "behind"); + } else { + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + mld->ctrl_interface, + strerror(errno)); + } + } + } + + dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst, + list) + os_free(dst); +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + os_free(mld->ctrl_interface); +} +#endif /* CONFIG_IEEE80211BE */ + + #ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h index 3341a66bdc6c..ec5a95be785c 100644 --- a/hostapd/ctrl_iface.h +++ b/hostapd/ctrl_iface.h @@ -14,6 +14,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd); void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); +#ifdef CONFIG_IEEE80211BE +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld); +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld); +#endif /* CONFIG_IEEE80211BE */ #else /* CONFIG_NO_CTRL_IFACE */ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { diff --git a/hostapd/main.c b/hostapd/main.c index 00e02bb034c9..aa1f69812fd8 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -748,6 +748,7 @@ static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) if (!interfaces->mld[i]) continue; + interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]); os_free(interfaces->mld[i]); interfaces->mld[i] = NULL; } @@ -793,6 +794,10 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; +#ifdef CONFIG_IEEE80211BE + interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init; + interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit; +#endif /* CONFIG_IEEE80211BE */ dl_list_init(&interfaces.global_ctrl_dst); #ifdef CONFIG_ETH_P_OUI dl_list_init(&interfaces.eth_p_oui); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 49c9d0ddefd7..2794bb14efdf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3095,9 +3095,18 @@ static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); dl_list_init(&mld->links); + mld->ctrl_sock = -1; + mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface); wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + /* + * Initialize MLD control interfaces early to allow external monitoring of + * link setup operations. + */ + if (interfaces->mld_ctrl_iface_init(mld)) + goto fail; + hapd->mld = mld; hostapd_mld_ref_inc(mld); hostapd_bss_alloc_link_id(hapd); @@ -3157,6 +3166,8 @@ static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) if (!remove && !forced_remove) continue; + interfaces->mld_ctrl_iface_deinit(mld); + wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name, forced_remove ? " (forced)" : ""); os_free(mld); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 34a665562d35..2ef63e5f2383 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -97,6 +97,8 @@ struct hapd_interfaces { #ifdef CONFIG_IEEE80211BE struct hostapd_mld **mld; size_t mld_count; + int (*mld_ctrl_iface_init)(struct hostapd_mld *mld); + void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld); #endif /* CONFIG_IEEE80211BE */ }; @@ -519,6 +521,10 @@ struct hostapd_mld { struct hostapd_data *fbss; struct dl_list links; /* List head of all affiliated links */ + + int ctrl_sock; + struct dl_list ctrl_dst; + char *ctrl_interface; /* directory for UNIX domain sockets */ }; #define HOSTAPD_MLD_MAX_REF_COUNT 0xFF -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:40 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:40 +0530 Subject: [PATCH v3 3/6] hostapd_cli: MLO: pass 'LINKID' in the command In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-4-quic_adisi@quicinc.com> MLD level socket can take 'LINKID '. Add changes to pass this via hostapd_cli. User needs to give "link_id=" in post fix fashion in the command in order to pass this link_id from cli. For example - $ hostapd_cli -i wlan0 status link_id=0 | grep freq= freq=2437 $ hostapd_cli -i wlan0 ... Interactive mode > ping PONG > > status link_id=0 Command for 'LINKID 0' state=ENABLED phy=phy0 freq=2437 Signed-off-by: Aditya Kumar Singh --- hostapd/hostapd_cli.c | 39 +++++++++++++++++++++++++++++++ src/common/wpa_ctrl.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/common/wpa_ctrl.h | 3 +++ 3 files changed, 96 insertions(+) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index f05a734fea90..d695255027ba 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1962,6 +1962,45 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); } else { +#ifdef CONFIG_IEEE80211BE + char *pos, *end; + int i, j, link_id; + bool link_found = false; + + wpa_ctrl_reset_mld_link(ctrl); + i = 0; + + while (i < argc) { + pos = os_strstr(argv[i], "link_id="); + if (!pos) { + i++; + continue; + } + + pos = pos + 8; + link_id = strtol(pos, &end, 10); + + if (link_id < 0 || link_id >= 15) { + printf("Invalid link ID '%d'\n", link_id); + return; + } + + link_found = true; + + /* remove this link_id= from the arguements */ + for (j = i + 1; j < argc; j++) + argv[j - 1] = argv[j]; + + argc--; + i = 0; + } + + if (link_found) { + wpa_ctrl_set_mld_link(ctrl, link_id); + printf("Command for '%s'\n", + wpa_ctrl_get_mld_link(ctrl)); + } +#endif /* CONFIG_IEEE80211BE */ match->handler(ctrl, argc - 1, &argv[1]); } } diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 7e197f094fd1..d0c174c05d48 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -72,6 +72,13 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +#ifdef CONFIG_IEEE80211BE + /* 'LINKID ' - 7 chars including space + * 'XX' - Two chars max for link id + * Total required 10 chars at least + */ + char link_id_str[10]; +#endif /* CONFIG_IEEE80211BE */ }; @@ -488,6 +495,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, fd_set rfds; const char *_cmd; char *cmd_buf = NULL; + char *link_cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP @@ -510,6 +518,28 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, _cmd_len = cmd_len; } +#ifdef CONFIG_IEEE80211BE + if (os_strlen(ctrl->link_id_str)) { + char *pos; + + _cmd_len = _cmd_len + 1 + os_strlen(ctrl->link_id_str); + link_cmd_buf = os_malloc(_cmd_len); + if (link_cmd_buf == NULL) { + if (cmd_buf) + os_free(cmd_buf); + return -1; + } + + pos = link_cmd_buf; + os_strlcpy(pos, _cmd, _cmd_len); + pos += os_strlen(_cmd); + *pos++ = ' '; + os_memcpy(pos, ctrl->link_id_str, os_strlen(ctrl->link_id_str)); + _cmd = link_cmd_buf; + wpa_ctrl_reset_mld_link(ctrl); + } +#endif /* CONFIG_IEEE80211BE */ + errno = 0; started_at.sec = 0; started_at.usec = 0; @@ -535,9 +565,11 @@ retry_send: } send_err: os_free(cmd_buf); + os_free(link_cmd_buf); return -1; } os_free(cmd_buf); + os_free(link_cmd_buf); os_get_reltime(&ending_at); ending_at.sec += 10; @@ -773,4 +805,26 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_IEEE80211BE +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl) +{ + os_memset(ctrl->link_id_str, '\0', sizeof(ctrl->link_id_str)); +} + + +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id) +{ + os_snprintf(ctrl->link_id_str, sizeof(ctrl->link_id_str), + "LINKID %d", link_id); +} + + +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl) +{ + return ctrl->link_id_str; +} +#endif /* CONFIG_IEEE80211BE */ + + #endif /* CONFIG_CTRL_IFACE */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 865ac6d91052..d1ce1dd299f4 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -676,6 +676,9 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); #ifdef CONFIG_IEEE80211BE #define WPA_CTRL_IFACE_LINK_NAME "link" +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl); +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id); +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl); #endif /* CONFIG_IEEE80211BE */ #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:41 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:41 +0530 Subject: [PATCH v3 4/6] hostapd_cli: MLO: add status command for MLD socket In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-5-quic_adisi@quicinc.com> Add MLD level 'status' command. Currently each link level socket has got 'status' command. When the same is passed on MLD level socket without any link id, it routes it to first BSS of the MLD if available. Handle this now properly. If link id is not passed then it will be treated as MLD level status command. $ hostapd_cli -i wlan0 .... Interactive mode > status name=wlan0 mld_address=AA:BB:CC:DD:EE:FF num_links=2 LINK INFORMATION link_id=0 link_addr=AA:BB:CC:DD:EE:EE link_id=1 link_addr=AA:BB:CC:DD:FF:FF Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 5fe29147fa38..a584d370edfe 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4700,6 +4700,49 @@ static int hostapd_mld_ctrl_iface_detach(struct hostapd_mld *mld, } +int hostapd_ctrl_mld_iface_status(struct hostapd_mld *mld, char *buf, + size_t buflen) +{ + struct hostapd_data *link_hapd; + int len = 0, ret; + + ret = os_snprintf(buf + len, buflen - len, + "name=%s\n" + "mld_address=" MACSTR "\n" + "num_links=%d\n", + mld->name, MAC2STR(mld->mld_addr), mld->num_links); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + if (!mld->fbss) { + ret = os_snprintf(buf + len, buflen - len, + "\n No Link information present\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, + "LINK INFORMATION\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + dl_list_for_each(link_hapd, &mld->links, struct hostapd_data, link) { + ret = os_snprintf(buf + len, buflen - len, + "link_id=%d\n" + "link_addr=" MACSTR "\n", + link_hapd->mld_link_id, MAC2STR(link_hapd->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + return len; +} + + static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, char *buf, char *reply, int reply_size, @@ -4766,6 +4809,9 @@ static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, } else if (os_strcmp(buf, "DETACH") == 0) { if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) reply_len = -1; + } else if (os_strcmp(buf, "STATUS") == 0 && link_id == -1){ + reply_len = hostapd_ctrl_mld_iface_status(mld, reply, + reply_size); } else { if (link_id == -1) wpa_printf(MSG_DEBUG, "Link ID not provided, using first link BSS (if available)"); -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:42 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:42 +0530 Subject: [PATCH v3 5/6] tests: MLO: use link ID to access control sockets In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-6-quic_adisi@quicinc.com> With MLO, each BSS will create sockets under the given ctrl_iface directory with the socket name being '_link'. Make necessary changes in MLO related test cases so that it can access the new socket and proceed further as expected. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/hostapd.py | 27 +++++++--- tests/hwsim/test_eht.py | 92 +++++++++++++++++++++++++++----- tests/hwsim/test_rsn_override.py | 2 + 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index ebb2e328af50..4fa19294a99e 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -147,14 +147,20 @@ class HostapdGlobal: class Hostapd: def __init__(self, ifname, bssidx=0, hostname=None, ctrl=hapd_ctrl, - port=8877): + port=8877, link=None): self.hostname = hostname self.host = remotehost.Host(hostname, ifname) self.ifname = ifname if hostname is None: - self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.dbg = ifname + if link is None: + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + else: + ifname = ifname + "_link" + link + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname else: self.ctrl = wpaspy.Ctrl(hostname, port) self.mon = wpaspy.Ctrl(hostname, port) @@ -740,6 +746,13 @@ def add_mld_link(apdev, params): hostname = None port = 8878 + if "link_id" not in params: + raise Exception("Link ID not passed in param") + + link_id = params["link_id"] + # Delete the 'link_id' key from params or else it will be added in config + del params["link_id"] + hapd_global = HostapdGlobal(apdev) confname, ctrl_iface = cfg_mld_link_file(ifname, params) hapd_global.send_file(confname, confname) @@ -749,7 +762,8 @@ def add_mld_link(apdev, params): if str(e) == "Could not add hostapd link": raise utils.HwsimSkip("No MLO support in hostapd") port = hapd_global.get_ctrl_iface_port(ifname) - hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) + hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port, + link=link_id) if not hapd.ping(): raise Exception("Could not ping hostapd") return hapd @@ -1023,9 +1037,6 @@ def cfg_mld_link_file(ifname, params): fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') f = os.fdopen(fd, 'w') - if idx != 0: - ctrl_iface="/var/run/hostapd_%d" % idx - f.write("ctrl_interface=%s\n" % ctrl_iface) f.write("driver=nl80211\n") f.write("ieee80211n=1\n") diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index 00d6adff7190..e9543936477c 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -302,10 +302,12 @@ def test_eht_mld_discovery(dev, apdev): ssid = "mld_ap" link0_params = {"ssid": ssid, "hw_mode": "g", - "channel": "1"} + "channel": "1", + "link_id": "0"} link1_params = {"ssid": ssid, "hw_mode": "g", - "channel": "2"} + "channel": "2", + "link_id": "1"} hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) @@ -387,12 +389,14 @@ def _eht_mld_owe_two_links(dev, apdev, second_link_disabled=False, ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' if second_link_disabled: params['mld_indicate_disabled'] = '1' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) # Check legacy client connection @@ -445,6 +449,7 @@ def test_eht_mld_sae_single_link(dev, apdev): ssid = "mld_ap_sae_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='2') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -470,10 +475,12 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1", params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1', beacon_prot=beacon_prot) + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -560,6 +567,7 @@ def test_eht_mld_sae_ext_one_link(dev, apdev): passphrase = 'qwertyuiop' ssid = "mld_ap_sae_ext_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -583,10 +591,12 @@ def test_eht_mld_sae_ext_two_links(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -606,10 +616,12 @@ def test_eht_mld_sae_legacy_client(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -646,10 +658,12 @@ def test_eht_mld_sae_transition(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -682,10 +696,12 @@ def test_eht_mld_ptk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_ptk_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -722,10 +738,12 @@ def test_eht_mld_gtk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_group_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -762,10 +780,12 @@ def test_eht_ml_probe_req(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -804,10 +824,14 @@ def test_eht_mld_connect_probes(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -849,10 +873,14 @@ def test_eht_tx_link_rejected_connect_other(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -879,10 +907,14 @@ def test_eht_all_links_rejected(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("mld_connect_bssid_pref", "00:11:22:33:44:01") wpas.set("sae_pwe", "1") @@ -922,10 +954,13 @@ def test_eht_connect_invalid_link(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, link_params) # We scan for both APs, then try to connect to link 0, but only the @@ -957,9 +992,12 @@ def test_eht_mld_link_removal(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1009,10 +1047,12 @@ def test_eht_mld_bss_trans_mgmt_link_removal_imminent(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1061,10 +1101,12 @@ def test_eht_ap_mld_proto(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1449,10 +1491,14 @@ def test_eht_mld_gas(dev, apdev): params['venue_group'] = "7" params['venue_type'] = "1" params['venue_name'] = "eng:Example venue" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) bssid0 = hapd0.own_addr() params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) bssid1 = hapd1.own_addr() @@ -1485,9 +1531,13 @@ def test_eht_mld_dpp_responder_while_assoc(dev, apdev): ssid = "owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1513,9 +1563,13 @@ def _eht_mld_disconnect(dev, apdev, disassoc=True): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1570,6 +1624,7 @@ def test_eht_mld_non_pref_chan(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1658,6 +1713,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): params["bss_transition"] = "1" params["mbo"] = "1" params["rrm_beacon_report"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1673,6 +1729,8 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): other_ssid = "other" params = eht_mld_ap_wpa2_params(other_ssid, key_mgmt="OWE", mfp="2") params["channel"] = '6' + params['link_id'] = '0' + hapd1 = eht_mld_enable_ap(hapd1_iface, params) # Issue a beacon request for the second AP @@ -1712,6 +1770,8 @@ def test_eht_mld_legacy_stas(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) for i in range(3): @@ -1751,6 +1811,8 @@ def test_eht_mld_and_mlds(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1816,9 +1878,13 @@ def test_eht_mlo_csa(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1903,7 +1969,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, params['sae_pwe'] = "2" params['group_mgmt_cipher'] = "AES-128-CMAC" params['beacon_prot'] = "1" - params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel) + params["ctrl_interface"] = "/var/run/hostapd/" params["bssid"] = bssid_regex % (i + 1) if rnr: @@ -1911,7 +1977,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, append_bss_conf_to_file(f, ifname, params, first=(i == 0)) - hapds.append([ifname, params["ctrl_interface"], i]) + hapds.append([ifname, i]) f.close() @@ -1956,15 +2022,15 @@ def get_mld_devs(hapd_iface, count, prefix, rnr=False): start_ap(prefix, fname1 + " " + fname2) - hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], - bssidx=hapds1[0][2]) - hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1], - bssidx=hapds2[0][2]) + hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], bssidx=hapds1[0][1], + link="0") + hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], bssidx=hapds2[0][1], + link="1") - hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1], - bssidx=hapds1[1][2]) - hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1], - bssidx=hapds2[1][2]) + hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], bssidx=hapds1[1][1], + link="0") + hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], bssidx=hapds2[1][1], + link="1") if not hapd_mld1_link0.ping(): raise Exception("Could not ping hostapd") @@ -2143,11 +2209,13 @@ def test_eht_mlo_color_change(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') params['he_bss_color'] = '42' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' params['he_bss_color'] = '24' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) diff --git a/tests/hwsim/test_rsn_override.py b/tests/hwsim/test_rsn_override.py index 6733102e7ba4..9ffcad1032d4 100644 --- a/tests/hwsim/test_rsn_override.py +++ b/tests/hwsim/test_rsn_override.py @@ -141,6 +141,7 @@ def run_rsn_override_mld(dev, apdev, mixed): params['sae_groups'] = '19 20' params['sae_require_mfp'] = '1' params['sae_pwe'] = '2' + params['link_id'] = '0' if not mixed: params['rsn_override_key_mgmt'] = 'SAE' params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY' @@ -166,6 +167,7 @@ def run_rsn_override_mld(dev, apdev, mixed): hapd0 = eht_mld_enable_ap(hapd_iface, params) params1['channel'] = '6' + params1['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params1) wpas.set("sae_pwe", "1") -- 2.34.1 From quic_adisi at quicinc.com Thu Aug 1 09:51:43 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Thu, 1 Aug 2024 22:21:43 +0530 Subject: [PATCH v3 6/6] tests: MLO: add MLD socket connectivity test case In-Reply-To: <20240801165143.3212598-1-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> Message-ID: <20240801165143.3212598-7-quic_adisi@quicinc.com> Add simple test case to bring up a 2 link MLD and get the status of each link via the MLD level socket. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/mld.py | 36 ++++++++++++++++++++++++++++++++++++ tests/hwsim/test_eht.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/hwsim/mld.py diff --git a/tests/hwsim/mld.py b/tests/hwsim/mld.py new file mode 100644 index 000000000000..af6695e601df --- /dev/null +++ b/tests/hwsim/mld.py @@ -0,0 +1,36 @@ +# Python class for controlling Multi Link Device +# Copyright (c) 2024, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import logging +import wpaspy + +logger = logging.getLogger() +hapd_ctrl = '/var/run/hostapd' + +class Multi_Link_Device: + def __init__(self, ifname, ctrl=hapd_ctrl, port=8877): + self.ifname = ifname + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + + def close_ctrl(self): + self.ctrl.close() + self.ctrl = None + + def request(self, cmd): + logger.debug(self.dbg + ": MLD CTRL: " + cmd) + return self.ctrl.request(cmd) + + def ping(self): + return "PONG" in self.request("PING") + +def get_mld_obj(ifname, ctrl=hapd_ctrl, port=8877): + mld = Multi_Link_Device(ifname, ctrl, port) + if not mld.ping(): + raise Exception("Could not ping MLD %s" % ifname) + + return mld diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index e9543936477c..943ee9809c8d 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -17,6 +17,7 @@ from tshark import run_tshark from test_gas import hs20_ap_params from test_dpp import check_dpp_capab, wait_auth_success from test_rrm import build_beacon_request, run_req_beacon, BeaconReport +import mld def eht_verify_wifi_version(dev): status = dev.get_status() @@ -2258,3 +2259,36 @@ def test_eht_mlo_color_change(dev, apdev): hapd0.dump_monitor() hapd1.dump_monitor() + +def test_eht_mld_socket_connectivity(dev, apdev): + """EHT MLD Socket Connectivity""" + with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \ + HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface): + + ssid = "mld_ap" + link0_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "1", + "link_id": "0"} + link1_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "2", + "link_id": "1"} + + hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) + hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) + + mld_dev = mld.get_mld_obj(hapd_iface) + + # Check status of each link + res = str(mld_dev.request("STATUS LINKID 0")) + if "state" not in res: + raise Exception("Failed to get link 0 status via MLD socket") + + logger.info("LINK 0 STATUS: \n" + res) + + res = mld_dev.request("STATUS LINKID 1") + if "state" not in res: + raise Exception("Failed to get link 1 status via MLD socket") + + logger.info("LINK 1 STATUS: \n" + res) -- 2.34.1 From mail at david-bauer.net Thu Aug 1 14:49:03 2024 From: mail at david-bauer.net (David Bauer) Date: Thu, 1 Aug 2024 23:49:03 +0200 Subject: [PATCH v2 3/5] bss: don't add hidden OWE transition-networks to scan-list In-Reply-To: References: <20240428131344.334314-1-mail@david-bauer.net> <20240428131344.334314-4-mail@david-bauer.net> Message-ID: <9e1710c5-fcc0-4aef-930c-370e3ab079c7@david-bauer.net> Hi Jouni, thanks for your review. On 8/1/24 17:13, Jouni Malinen wrote: > On Sun, Apr 28, 2024 at 03:13:42PM +0200, David Bauer wrote: >> When adding these networks hidden, they get re-added for the same BSSID >> when scanning for the transition-SSID. Skip adding the OWE-SSIDs in case >> the SSID was not explicitly scanned for. > > This breaks multiple hwsim test cases for OWE since the expected BSS > entry is not available. While I think I understand what this is trying > to do, it is not really acceptable to break test cases, so I cannot > apply this as-is. At minimum, those test cases would need to be > modified, but I'm not really sure this is actually correct behavior > since BSSs with a hidden SSID have been added to the scan results in all > existing cases for years. Understood. How about replacing hidden scan entries when we discover the SSID name upon trying to connect to the transition network? I hope it is understandable what i mean. Currently the scan-list is flooded with multiple entries for a single BSSID. As all roaming code just takes the first one upon iterating, this effectively breaks roaming at the moment. Best David > >> + /* Don't add hidden OWE transition networks with RSN. They are explicitly scanned for. */ >> + rsn = wpa_scan_get_ie(res, WLAN_EID_RSN); >> + owe = wpa_scan_get_vendor_ie(res, OWE_IE_VENDOR_TYPE); >> + if (owe && rsn && (ssid[1] == 0 || ssid[2] == 0)) >> + return; > > And this should likely be within #ifdef CONFIG_OWE even if that were to > compile successfully without such conditional check. > From j at w1.fi Fri Aug 2 03:26:23 2024 From: j at w1.fi (Jouni Malinen) Date: Fri, 2 Aug 2024 13:26:23 +0300 Subject: [PATCH 13/16] WNM: Consolidate the scanning paths for BTM requests In-Reply-To: <20240429115157.211073-14-benjamin@sipsolutions.net> References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-14-benjamin@sipsolutions.net> Message-ID: On Mon, Apr 29, 2024 at 01:51:54PM +0200, benjamin at sipsolutions.net wrote: > There was an ancient code path to trigger a scan that was apparently > forgotten when the code was extended over time. It does not make any > sense to trigger a scan twice, so remove the earlier scan. > > The earlier scan call was avoiding to trigger a new scan if a fixed > BSSID is configured. This seems like a reasonable restriction to do, so > add this check before starting a scan. > > Consolidate everything so that scanning happens at the end of the > functions unless we bail out before. Add a "reset" label for all other > cases to ensure that we don't leave things in the a bad state. > tests/hwsim/test_ap_hs20.py | 1 + > tests/hwsim/test_hapd_ctrl.py | 1 + > tests/hwsim/test_wnm.py | 2 + > wpa_supplicant/wnm_sta.c | 129 +++++++++++++++++++--------------- Those test case changes do not seem to have anything to do with this commit message, so I'm dropping them from this patch. > diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py > @@ -2813,6 +2813,7 @@ def _test_ap_hs20_session_info(dev, apdev): > interworking_select(dev[0], bssid, freq="2412") > interworking_connect(dev[0], bssid, "TTLS") > + dev[0].flush_scan_cache() .. It feels strange to flush the scan results after connection, so if these are really needed, there needs to be a clear commit message that describe the reasons. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Fri Aug 2 03:30:12 2024 From: j at w1.fi (Jouni Malinen) Date: Fri, 2 Aug 2024 13:30:12 +0300 Subject: [PATCH 08/16] WNM: Move driver MBO transition rejection into wnm_is_bss_excluded In-Reply-To: <20240429115157.211073-9-benjamin@sipsolutions.net> References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-9-benjamin@sipsolutions.net> Message-ID: On Mon, Apr 29, 2024 at 01:51:49PM +0200, benjamin at sipsolutions.net wrote: > Change the logic a bit to not directly use the result of the > wpa_drv_get_bss_trans_status call and instead use the same selection > logic as usual but taking into account the driver rejections. > > This changes the logic in minor ways. The main change is that this > aligns the ordering of BSSs to be identical in all cases. More > precisely, we'll select the best BSS as found by find_better_target. > > Beyond that, it also means that in the case of an non-abridged BTM > request we'll also consider candidates that were found through the scan > and not in the neighbor report. In this case, the driver will not have a > chance to reject them. This feels a bit scary especially if the updated design has not actually been tested with a driver that uses the driver-based mechanism for updating candidate lists (which I'm assuming has not been done here). And there is something strange here: > diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c > #ifdef CONFIG_MBO > -static struct wpa_bss * > -get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, > +static void > +fetch_drv_mbo_candidate_info(struct wpa_supplicant *wpa_s, > enum mbo_transition_reject_reason *reason) > { > + if (nei->preference_present && nei->preference == 0) > continue; > + > + /* FIXME: Should we go through wpa_scan_res_match? */ Well, that is not the strange part, but again, something that makes me unhappy about applying this without full testing. > +#else > +static void > +fetch_drv_mbo_transition_candidate_info(struct wpa_supplicant *wpa_s) > +{ > } > #endif /* CONFIG_MBO */ That is the strange part.. What was that supposed to be? That same function with empty payload? Now the function name is different and so is the list of arguments. This would obviously not work without CONFIG_MBO defined. If this is just to skip the functionality within the function, defining the function once with the actually body within #ifdef CONFIG_MBO would be much cleaner. -- Jouni Malinen PGP id EFC895FA From benjamin at sipsolutions.net Fri Aug 2 03:32:39 2024 From: benjamin at sipsolutions.net (Benjamin Berg) Date: Fri, 2 Aug 2024 10:32:39 +0000 Subject: [PATCH 13/16] WNM: Consolidate the scanning paths for BTM requests In-Reply-To: References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-14-benjamin@sipsolutions.net> Message-ID: Hi, just a quick response. The reason the test change is needed is because the test verifies a scan is being done. However, the code has a fast path to not scan if there are recent results available. Before the change, a scan happened anyway, but that isn't the case anymore making the flush (or sufficiently long sleep) necessary. But I agree, I should have pointed out in the commit message why the test changes are needes (and why one can argue that it is a fix of the test behavior). Benjamin On Friday, 2 August 2024, Jouni Malinen wrote: > On Mon, Apr 29, 2024 at 01:51:54PM +0200, benjamin at sipsolutions.net wrote: > > There was an ancient code path to trigger a scan that was apparently > > forgotten when the code was extended over time. It does not make any > > sense to trigger a scan twice, so remove the earlier scan. > > > > The earlier scan call was avoiding to trigger a new scan if a fixed > > BSSID is configured. This seems like a reasonable restriction to do, so > > add this check before starting a scan. > > > > Consolidate everything so that scanning happens at the end of the > > functions unless we bail out before. Add a "reset" label for all other > > cases to ensure that we don't leave things in the a bad state. > > > tests/hwsim/test_ap_hs20.py | 1 + > > tests/hwsim/test_hapd_ctrl.py | 1 + > > tests/hwsim/test_wnm.py | 2 + > > wpa_supplicant/wnm_sta.c | 129 +++++++++++++++++++--------------- > > Those test case changes do not seem to have anything to do with this > commit message, so I'm dropping them from this patch. > > > diff --git a/tests/hwsim/test_ap_hs20.py b/tests/hwsim/test_ap_hs20.py > > @@ -2813,6 +2813,7 @@ def _test_ap_hs20_session_info(dev, apdev): > > interworking_select(dev[0], bssid, freq="2412") > > interworking_connect(dev[0], bssid, "TTLS") > > + dev[0].flush_scan_cache() > > .. > > It feels strange to flush the scan results after connection, so if these > are really needed, there needs to be a clear commit message that > describe the reasons. > > -- > Jouni Malinen PGP id EFC895FA > > From j at w1.fi Fri Aug 2 03:59:25 2024 From: j at w1.fi (Jouni Malinen) Date: Fri, 2 Aug 2024 13:59:25 +0300 Subject: [PATCH 10/16] WNM: Use standard BSS selection and enable abridged bit handling In-Reply-To: <20240429115157.211073-11-benjamin@sipsolutions.net> References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-11-benjamin@sipsolutions.net> Message-ID: On Mon, Apr 29, 2024 at 01:51:51PM +0200, benjamin at sipsolutions.net wrote: > Most of the logic to reject BSSs during transition has been moved into > wnm_is_bss_excluded. In addition to this, since commit 67bf89f55442 > ("WNM: Choose the best available BSS, not just the first one") we will > simply choose the BSS with the best throughput. > > Overall, this matches the behaviour that the supplicant will use anyway > in wpa_supplicant_select_bss. The only bigger difference is that using > this will check all known BSSs instead of only the ones in the candidate > list. This means that with this change the abridged bit is handled > according to spec. > > Another slight change is that this drops the logic to reject candidates > with a very low signal level. This does not seem to very relevant > anymore as we prefere stronger BSSs to begin with. This does not apply without patch 8/16 which has open questions. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Fri Aug 2 04:06:09 2024 From: j at w1.fi (Jouni Malinen) Date: Fri, 2 Aug 2024 14:06:09 +0300 Subject: [PATCH 00/16] BTM refactorings and abridged bit handling In-Reply-To: <20240429115157.211073-1-benjamin@sipsolutions.net> References: <20240429115157.211073-1-benjamin@sipsolutions.net> Message-ID: On Mon, Apr 29, 2024 at 01:51:41PM +0200, benjamin at sipsolutions.net wrote: > This patchset refactors the BSS selection when handling BTM requests to > use the normal selection mechanism. This is done by moving all checks > into wnm_is_bss_excluded. The advantage of this is that the code is > simpler overall and that the tests in wnm_is_bss_excluded are also used > when doing link selection during MLO. > > As part of this, the behaviour of the BTM handling code is updated > somewhat to handle the abridged bit and also parse the candidate list > even if it is not mandatory to do so. > > Avraham Stern (1): > MBO: Always accept BTM request with disassociation imminent bit set > > Benjamin Berg (15): > WNM: Only trigger selection logic for own scans > WNM: Store whether disassociation address is an MLD Address > WNM: Use os_relatime_add_ms helper > WNM: Split candidate list parsing into a separate function > WNM: Remove unused age parameter for neighbor comparison > WNM: Swap logic in wnm_is_bss_excluded to allow more checks > WNM: Move neighbor report test into wnm_is_bss_excluded > WNM: Move driver MBO transition rejection into wnm_is_bss_excluded > tests: Set the abridged bit in BTM tests > WNM: Use standard BSS selection and enable abridged bit handling > WNM: Reject requests with an invalid dialog token > WNM: Consolidate the scanning paths for BTM requests > WNM: Always parse candidate list > tests: Add a WNM tests to check candidate list is used if not required > WNM: Scan for BSSID if there are forbidden neighbors Thanks, applied patches 1-7, 9, and 11-16 with some cleanup. Patch 8 has open questions and 10 depends on 8. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 01:55:22 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 11:55:22 +0300 Subject: [PATCH] Scan other networks first to unlock 5GHz bands on Intel cards In-Reply-To: <5TLtkCSwaUx-RqmmGmjkvZYDuOoygMMyJo5CGL76zpDSc4DrPeUsskBfK_dfts8Uxl5Rk4BqrZD1L6uQKsSJWPSlNj__T7dHdz7zzVPo_J8=@protonmail.com> References: <5TLtkCSwaUx-RqmmGmjkvZYDuOoygMMyJo5CGL76zpDSc4DrPeUsskBfK_dfts8Uxl5Rk4BqrZD1L6uQKsSJWPSlNj__T7dHdz7zzVPo_J8=@protonmail.com> Message-ID: On Wed, Jul 17, 2024 at 07:56:04PM +0000, Pedro Goncalves (developer account) wrote: > Subject: [PATCH] For intel Wi-Fi cards, force to scan other wireless networks so the drive is able to set the correct region - master > > Signed-off-by: Pedro Goncalves This would need much more detailed commit message to justify why this is needed and why this is appropriate behavior. How is this specific to Intel cards? Why would an AP be allowed to operate on the 5 GHz band based on just a single scan if it was not allowed to do so without that scan? > Index: src/ap/hostapd.h > IDEA additional info: > Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP > <+>UTF-8 > =================================================================== > diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h And this format is pretty strange and requires manual operations to apply with 'git am'. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 02:57:28 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 12:57:28 +0300 Subject: [PATCH] Add non-PSC channels to 6GHz scan request In-Reply-To: <20240405073708.3846816-1-rmekonnen@chromium.org> References: <20240405073708.3846816-1-rmekonnen@chromium.org> Message-ID: On Fri, Apr 05, 2024 at 07:36:48AM +0000, Ruth Mekonnen wrote: > When non_coloc_6ghz = false, the STA is expected to scan for > colocated APs. However, if the colocated AP is on a non-PSC > channel, it will not be detected during the 6GHz-only scan > because the frequency list is limited to PSC channels. Even when > the NL80211_SCAN_FLAG_COLOCATED_6GHZ is set, the cfg80211 only > scans a subset of the channels in the original 6GHz scan request. > Therefore, this patch adds non-PSC channels to the original 6GHz > scan request. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 02:57:55 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 12:57:55 +0300 Subject: [PATCH] Trigger 6GHz scan if RNR contains matching short SSID In-Reply-To: <20240604210216.331287-1-matthewmwang@chromium.org> References: <20240604210216.331287-1-matthewmwang@chromium.org> Message-ID: On Tue, Jun 04, 2024 at 09:02:16PM +0000, Matthew Wang wrote: > If a scan triggers a regdom update into a 6GHz-allowed regdom, and an > RNR IE in one of the legacy band scan results points to a 6GHz scan > result with a short SSID matching the current_ssid, delay connection in > favor of a 6GHz-only scan. This will optimize the case in which we first > connect to a 5GHz AP, then later roam to a 6GHz one by directly > connecting to the 6GHz one. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 02:58:20 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 12:58:20 +0300 Subject: [PATCH v3] Emit ScanInProgress6GHz property In-Reply-To: <20240612200948.3322887-1-rmekonnen@chromium.org> References: <20240612200948.3322887-1-rmekonnen@chromium.org> Message-ID: On Wed, Jun 12, 2024 at 08:09:43PM +0000, Ruth Mekonnen wrote: > Expose whether a 6GHz scan is in progress with the > ScanInProgress6GHz property and flush properties as soon as the > property is updated, so that platforms can choose not to > disconnect while a 6GHz scan is in progress. Once the 6GHz scan > has completed and scan results have been received, the > ScanInProgress6GHz property is reset to false. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 02:58:39 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 12:58:39 +0300 Subject: [PATCH] P2P: use specified frequency for group client in P2P_GROUP_ADD command In-Reply-To: <20240731185001.3540529-1-jintaolin@chromium.org> References: <20240731185001.3540529-1-jintaolin@chromium.org> Message-ID: On Wed, Jul 31, 2024 at 06:50:01PM +0000, Jintao Lin wrote: > In P2P_GROUP_ADD command and GroupAdd dbus method, frequency is passed > in as a parameter. This is the group operating frequency determined out > of band. Use this pre-determined frequency in P2P client as well to > expedite the P2P scan. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 08:40:44 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 18:40:44 +0300 Subject: [PATCH v2 1/5] tests: add RemoteCtrl class In-Reply-To: <20240530191904.1426538-1-janusz.dziedzic@gmail.com> References: <20240530191904.1426538-1-janusz.dziedzic@gmail.com> Message-ID: Thanks, all five patches applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 10:35:35 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 20:35:35 +0300 Subject: [PATCH] Avoid sending DEAUTH or DISASSOC packet when using flag tx=0 In-Reply-To: References: Message-ID: On Thu, May 02, 2024 at 07:55:45AM +0000, Gal Savion wrote: > > hostapd would send DISASSOC packet (after quiet DEAUTH) or DEAUTH packet (after > quiet DISASSOC) to the station after some inactivity timeout, even though the > command has tx=0 parameter. Fix this so that tx=0 cleans the STA info without > sending any DISASSOC or DEAUTH packets. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 3 10:35:55 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 3 Aug 2024 20:35:55 +0300 Subject: [PATCH] build: Add simple compile_commands.json generation In-Reply-To: <20240508105610.30837-1-benjamin@sipsolutions.net> References: <20240508101727.27156-1-benjamin@sipsolutions.net> <20240508105610.30837-1-benjamin@sipsolutions.net> Message-ID: On Wed, May 08, 2024 at 12:56:10PM +0200, benjamin at sipsolutions.net wrote: > This can be used with a clangd server to get code completion and cross > references in editor. To simplify the generation, create .cmd files for > most object files while building that contains the base directory and > command that was used when compiling it. > > A very simple gen_compile_commands.py is provided which will read one or > more build directories and generate the compile_commands.json file for > it. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at jannau.net Sun Aug 4 05:23:56 2024 From: j at jannau.net (Janne Grunau) Date: Sun, 04 Aug 2024 14:23:56 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac Message-ID: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> Hej, wpa_supplicant 2.11 on Linux's 6.9.y / 6.10.y brcmfmac driver runs in authentication timeouts with WPA2-PSK and WPA3-SAE. This was reported with Apple silicon devices using Fedora Asahi remix with a patched driver as well as other devices without additional brcmfmac patches. See https://bugzilla.redhat.com/show_bug.cgi?id=2302577 for some reports. I've bisected this to https://w1.fi/cgit/hostap/commit/?id=41638606054a09867fe3f9a2b5523aa4678cbfa5 "Mark authorization completed on driver indication during 4-way HS offload". Reverting this commit on top of hostap_2_11 properly authenticates the connections. Looking at that change and the code it looks clearly broken to to me. As far as I can see is `assoc_info.authorized` for the nl80211 driver only set when QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED is set (in main, I did not check older revisions). This doesn't seem appropriate to expect this on chipsets from different vendors. A revert looks to me like a possible/proper fix. I can send that later if no alternative materializes. Thanks and best regards, Janne From maochen.wang at nxp.com Sun Aug 4 20:16:08 2024 From: maochen.wang at nxp.com (Maochen Wang) Date: Mon, 5 Aug 2024 03:16:08 +0000 Subject: [PATCH] eap: fix the duplicated registration of eap server Message-ID: >From ca0b2812a3f2ce1952a805212a02e99f70da786f Mon Sep 17 00:00:00 2001 From: Maochen Wang mailto:maochen.wang at nxp.com Date: Tue, 30 Jul 2024 17:30:40 +0800 Subject: [PATCH] eap: fix the duplicated registration of eap server method Fix the duplicated registration of eap server method, as on Zephyr OS, hostapd and supplicant are running in same task, when hostapd enabled, eap_server_register_methods() will also call the eap server related functions, which leads to the duplicated registration of eap server method. Signed-off-by: Maochen Wang mailto:maochen.wang at nxp.com --- wpa_supplicant/eap_register.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c index 3f018c4b3..d009be5dd 100644 --- a/wpa_supplicant/eap_register.c +++ b/wpa_supplicant/eap_register.c @@ -152,6 +152,7 @@ int eap_register_methods(void) ??????????? ret = eap_peer_eke_register(); #endif /* EAP_EKE */ +#ifndef HOSTAPD #ifdef EAP_SERVER_IDENTITY ???? if (ret == 0) ??????????? ret = eap_server_identity_register(); @@ -266,6 +267,6 @@ int eap_register_methods(void) ???? if (ret == 0) ??????????? ret = eap_server_pwd_register(); #endif /* EAP_SERVER_PWD */ - +#endif /* HOSTAPD * ???? return ret; } -- 2.25.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-noup-eap-fix-the-duplicated-registration-of-eap-serv.patch Type: application/octet-stream Size: 1234 bytes Desc: 0001-noup-eap-fix-the-duplicated-registration-of-eap-serv.patch URL: From quic_shivbara at quicinc.com Mon Aug 5 02:32:58 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:02:58 +0530 Subject: [PATCH v3 00/25] Add support for P2P2 Message-ID: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Implementation to support the P2P2 discovery and PASN pairing, join and verification. Shivani Baranwal (25): NAN: Option to offload NAN DE for USD into the driver P2P: Allow P2P IE to be added into NAN SDFs P2P: Add PCEA and PBMA attributes to P2P2 IE of NAN SDFs P2P: Add DIRA attributes to P2P2 IE of NAN SDFs P2P: Add config support to fetch Device Identity key P2P: Add freq list to subscriber to search for publisher on mutli channels P2P: Allow to process Element container attr from NAN SDFs P2P: Cleanup of provision discovery req and resp processing P2P: Add bootstrapping support with pd frames P2P: Notify bootstrapping request and completed events WPA: Add support for KEK derivation in PTK Define PMKSA helper functions for PASN initiator and responder P2P: Cleanup of go-negotiation and invitation processing P2P: Add support for go negotiation action wrapper format for p2p2 P2P: Encapsulate P2P2 vendor IE with size more than 255 bytes P2P: Add support for GO negotiation wrapped in PASN auth frame p2p: Add support for p2p2 set apis Add p2p2 support for group formation on successful negotiation p2p: Add support for Invitation using pairing verification P2P: Add P2P2 support for autogo and client join P2P: Add device identity block to p2p_supplicant.conf P2P: Add support to validate DIRA and configure PMK P2P: Add support to store indentity key in conf file P2P: Add support to get PASN PTK P2P: Add support for Assited DFS for P2P2 GO in 5GHz hostapd/ctrl_iface.c | 16 +- src/ap/ap_drv_ops.c | 23 + src/ap/ap_drv_ops.h | 5 + src/ap/hostapd.c | 15 +- src/ap/hostapd.h | 3 + src/ap/hw_features.c | 3 +- src/ap/ieee802_11.c | 34 +- src/ap/ieee802_11.h | 2 + src/ap/nan_usd_ap.c | 10 +- src/ap/nan_usd_ap.h | 4 +- src/ap/wpa_auth.c | 18 + src/ap/wpa_auth.h | 3 + src/ap/wpa_auth_ie.c | 17 + src/common/common_module_tests.c | 2 +- src/common/ieee802_11_common.c | 23 +- src/common/ieee802_11_common.h | 4 + src/common/ieee802_11_defs.h | 48 + src/common/nan_de.c | 79 +- src/common/nan_de.h | 14 +- src/common/wpa_common.c | 22 +- src/common/wpa_common.h | 5 +- src/common/wpa_ctrl.h | 4 + src/drivers/driver.h | 77 ++ src/p2p/p2p.c | 1482 ++++++++++++++++++++++++++- src/p2p/p2p.h | 332 +++++- src/p2p/p2p_build.c | 262 +++++ src/p2p/p2p_go_neg.c | 372 +++++-- src/p2p/p2p_group.c | 61 +- src/p2p/p2p_i.h | 224 +++- src/p2p/p2p_invitation.c | 161 ++- src/p2p/p2p_parse.c | 63 ++ src/p2p/p2p_pd.c | 775 ++++++++++---- src/p2p/p2p_utils.c | 50 + src/pasn/pasn_common.h | 34 +- src/pasn/pasn_initiator.c | 111 +- src/pasn/pasn_responder.c | 81 +- src/rsn_supp/wpa.c | 17 + src/rsn_supp/wpa.h | 2 + wpa_supplicant/ap.c | 1 + wpa_supplicant/config.c | 138 +++ wpa_supplicant/config.h | 73 ++ wpa_supplicant/config_file.c | 104 +- wpa_supplicant/ctrl_iface.c | 154 ++- wpa_supplicant/dbus/dbus_new.c | 107 ++ wpa_supplicant/dbus/dbus_new.h | 16 + wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 12 +- wpa_supplicant/driver_i.h | 73 ++ wpa_supplicant/events.c | 67 +- wpa_supplicant/nan_usd.c | 79 +- wpa_supplicant/nan_usd.h | 4 +- wpa_supplicant/notify.c | 12 + wpa_supplicant/notify.h | 4 + wpa_supplicant/p2p_supplicant.c | 1131 ++++++++++++++++++-- wpa_supplicant/p2p_supplicant.h | 51 +- wpa_supplicant/pasn_supplicant.c | 5 + wpa_supplicant/wpa_supplicant_i.h | 15 + 56 files changed, 5965 insertions(+), 539 deletions(-) -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:32:59 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:02:59 +0530 Subject: [PATCH v3 01/25] NAN: Option to offload NAN DE for USD into the driver In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-2-git-send-email-quic_shivbara@quicinc.com> Support implementation architecture where the NAN discovery engine is located in the driver/firmware instead of wpa_supplicant. Signed-off-by: Shivani Baranwal --- src/ap/nan_usd_ap.c | 2 +- src/common/nan_de.c | 24 ++++++++++++--- src/common/nan_de.h | 3 +- src/drivers/driver.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ wpa_supplicant/driver_i.h | 73 ++++++++++++++++++++++++++++++++++++++++++++ wpa_supplicant/nan_usd.c | 45 +++++++++++++++++++++++++-- 6 files changed, 216 insertions(+), 8 deletions(-) diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c index 52a967a..70c6139 100644 --- a/src/ap/nan_usd_ap.c +++ b/src/ap/nan_usd_ap.c @@ -158,7 +158,7 @@ int hostapd_nan_usd_init(struct hostapd_data *hapd) 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); + hapd->nan_de = nan_de_init(hapd->own_addr, false, true, &cb); if (!hapd->nan_de) return -1; return 0; diff --git a/src/common/nan_de.c b/src/common/nan_de.c index 12fad31..0b54f11 100644 --- a/src/common/nan_de.c +++ b/src/common/nan_de.c @@ -62,6 +62,7 @@ struct nan_de_service { struct nan_de { u8 nmi[ETH_ALEN]; + bool offload; bool ap; struct nan_callbacks cb; @@ -77,7 +78,7 @@ struct nan_de { }; -struct nan_de * nan_de_init(const u8 *nmi, bool ap, +struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb) { struct nan_de *de; @@ -87,6 +88,7 @@ struct nan_de * nan_de_init(const u8 *nmi, bool ap, return NULL; os_memcpy(de->nmi, nmi, ETH_ALEN); + de->offload = offload; de->ap = ap; os_memcpy(&de->cb, cb, sizeof(*cb)); @@ -590,7 +592,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (srv_next >= 0 && (next == -1 || srv_next < next)) next = srv_next; - if (srv_next == 0 && !started && + if (srv_next == 0 && !started && !de->offload && de->listen_freq == 0 && de->ext_listen_freq == 0 && de->tx_wait_end_freq == 0 && nan_de_next_multicast(de, srv, &now) == 0) { @@ -598,7 +600,7 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) nan_de_tx_multicast(de, srv, 0); } - if (!started && de->cb.listen && + if (!started && !de->offload && de->cb.listen && de->listen_freq == 0 && de->ext_listen_freq == 0 && de->tx_wait_end_freq == 0 && ((srv->type == NAN_DE_PUBLISH && @@ -626,7 +628,8 @@ static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) if (next == 0) next = 1; - wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next); + else + wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next); eloop_register_timeout(next / 1000, (next % 1000) * 1000, nan_de_timer, de, NULL); } @@ -1196,6 +1199,19 @@ static int nan_de_derive_service_id(struct nan_de_service *srv) } +const u8 * nan_de_get_service_id(struct nan_de *de, int id) +{ + struct nan_de_service *srv; + + if (id < 1 || id > NAN_DE_MAX_SERVICE) + return NULL; + srv = de->service[id - 1]; + if (!srv) + return NULL; + return srv->service_id; +} + + int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, diff --git a/src/common/nan_de.h b/src/common/nan_de.h index 6223506..ae77cf3 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -55,7 +55,7 @@ struct nan_callbacks { const u8 *peer_addr); }; -struct nan_de * nan_de_init(const u8 *nmi, bool ap, +struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, const struct nan_callbacks *cb); void nan_de_flush(struct nan_de *de); void nan_de_deinit(struct nan_de *de); @@ -68,6 +68,7 @@ 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); +const u8 * nan_de_get_service_id(struct nan_de *de, int id); struct nan_publish_params { /* configuration_parameters */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 4331782..3818397 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -27,6 +27,10 @@ #endif /* CONFIG_MACSEC */ #include "utils/list.h" +struct nan_subscribe_params; +struct nan_publish_params; +enum nan_service_protocol_type; + #define HOSTAPD_CHAN_DISABLED 0x00000001 #define HOSTAPD_CHAN_NO_IR 0x00000002 #define HOSTAPD_CHAN_RADAR 0x00000008 @@ -2332,6 +2336,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER 0x0000000000200000ULL /** Driver supports RSN override elements */ #define WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA 0x0000000000400000ULL +/** Driver supports NAN offload */ +#define WPA_DRIVER_FLAGS2_NAN_OFFLOAD 0x0000000000800000ULL u64 flags2; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -5215,6 +5221,77 @@ struct wpa_driver_ops { */ int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr); + /** + * nan_flush - Flush all NAN offload services + * @priv: Private driver interface data + * Returns: 0 on success, negative value on failure + */ + int (*nan_flush)(void *priv); + + /** + * nan_publish - NAN offload for Publish() + * @priv: Private driver interface data + * @src: Source P2P device addr + * @publish_id: Publish instance to add + * @service_name: Service name + * @service_id: Service ID (6 octet value derived from service name) + * @srv_proto_type: Service protocol type + * @ssi: Service specific information or %NULL + * @elems: Information elements for Element Container attribute or %NULL + * @params: Configuration parameters + * Returns: 0 on success, negative value on failure + */ + int (*nan_publish)(void *priv, const u8 *src, int publish_id, + const char *service_name, const u8 *service_id, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params); + + /** + * nan_cancel_publish - NAN offload for CancelPublish() + * @priv: Private driver interface data + * @publish_id: Publish instance to cancel + * Returns: 0 on success, negative value on failure + */ + int (*nan_cancel_publish)(void *priv, int publish_id); + + /** + * nan_update_publish - NAN offload for UpdatePublish() + * @priv: Private driver interface data + * @ssi: Service specific information or %NULL + * Returns: 0 on success, negative value on failure + */ + int (*nan_update_publish)(void *priv, int publish_id, + const struct wpabuf *ssi); + + /** + * nan_subscribe - NAN offload for Subscribe() + * @priv: Private driver interface data + * @src: Source P2P device addr + * @subscribe_id: Subscribe instance to add + * @service_name: Service name + * @service_id: Service ID (6 octet value derived from service name) + * @srv_proto_type: Service protocol type + * @ssi: Service specific information or %NULL + * @elems: Information elements for Element Container attribute or %NULL + * @params: Configuration parameters + * Returns: 0 on success, negative value on failure + */ + int (*nan_subscribe)(void *priv, const u8 *src, int subscribe_id, + const char *service_name, const u8 *service_id, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + const struct wpabuf *elems, + struct nan_subscribe_params *params); + + /** + * nan_cancel_subscribe - NAN offload for CancelSubscribe() + * @priv: Private driver interface data + * @subscribe_id: Subscribe instance to cancel + * Returns: 0 on success, negative value on failure + */ + int (*nan_cancel_subscribe)(void *priv, int subscribe_id); + #ifdef CONFIG_TESTING_OPTIONS int (*register_frame)(void *priv, u16 type, const u8 *match, size_t match_len, diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index d01b52b..e8aeb2e 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -10,6 +10,7 @@ #define DRIVER_I_H #include "drivers/driver.h" +#include "common/nan_de.h" /* driver_ops */ static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s, @@ -1175,4 +1176,76 @@ wpas_drv_get_sta_mlo_info(struct wpa_supplicant *wpa_s, return wpa_s->driver->get_sta_mlo_info(wpa_s->drv_priv, mlo_info); } +static inline int +wpas_drv_nan_flush(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->nan_flush) + return 0; + + return wpa_s->driver->nan_flush(wpa_s->drv_priv); +} + +static inline int +wpas_drv_nan_publish(struct wpa_supplicant *wpa_s, const u8 *addr, + int publish_id, const char *service_name, + const u8 *service_id, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params) +{ + if (!wpa_s->driver->nan_publish) + return 0; + + return wpa_s->driver->nan_publish(wpa_s->drv_priv, addr, publish_id, + service_name, service_id, + srv_proto_type, ssi, elems, params); +} + +static inline int +wpas_drv_nan_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id) +{ + if (!wpa_s->driver->nan_cancel_publish) + return 0; + + return wpa_s->driver->nan_cancel_publish(wpa_s->drv_priv, + publish_id); +} + +static inline int +wpas_drv_nan_update_publish(struct wpa_supplicant *wpa_s, int publish_id, + const struct wpabuf *ssi) +{ + if (!wpa_s->driver->nan_update_publish) + return 0; + + return wpa_s->driver->nan_update_publish(wpa_s->drv_priv, + publish_id, ssi); +} + +static inline int +wpas_drv_nan_subscribe(struct wpa_supplicant *wpa_s, const u8 *addr, + int subscribe_id, const char *service_name, + const u8 *service_id, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_subscribe_params *params) +{ + if (!wpa_s->driver->nan_subscribe) + return 0; + + return wpa_s->driver->nan_subscribe(wpa_s->drv_priv, addr, subscribe_id, + service_name, service_id, + srv_proto_type, ssi, elems, params); +} + +static inline int +wpas_drv_nan_cancel_subscribe(struct wpa_supplicant *wpa_s, int subscribe_id) +{ + if (!wpa_s->driver->nan_cancel_subscribe) + return 0; + + return wpa_s->driver->nan_cancel_subscribe(wpa_s->drv_priv, + subscribe_id); +} + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c index 657b302..884e416 100644 --- a/wpa_supplicant/nan_usd.c +++ b/wpa_supplicant/nan_usd.c @@ -338,6 +338,7 @@ static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id, int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) { struct nan_callbacks cb; + bool offload = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD; os_memset(&cb, 0, sizeof(cb)); cb.ctx = wpa_s; @@ -349,7 +350,7 @@ int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) cb.subscribe_terminated = wpas_nan_de_subscribe_terminated; cb.receive = wpas_nan_de_receive; - wpa_s->nan_de = nan_de_init(wpa_s->own_addr, false, &cb); + wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false, &cb); if (!wpa_s->nan_de) return -1; return 0; @@ -377,6 +378,8 @@ void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s) if (!wpa_s->nan_de) return; nan_de_flush(wpa_s->nan_de); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) + wpas_drv_nan_flush(wpa_s); } @@ -393,6 +396,20 @@ int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type, ssi, elems, params); + if (publish_id <= 0) + goto fail; + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) && + wpas_drv_nan_publish(wpa_s, wpa_s->own_addr, publish_id, + service_name, + nan_de_get_service_id(wpa_s->nan_de, + publish_id), + srv_proto_type, ssi, elems, params) < 0) { + nan_de_cancel_publish(wpa_s->nan_de, publish_id); + publish_id = -1; + goto fail; + } + +fail: wpabuf_free(elems); return publish_id; } @@ -403,15 +420,23 @@ void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id) if (!wpa_s->nan_de) return; nan_de_cancel_publish(wpa_s->nan_de, publish_id); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) + wpas_drv_nan_cancel_publish(wpa_s, publish_id); } int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, const struct wpabuf *ssi) { + int ret; + if (!wpa_s->nan_de) return -1; - return nan_de_update_publish(wpa_s->nan_de, publish_id, ssi); + ret = nan_de_update_publish(wpa_s->nan_de, publish_id, ssi); + if (ret == 0 && (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) && + wpas_drv_nan_cancel_publish(wpa_s, publish_id) < 0) + return -1; + return ret; } @@ -429,6 +454,20 @@ int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name, srv_proto_type, ssi, elems, params); + if (subscribe_id <= 0) + goto fail; + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) && + wpas_drv_nan_subscribe(wpa_s, wpa_s->own_addr, subscribe_id, + service_name, + nan_de_get_service_id(wpa_s->nan_de, + subscribe_id), + srv_proto_type, ssi, elems, params) < 0) { + nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id); + subscribe_id = -1; + goto fail; + } + +fail: wpabuf_free(elems); return subscribe_id; } @@ -440,6 +479,8 @@ void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, if (!wpa_s->nan_de) return; nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) + wpas_drv_nan_cancel_subscribe(wpa_s, subscribe_id); } -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:00 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:00 +0530 Subject: [PATCH v3 02/25] P2P: Allow P2P IE to be added into NAN SDFs In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-3-git-send-email-quic_shivbara@quicinc.com> Extend the NAN Subscribe and Publish methods to allow p2p=1 to be specified to include P2P attributes in a P2P IE to be added into the NAN Element Container attribute. Signed-off-by: Shivani Baranwal --- hostapd/ctrl_iface.c | 16 ++++++++++++++-- src/ap/nan_usd_ap.c | 8 ++++---- src/ap/nan_usd_ap.h | 4 ++-- src/common/ieee802_11_defs.h | 1 + src/common/nan_de.c | 7 +++++-- src/common/nan_de.h | 4 ++-- src/p2p/p2p.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/p2p/p2p.h | 1 + src/p2p/p2p_build.c | 18 ++++++++++++++++++ src/p2p/p2p_i.h | 2 ++ wpa_supplicant/ctrl_iface.c | 16 ++++++++++++++-- wpa_supplicant/nan_usd.c | 32 ++++++++++++++++++++++++-------- wpa_supplicant/nan_usd.h | 4 ++-- wpa_supplicant/p2p_supplicant.c | 10 ++++++++++ wpa_supplicant/p2p_supplicant.h | 6 ++++++ 15 files changed, 145 insertions(+), 24 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 39b9ef5..fcdbb5c 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -3705,6 +3705,7 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd, struct wpabuf *ssi = NULL; int ret = -1; enum nan_service_protocol_type srv_proto_type = 0; + bool p2p = false; os_memset(¶ms, 0, sizeof(params)); /* USD shall use both solicited and unsolicited transmissions */ @@ -3738,6 +3739,11 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd, continue; } + if (os_strcmp(token, "p2p=1") == 0) { + p2p = true; + continue; + } + if (os_strcmp(token, "solicited=0") == 0) { params.solicited = false; continue; @@ -3759,7 +3765,7 @@ static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd, } publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type, - ssi, ¶ms); + ssi, ¶ms, p2p); if (publish_id > 0) ret = os_snprintf(buf, buflen, "%d", publish_id); fail: @@ -3842,6 +3848,7 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd, struct wpabuf *ssi = NULL; int ret = -1; enum nan_service_protocol_type srv_proto_type = 0; + bool p2p = false; os_memset(¶ms, 0, sizeof(params)); @@ -3875,6 +3882,11 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd, continue; } + if (os_strcmp(token, "p2p=1") == 0) { + p2p = true; + continue; + } + wpa_printf(MSG_INFO, "CTRL: Invalid NAN_SUBSCRIBE parameter: %s", token); @@ -3883,7 +3895,7 @@ static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd, subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name, srv_proto_type, ssi, - ¶ms); + ¶ms, p2p); if (subscribe_id > 0) ret = os_snprintf(buf, buflen, "%d", subscribe_id); fail: diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c index 70c6139..570abfc 100644 --- a/src/ap/nan_usd_ap.c +++ b/src/ap/nan_usd_ap.c @@ -192,7 +192,7 @@ 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) + struct nan_publish_params *params, bool p2p) { int publish_id; struct wpabuf *elems = NULL; @@ -201,7 +201,7 @@ int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name, return -1; publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type, - ssi, elems, params); + ssi, elems, params, p2p); wpabuf_free(elems); return publish_id; } @@ -231,7 +231,7 @@ 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) + struct nan_subscribe_params *params, bool p2p) { int subscribe_id; struct wpabuf *elems = NULL; @@ -240,7 +240,7 @@ int hostapd_nan_usd_subscribe(struct hostapd_data *hapd, return -1; subscribe_id = nan_de_subscribe(hapd->nan_de, service_name, - srv_proto_type, ssi, elems, params); + srv_proto_type, ssi, elems, params, p2p); wpabuf_free(elems); return subscribe_id; } diff --git a/src/ap/nan_usd_ap.h b/src/ap/nan_usd_ap.h index 58ff5fc..0571643 100644 --- a/src/ap/nan_usd_ap.h +++ b/src/ap/nan_usd_ap.h @@ -21,7 +21,7 @@ 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); + struct nan_publish_params *params, bool p2p); 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); @@ -29,7 +29,7 @@ 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); + struct nan_subscribe_params *params, bool p2p); void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd, int subscribe_id); int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index db9e903..434844a 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1425,6 +1425,7 @@ struct ieee80211_ampe_ie { #define WPS_IE_VENDOR_TYPE 0x0050f204 #define OUI_WFA 0x506f9a #define P2P_IE_VENDOR_TYPE 0x506f9a09 +#define P2P2_IE_VENDOR_TYPE 0x506f9a28 #define WFD_IE_VENDOR_TYPE 0x506f9a0a #define WFD_OUI_TYPE 10 #define HS20_IE_VENDOR_TYPE 0x506f9a10 diff --git a/src/common/nan_de.c b/src/common/nan_de.c index 0b54f11..5a68cc9 100644 --- a/src/common/nan_de.c +++ b/src/common/nan_de.c @@ -58,6 +58,7 @@ struct nan_de_service { struct os_reltime next_publish_state; struct os_reltime next_publish_chan; unsigned int next_publish_duration; + bool is_p2p; }; struct nan_de { @@ -1215,7 +1216,7 @@ const u8 * nan_de_get_service_id(struct nan_de *de, int id) int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_publish_params *params) + struct nan_publish_params *params, bool p2p) { int publish_id; struct nan_de_service *srv; @@ -1277,6 +1278,7 @@ int nan_de_publish(struct nan_de *de, const char *service_name, wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s", publish_id, service_name); srv->id = publish_id; + srv->is_p2p = p2p; nan_de_add_srv(de, srv); nan_de_run_timer(de); return publish_id; @@ -1328,7 +1330,7 @@ int nan_de_update_publish(struct nan_de *de, int publish_id, int nan_de_subscribe(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_subscribe_params *params) + struct nan_subscribe_params *params, bool p2p) { int subscribe_id; struct nan_de_service *srv; @@ -1368,6 +1370,7 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name, wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s", subscribe_id, service_name); srv->id = subscribe_id; + srv->is_p2p = p2p; nan_de_add_srv(de, srv); nan_de_run_timer(de); return subscribe_id; diff --git a/src/common/nan_de.h b/src/common/nan_de.h index ae77cf3..bdac284 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -106,7 +106,7 @@ struct nan_publish_params { int nan_de_publish(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_publish_params *params); + struct nan_publish_params *params, bool p2p); void nan_de_cancel_publish(struct nan_de *de, int publish_id); @@ -133,7 +133,7 @@ struct nan_subscribe_params { int nan_de_subscribe(struct nan_de *de, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, const struct wpabuf *elems, - struct nan_subscribe_params *params); + struct nan_subscribe_params *params, bool p2p); void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 8e0fc35..0c26086 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -5688,3 +5688,43 @@ void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value) { p2p->allow_6ghz = value; } + + +struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) +{ + struct wpabuf *buf; + u8 *len; + u8 group_capab; + + buf = wpabuf_alloc(1000); + if (!buf) + return NULL; + + len = p2p_buf_add_ie_hdr(buf); + + /* P2P Capability attribute */ + group_capab = 0; + if (p2p->num_groups) { + group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; + if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && + (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && + p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + } + if (p2p->cfg->p2p_intra_bss) + group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; + p2p_buf_add_capability(buf, p2p->dev_capab & + ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, + group_capab); + + /* P2P Device Info attribute */ + p2p_buf_add_device_info(buf, p2p, NULL); + + p2p_buf_update_ie_hdr(buf, len); + + len = p2p_buf_add_p2p2_ie_hdr(buf); + + p2p_buf_update_p2p2_ie_hdr(buf, len); + + return buf; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 27bdac3..ab6e9ca 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -2429,5 +2429,6 @@ bool is_p2p_allow_6ghz(struct p2p_data *p2p); void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value); int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size); int p2p_channel_to_freq(int op_class, int channel); +struct wpabuf * p2p_usd_elems(struct p2p_data *p2p); #endif /* P2P_H */ diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index e4f40fe..0bb0903 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -59,6 +59,24 @@ void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) *len = (u8 *) wpabuf_put(buf, 0) - len - 1; } +u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf) +{ + u8 *len; + + /* P2P2 IE header */ + wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); + len = wpabuf_put(buf, 1); /* IE length to be filled */ + wpabuf_put_be32(buf, P2P2_IE_VENDOR_TYPE); + wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header"); + return len; +} + + +void p2p_buf_update_p2p2_ie_hdr(struct wpabuf *buf, u8 *len) +{ + /* Update P2P2 IE Length */ + *len = (u8 *) wpabuf_put(buf, 0) - len - 1; +} void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) { diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 0a487e0..d6826c7 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -748,11 +748,13 @@ void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token); void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token); u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf); +u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf); void p2p_buf_add_status(struct wpabuf *buf, u8 status); void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, struct p2p_device *peer); void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr); void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len); +void p2p_buf_update_p2p2_ie_hdr(struct wpabuf *buf, u8 *len); void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab); void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent); void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 96e0740..f3d74a8 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12202,6 +12202,7 @@ static int wpas_ctrl_nan_publish(struct wpa_supplicant *wpa_s, char *cmd, int ret = -1; enum nan_service_protocol_type srv_proto_type = 0; int *freq_list = NULL; + bool p2p = false; os_memset(¶ms, 0, sizeof(params)); /* USD shall use both solicited and unsolicited transmissions */ @@ -12262,6 +12263,11 @@ static int wpas_ctrl_nan_publish(struct wpa_supplicant *wpa_s, char *cmd, continue; } + if (os_strcmp(token, "p2p=1") == 0) { + p2p = true; + continue; + } + if (os_strcmp(token, "solicited=0") == 0) { params.solicited = false; continue; @@ -12283,7 +12289,7 @@ static int wpas_ctrl_nan_publish(struct wpa_supplicant *wpa_s, char *cmd, } publish_id = wpas_nan_usd_publish(wpa_s, service_name, srv_proto_type, - ssi, ¶ms); + ssi, ¶ms, p2p); if (publish_id > 0) ret = os_snprintf(buf, buflen, "%d", publish_id); fail: @@ -12367,6 +12373,7 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, struct wpabuf *ssi = NULL; int ret = -1; enum nan_service_protocol_type srv_proto_type = 0; + bool p2p = false; os_memset(¶ms, 0, sizeof(params)); params.freq = NAN_USD_DEFAULT_FREQ; @@ -12406,6 +12413,11 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, continue; } + if (os_strcmp(token, "p2p=1") == 0) { + p2p = true; + continue; + } + wpa_printf(MSG_INFO, "CTRL: Invalid NAN_SUBSCRIBE parameter: %s", token); @@ -12414,7 +12426,7 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, subscribe_id = wpas_nan_usd_subscribe(wpa_s, service_name, srv_proto_type, ssi, - ¶ms); + ¶ms, p2p); if (subscribe_id > 0) ret = os_snprintf(buf, buflen, "%d", subscribe_id); fail: diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c index 884e416..eb84019 100644 --- a/wpa_supplicant/nan_usd.c +++ b/wpa_supplicant/nan_usd.c @@ -13,6 +13,7 @@ #include "wpa_supplicant_i.h" #include "offchannel.h" #include "driver_i.h" +#include "p2p_supplicant.h" #include "nan_usd.h" @@ -386,21 +387,28 @@ void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s) int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, - struct nan_publish_params *params) + struct nan_publish_params *params, bool p2p) { int publish_id; struct wpabuf *elems = NULL; + const u8 *addr; if (!wpa_s->nan_de) return -1; + if (p2p) { + elems = wpas_p2p_usd_elems(wpa_s); + addr = wpa_s->global->p2p_dev_addr; + } else { + addr = wpa_s->own_addr; + } + publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type, - ssi, elems, params); + ssi, elems, params, p2p); if (publish_id <= 0) goto fail; if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) && - wpas_drv_nan_publish(wpa_s, wpa_s->own_addr, publish_id, - service_name, + wpas_drv_nan_publish(wpa_s, addr, publish_id, service_name, nan_de_get_service_id(wpa_s->nan_de, publish_id), srv_proto_type, ssi, elems, params) < 0) { @@ -444,21 +452,29 @@ int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, - struct nan_subscribe_params *params) + struct nan_subscribe_params *params, bool p2p) { int subscribe_id; struct wpabuf *elems = NULL; + const u8 *addr; if (!wpa_s->nan_de) return -1; + if (p2p) { + elems = wpas_p2p_usd_elems(wpa_s); + addr = wpa_s->global->p2p_dev_addr; + } else { + addr = wpa_s->own_addr; + } + subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name, - srv_proto_type, ssi, elems, params); + srv_proto_type, ssi, elems, params, + p2p); if (subscribe_id <= 0) goto fail; if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) && - wpas_drv_nan_subscribe(wpa_s, wpa_s->own_addr, subscribe_id, - service_name, + wpas_drv_nan_subscribe(wpa_s, addr, subscribe_id, service_name, nan_de_get_service_id(wpa_s->nan_de, subscribe_id), srv_proto_type, ssi, elems, params) < 0) { diff --git a/wpa_supplicant/nan_usd.h b/wpa_supplicant/nan_usd.h index 149ac9e..ecb4973 100644 --- a/wpa_supplicant/nan_usd.h +++ b/wpa_supplicant/nan_usd.h @@ -21,7 +21,7 @@ void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s); int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, - struct nan_publish_params *params); + struct nan_publish_params *params, bool p2p); void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id); int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, const struct wpabuf *ssi); @@ -29,7 +29,7 @@ int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, const char *service_name, enum nan_service_protocol_type srv_proto_type, const struct wpabuf *ssi, - struct nan_subscribe_params *params); + 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_transmit(struct wpa_supplicant *wpa_s, int handle, diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 70025f1..2df2d10 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -10242,3 +10242,13 @@ int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s) wpa_s->p2p_lo_started = 0; return ret; } + + +struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + + if (wpa_s->global->p2p_disabled || !p2p) + return NULL; + return p2p_usd_elems(p2p); +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index d71f770..441e063 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -225,6 +225,7 @@ int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int count); int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s); int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s); +struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ @@ -351,6 +352,11 @@ static inline int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, return 0; } +static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s) +{ + return NULL; +} + #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:01 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:01 +0530 Subject: [PATCH v3 03/25] P2P: Add PCEA and PBMA attributes to P2P2 IE of NAN SDFs In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-4-git-send-email-quic_shivbara@quicinc.com> Add PCEA and PBMA attribute in P2P2 IE of NAN Subscribe and Publish frames to include the P2P2 capabilities and bootstrapping methods. Signed-off-by: Shivani Baranwal --- src/common/ieee802_11_defs.h | 18 +++++++++++ src/p2p/p2p.c | 36 +++++++++++++++++++++ src/p2p/p2p.h | 57 +++++++++++++++++++++++++++++++++ src/p2p/p2p_build.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ src/p2p/p2p_i.h | 17 ++++++++++ 5 files changed, 204 insertions(+) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 434844a..452f2dc 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1749,6 +1749,12 @@ enum p2p_attr_id { P2P_ATTR_SESSION_ID = 26, P2P_ATTR_FEATURE_CAPABILITY = 27, P2P_ATTR_PERSISTENT_GROUP = 28, + P2P_ATTR_CAPABILITY_EXTENSION = 29, + P2P_ATTR_DEVICE_IDENTITY_KEY = 31, + P2P_ATTR_DEVICE_IDENTITY_RESOLUTION = 32, + P2P_ATTR_PAIRING_AND_BOOTSTRAPPING = 33, + P2P_ATTR_PASSWORD = 34, + P2P_ATTR_ACTION_FRAME_WRAPPER = 35, P2P_ATTR_VENDOR_SPECIFIC = 221 }; @@ -1773,6 +1779,18 @@ enum p2p_attr_id { #define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6) #define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7) +/* P2P Capability Extension attribute - Capability info */ +#define P2P_PCEA_LEN_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3)) +#define P2P_PCEA_6GHZ BIT(4) +#define P2P_PCEA_REG_INFO BIT(5) +#define P2P_PCEA_DFS_OWNER BIT(6) +#define P2P_PCEA_CLI_REQ_CS BIT(7) +#define P2P_PCEA_PAIRING_CAPABLE BIT(8) +#define P2P_PCEA_PAIRING_SETUP_ENABLE BIT(9) +#define P2P_PCEA_PMK_CACHING BIT(10) +#define P2P_PCEA_PASN_TYPE BIT(11) +#define P2P_PCEA_TWT_POWER_MGMT BIT(12) + /* P2PS Coordination Protocol Transport Bitmap */ #define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0) #define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 0c26086..2f9482a 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -2967,6 +2967,30 @@ bool is_p2p_6ghz_disabled(struct p2p_data *p2p) return false; } +int p2p_pairing_info_init(struct p2p_data *p2p) +{ + struct p2p_pairing_info *pairing_info; + + if (!p2p) { + p2p_dbg(p2p, "P2P data NULL"); + return -1; + } + + pairing_info = os_zalloc(sizeof(struct p2p_pairing_info)); + if (!pairing_info) + return -1; + + pairing_info->enable_pairing_setup = + p2p->cfg->pairing_config.enable_pairing_setup; + pairing_info->enable_pairing_cache = + p2p->cfg->pairing_config.enable_pairing_cache; + pairing_info->supported_bootstrap = + p2p->cfg->pairing_config.bootstrap_methods; + + p2p->pairing_info = pairing_info; + + return 0; +} struct p2p_data * p2p_init(const struct p2p_config *cfg) { @@ -3023,6 +3047,7 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->go_timeout = 100; p2p->client_timeout = 20; p2p->num_p2p_sd_queries = 0; + p2p_pairing_info_init(p2p); p2p_dbg(p2p, "initialized"); p2p_channels_dump(p2p, "channels", &p2p->cfg->channels); @@ -3031,6 +3056,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) return p2p; } +void p2p_pairing_info_deinit(struct p2p_data *p2p) +{ + os_free(p2p->pairing_info); +} void p2p_deinit(struct p2p_data *p2p) { @@ -3066,6 +3095,7 @@ void p2p_deinit(struct p2p_data *p2p) p2p_remove_wps_vendor_extensions(p2p); os_free(p2p->no_go_freq.range); p2p_service_flush_asp(p2p); + p2p_pairing_info_deinit(p2p); os_free(p2p); } @@ -5723,6 +5753,12 @@ struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) p2p_buf_update_ie_hdr(buf, len); len = p2p_buf_add_p2p2_ie_hdr(buf); + /* P2P Capability Extension attribute */ + p2p_buf_add_pcea(buf, p2p); + + /* P2P Pairing Bootstrapping Method attribute */ + p2p_buf_add_pbma(buf, p2p->cfg->pairing_config.bootstrap_methods, NULL, + 0, 0); p2p_buf_update_p2p2_ie_hdr(buf, len); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index ab6e9ca..700f839 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -321,6 +321,43 @@ enum p2p_scan_type { #define P2P_MAX_WPS_VENDOR_EXT 10 /** + * struct p2p_pairing_config - P2P pairing config. + */ +struct p2p_pairing_config { + /** + * Pairing capable + */ + u8 pairing_capable; + + /** + * Enable P2P pairing setup + */ + u32 enable_pairing_setup; + + /** + * Enable pairing cache to allow verification + */ + u32 enable_pairing_cache; + + /** + * Enable P2P pairing verification with cached NIK/NPK + */ + u32 enable_pairing_verification; + + /** + * P2P bootstrapping methods supported + */ + u16 bootstrap_methods; + + /** + * The set of supported PASN type + */ + u8 pasn_type; + +}; + + +/** * struct p2p_peer_info - P2P peer information */ struct p2p_peer_info { @@ -590,6 +627,26 @@ struct p2p_config { unsigned int passphrase_len; /** + * p2p_pairing_config - P2P Pairing configuration + */ + struct p2p_pairing_config pairing_config; + + /** + * reg_info - regulatory info encoding for operation in 6 GHz band + */ + u8 reg_info; + + /** + * dfs_owner - Enable p2p GO to act as DFS Owner + */ + bool dfs_owner; + + /** + * twt_power_mgmt - Enable TWT based power mgmt for P2P + */ + bool twt_power_mgmt; + + /** * cb_ctx - Context to use with callback functions */ void *cb_ctx; diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 0bb0903..4bdfb7e 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -727,6 +727,82 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, } +void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p) +{ + u8 *len; + u16 capability_info = 0; + + /* P2P Capability Extension */ + wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY_EXTENSION); + /* Length to be filled */ + len = wpabuf_put(buf, 2); + + if (!p2p->cfg->p2p_6ghz_disable) + capability_info |= P2P_PCEA_6GHZ; + + if (p2p->cfg->reg_info) + capability_info |= P2P_PCEA_REG_INFO; + + if (p2p->cfg->dfs_owner) + capability_info |= P2P_PCEA_DFS_OWNER; + + if (p2p->cfg->pairing_config.pairing_capable) + capability_info |= P2P_PCEA_PAIRING_CAPABLE; + + if (p2p->cfg->pairing_config.enable_pairing_setup) + capability_info |= P2P_PCEA_PAIRING_SETUP_ENABLE; + + if (p2p->cfg->pairing_config.enable_pairing_cache) + capability_info |= P2P_PCEA_PMK_CACHING; + + if (p2p->cfg->pairing_config.pasn_type) + capability_info |= P2P_PCEA_PASN_TYPE; + + if (p2p->cfg->twt_power_mgmt) + capability_info |= P2P_PCEA_TWT_POWER_MGMT; + + /* Field length is (n-1), n in octets */ + capability_info |= (2 - 1) & P2P_PCEA_LEN_MASK; + wpabuf_put_le16(buf, capability_info); + + if (capability_info & P2P_PCEA_REG_INFO) + wpabuf_put_u8(buf, p2p->cfg->reg_info); + + if (capability_info & P2P_PCEA_PASN_TYPE) + wpabuf_put_u8(buf, p2p->cfg->pairing_config.pasn_type); + + /* Update attribute length */ + WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); + + wpa_printf(MSG_DEBUG, "P2P: * Capability Extension info=0x%x", + capability_info); +} + +void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, + size_t cookie_len, int comeback_after) +{ + u8 *len; + + /* P2P Pairing and Bootstrapping methods */ + wpabuf_put_u8(buf, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING); + /* Length to be filled */ + len = wpabuf_put(buf, 2); + + if (cookie && cookie_len) { + if (comeback_after) + wpabuf_put_le16(buf, comeback_after); + wpabuf_put_u8(buf, cookie_len); + wpabuf_put_data(buf, cookie, cookie_len); + } + wpabuf_put_le16(buf, bootstrap); + + /* Update attribute length */ + WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); + + wpa_printf(MSG_DEBUG, "P2P: * Bootstrapping method=0x%x", + bootstrap); +} + static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, const char *val) { diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index d6826c7..381a02e 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -160,6 +160,18 @@ struct p2p_sd_query { struct wpabuf *tlvs; }; + +struct p2p_pairing_info { + /* P2P device own address */ + u8 own_addr[ETH_ALEN]; + /* device capability to enable pairing setup */ + u32 enable_pairing_setup; + /* device capability to enable pairing cache */ + u32 enable_pairing_cache; + /* device supported bootstrapping */ + u16 supported_bootstrap; +}; + /** * struct p2p_data - P2P module data (internal to P2P module) */ @@ -554,6 +566,8 @@ struct p2p_data { bool p2p_6ghz_capable; bool include_6ghz; bool allow_6ghz; + + struct p2p_pairing_info *pairing_info; }; /** @@ -790,6 +804,9 @@ void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask); void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, const u8 *ssid, size_t ssid_len); +void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p); +void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, + size_t cookie_len, int comeback_after); int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, int all_attr); void p2p_buf_add_pref_channel_list(struct wpabuf *buf, -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:02 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:02 +0530 Subject: [PATCH v3 04/25] P2P: Add DIRA attributes to P2P2 IE of NAN SDFs In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-5-git-send-email-quic_shivbara@quicinc.com> Add DIRA attribute in P2P2 IE of NAN Subscribe and Publish frames to enable support for Device identity of paired peers. Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 10 ++++++ src/p2p/p2p.h | 18 +++++++++++ src/p2p/p2p_build.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/p2p/p2p_i.h | 25 +++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 2f9482a..73fcb16 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -2987,6 +2987,13 @@ int p2p_pairing_info_init(struct p2p_data *p2p) pairing_info->supported_bootstrap = p2p->cfg->pairing_config.bootstrap_methods; + pairing_info->dev_ik.cipher_version = + p2p->cfg->pairing_config.dik_cipher; + pairing_info->dev_ik.dik_len = + p2p->cfg->pairing_config.dik_len; + os_memcpy(pairing_info->dev_ik.dik_data, + p2p->cfg->pairing_config.dik_data, + p2p->cfg->pairing_config.dik_len); p2p->pairing_info = pairing_info; return 0; @@ -5760,6 +5767,9 @@ struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) p2p_buf_add_pbma(buf, p2p->cfg->pairing_config.bootstrap_methods, NULL, 0, 0); + /* P2P Device Identity Resolution attribute */ + p2p_buf_add_dira(buf, p2p); + p2p_buf_update_p2p2_ie_hdr(buf, len); return buf; diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 700f839..b7d05e9 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -12,6 +12,16 @@ #include "common/ieee802_11_defs.h" #include "wps/wps.h" +#define DEVICE_IDENTITY_KEY_MAX_LEN 64 +#define DEVICE_IDENTITY_KEY_LEN 16 +#define DEVICE_IDENTITY_TAG_LEN 8 +#define DEVICE_IDENTITY_NONCE_LEN 8 +#define DEVICE_MAX_HASH_LEN 32 +#define DIR_STR_LEN 3 + +/* DIRA Cipher versions */ +#define DIRA_CIPHER_VERSION_128 0 + struct weighted_pcl; /* P2P ASP Setup Capability */ @@ -354,6 +364,14 @@ struct p2p_pairing_config { */ u8 pasn_type; + /* cipher version type */ + int dik_cipher; + + /* buffer to hold the DevIK */ + u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN]; + + /* length of DevIK */ + size_t dik_len; }; diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 4bdfb7e..347e8a1 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -12,6 +12,8 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/qca-vendor.h" +#include "crypto/random.h" +#include "crypto/sha256.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -803,6 +805,92 @@ void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, bootstrap); } +static int p2p_derive_nonce_tag(struct p2p_data *p2p) +{ + int ret; + u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN]; + u8 dira_tag[DEVICE_MAX_HASH_LEN]; + u8 data[DIR_STR_LEN + DEVICE_IDENTITY_NONCE_LEN + ETH_ALEN]; + struct p2p_id_key *dev_ik; + + dev_ik = &p2p->pairing_info->dev_ik; + + if (dev_ik->cipher_version != DIRA_CIPHER_VERSION_128) { + wpa_printf(MSG_ERROR, "Unsupported DIRA Cipher version = %d", + dev_ik->cipher_version); + return -1; + } + + if (dev_ik->dik_len != DEVICE_IDENTITY_KEY_LEN) { + wpa_printf(MSG_ERROR, "Invalid DIK length = %ld", + dev_ik->dik_len); + return -1; + } + + os_memset(data, 0, sizeof(data)); + os_memset(dira_tag, 0, sizeof(dira_tag)); + + ret = random_get_bytes(dira_nonce, DEVICE_IDENTITY_NONCE_LEN); + if (ret < 0) { + wpa_printf(MSG_ERROR, "Get DIRA nonce Failed, err = %d", ret); + return -1; + } + + os_memcpy(data, "DIR", DIR_STR_LEN); + os_memcpy(&data[DIR_STR_LEN], p2p->cfg->dev_addr, ETH_ALEN); + os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], dira_nonce, + DEVICE_IDENTITY_NONCE_LEN); + + ret = hmac_sha256(dev_ik->dik_data, dev_ik->dik_len, data, sizeof(data), + dira_tag); + if (ret < 0) { + wpa_printf(MSG_ERROR, "Could not derive DIRA tag, err = %d", ret); + return -1; + } + + dev_ik->dira_nonce_len = DEVICE_IDENTITY_NONCE_LEN; + os_memcpy(dev_ik->dira_nonce, dira_nonce, DEVICE_IDENTITY_NONCE_LEN); + dev_ik->dira_tag_len = DEVICE_IDENTITY_TAG_LEN; + os_memcpy(dev_ik->dira_tag, dira_tag, DEVICE_IDENTITY_TAG_LEN); + + wpa_hexdump_key(MSG_DEBUG, "P2P: DIK", dev_ik->dik_data, + dev_ik->dik_len); + wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-NONCE", dev_ik->dira_nonce, + dev_ik->dira_nonce_len); + wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-TAG", dev_ik->dira_tag, + dev_ik->dira_tag_len); + return 0; +} + +void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p) +{ + u8 *len; + struct p2p_id_key *dev_ik; + + if (!p2p->cfg->pairing_config.pairing_capable || + !p2p->cfg->pairing_config.enable_pairing_cache || + !p2p->cfg->pairing_config.enable_pairing_verification) + return; + + if (p2p_derive_nonce_tag(p2p)) + return; + + dev_ik = &p2p->pairing_info->dev_ik; + /* P2P DIRA */ + wpabuf_put_u8(buf, P2P_ATTR_DEVICE_IDENTITY_RESOLUTION); + /* Length to be filled */ + len = wpabuf_put(buf, 2); + + wpabuf_put_u8(buf, dev_ik->cipher_version); + wpabuf_put_data(buf, dev_ik->dira_nonce, dev_ik->dira_nonce_len); + wpabuf_put_data(buf, dev_ik->dira_tag, dev_ik->dira_tag_len); + + /* Update attribute length */ + WPA_PUT_LE16(len, (u8 *)wpabuf_put(buf, 0) - len - 2); + + wpa_printf(MSG_DEBUG, "P2P: * Added DIRA"); +} + static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, const char *val) { diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 381a02e..0879add 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -161,6 +161,28 @@ struct p2p_sd_query { }; +/* This is p2p device identity key params */ +struct p2p_id_key { + /* AKMP used for DevIK derviation */ + int akmp; + /* cipher version type */ + int cipher_version; + /* DevIK expiration time in seconds */ + u32 expiration; + /* buffer to hold the DevIK */ + u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN]; + /* length of DevIK */ + size_t dik_len; + /* nonce used in DIRA attribute */ + u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN]; + /* length of nonce */ + size_t dira_nonce_len; + /* tag computed for nonce using NIK */ + u8 dira_tag[DEVICE_IDENTITY_TAG_LEN]; + /* length of tag */ + size_t dira_tag_len; +}; + struct p2p_pairing_info { /* P2P device own address */ u8 own_addr[ETH_ALEN]; @@ -170,6 +192,8 @@ struct p2p_pairing_info { u32 enable_pairing_cache; /* device supported bootstrapping */ u16 supported_bootstrap; + /* p2p device identity key info */ + struct p2p_id_key dev_ik; }; /** @@ -807,6 +831,7 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p); void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, size_t cookie_len, int comeback_after); +void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p); int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, int all_attr); void p2p_buf_add_pref_channel_list(struct wpabuf *buf, -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:04 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:04 +0530 Subject: [PATCH v3 06/25] P2P: Add freq list to subscriber to search for publisher on mutli channels In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-7-git-send-email-quic_shivbara@quicinc.com> Add freq list to active NAN USD subscriber to search for a publisher on multiple channels. These are the publish channel list used by the subscriber to periodically search for a service on these channels. In P2P2 seeker is an active subscriber looking for advertiser on list of publish channels. Signed-off-by: Shivani Baranwal --- src/common/nan_de.c | 11 +++++++++++ src/common/nan_de.h | 3 +++ wpa_supplicant/ctrl_iface.c | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/common/nan_de.c b/src/common/nan_de.c index 5a68cc9..938a357 100644 --- a/src/common/nan_de.c +++ b/src/common/nan_de.c @@ -1355,6 +1355,17 @@ int nan_de_subscribe(struct nan_de *de, const char *service_name, if (nan_de_derive_service_id(srv) < 0) goto fail; os_memcpy(&srv->subscribe, params, sizeof(*params)); + + if (params->freq_list) { + size_t len; + + len = (int_array_len(params->freq_list) + 1) * sizeof(int); + srv->freq_list = os_memdup(params->freq_list, len); + if (!srv->freq_list) + goto fail; + } + srv->subscribe.freq_list = NULL; + srv->srv_proto_type = srv_proto_type; if (ssi) { srv->ssi = wpabuf_dup(ssi); diff --git a/src/common/nan_de.h b/src/common/nan_de.h index bdac284..73f6c9c 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -125,6 +125,9 @@ struct nan_subscribe_params { /* Selected frequency */ unsigned int freq; + /* Multi-channel frequencies (publishChannelList) */ + const int *freq_list; + /* Query period in ms; 0 = use default */ unsigned int query_period; }; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index f3d74a8..5588e79 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12373,6 +12373,7 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, struct wpabuf *ssi = NULL; int ret = -1; enum nan_service_protocol_type srv_proto_type = 0; + int *freq_list = NULL; bool p2p = false; os_memset(¶ms, 0, sizeof(params)); @@ -12399,6 +12400,27 @@ static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, continue; } + if (os_strncmp(token, "freq_list=", 10) == 0) { + char *pos = token + 10; + + if (os_strcmp(pos, "all") == 0) { + os_free(freq_list); + freq_list = wpas_nan_usd_all_freqs(wpa_s); + params.freq_list = freq_list; + continue; + } + + while (pos && pos[0]) { + int_array_add_unique(&freq_list, atoi(pos)); + pos = os_strchr(pos, ','); + if (pos) + pos++; + } + + params.freq_list = freq_list; + continue; + } + if (os_strncmp(token, "srv_proto_type=", 15) == 0) { srv_proto_type = atoi(token + 15); continue; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:05 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:05 +0530 Subject: [PATCH v3 07/25] P2P: Allow to process Element container attr from NAN SDFs In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-8-git-send-email-quic_shivbara@quicinc.com> Extend support to process element container attribute from NAN SDF frames and check if P2P attributes are present. Add P2P device entry if the NAN SDF frames has matching service and P2P capabilities. Signed-off-by: Shivani Baranwal --- src/common/ieee802_11_common.c | 5 +++ src/common/ieee802_11_common.h | 2 ++ src/common/ieee802_11_defs.h | 2 ++ src/common/nan_de.c | 37 ++++++++++++++++++++++ src/common/nan_de.h | 4 +++ src/p2p/p2p.c | 66 +++++++++++++++++++++++++++++++++++++++ src/p2p/p2p.h | 16 +++++++++- src/p2p/p2p_i.h | 9 ++++++ src/p2p/p2p_parse.c | 34 ++++++++++++++++++++ src/p2p/p2p_pd.c | 37 ++++++++++++++++++++++ wpa_supplicant/nan_usd.c | 10 ++++++ wpa_supplicant/p2p_supplicant.c | 11 +++++++ wpa_supplicant/wpa_supplicant_i.h | 3 ++ 13 files changed, 235 insertions(+), 1 deletion(-) diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 3e6fba5..2d4540b 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -157,6 +157,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, elems->rsn_selection = pos + 4; elems->rsn_selection_len = elen - 4; break; + case P2P_2_OUI_TYPE: + /* Wi-Fi Alliance - P2P_2 IE */ + elems->p2p2_ie = pos; + elems->p2p2_ie_len = elen; + break; default: wpa_printf(MSG_MSGDUMP, "Unknown WFA " "information element ignored " diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index d4c691e..e4321b5 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -65,6 +65,7 @@ struct ieee802_11_elems { const u8 *vendor_ht_cap; const u8 *vendor_vht; const u8 *p2p; + const u8 *p2p2_ie; const u8 *wfd; const u8 *link_id; const u8 *interworking; @@ -139,6 +140,7 @@ struct ieee802_11_elems { u8 vendor_ht_cap_len; u8 vendor_vht_len; u8 p2p_len; + u8 p2p2_ie_len; u8 wfd_len; u8 interworking_len; u8 qos_map_set_len; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 452f2dc..8791318 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1719,6 +1719,8 @@ enum mbo_transition_reject_reason { /* Wi-Fi Direct (P2P) */ #define P2P_OUI_TYPE 9 +#define P2P_2_OUI_TYPE 0x28 + enum p2p_attr_id { P2P_ATTR_STATUS = 0, diff --git a/src/common/nan_de.c b/src/common/nan_de.c index 938a357..b1f798c 100644 --- a/src/common/nan_de.c +++ b/src/common/nan_de.c @@ -778,6 +778,33 @@ static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id, } +void nan_de_process_elem_container(struct nan_de *de, const u8 *buf, size_t len, + const u8 *peer_addr, unsigned int freq, + bool p2p) +{ + const u8 *elem; + u16 elem_len; + + elem = nan_de_get_attr(buf, len, NAN_ATTR_ELEM_CONTAINER, 0); + if (!elem) + return; + + elem++; + elem_len = WPA_GET_LE16(elem); + elem += 2; + if (elem_len < 1 + 2) + return; + + /* Skip Map ID */ + elem++; + elem_len--; + + if (p2p && de->cb.process_p2p_usd_elems) + de->cb.process_p2p_usd_elems(de->cb.ctx, elem, elem_len, + peer_addr, freq); +} + + static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, const u8 *peer_addr, u8 instance_id, u8 req_instance_id, u16 sdea_control, @@ -791,6 +818,9 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, nan_de_run_timer(de); } + if (de->offload) + goto offload; + if (srv->subscribe.active && req_instance_id == 0) { /* Active subscriber replies with a Subscribe message if it * received a matching unsolicited Publish message. */ @@ -805,6 +835,7 @@ static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, instance_id); } +offload: if (de->cb.discovery_result) de->cb.discovery_result( de->cb.ctx, srv->id, srv_proto_type, @@ -877,6 +908,9 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, return; } + if (de->offload) + goto offload; + /* Reply with a solicited Publish message */ /* Service Descriptor attribute */ sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; @@ -943,6 +977,7 @@ static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, nan_de_pause_state(srv, peer_addr, instance_id); +offload: if (!srv->publish.disable_events && de->cb.replied) de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id, srv_proto_type, ssi, ssi_len); @@ -1098,6 +1133,8 @@ static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", ssi, ssi_len); } + nan_de_process_elem_container(de, buf, len, peer_addr, + freq, srv->is_p2p); } switch (type) { diff --git a/src/common/nan_de.h b/src/common/nan_de.h index 73f6c9c..f369a57 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -53,6 +53,10 @@ struct nan_callbacks { void (*receive)(void *ctx, int id, int peer_instance_id, const u8 *ssi, size_t ssi_len, const u8 *peer_addr); + + void (*process_p2p_usd_elems)(void *ctx, const u8 *buf, + u16 buf_len, const u8 *peer_addr, + unsigned int freq); }; struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap, diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 73fcb16..023479b 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -5774,3 +5774,69 @@ struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) return buf; } + +void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, + const u8 *peer_addr, unsigned int freq) +{ + struct p2p_device *dev; + struct p2p_message msg; + const u8 *p2p_dev_addr; + + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_ies(ies, ies_len, &msg)) { + p2p_dbg(p2p, "Failed to parse P2P IE for a device entry"); + p2p_parse_free(&msg); + return; + } + if (msg.p2p_device_addr) + p2p_dev_addr = msg.p2p_device_addr; + else + p2p_dev_addr = peer_addr; + + dev = p2p_create_device(p2p, p2p_dev_addr); + if (!dev) { + p2p_parse_free(&msg); + p2p_dbg(p2p, "P2P Device Add failure"); + return; + } + + /* Reset info from old IEs */ + dev->info.reg_info = 0; + memset(&dev->info.pairing_config, 0, sizeof(struct p2p_pairing_config)); + + os_get_reltime(&dev->last_seen); + dev->listen_freq = freq; + dev->oper_freq = freq; + + if (msg.capability) { + /* + * P2P Client Discoverability bit is reserved in all frames + * that use this function, so do not change its value here. + */ + dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; + dev->info.dev_capab |= msg.capability[0] & + ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; + dev->info.group_capab = msg.capability[1]; + } + + if (msg.pcea_info && msg.pcea_info_len >= 2) + p2p_process_pcea(p2p, &msg, dev); + + if (msg.pbma_info && msg.pbma_info_len == 2) + dev->info.pairing_config.bootstrap_methods = + WPA_GET_LE16(msg.pbma_info); + + if (!ether_addr_equal(peer_addr, p2p_dev_addr)) + os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN); + + p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR + " dev_capab=0x%x group_capab=0x%x listen_freq=%d", + MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab, + dev->info.group_capab, dev->listen_freq); + + p2p->cfg->dev_found(p2p->cfg->cb_ctx, + dev->info.p2p_device_addr, + &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE)); + + p2p_parse_free(&msg); +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index b7d05e9..a092887 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -466,6 +466,19 @@ struct p2p_peer_info { * p2ps_instance - P2PS Application Service Info */ struct wpabuf *p2ps_instance; + + /* capability info in PCEA attribute */ + u16 pcea_cap_info; + + /** + * The regulatory info encoding for operation in 6 GHz band + */ + u8 reg_info; + + /** + * p2p_pairing_config - P2P Pairing configuration + */ + struct p2p_pairing_config pairing_config; }; enum p2p_prov_disc_status { @@ -2505,5 +2518,6 @@ void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value); int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size); int p2p_channel_to_freq(int op_class, int channel); struct wpabuf * p2p_usd_elems(struct p2p_data *p2p); - +void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, + const u8 *peer_addr, unsigned int freq); #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 0879add..b007692 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -599,6 +599,7 @@ struct p2p_data { */ struct p2p_message { struct wpabuf *p2p_attributes; + struct wpabuf *p2p2_attributes; struct wpabuf *wps_attributes; struct wpabuf *wfd_subelems; @@ -697,6 +698,12 @@ struct p2p_message { const u8 *pref_freq_list; size_t pref_freq_list_len; + + const u8 *pcea_info; + size_t pcea_info_len; + + const u8 *pbma_info; + size_t pbma_info_len; }; @@ -878,6 +885,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq); void p2p_reset_pending_pd(struct p2p_data *p2p); void p2ps_prov_free(struct p2p_data *p2p); +void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, + struct p2p_device *dev); /* p2p_invitation.c */ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index 07d6ca0..a70e180 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -417,6 +417,26 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, msg->persistent_ssid_len)); break; } + case P2P_ATTR_CAPABILITY_EXTENSION: + if (len < 2) { + wpa_printf(MSG_DEBUG, "P2P: Too short PCEA (length %d)", + len); + return -1; + } + msg->pcea_info = data; + msg->pcea_info_len = len; + wpa_printf(MSG_DEBUG, "P2P: * PCEA (length=%u)", len); + break; + case P2P_ATTR_PAIRING_AND_BOOTSTRAPPING: + if (len < 1) { + wpa_printf(MSG_DEBUG, "P2P: Too short PBMA (length %d)", + len); + return -1; + } + msg->pbma_info = data; + msg->pbma_info_len = len; + wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len); + break; default: wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " "(length %d)", id, len); @@ -573,6 +593,18 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) return -1; } + msg->p2p2_attributes = ieee802_11_vendor_ie_concat(data, len, + P2P2_IE_VENDOR_TYPE); + if (msg->p2p2_attributes && + p2p_parse_p2p_ie(msg->p2p2_attributes, msg)) { + wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P2 IE data"); + if (msg->p2p2_attributes) + wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P2 IE data", + msg->p2p2_attributes); + p2p_parse_free(msg); + return -1; + } + #ifdef CONFIG_WIFI_DISPLAY if (elems.wfd) { msg->wfd_subelems = ieee802_11_vendor_ie_concat( @@ -647,6 +679,8 @@ void p2p_parse_free(struct p2p_message *msg) { wpabuf_free(msg->p2p_attributes); msg->p2p_attributes = NULL; + wpabuf_free(msg->p2p2_attributes); + msg->p2p2_attributes = NULL; wpabuf_free(msg->wps_attributes); msg->wps_attributes = NULL; #ifdef CONFIG_WIFI_DISPLAY diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 542521e..e0c58c1 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -562,6 +562,43 @@ do { \ return 0; } +void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, + struct p2p_device *dev) +{ + const u8 *pos; + u8 cap_info_len; + + if (!p2p || !dev || !msg || !msg->pcea_info) + return; + + pos = msg->pcea_info; + dev->info.pcea_cap_info = WPA_GET_LE16(pos); + cap_info_len = dev->info.pcea_cap_info & P2P_PCEA_LEN_MASK; + + /* Field length is (n-1), n in octets */ + pos += cap_info_len + 1; + + if (dev->info.pcea_cap_info & P2P_PCEA_6GHZ) + dev->support_6ghz = true; + + if (dev->info.pcea_cap_info & P2P_PCEA_REG_INFO) + dev->info.reg_info = *pos++; + + if (dev->info.pcea_cap_info & P2P_PCEA_PASN_TYPE) + dev->info.pairing_config.pasn_type = *pos++; + + if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_CAPABLE) + dev->info.pairing_config.pairing_capable = 1; + + if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_SETUP_ENABLE) + dev->info.pairing_config.enable_pairing_setup = 1; + + if (dev->info.pcea_cap_info & P2P_PCEA_PMK_CACHING) { + dev->info.pairing_config.enable_pairing_cache = 1; + dev->info.pairing_config.enable_pairing_verification = 1; + } +} + void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c index eb84019..04ebec9 100644 --- a/wpa_supplicant/nan_usd.c +++ b/wpa_supplicant/nan_usd.c @@ -335,6 +335,15 @@ static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id, os_free(ssi_hex); } +static void wpas_nan_process_p2p_usd_elems(void *ctx, const u8 *buf, + u16 buf_len, const u8 *peer_addr, + unsigned int freq) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_p2p_process_usd_elems(wpa_s, buf, buf_len, peer_addr, freq); +} + int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) { @@ -350,6 +359,7 @@ int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) cb.publish_terminated = wpas_nan_de_publish_terminated; cb.subscribe_terminated = wpas_nan_de_subscribe_terminated; cb.receive = wpas_nan_de_receive; + cb.process_p2p_usd_elems = wpas_nan_process_p2p_usd_elems; wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false, &cb); if (!wpa_s->nan_de) diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index f92a608..d756d28 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -10281,3 +10281,14 @@ struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s) return NULL; return p2p_usd_elems(p2p); } + +void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf, + u16 buf_len, const u8 *peer_addr, + unsigned int freq) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + + if (wpa_s->global->p2p_disabled || !p2p) + return; + p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq); +} diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 7f9d722..47a1151 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -2022,5 +2022,8 @@ bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid, const u8 **ssid, size_t *ssid_len); +void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf, + u16 buf_len, const u8 *peer_addr, + unsigned int freq); #endif /* WPA_SUPPLICANT_I_H */ -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:03 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:03 +0530 Subject: [PATCH v3 05/25] P2P: Add config support to fetch Device Identity key In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-6-git-send-email-quic_shivbara@quicinc.com> Generate a random device identity key and save it to the config file. Use the same identity key from config to derive DIRA of NAN SDF frames. Signed-off-by: Shivani Baranwal --- wpa_supplicant/config.c | 4 ++++ wpa_supplicant/config.h | 9 +++++++++ wpa_supplicant/config_file.c | 8 +++++++- wpa_supplicant/p2p_supplicant.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b02b694..d0957eb 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3095,6 +3095,7 @@ void wpa_config_free(struct wpa_config *config) os_free(config->dpp_mud_url); os_free(config->dpp_extra_conf_req_name); os_free(config->dpp_extra_conf_req_value); + os_free(config->dik_data); os_free(config); } @@ -5595,6 +5596,9 @@ static const struct global_parse_data global_fields[] = { /* NOTE: When adding new parameters here, add_interface() in * wpa_supplicant/dbus_new_introspect.c may need to be modified to * increase the size of the iface->xml buffer. */ + { INT(dik_cipher), 0}, + { INT(dik_len), 0}, + { STR(dik_data), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index d74b5c4..6b8f0cb 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1814,6 +1814,15 @@ struct wpa_config { int mld_force_single_link; #endif /* CONFIG_TESTING_OPTIONS */ + + /* cipher version type */ + int dik_cipher; + + /* buffer to hold the DevIK */ + char *dik_data; + + /* length of DevIK */ + size_t dik_len; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index fd8eafe..68aed57 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1628,7 +1628,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) MAC2STR(config->mld_connect_bssid_pref)); #endif /* CONFIG_TESTING_OPTIONS */ if (config->ft_prepend_pmkid) - fprintf(f, "ft_prepend_pmkid=%d", config->ft_prepend_pmkid); + fprintf(f, "ft_prepend_pmkid=%d\n", config->ft_prepend_pmkid); + if (config->dik_len) { + fprintf(f, "dik_cipher=%d\n", config->dik_cipher); + fprintf(f, "dik_len=%ld\n", config->dik_len); + if (config->dik_data) + fprintf(f, "dik_data=%s\n", config->dik_data); + } } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 2df2d10..f92a608 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -37,6 +37,7 @@ #include "wps_supplicant.h" #include "p2p_supplicant.h" #include "wifi_display.h" +#include "crypto/random.h" /* @@ -5057,6 +5058,34 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) else p2p.passphrase_len = 8; + if (wpa_s->conf->dik_len && wpa_s->conf->dik_data) { + p2p.pairing_config.dik_cipher = wpa_s->conf->dik_cipher; + p2p.pairing_config.dik_len = wpa_s->conf->dik_len; + hexstr2bin(wpa_s->conf->dik_data, p2p.pairing_config.dik_data, + p2p.pairing_config.dik_len); + } else { + p2p.pairing_config.dik_cipher = DIRA_CIPHER_VERSION_128; + p2p.pairing_config.dik_len = DEVICE_IDENTITY_KEY_LEN; + random_get_bytes(p2p.pairing_config.dik_data, + p2p.pairing_config.dik_len); + + wpa_s->conf->dik_data = + os_zalloc(p2p.pairing_config.dik_len * 2 + 1); + if (!wpa_s->conf->dik_data) + return -1; + + wpa_snprintf_hex(wpa_s->conf->dik_data, + p2p.pairing_config.dik_len * 2 + 1, + p2p.pairing_config.dik_data, + p2p.pairing_config.dik_len); + wpa_s->conf->dik_len = p2p.pairing_config.dik_len; + wpa_s->conf->dik_cipher = p2p.pairing_config.dik_cipher; + + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) + wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); + } + global->p2p = p2p_init(&p2p); if (global->p2p == NULL) return -1; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:07 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:07 +0530 Subject: [PATCH v3 09/25] P2P: Add bootstrapping support with pd frames In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-10-git-send-email-quic_shivbara@quicinc.com> Add support for p2p2 bootstrapping with comeback mechanism using provision discovery frames. Add control iface to extend p2p_connect to allow p2p2 bootstrapping handshake. Signed-off-by: Shivani Baranwal --- src/common/ieee802_11_defs.h | 16 ++ src/p2p/p2p.c | 31 ++- src/p2p/p2p.h | 30 ++- src/p2p/p2p_build.c | 1 + src/p2p/p2p_go_neg.c | 2 + src/p2p/p2p_i.h | 40 ++- src/p2p/p2p_pd.c | 370 +++++++++++++++++++++++++++- wpa_supplicant/ctrl_iface.c | 28 ++- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2 +- wpa_supplicant/p2p_supplicant.c | 79 +++++- wpa_supplicant/p2p_supplicant.h | 3 +- wpa_supplicant/wpa_supplicant_i.h | 3 + 12 files changed, 574 insertions(+), 31 deletions(-) diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 8791318..0e88797 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1793,6 +1793,21 @@ enum p2p_attr_id { #define P2P_PCEA_PASN_TYPE BIT(11) #define P2P_PCEA_TWT_POWER_MGMT BIT(12) + +/* P2P Pairing Bootstrapping Method attribute - Bootstrapping Method */ +#define P2P_PBMA_OPPORTUNISTIC BIT(0) +#define P2P_PBMA_PIN_CODE_DISPLAY BIT(1) +#define P2P_PBMA_PASSPHRASE_DISPLAY BIT(2) +#define P2P_PBMA_QR_DISPLAY BIT(3) +#define P2P_PBMA_NFC_TAG BIT(4) +#define P2P_PBMA_PIN_CODE_KEYPAD BIT(5) +#define P2P_PBMA_PASSPHRASE_KEYPAD BIT(6) +#define P2P_PBMA_QR_SCAN BIT(7) +#define P2P_PBMA_NFC_READER BIT(8) +#define P2P_PBMA_SERVICE_MANAGED BIT(14) +#define P2P_PBMA_HANDSHAKE_SHIP BIT(15) + + /* P2PS Coordination Protocol Transport Bitmap */ #define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0) #define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1) @@ -1824,6 +1839,7 @@ enum p2p_status_code { P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, P2P_SC_FAIL_REJECTED_BY_USER = 11, P2P_SC_SUCCESS_DEFERRED = 12, + P2P_SC_COMEBACK = 13, }; enum p2p_role_indication { diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index ba2708d..a66f0c4 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -954,6 +954,11 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) dev->info.wps_vendor_ext[i] = NULL; } + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + wpabuf_free(dev->info.wfd_subelems); wpabuf_free(dev->info.vendor_elems); wpabuf_free(dev->go_neg_conf); @@ -1599,7 +1604,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id) + int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id, + bool p2p2, u16 bootstrap, const char *password) { struct p2p_device *dev; @@ -1683,6 +1689,12 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, dev->wps_method = wps_method; dev->oob_pw_id = oob_pw_id; + dev->p2p2 = p2p2; + dev->req_bootstrap_method = bootstrap; + if (password) { + strcpy(dev->password, password); + dev->password_len = strlen(password); + } dev->status = P2P_SC_SUCCESS; if (p2p->p2p_scan_running) { @@ -1701,7 +1713,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id) + unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap, + const char *password) { struct p2p_device *dev; @@ -1735,6 +1748,12 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, dev->flags &= ~P2P_DEV_USER_REJECTED; dev->go_neg_req_sent = 0; dev->go_state = UNKNOWN_GO; + dev->req_bootstrap_method = bootstrap; + + if (password) { + strcpy(dev->password, password); + dev->password_len = strlen(password); + } p2p_set_dev_persistent(dev, persistent_group); p2p->go_intent = go_intent; os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); @@ -1927,7 +1946,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_PROV_DISC_RESP: - p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1); + p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_DEV_DISC_REQ: p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); @@ -3054,6 +3073,9 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->go_timeout = 100; p2p->client_timeout = 20; p2p->num_p2p_sd_queries = 0; + /*Default comeback after 1 sec */ + if (!p2p->cfg->comeback_after) + p2p->cfg->comeback_after = 1024; p2p_pairing_info_init(p2p); p2p_dbg(p2p, "initialized"); @@ -3436,7 +3458,7 @@ static void p2p_retry_pd(struct p2p_data *p2p) if (!ether_addr_equal(p2p->pending_pd_devaddr, dev->info.p2p_device_addr)) continue; - if (!dev->req_config_methods) + if (!dev->req_config_methods && !dev->req_bootstrap_method) continue; p2p_dbg(p2p, "Send pending Provision Discovery Request to " @@ -5800,6 +5822,7 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, return; } + dev->p2p2 = true; /* Reset info from old IEs */ dev->info.reg_info = 0; memset(&dev->info.pairing_config, 0, sizeof(struct p2p_pairing_config)); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index a092887..5e7d1b7 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -678,6 +678,13 @@ struct p2p_config { bool twt_power_mgmt; /** + * comeback_after - Bootstrap request unauthorised for peer, + * ask to comeback after given time in ms + */ + u16 comeback_after; + + + /** * cb_ctx - Context to use with callback functions */ void *cb_ctx; @@ -1224,6 +1231,19 @@ struct p2p_config { int (*get_pref_freq_list)(void *ctx, int go, unsigned int *len, struct weighted_pcl *freq_list); + + /** + * register_bootstrap_comeback - register timeout to initiate bootstrap + * comeback request + * @ctx: Callback context from cb_ctx + * @addr: p2p device address to which comeback request to be sent + * @comeback_after: time in ms after which comeback request is sent + * + * This function can be used to send comeback request after given + * timeout. + */ + void (*register_bootstrap_comeback)(void *ctx, const u8 *addr, + u16 comeback_after); }; @@ -1407,6 +1427,10 @@ void p2p_stop_listen(struct p2p_data *p2p); * formation * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if * force_freq == 0) + * @oob_pw_id: oob password identifier + * @p2p2: Device supports p2p2 features + * @bootstrap: Bootstrapping method requested for p2p2 provision discovery + * @password: p2p2 pairing password or NULL for opportunistic method * Returns: 0 on success, -1 on failure */ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, @@ -1414,7 +1438,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id); + int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id, + bool p2p2, u16 bootstrap, const char *password); /** * p2p_authorize - Authorize P2P group formation (GO negotiation) @@ -1442,7 +1467,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, const u8 *force_ssid, size_t force_ssid_len, - unsigned int pref_freq, u16 oob_pw_id); + unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap, + const char *password); /** * p2p_reject - Reject peer device (explicitly block connection attempts) diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 347e8a1..182af37 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -796,6 +796,7 @@ void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie, wpabuf_put_u8(buf, cookie_len); wpabuf_put_data(buf, cookie, cookie_len); } + wpabuf_put_le16(buf, bootstrap); /* Update attribute length */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 30901b3..04e5139 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -244,6 +244,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev) config_method = WPS_CONFIG_PUSHBUTTON; else if (dev->wps_method == WPS_P2PS) config_method = WPS_CONFIG_P2PS; + else if (dev->p2p2 && dev->req_bootstrap_method) + config_method = WPS_NOT_READY; else return -1; return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr, diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 2118052..ef2bb9d 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -36,6 +36,28 @@ enum p2p_go_state { REMOTE_GO }; + +/** + * struct bootstrap_params - P2P Device bootstrap request params + */ + +struct p2p_bootstrap_params { + /* bootstrap method */ + u16 bootstrap_method; + + /* status code */ + enum p2p_status_code status; + + /* cookie for comeback */ + u8 cookie[50]; + + /* cookie length */ + size_t cookie_len; + + /* Comeback time in TUs after which receiver is requested to retry */ + int comeback_after; +}; + /** * struct p2p_device - P2P Device data (internal to P2P module) */ @@ -150,6 +172,22 @@ struct p2p_device { int sd_pending_bcast_queries; bool support_6ghz; + + /* support p2p2 */ + bool p2p2; + + /* requested bootstrap method */ + u16 req_bootstrap_method; + + /* bootstrap params received from peer */ + struct p2p_bootstrap_params *bootstrap_params; + + /* password for p2p2 go negotiation */ + char password[100]; + /** + * password length. Non zero if valid + */ + u16 password_len; }; struct p2p_sd_query { @@ -880,7 +918,7 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq); void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); + const u8 *data, size_t len, int rx_freq); int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq); void p2p_reset_pending_pd(struct p2p_data *p2p); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index b91b6c3..c0b7411 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -14,6 +14,7 @@ #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" +#include "crypto/random.h" /* @@ -180,6 +181,62 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, } } +static struct wpabuf * p2p_build_prov_disc_bootstrap_req(struct p2p_data *p2p, + struct p2p_device *dev) +{ + struct wpabuf *buf; + u8 *len; + size_t cookie_len = 0; + const u8 *cookie = NULL; + u8 dialog_token = dev->dialog_token; + u8 group_capab; + + buf = wpabuf_alloc(1000); + if (buf == NULL) + return NULL; + + wpa_printf(MSG_DEBUG, "P2P2: Building bootstrapping PD req"); + p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); + + len = p2p_buf_add_ie_hdr(buf); + + group_capab = 0; + + if (p2p->num_groups) { + group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; + if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && + (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && + p2p->cross_connect) + group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; + } + if (p2p->cfg->p2p_intra_bss) + group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; + + p2p_buf_add_capability(buf, p2p->dev_capab & + ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, + group_capab); + p2p_buf_add_device_info(buf, p2p, NULL); + + if (dev->bootstrap_params) { + cookie = dev->bootstrap_params->cookie; + cookie_len = dev->bootstrap_params->cookie_len; + + if (dev->bootstrap_params->status == P2P_SC_COMEBACK) + p2p_buf_add_status(buf, dev->bootstrap_params->status); + } + + p2p_buf_update_ie_hdr(buf, len); + + len = p2p_buf_add_p2p2_ie_hdr(buf); + + p2p_buf_add_pcea(buf, p2p); + p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, 0); + + p2p_buf_update_p2p2_ie_hdr(buf, len); + + wpa_printf(MSG_DEBUG, "P2P2: Added PCEA and PBMA in PD req"); + return buf; +} static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, @@ -248,6 +305,40 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, return buf; } +static struct wpabuf * p2p_build_prov_disc_bootstrap_resp(struct p2p_data *p2p, + struct p2p_device *dev, + u8 dialog_token, + enum p2p_status_code status) +{ + struct wpabuf *buf; + u8 *cookie = NULL; + size_t cookie_len = 0; + int comeback_after = 0; + + buf = wpabuf_alloc(1000); + if (!buf) + return NULL; + + wpa_printf(MSG_DEBUG, "P2P2: Building boostrapping PD rsp"); + if (status == P2P_SC_COMEBACK && dev->bootstrap_params) { + cookie = dev->bootstrap_params->cookie; + cookie_len = dev->bootstrap_params->cookie_len; + comeback_after = dev->bootstrap_params->comeback_after; + } + + p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); + + u8 *len = p2p_buf_add_p2p2_ie_hdr(buf); + + p2p_buf_add_status(buf, status); + p2p_buf_add_pcea(buf, p2p); + p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, + comeback_after); + + p2p_buf_update_p2p2_ie_hdr(buf, len); + + return buf; +} static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, struct p2p_device *dev, @@ -600,6 +691,164 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, } +static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p, + struct p2p_message *msg, + const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + struct p2p_device *dev; + int freq; + struct wpabuf *resp; + u16 bootstrap; + size_t cookie_len = 0; + const u8 *pos, *cookie; + enum p2p_status_code status = P2P_SC_FAIL_INVALID_PARAMS; + + p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR + " with bootstrapping Attribute (freq=%d)", + MAC2STR(sa), rx_freq); + + dev = p2p_get_device(p2p, sa); + if (!dev) { + p2p_dbg(p2p, "Provision Discovery Request from unknown peer " + MACSTR, MAC2STR(sa)); + + if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) { + p2p_dbg(p2p, "Provision Discovery Request add device failed " + MACSTR, MAC2STR(sa)); + return; + } + + dev = p2p_get_device(p2p, sa); + if (!dev) { + p2p_dbg(p2p, + "Provision Discovery device not found " + MACSTR, MAC2STR(sa)); + return; + } + } + dev->p2p2 = true; + + if (p2p->send_action_in_progress) { + p2p_dbg(p2p, "Dropping retry frame as response tx pending"); + return; + } + + + p2p_update_peer_6ghz_capab(dev, msg); + + if (msg->pcea_info && msg->pcea_info_len >= 2) + p2p_process_pcea(p2p, msg, dev); + + pos = msg->pbma_info; + + if (msg->pbma_info_len > 2 && msg->status && + *msg->status == P2P_SC_COMEBACK) { + /* PBMA comeback request */ + cookie_len = *pos++; + cookie = pos; + + if (!dev->bootstrap_params || + dev->bootstrap_params->cookie_len != cookie_len || + memcmp(cookie, dev->bootstrap_params->cookie, cookie_len)) { + status = P2P_SC_FAIL_REJECTED_BY_USER; + goto out; + } + + bootstrap = dev->bootstrap_params->bootstrap_method; + + if (!dev->req_bootstrap_method) { + status = P2P_SC_COMEBACK; + goto out; + } + } else { + /* PBMA request */ + bootstrap = WPA_GET_LE16(pos); + + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + + if (!dev->req_bootstrap_method) { + dev->bootstrap_params = + os_zalloc(sizeof(struct p2p_bootstrap_params)); + if (!dev->bootstrap_params) + return; + dev->bootstrap_params->bootstrap_method = bootstrap; + dev->bootstrap_params->cookie_len = 4; + random_get_bytes(dev->bootstrap_params->cookie, + dev->bootstrap_params->cookie_len); + dev->bootstrap_params->comeback_after = + p2p->cfg->comeback_after; + status = P2P_SC_COMEBACK; + goto out; + } + } + + if (bootstrap == P2P_PBMA_PIN_CODE_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_KEYPAD) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PIN_CODE_KEYPAD && + dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PASSPHRASE_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_KEYPAD) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_PASSPHRASE_KEYPAD && + dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_NFC_TAG && + dev->req_bootstrap_method == P2P_PBMA_NFC_READER) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_NFC_READER && + dev->req_bootstrap_method == P2P_PBMA_NFC_TAG) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_QR_DISPLAY && + dev->req_bootstrap_method == P2P_PBMA_QR_SCAN) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_QR_SCAN && + dev->req_bootstrap_method == P2P_PBMA_QR_DISPLAY) + status = P2P_SC_SUCCESS; + else if (bootstrap == P2P_PBMA_OPPORTUNISTIC && + dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC) + status = P2P_SC_SUCCESS; + else + status = P2P_SC_FAIL_INVALID_PARAMS; + + wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap); + +out: + /* + * Send PD Bootstrapping Response for the PD Request + */ + resp = p2p_build_prov_disc_bootstrap_resp(p2p, dev, msg->dialog_token, + status); + if (!resp) + return; + + p2p_dbg(p2p, "Sending Provision Discovery Bootstrap Response"); + if (rx_freq > 0) + freq = rx_freq; + else + freq = p2p_channel_to_freq(p2p->cfg->reg_class, + p2p->cfg->channel); + if (freq < 0) { + p2p_dbg(p2p, "Unknown regulatory class/channel"); + wpabuf_free(resp); + return; + } + p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; + if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, + p2p->cfg->dev_addr, wpabuf_head(resp), + wpabuf_len(resp), 50) < 0) + p2p_dbg(p2p, "Failed to send Action frame"); + else + p2p->send_action_in_progress = 1; + + wpabuf_free(resp); +} + static void p2p_process_prov_disc_req(struct p2p_data *p2p, struct p2p_message *msg, const u8 *sa, const u8 *data, size_t len, int rx_freq) @@ -1241,7 +1490,13 @@ void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, if (p2p_parse(data, len, &msg)) return; - p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, rx_freq); + if (msg.pcea_info && msg.pbma_info) + p2p_process_prov_disc_bootstrap_req(p2p, &msg, sa, data + 1, + len - 1, rx_freq); + else + p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, + rx_freq); + p2p_parse_free(&msg); } @@ -1344,6 +1599,88 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, } +static void p2p_process_prov_disc_bootstrap_resp(struct p2p_data *p2p, + struct p2p_message *msg, + const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + struct p2p_device *dev; + u8 status = P2P_SC_SUCCESS; + size_t cookie_len = 0; + const u8 *pos, *cookie; + u16 comeback_after; + + /* Parse the P2P status present */ + if (msg->status) + status = *msg->status; + + p2p_dbg(p2p, "Received Provision Discovery Bootstrap Response from " MACSTR, + MAC2STR(sa)); + + dev = p2p_get_device(p2p, sa); + if (!dev || !dev->req_bootstrap_method) { + p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR + " with no pending request", MAC2STR(sa)); + return; + } + + p2p_update_peer_6ghz_capab(dev, msg); + + if (dev->dialog_token != msg->dialog_token) { + p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", + msg->dialog_token, dev->dialog_token); + return; + } + + if (p2p->pending_action_state == P2P_PENDING_PD) { + os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); + p2p->pending_action_state = P2P_NO_PENDING_ACTION; + } + + if (dev->bootstrap_params) { + os_free(dev->bootstrap_params); + dev->bootstrap_params = NULL; + } + + /* + * If the response is from the peer to whom a user initiated request + * was sent earlier, we reset that state info here. + */ + if (p2p->user_initiated_pd && + ether_addr_equal(p2p->pending_pd_devaddr, sa)) + p2p_reset_pending_pd(p2p); + + if (status == P2P_SC_COMEBACK) { + /* PBMA comeback response */ + pos = msg->pbma_info; + comeback_after = WPA_GET_LE16(pos); + pos += 2; + cookie_len = *pos++; + cookie = pos; + + dev->bootstrap_params = + os_zalloc(sizeof(struct p2p_bootstrap_params)); + if (!dev->bootstrap_params) + return; + dev->bootstrap_params->cookie_len = cookie_len; + memcpy(dev->bootstrap_params->cookie, cookie, cookie_len); + dev->bootstrap_params->comeback_after = comeback_after; + dev->bootstrap_params->bootstrap_method = + dev->req_bootstrap_method; + dev->bootstrap_params->status = status; + + p2p->cfg->register_bootstrap_comeback(p2p->cfg->cb_ctx, sa, + comeback_after); + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); + return; + } + + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); + if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) + dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; +} + + static void p2p_process_prov_disc_resp(struct p2p_data *p2p, struct p2p_message *msg, const u8 *sa, const u8 *data, size_t len) @@ -1634,14 +1971,19 @@ out: void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) + const u8 *data, size_t len, int rx_freq) { struct p2p_message msg; if (p2p_parse(data, len, &msg)) return; - p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1); + if (msg.pcea_info && msg.pbma_info) + p2p_process_prov_disc_bootstrap_resp(p2p, &msg, sa, data + 1, + len - 1, rx_freq); + else + p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1); + p2p_parse_free(&msg); } @@ -1675,7 +2017,7 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, /* TODO: use device discoverability request through GO */ } - if (p2p->p2ps_prov) { + if (!dev->p2p2 && p2p->p2ps_prov) { if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) { if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY) dev->req_config_methods = WPS_CONFIG_KEYPAD; @@ -1705,7 +2047,11 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, return -1; } - req = p2p_build_prov_disc_req(p2p, dev, join); + if (dev->p2p2) + req = p2p_build_prov_disc_bootstrap_req(p2p, dev); + else + req = p2p_build_prov_disc_req(p2p, dev, join); + if (req == NULL) return -1; @@ -1744,13 +2090,22 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, return -1; } + if (dev->p2p2 && dev->req_bootstrap_method) { + p2p_dbg(p2p, "Provision Discovery Request with " MACSTR + " (bootstrap methods 0x%x)", + MAC2STR(peer_addr), dev->req_bootstrap_method); + goto out; + } + p2p_dbg(p2p, "Provision Discovery Request with " MACSTR " (config methods 0x%x)", MAC2STR(peer_addr), config_methods); + if (config_methods == 0 && !p2ps_prov) { os_free(p2ps_prov); return -1; } + dev->req_config_methods = config_methods; if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { @@ -1758,12 +2113,12 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, p2ps_prov->method = p2p->p2ps_prov->method; } +out: /* Reset provisioning info */ dev->wps_prov_info = 0; p2ps_prov_free(p2p); p2p->p2ps_prov = p2ps_prov; - dev->req_config_methods = config_methods; if (join) dev->flags |= P2P_DEV_PD_FOR_JOIN; else @@ -1772,8 +2127,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && p2p->state != P2P_LISTEN_ONLY) { p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with " - MACSTR " (config methods 0x%x)", - MAC2STR(peer_addr), config_methods); + MACSTR, MAC2STR(peer_addr)); return 0; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 5588e79..b223b7c 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -6376,6 +6376,10 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, size_t group_ssid_len = 0; int he; bool allow_6ghz; + bool p2p2; + u16 bootstrap = 0; + const char *password = NULL; + char *token, *context = NULL; if (!wpa_s->global->p2p_init_wpa_s) return -1; @@ -6388,7 +6392,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, /* <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] * [persistent|persistent=] * [join] [auth] [go_intent=<0..15>] [freq=] [provdisc] - * [ht40] [vht] [he] [edmg] [auto] [ssid=] */ + * [ht40] [vht] [he] [edmg] [auto] [ssid=] + * [p2p2] [bstrapmethod=] [password=] + */ if (hwaddr_aton(cmd, addr)) return -1; @@ -6422,6 +6428,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, vht; he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he; edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg; + p2p2 = os_strstr(pos, "p2p2") != NULL; pos2 = os_strstr(pos, " go_intent="); if (pos2) { @@ -6477,6 +6484,8 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, wps_method = WPS_PBC; } else if (os_strstr(pos, "p2ps") != NULL) { wps_method = WPS_P2PS; + } else if (p2p2) { + wps_method = WPS_NOT_READY; } else { pin = pos; pos = os_strchr(pin, ' '); @@ -6492,11 +6501,26 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, } } + pos2 = os_strstr(pos, "bstrapmethod="); + if (pos2) { + pos2 += 13; + bootstrap = atoi(pos2); + pd = true; + } + + while ((token = str_token(pos, " ", &context))) { + if (os_strncmp(token, "password=", 9) == 0) { + password = token + 9; + continue; + } + } + new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, automatic, join, auth, go_intent, freq, freq2, persistent_id, pd, ht40, vht, max_oper_chwidth, he, edmg, - group_ssid, group_ssid_len, allow_6ghz); + group_ssid, group_ssid_len, allow_6ghz, p2p2, + bootstrap, password); if (new_pin == -2) { os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25); return 25; diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 3de6ed8..65bd478 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -706,7 +706,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, persistent_group, 0, join, authorize_only, go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0, - NULL, 0, false); + NULL, 0, false, 0, 0, NULL); if (new_pin >= 0) { char npin[9]; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index d756d28..c524084 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -4823,6 +4823,39 @@ static int wpas_p2p_get_pref_freq_list(void *ctx, int go, WPA_IF_P2P_CLIENT, len, freq_list); } +static void wpas_p2p_send_bootstrap_comeback(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + wpa_printf(MSG_DEBUG, "P2P2: Send Bootstrapping comeback PD req"); + wpas_p2p_connect(wpa_s, wpa_s->p2p_bootstrap_dev_addr, wpa_s->p2p_pin, + wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, + 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq, + wpa_s->p2p_go_vht_center_freq2, + wpa_s->p2p_persistent_id, + wpa_s->p2p_pd_before_go_neg, + wpa_s->p2p_go_ht40, + wpa_s->p2p_go_vht, + wpa_s->p2p_go_max_oper_chwidth, + wpa_s->p2p_go_he, + wpa_s->p2p_go_edmg, + NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL); +} + +static void wpas_p2p_register_bootstrap_comeback(void *ctx, const u8 *addr, + u16 comeback_after) +{ + unsigned int timeout_us; + struct wpa_supplicant *wpa_s = ctx; + + timeout_us = comeback_after * 1024; + memcpy(wpa_s->p2p_bootstrap_dev_addr, addr, ETH_ALEN); + + eloop_cancel_timeout(wpas_p2p_send_bootstrap_comeback, wpa_s, NULL); + eloop_register_timeout(0, timeout_us, wpas_p2p_send_bootstrap_comeback, + wpa_s, NULL); +} int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) { @@ -4943,6 +4976,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.p2ps_group_capability = p2ps_group_capability; p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list; p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable; + p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); @@ -5222,7 +5256,8 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, - struct wpa_ssid *ssid, unsigned int pref_freq) + struct wpa_ssid *ssid, unsigned int pref_freq, + bool p2p2, u16 bootstrap, const char *password) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -5240,7 +5275,7 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, ssid ? ssid->ssid_len : 0, wpa_s->p2p_pd_before_go_neg, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : - 0); + 0, p2p2, bootstrap, password); } @@ -5249,7 +5284,8 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, enum p2p_wps_method wps_method, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group, - struct wpa_ssid *ssid, unsigned int pref_freq) + struct wpa_ssid *ssid, unsigned int pref_freq, + u16 bootstrap, const char *password) { if (persistent_group && wpa_s->conf->persistent_reconnect) persistent_group = 2; @@ -5259,7 +5295,7 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, persistent_group, ssid ? ssid->ssid : NULL, ssid ? ssid->ssid_len : 0, pref_freq, wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id : - 0); + 0, bootstrap, password); } @@ -5443,7 +5479,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, NULL, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p)); + is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, + NULL); return; } @@ -5937,6 +5975,9 @@ static bool is_p2p_6ghz_supported(struct wpa_supplicant *wpa_s, HOSTAPD_MODE_IEEE80211A, true)) return false; + if (wpa_s->p2p2) + return true; + if (!p2p_wfd_enabled(wpa_s->global->p2p)) return false; if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr)) @@ -5988,6 +6029,10 @@ static int wpas_p2p_check_6ghz(struct wpa_supplicant *wpa_s, * @group_ssid: Specific Group SSID for join or %NULL if not set * @group_ssid_len: Length of @group_ssid in octets * @allow_6ghz: Allow P2P connection on 6 GHz channels + * @p2p2: Device in P2P R2 mode + * @bootstrap: Requested bootstrap method for pairing in p2p2 + * @password: Password for pairing setup or NULL for oppurtunistic method + * in p2p2 * Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified * failure, -2 on failure due to channel not currently available, * -3 if forced channel is not supported @@ -5999,7 +6044,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, const u8 *group_ssid, size_t group_ssid_len, - bool allow_6ghz) + bool allow_6ghz, bool p2p2, u16 bootstrap, + const char *password) { int force_freq = 0, pref_freq = 0; int ret = 0, res; @@ -6019,6 +6065,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return -1; } + wpa_s->p2p2 = p2p2; + if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq)) return -2; @@ -6049,6 +6097,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_go_max_oper_chwidth = vht_chwidth; wpa_s->p2p_go_he = !!he; wpa_s->p2p_go_edmg = !!edmg; + wpa_s->p2p_bootstrap = bootstrap; if (pin) os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin)); @@ -6134,14 +6183,15 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, persistent_group, ssid, - pref_freq) < 0) + pref_freq, bootstrap, password) < 0) return -1; return ret; } if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent, if_addr, force_freq, - persistent_group, ssid, pref_freq) < 0) { + persistent_group, ssid, pref_freq, p2p2, + bootstrap, password) < 0) { if (wpa_s->create_p2p_iface) wpas_p2p_remove_pending_group_interface(wpa_s); return -1; @@ -8769,7 +8819,8 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); + NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL); return ret; } @@ -9307,7 +9358,8 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, params->go_ssid_len ? params->go_ssid : NULL, - params->go_ssid_len, false); + params->go_ssid_len, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); } @@ -9386,7 +9438,8 @@ static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, false); + NULL, 0, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); } @@ -9403,7 +9456,9 @@ static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s, forced_freq, wpa_s->p2p_go_vht_center_freq2, -1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth, wpa_s->p2p_go_he, wpa_s->p2p_go_edmg, - NULL, 0, false); + NULL, 0, false, wpa_s->p2p2, + wpa_s->p2p_bootstrap, NULL); + if (res) return res; diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 441e063..a2cb78d 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -39,7 +39,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int persistent_id, int pd, int ht40, int vht, unsigned int vht_chwidth, int he, int edmg, const u8 *group_ssid, size_t group_ssid_len, - bool allow_6ghz); + bool allow_6ghz, bool p2p2, u16 bootstrap, + const char *password); int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 47a1151..35f541f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1113,6 +1113,7 @@ struct wpa_supplicant { int pending_pd_before_join; u8 pending_join_iface_addr[ETH_ALEN]; u8 pending_join_dev_addr[ETH_ALEN]; + u8 p2p_bootstrap_dev_addr[ETH_ALEN]; int pending_join_wps_method; u8 p2p_join_ssid[SSID_MAX_LEN]; size_t p2p_join_ssid_len; @@ -1167,6 +1168,8 @@ struct wpa_supplicant { unsigned int p2ps_method_config_any:1; unsigned int p2p_cli_probe:1; unsigned int p2p_go_allow_dfs:1; + unsigned int p2p2:1; + u16 p2p_bootstrap; enum hostapd_hw_mode p2p_go_acs_band; int p2p_persistent_go_freq; int p2p_persistent_id; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:06 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:06 +0530 Subject: [PATCH v3 08/25] P2P: Cleanup of provision discovery req and resp processing In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-9-git-send-email-quic_shivbara@quicinc.com> Parse the p2p ies in handle provision discovery req and response functions and process the frames based on the ies received in the pd frames. Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 4 +- src/p2p/p2p_i.h | 8 +- src/p2p/p2p_pd.c | 358 ++++++++++++++++++++++++++++--------------------------- 3 files changed, 188 insertions(+), 182 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 023479b..ba2708d 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1924,10 +1924,10 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); break; case P2P_PROV_DISC_REQ: - p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); + p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_PROV_DISC_RESP: - p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1); + p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1); break; case P2P_DEV_DISC_REQ: p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index b007692..2118052 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -877,10 +877,10 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg); /* p2p_pd.c */ -void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); +void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq); +void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len); int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq); void p2p_reset_pending_pd(struct p2p_data *p2p); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index e0c58c1..b91b6c3 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -600,10 +600,10 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, } -void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) +static void p2p_process_prov_disc_req(struct p2p_data *p2p, + struct p2p_message *msg, const u8 *sa, + const u8 *data, size_t len, int rx_freq) { - struct p2p_message msg; struct p2p_device *dev; int freq; enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; @@ -624,21 +624,17 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, u8 remote_conncap; u16 method; - if (p2p_parse(data, len, &msg)) - return; - p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR " with config methods 0x%x (freq=%d)", - MAC2STR(sa), msg.wps_config_methods, rx_freq); - group_mac = msg.intended_addr; + MAC2STR(sa), msg->wps_config_methods, rx_freq); + group_mac = msg->intended_addr; dev = p2p_get_device(p2p, sa); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { p2p_dbg(p2p, "Provision Discovery Request from unknown peer " MACSTR, MAC2STR(sa)); - if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, - 0)) { + if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) { p2p_dbg(p2p, "Provision Discovery Request add device failed " MACSTR, MAC2STR(sa)); goto out; @@ -651,29 +647,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, MACSTR, MAC2STR(sa)); goto out; } - } else if (msg.wfd_subelems) { + } else if (msg->wfd_subelems) { wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems); } - p2p_update_peer_6ghz_capab(dev, &msg); + p2p_update_peer_6ghz_capab(dev, msg); - if (!msg.adv_id) { + if (!msg->adv_id) { allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; - if (!(msg.wps_config_methods & allowed_config_methods)) { + if (!(msg->wps_config_methods & allowed_config_methods)) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; } /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ - if (msg.group_id) { + if (msg->group_id) { size_t i; for (i = 0; i < p2p->num_groups; i++) { if (p2p_group_is_group_id_match( p2p->groups[i], - msg.group_id, msg.group_id_len)) + msg->group_id, msg->group_id_len)) break; } if (i == p2p->num_groups) { @@ -689,29 +685,29 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, * Set adv_id here, so in case of an error, a P2PS PD Response * will be sent. */ - adv_id = WPA_GET_LE32(msg.adv_id); - if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) { + adv_id = WPA_GET_LE32(msg->adv_id); + if (p2ps_validate_pd_req(p2p, msg, sa) < 0) { reject = P2P_SC_FAIL_INVALID_PARAMS; goto out; } - req_fcap = (struct p2ps_feature_capab *) msg.feature_cap; + req_fcap = (struct p2ps_feature_capab *) msg->feature_cap; - os_memcpy(session_mac, msg.session_mac, ETH_ALEN); - os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); + os_memcpy(session_mac, msg->session_mac, ETH_ALEN); + os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN); - session_id = WPA_GET_LE32(msg.session_id); + session_id = WPA_GET_LE32(msg->session_id); - if (msg.conn_cap) - conncap = *msg.conn_cap; + if (msg->conn_cap) + conncap = *msg->conn_cap; /* * We need to verify a P2PS config methog in an initial PD * request or in a follow-on PD request with the status * SUCCESS_DEFERRED. */ - if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) && - !(msg.wps_config_methods & allowed_config_methods)) { + if ((!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) && + !(msg->wps_config_methods & allowed_config_methods)) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; @@ -727,18 +723,18 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); - if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { + if (msg->wps_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " requested us to show a PIN on display", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; - } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { + } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " requested us to write its PIN using keypad", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; - } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { + } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_P2PS; @@ -749,8 +745,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups( p2p->cfg->cb_ctx, dev->info.p2p_device_addr, - msg.persistent_dev, - msg.persistent_ssid, msg.persistent_ssid_len); + msg->persistent_dev, + msg->persistent_ssid, msg->persistent_ssid_len); } reject = P2P_SC_SUCCESS; @@ -759,15 +755,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, * End of a legacy P2P PD Request processing, from this point continue * with P2PS one. */ - if (!msg.adv_id) + if (!msg->adv_id) goto out; remote_conncap = conncap; - if (!msg.status) { + if (!msg->status) { unsigned int forced_freq, pref_freq; - if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) { + if (!ether_addr_equal(p2p->cfg->dev_addr, msg->adv_mac)) { p2p_dbg(p2p, "P2PS PD adv mac does not match the local one"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; @@ -804,12 +800,12 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (p2ps_adv->config_methods && - !(msg.wps_config_methods & + !(msg->wps_config_methods & p2ps_adv->config_methods)) { p2p_dbg(p2p, "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", p2ps_adv->config_methods, - msg.wps_config_methods); + msg->wps_config_methods); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!p2ps_adv->state) { p2p_dbg(p2p, "P2PS state unavailable"); @@ -819,24 +815,24 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } - if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { + if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Keypad - always defer"); auto_accept = 0; } if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || - msg.persistent_dev) && conncap != P2PS_SETUP_NEW && - msg.channel_list && msg.channel_list_len && + msg->persistent_dev) && conncap != P2PS_SETUP_NEW && + msg->channel_list && msg->channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, - msg.channel_list, - msg.channel_list_len) < 0) { + msg->channel_list, + msg->channel_list_len) < 0) { p2p_dbg(p2p, "No common channels - force deferred flow"); auto_accept = 0; } if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) || - msg.persistent_dev) && msg.operating_channel) { + msg->persistent_dev) && msg->operating_channel) { struct p2p_channels intersect; /* @@ -847,15 +843,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, */ if (dev->channels.reg_classes == 0 || !p2p_channels_includes(&dev->channels, - msg.operating_channel[3], - msg.operating_channel[4])) { + msg->operating_channel[3], + msg->operating_channel[4])) { struct p2p_channels *ch = &dev->channels; os_memset(ch, 0, sizeof(*ch)); ch->reg_class[0].reg_class = - msg.operating_channel[3]; + msg->operating_channel[3]; ch->reg_class[0].channel[0] = - msg.operating_channel[4]; + msg->operating_channel[4]; ch->reg_class[0].channels = 1; ch->reg_classes = 1; } @@ -874,7 +870,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, struct p2ps_provision *tmp; if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, - msg.wps_config_methods, + msg->wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; @@ -896,7 +892,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, } } - if (!msg.status && !auto_accept && + if (!msg->status && !auto_accept && (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { struct p2ps_provision *tmp; @@ -906,7 +902,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, } if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, - msg.wps_config_methods, + msg->wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; @@ -917,26 +913,26 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, } /* Not a P2PS Follow-on PD */ - if (!msg.status) + if (!msg->status) goto out; - if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { - reject = *msg.status; + if (*msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) { + reject = *msg->status; goto out; } - if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov) + if (*msg->status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov) goto out; if (p2p->p2ps_prov->adv_id != adv_id || - !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) { + !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Advertisement ID/MAC"); goto out; } if (p2p->p2ps_prov->session_id != session_id || - !ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) { + !ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC"); goto out; } @@ -967,7 +963,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, else if (method & WPS_CONFIG_KEYPAD) method = WPS_CONFIG_DISPLAY; - if (!conncap || !(msg.wps_config_methods & method)) { + if (!conncap || !(msg->wps_config_methods & method)) { /* * Reject this "Deferred Accept* * if incompatible conncap or method @@ -978,11 +974,11 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || - msg.persistent_dev) && conncap != P2PS_SETUP_NEW && - msg.channel_list && msg.channel_list_len && + msg->persistent_dev) && conncap != P2PS_SETUP_NEW && + msg->channel_list && msg->channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, - msg.channel_list, - msg.channel_list_len) < 0) { + msg->channel_list, + msg->channel_list_len) < 0) { p2p_dbg(p2p, "No common channels in Follow-On Provision Discovery Request"); reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; @@ -994,10 +990,10 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) { u8 tmp; - if (msg.operating_channel) + if (msg->operating_channel) dev->oper_freq = - p2p_channel_to_freq(msg.operating_channel[3], - msg.operating_channel[4]); + p2p_channel_to_freq(msg->operating_channel[3], + msg->operating_channel[4]); if ((conncap & P2PS_SETUP_GROUP_OWNER) && p2p_go_select_channel(p2p, dev, &tmp) < 0) @@ -1010,7 +1006,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, out: if (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) - config_methods = msg.wps_config_methods; + config_methods = msg->wps_config_methods; else config_methods = 0; @@ -1018,18 +1014,17 @@ out: * Send PD Response for an initial PD Request or for follow-on * PD Request with P2P_SC_SUCCESS_DEFERRED status. */ - if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) { - resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, + if (!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) { + resp = p2p_build_prov_disc_resp(p2p, dev, msg->dialog_token, reject, config_methods, adv_id, - msg.group_id, msg.group_id_len, - msg.persistent_ssid, - msg.persistent_ssid_len, + msg->group_id, msg->group_id_len, + msg->persistent_ssid, + msg->persistent_ssid_len, (const u8 *) &resp_fcap, sizeof(resp_fcap)); - if (!resp) { - p2p_parse_free(&msg); + if (!resp) return; - } + p2p_dbg(p2p, "Sending Provision Discovery Response"); if (rx_freq > 0) freq = rx_freq; @@ -1039,7 +1034,6 @@ out: if (freq < 0) { p2p_dbg(p2p, "Unknown regulatory class/channel"); wpabuf_free(resp); - p2p_parse_free(&msg); return; } p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; @@ -1054,10 +1048,8 @@ out: wpabuf_free(resp); } - if (!dev) { - p2p_parse_free(&msg); + if (!dev) return; - } freq = 0; if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) { @@ -1069,17 +1061,17 @@ out: if (!p2p->cfg->p2ps_prov_complete) { /* Don't emit anything */ - } else if (msg.status && *msg.status != P2P_SC_SUCCESS && - *msg.status != P2P_SC_SUCCESS_DEFERRED) { - reject = *msg.status; + } else if (msg->status && *msg->status != P2P_SC_SUCCESS && + *msg->status != P2P_SC_SUCCESS_DEFERRED) { + reject = *msg->status; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, - 0, 0, msg.persistent_ssid, - msg.persistent_ssid_len, + 0, 0, msg->persistent_ssid, + msg->persistent_ssid_len, 0, 0, NULL, NULL, 0, freq, NULL, 0); - } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && + } else if (msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; @@ -1089,77 +1081,77 @@ out: sa, adv_mac, session_mac, NULL, adv_id, session_id, conncap, 0, - msg.persistent_ssid, - msg.persistent_ssid_len, 0, + msg->persistent_ssid, + msg->persistent_ssid_len, 0, 0, NULL, NULL, 0, freq, NULL, 0); else p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, - *msg.status, + *msg->status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, - msg.persistent_ssid, - msg.persistent_ssid_len, 0, + msg->persistent_ssid, + msg->persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq, NULL, 0); - } else if (msg.status && p2p->p2ps_prov) { + } else if (msg->status && p2p->p2ps_prov) { p2p->p2ps_prov->status = P2P_SC_SUCCESS; - p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, + p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg->status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, - msg.persistent_ssid, - msg.persistent_ssid_len, + msg->persistent_ssid, + msg->persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq, NULL, 0); - } else if (msg.status) { + } else if (msg->status) { } else if (auto_accept && reject == P2P_SC_SUCCESS) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, - msg.persistent_ssid, - msg.persistent_ssid_len, + msg->persistent_ssid, + msg->persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq, - msg.group_id ? - msg.group_id + ETH_ALEN : NULL, - msg.group_id ? - msg.group_id_len - ETH_ALEN : 0); + msg->group_id ? + msg->group_id + ETH_ALEN : NULL, + msg->group_id ? + msg->group_id_len - ETH_ALEN : 0); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && - (!msg.session_info || !msg.session_info_len)) { - p2p->p2ps_prov->method = msg.wps_config_methods; + (!msg->session_info || !msg->session_info_len)) { + p2p->p2ps_prov->method = msg->wps_config_methods; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, - msg.persistent_ssid, - msg.persistent_ssid_len, + msg->persistent_ssid, + msg->persistent_ssid_len, 0, 1, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq, NULL, 0); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { - size_t buf_len = msg.session_info_len; + size_t buf_len = msg->session_info_len; char *buf = os_malloc(2 * buf_len + 1); if (buf) { - p2p->p2ps_prov->method = msg.wps_config_methods; + p2p->p2ps_prov->method = msg->wps_config_methods; - utf8_escape((char *) msg.session_info, buf_len, + utf8_escape((char *) msg->session_info, buf_len, buf, 2 * buf_len + 1); p2p->cfg->p2ps_prov_complete( p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, - msg.persistent_ssid, msg.persistent_ssid_len, + msg->persistent_ssid, msg->persistent_ssid_len, 0, 1, buf, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq, NULL, 0); @@ -1187,29 +1179,29 @@ out: * seeker: KEYPAD, response status: SUCCESS */ if (p2p->cfg->prov_disc_req && - ((reject == P2P_SC_SUCCESS && !msg.adv_id) || - (!msg.status && + ((reject == P2P_SC_SUCCESS && !msg->adv_id) || + (!msg->status && (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) && passwd_id == DEV_PW_USER_SPECIFIED) || - (!msg.status && + (!msg->status && reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || (reject == P2P_SC_SUCCESS && - msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && + msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED && passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) { const u8 *dev_addr = sa; - if (msg.p2p_device_addr) - dev_addr = msg.p2p_device_addr; + if (msg->p2p_device_addr) + dev_addr = msg->p2p_device_addr; p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, - msg.wps_config_methods, - dev_addr, msg.pri_dev_type, - msg.device_name, msg.config_methods, - msg.capability ? msg.capability[0] : 0, - msg.capability ? msg.capability[1] : + msg->wps_config_methods, + dev_addr, msg->pri_dev_type, + msg->device_name, msg->config_methods, + msg->capability ? msg->capability[0] : 0, + msg->capability ? msg->capability[1] : 0, - msg.group_id, msg.group_id_len); + msg->group_id, msg->group_id_len); } if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) @@ -1234,10 +1226,22 @@ out: break; } - if (msg.intended_addr) - os_memcpy(dev->interface_addr, msg.intended_addr, + if (msg->intended_addr) + os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN); } +} + + +void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq) +{ + struct p2p_message msg; + + if (p2p_parse(data, len, &msg)) + return; + + p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1, rx_freq); p2p_parse_free(&msg); } @@ -1340,10 +1344,10 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, } -void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) +static void p2p_process_prov_disc_resp(struct p2p_data *p2p, + struct p2p_message *msg, const u8 *sa, + const u8 *data, size_t len) { - struct p2p_message msg; struct p2p_device *dev; u16 report_config_methods = 0, req_config_methods; u8 status = P2P_SC_SUCCESS; @@ -1354,30 +1358,26 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, int passwd_id = DEV_PW_DEFAULT; int p2ps_seeker; - if (p2p_parse(data, len, &msg)) - return; - - if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) { - p2p_parse_free(&msg); + if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, msg)) { return; } /* Parse the P2PS members present */ - if (msg.status) - status = *msg.status; + if (msg->status) + status = *msg->status; - group_mac = msg.intended_addr; + group_mac = msg->intended_addr; - if (msg.adv_mac) - os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); + if (msg->adv_mac) + os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN); else os_memset(adv_mac, 0, ETH_ALEN); - if (msg.adv_id) - adv_id = WPA_GET_LE32(msg.adv_id); + if (msg->adv_id) + adv_id = WPA_GET_LE32(msg->adv_id); - if (msg.conn_cap) { - conncap = *msg.conn_cap; + if (msg->conn_cap) { + conncap = *msg->conn_cap; /* Switch bits to local relative */ switch (conncap) { @@ -1392,25 +1392,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR " with config methods 0x%x", - MAC2STR(sa), msg.wps_config_methods); + MAC2STR(sa), msg->wps_config_methods); dev = p2p_get_device(p2p, sa); if (dev == NULL || !dev->req_config_methods) { p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR " with no pending request", MAC2STR(sa)); - p2p_parse_free(&msg); return; - } else if (msg.wfd_subelems) { + } else if (msg->wfd_subelems) { wpabuf_free(dev->info.wfd_subelems); - dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems); } - p2p_update_peer_6ghz_capab(dev, &msg); + p2p_update_peer_6ghz_capab(dev, msg); - if (dev->dialog_token != msg.dialog_token) { + if (dev->dialog_token != msg->dialog_token) { p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", - msg.dialog_token, dev->dialog_token); - p2p_parse_free(&msg); + msg->dialog_token, dev->dialog_token); return; } @@ -1435,14 +1433,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, ether_addr_equal(p2p->pending_pd_devaddr, sa)) p2p_reset_pending_pd(p2p); - if (msg.wps_config_methods != req_config_methods) { + if (msg->wps_config_methods != req_config_methods) { p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", - msg.wps_config_methods, req_config_methods); + msg->wps_config_methods, req_config_methods); if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, adv_id, adv_mac, NULL); - p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } @@ -1456,13 +1453,13 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, " accepted to show a PIN on display", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; - } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { + } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " accepted to write our PIN using keypad", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; - } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { + } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_P2PS; @@ -1481,23 +1478,23 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, * fails the flow would continue, although it would probably * fail. Same is true for the operating channel. */ - if (msg.channel_list && msg.channel_list_len && + if (msg->channel_list && msg->channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, - msg.channel_list, - msg.channel_list_len) < 0) + msg->channel_list, + msg->channel_list_len) < 0) p2p_dbg(p2p, "P2PS PD Response - no common channels"); - if (msg.operating_channel) { + if (msg->operating_channel) { if (p2p_channels_includes(&p2p->channels, - msg.operating_channel[3], - msg.operating_channel[4]) && + msg->operating_channel[3], + msg->operating_channel[4]) && p2p_channels_includes(&dev->channels, - msg.operating_channel[3], - msg.operating_channel[4])) { + msg->operating_channel[3], + msg->operating_channel[4])) { dev->oper_freq = p2p_channel_to_freq( - msg.operating_channel[3], - msg.operating_channel[4]); + msg->operating_channel[3], + msg->operating_channel[4]); } else { p2p_dbg(p2p, "P2PS PD Response - invalid operating channel"); @@ -1529,11 +1526,11 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->p2ps_prov->session_mac, group_mac, adv_id, p2p->p2ps_prov->session_id, - conncap, passwd_id, msg.persistent_ssid, - msg.persistent_ssid_len, 1, 0, NULL, - msg.feature_cap, msg.feature_cap_len, freq, - msg.group_id ? msg.group_id + ETH_ALEN : NULL, - msg.group_id ? msg.group_id_len - ETH_ALEN : 0); + conncap, passwd_id, msg->persistent_ssid, + msg->persistent_ssid_len, 1, 0, NULL, + msg->feature_cap, msg->feature_cap_len, freq, + msg->group_id ? msg->group_id + ETH_ALEN : NULL, + msg->group_id ? msg->group_id_len - ETH_ALEN : 0); } p2ps_prov_free(p2p); } else if (status != P2P_SC_SUCCESS && @@ -1555,16 +1552,15 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, NULL, NULL, 0); } - if (msg.session_info && msg.session_info_len) { - size_t info_len = msg.session_info_len; + if (msg->session_info && msg->session_info_len) { + size_t info_len = msg->session_info_len; char *deferred_sess_resp = os_malloc(2 * info_len + 1); if (!deferred_sess_resp) { - p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } - utf8_escape((char *) msg.session_info, info_len, + utf8_escape((char *) msg->session_info, info_len, deferred_sess_resp, 2 * info_len + 1); if (p2p->cfg->prov_disc_fail) @@ -1586,17 +1582,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, adv_id, adv_mac, NULL); - p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } /* Store the provisioning info */ - dev->wps_prov_info = msg.wps_config_methods; - if (msg.intended_addr) - os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); - - p2p_parse_free(&msg); + dev->wps_prov_info = msg->wps_config_methods; + if (msg->intended_addr) + os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN); out: dev->req_config_methods = 0; @@ -1640,6 +1633,19 @@ out: } +void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len) +{ + struct p2p_message msg; + + if (p2p_parse(data, len, &msg)) + return; + + p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1); + p2p_parse_free(&msg); +} + + int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join, int force_freq) { -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:08 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:08 +0530 Subject: [PATCH v3 10/25] P2P: Notify bootstrapping request and completed events In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-11-git-send-email-quic_shivbara@quicinc.com> Add support to notify p2p2 bootstrapping request and completed events to the user. Signed-off-by: Shivani Baranwal --- src/common/wpa_ctrl.h | 4 ++ src/p2p/p2p.h | 25 ++++++++++ src/p2p/p2p_pd.c | 10 ++++ wpa_supplicant/dbus/dbus_new.c | 107 ++++++++++++++++++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new.h | 16 ++++++ wpa_supplicant/notify.c | 12 +++++ wpa_supplicant/notify.h | 4 ++ wpa_supplicant/p2p_supplicant.c | 36 ++++++++++++++ 8 files changed, 214 insertions(+) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f614250..2acfdec 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -304,6 +304,10 @@ extern "C" { #define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START " #define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE " +#define P2P_EVENT_BOOTSTRAP_REQUEST "P2P-BOOTSTRAP-REQUEST " +#define P2P_EVENT_BOOTSTRAP_SUCCESS "P2P-BOOTSTRAP-SUCCESS " +#define P2P_EVENT_BOOTSTRAP_FAILURE "P2P-BOOTSTRAP-FAILURE " + #define INTERWORKING_AP "INTERWORKING-AP " #define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED " #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 5e7d1b7..c9bc12f 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1244,6 +1244,31 @@ struct p2p_config { */ void (*register_bootstrap_comeback)(void *ctx, const u8 *addr, u16 comeback_after); + + /** + * bootstrap_req_rx - Indicate bootstrap request from a p2p peer + * @ctx: Callback context from cb_ctx + * @addr: p2p device address from which bootstrap request received + * @bootstrap_method: bootstrapping method request by peer device + * + * This function can be used to notify that bootstrap request is + * received from the p2p peer. + */ + void (*bootstrap_req_rx)(void *ctx, const u8 *addr, + u16 bootstrap_method); + + /** + * bootstrap_completed - Indicate bootstrapping completed with p2p peer + * @ctx: Callback context from cb_ctx + * @addr: p2p device address with which bootstrapping is completed + * @status: status of bootstrapping handshake + * @freq: freq in which bootstrapping is done + * + * This function can be used to notify the status of bootstrapping + * handshake. + */ + void (*bootstrap_completed)(void *ctx, const u8 *addr, int status, + int freq); }; diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index c0b7411..56022ff 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -759,6 +759,9 @@ static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p, if (!dev->req_bootstrap_method) { status = P2P_SC_COMEBACK; + if (p2p->cfg->bootstrap_req_rx) + p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx, + sa, bootstrap); goto out; } } else { @@ -782,6 +785,9 @@ static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p, dev->bootstrap_params->comeback_after = p2p->cfg->comeback_after; status = P2P_SC_COMEBACK; + if (p2p->cfg->bootstrap_req_rx) + p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx, + sa, bootstrap); goto out; } } @@ -1678,6 +1684,10 @@ static void p2p_process_prov_disc_bootstrap_resp(struct p2p_data *p2p, p2p->cfg->send_action_done(p2p->cfg->cb_ctx); if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; + + if (p2p->cfg->bootstrap_completed) + p2p->cfg->bootstrap_completed(p2p->cfg->cb_ctx, sa, status, + rx_freq); } diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 5ad5bcd..fdcf08c 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -2332,6 +2332,113 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, } +/** + * wpas_dbus_signal_p2p_bootstrap_req - Signal P2P Bootstrap Request RX + * @wpa_s: %wpa_supplicant network interface data + * @src: Source address of the message triggering this notification + * @bootstrap_method: Peer's Bootstrap method + * + * Sends signal to notify that a peer P2P Device is requesting bootstrapping + * negotiation with us. + */ +void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 bootstrap_method) +{ + DBusMessage *msg; + DBusMessageIter iter; + struct wpas_dbus_priv *iface; + char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface) + return; + + if (wpa_s->p2p_mgmt) + wpa_s = wpa_s->parent; + if (!wpa_s->dbus_new_path) + return; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(src)); + path = peer_obj_path; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "BootstrappingRequest"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16, + &bootstrap_method)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_p2p_bootstrap_completed - Signal P2P Bootstrap completed + * event + * @wpa_s: %wpa_supplicant network interface data + * @src: Source address of the peer with which bootstrapping is done + * @status: status of Bootstrapping handshake + * + * Sends signal to notify that a peer P2P Device is requesting bootstrapping + * negotiation with us. + */ +void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s, + const u8 *src, int status) +{ + DBusMessage *msg; + DBusMessageIter iter; + struct wpas_dbus_priv *iface; + char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface) + return; + + if (wpa_s->p2p_mgmt) + wpa_s = wpa_s->parent; + if (!wpa_s->dbus_new_path) + return; + + os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, + "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR, + wpa_s->dbus_new_path, MAC2STR(src)); + path = peer_obj_path; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_P2PDEVICE, + "BootstrappingCompleted"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &path) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, + &status)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + #endif /* CONFIG_P2P */ diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 1db5fe8..b09e4b0 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -265,6 +265,10 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *dev_addr, const u8 *bssid, int id, int op_freq); +void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 bootstrap_method); +void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s, + const u8 *src, int status); void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s, @@ -617,6 +621,18 @@ void wpas_dbus_signal_p2p_invitation_received(struct wpa_supplicant *wpa_s, } static inline +void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 bootstrap_method) +{ +} + +static inline +void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s, + const u8 *src, int status) +{ +} + +static inline void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 308b93d..a3b1305 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -792,6 +792,18 @@ void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s, id, op_freq); } +void wpas_notify_p2p_bootstrap_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 bootstrap_method) +{ + wpas_dbus_signal_p2p_bootstrap_req(wpa_s, src, bootstrap_method); +} + +void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s, + const u8 *src, int status) +{ + wpas_dbus_signal_p2p_bootstrap_completed(wpa_s, src, status); +} + #endif /* CONFIG_P2P */ diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 9749e9c..27716ca 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -154,6 +154,10 @@ void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr, const u8 *bssid, int id, int op_freq); +void wpas_notify_p2p_bootstrap_req(struct wpa_supplicant *wpa_s, + const u8 *src, u16 bootstrap_method); +void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s, + const u8 *src, int status); void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index c524084..6e7cf8f 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -4857,6 +4857,40 @@ static void wpas_p2p_register_bootstrap_comeback(void *ctx, const u8 *addr, wpa_s, NULL); } + +static void wpas_bootstrap_req_rx(void *ctx, const u8 *addr, + u16 bootstrap_method) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_BOOTSTRAP_REQUEST MACSTR + " bootstrap_method=%u", MAC2STR(addr), bootstrap_method); + + wpas_notify_p2p_bootstrap_req(wpa_s, addr, bootstrap_method); +} + +static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status, + int freq) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_notify_p2p_bootstrap_completed(wpa_s, addr, status); + + if (status) { + wpa_msg_global(wpa_s, MSG_INFO, + P2P_EVENT_BOOTSTRAP_FAILURE MACSTR "status=%d", + MAC2STR(addr), status); + } else { + wpa_msg_global(wpa_s, MSG_INFO, + P2P_EVENT_BOOTSTRAP_SUCCESS MACSTR "status=%d", + MAC2STR(addr), status); + } + + if (status) + return; +} + + int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) { u8 addr[ETH_ALEN] = {0}; @@ -4977,6 +5011,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list; p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable; p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; + p2p.bootstrap_req_rx = wpas_bootstrap_req_rx; + p2p.bootstrap_completed = wpas_bootstrap_completed; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:10 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:10 +0530 Subject: [PATCH v3 12/25] Define PMKSA helper functions for PASN initiator and responder In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-13-git-send-email-quic_shivbara@quicinc.com> Define helper functions to init, add, get, remove, flush and deinit PMKSA cache for PASN initiator and responder. P2P devices can be in a role of pairing initiator and responder. Hence define a cache for each role separately. Signed-off-by: Shivani Baranwal --- src/pasn/pasn_common.h | 26 +++++++++++++++++++-- src/pasn/pasn_initiator.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ src/pasn/pasn_responder.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 2 deletions(-) diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index 42ff83b..e3ff746 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -203,9 +203,18 @@ void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr); void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr); void pasn_set_initiator_pmksa(struct pasn_data *pasn, struct rsn_pmksa_cache *pmksa); -void pasn_set_responder_pmksa(struct pasn_data *pasn, - struct rsn_pmksa_cache *pmksa); int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt); +struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void); +void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); +int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, + const u8 *own_addr, const u8 *bssid, u8 *pmk, + size_t pmk_len, u8 *pmkid); +int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *bssid, u8 *pmkid, u8 *pmk, + size_t *pmk_len); +void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + const u8 *bssid); +void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa); /* Responder */ void pasn_set_password(struct pasn_data *pasn, const char *password); @@ -216,6 +225,19 @@ void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie); void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid); int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies, size_t extra_ies_len); +void pasn_set_responder_pmksa(struct pasn_data *pasn, + struct rsn_pmksa_cache *pmksa); +struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void); +void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); +int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, + const u8 *own_addr, const u8 *bssid, u8 *pmk, + size_t pmk_len, u8 *pmkid); +int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *bssid, u8 *pmkid, u8 *pmk, + size_t *pmk_len); +void pasn_responder_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + const u8 *bssid); +void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa); int pasn_get_akmp(struct pasn_data *pasn); int pasn_get_cipher(struct pasn_data *pasn); diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index c9771c7..dbcc91a 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -26,6 +26,65 @@ #include "pasn_common.h" +struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void) +{ + return pmksa_cache_init(NULL, NULL, NULL, NULL, NULL); +} + + +void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +{ + return pmksa_cache_deinit(pmksa); +} + + +int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, + const u8 *own_addr, const u8 *bssid, u8 *pmk, + size_t pmk_len, u8 *pmkid) +{ + if (pmksa_cache_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid, + own_addr, NULL, WPA_KEY_MGMT_SAE, 0)) + return 0; + return -1; +} + + +void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + const u8 *bssid) +{ + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0); + if (!entry) + return; + + pmksa_cache_remove(pmksa, entry); +} + + +int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *bssid, u8 *pmkid, u8 *pmk, + size_t *pmk_len) +{ + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0); + if (entry) { + os_memcpy(pmkid, entry->pmkid, PMKID_LEN); + os_memcpy(pmk, entry->pmk, entry->pmk_len); + *pmk_len = entry->pmk_len; + return 0; + } + return -1; +} + + +void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa) +{ + return pmksa_cache_flush(pmksa, NULL, NULL, 0, false); +} + + void pasn_set_initiator_pmksa(struct pasn_data *pasn, struct rsn_pmksa_cache *pmksa) { diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index fd67fba..c75ba87 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -26,6 +26,65 @@ #include "pasn_common.h" +struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void) +{ + return pmksa_cache_auth_init(NULL, NULL); +} + + +void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +{ + return pmksa_cache_auth_deinit(pmksa); +} + + +int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa, + const u8 *own_addr, const u8 *bssid, u8 *pmk, + size_t pmk_len, u8 *pmkid) +{ + if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, own_addr, + bssid, 0, NULL, WPA_KEY_MGMT_SAE)) + return 0; + return -1; +} + + +int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, + const u8 *bssid, u8 *pmkid, u8 *pmk, + size_t *pmk_len) +{ + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa_cache_auth_get(pmksa, bssid, NULL); + if (entry) { + os_memcpy(pmkid, entry->pmkid, PMKID_LEN); + os_memcpy(pmk, entry->pmk, entry->pmk_len); + *pmk_len = entry->pmk_len; + return 0; + } + return -1; +} + + +void pasn_responder_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + const u8 *bssid) +{ + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa_cache_auth_get(pmksa, bssid, NULL); + if (!entry) + return; + + pmksa_cache_free_entry(pmksa, entry); +} + + +void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa) +{ + return pmksa_cache_auth_flush(pmksa); +} + + void pasn_set_responder_pmksa(struct pasn_data *pasn, struct rsn_pmksa_cache *pmksa) { -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:09 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:09 +0530 Subject: [PATCH v3 11/25] WPA: Add support for KEK derivation in PTK In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-12-git-send-email-quic_shivbara@quicinc.com> Add support to derive KEK in PTK to encrypt keys and passwords in opportunistic P2P pairing defined in P2P2. Signed-off-by: Shivani Baranwal --- src/ap/ieee802_11.c | 3 ++- src/common/common_module_tests.c | 2 +- src/common/wpa_common.c | 20 +++++++++++++------- src/common/wpa_common.h | 4 +++- src/pasn/pasn_common.h | 1 + src/pasn/pasn_initiator.c | 2 +- src/pasn/pasn_responder.c | 2 +- 7 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index fd1de5e..38fcba5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2462,7 +2462,8 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd, wpabuf_head(pasn->secret), wpabuf_len(pasn->secret), pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn), - pasn_get_cipher(sta->pasn), sta->pasn->kdk_len); + pasn_get_cipher(sta->pasn), sta->pasn->kdk_len, + sta->pasn->kek_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK"); goto fail; diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c index a95ae36..5763c51 100644 --- a/src/common/common_module_tests.c +++ b/src/common/common_module_tests.c @@ -651,7 +651,7 @@ static int pasn_test_pasn_auth(void) spa_addr, bssid, dhss, sizeof(dhss), &ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP, - WPA_KDK_MAX_LEN); + WPA_KDK_MAX_LEN, 0); if (ret) return ret; diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index f62f3a2..28f478c 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1462,9 +1462,9 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *bssid, const u8 *dhss, size_t dhss_len, struct wpa_ptk *ptk, int akmp, int cipher, - size_t kdk_len) + size_t kdk_len, size_t kek_len) { - u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN]; + u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN]; u8 *data; size_t data_len, ptk_len; int ret = -1; @@ -1499,7 +1499,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, ptk->kck_len = WPA_PASN_KCK_LEN; ptk->tk_len = wpa_cipher_key_len(cipher); ptk->kdk_len = kdk_len; - ptk->kek_len = 0; + ptk->kek_len = kek_len; ptk->kek2_len = 0; ptk->kck2_len = 0; @@ -1510,7 +1510,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, goto err; } - ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len; + ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len + ptk->kek_len; if (ptk_len > sizeof(tmp)) goto err; @@ -1539,12 +1539,18 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN); wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN); - os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len); + if (kek_len) { + os_memcpy(ptk->kek, tmp + WPA_PASN_KCK_LEN, ptk->kek_len); + wpa_hexdump_key(MSG_DEBUG, "PASN: KEK:", + ptk->kek, ptk->kek_len); + } + + os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN + ptk->kek_len, ptk->tk_len); wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len); if (kdk_len) { - os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len, - ptk->kdk_len); + os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->kek_len + + ptk->tk_len, ptk->kdk_len); wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:", ptk->kdk, ptk->kdk_len); } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 6f513f2..8f77d38 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -249,6 +249,8 @@ struct wpa_eapol_key { #define WPA_PASN_KCK_LEN 32 #define WPA_PASN_MIC_MAX_LEN 24 #define WPA_LTF_KEYSEED_MAX_LEN 48 +#define WPA_KEK_128 16 +#define WPA_KEK_256 32 /** * struct wpa_ptk - WPA Pairwise Transient Key @@ -770,7 +772,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *bssid, const u8 *dhss, size_t dhss_len, struct wpa_ptk *ptk, int akmp, int cipher, - size_t kdk_len); + size_t kdk_len, size_t kek_len); u8 pasn_mic_len(int akmp, int cipher); diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index 36710c2..42ff83b 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -66,6 +66,7 @@ struct pasn_data { size_t extra_ies_len; /* External modules do not access below variables */ + size_t kek_len; u16 group; bool secure_ltf; int freq; diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index d273067..c9771c7 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -1233,7 +1233,7 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len, pasn->own_addr, pasn->peer_addr, wpabuf_head(secret), wpabuf_len(secret), &pasn->ptk, pasn->akmp, pasn->cipher, - pasn->kdk_len); + pasn->kdk_len, pasn->kek_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); goto fail; diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index b991364..fd67fba 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -349,7 +349,7 @@ pasn_derive_keys(struct pasn_data *pasn, ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr, wpabuf_head(secret), wpabuf_len(secret), &pasn->ptk, pasn->akmp, - pasn->cipher, pasn->kdk_len); + pasn->cipher, pasn->kdk_len, pasn->kek_len); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); return -1; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:12 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:12 +0530 Subject: [PATCH v3 14/25] P2P: Add support for go negotiation action wrapper format for p2p2 In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-15-git-send-email-quic_shivbara@quicinc.com> Changes to support p2p2 go negotiation action wrapper format Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 2 +- src/p2p/p2p_go_neg.c | 25 ++++++++++++++++--------- src/p2p/p2p_i.h | 6 +++--- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index d61f769..01490e2 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1933,7 +1933,7 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, p2p_handle_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_GO_NEG_CONF: - p2p_handle_go_neg_conf(p2p, sa, data + 1, len - 1); + p2p_handle_go_neg_conf(p2p, sa, data + 1, len - 1, false); break; case P2P_INVITATION_REQ: p2p_handle_invitation_req(p2p, sa, data + 1, len - 1, rx_freq); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 0308216..58ea89c 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -802,7 +802,7 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) + const u8 *data, size_t len, int rx_freq, bool p2p2) { struct p2p_device *dev = NULL; struct p2p_message msg; @@ -920,7 +920,7 @@ int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "User has rejected this peer"); status = P2P_SC_FAIL_REJECTED_BY_USER; } else if (dev == NULL || - (dev->wps_method == WPS_NOT_READY && + (dev->wps_method == WPS_NOT_READY && !p2p2 && (p2p->authorized_oob_dev_pw_id == 0 || p2p->authorized_oob_dev_pw_id != msg.dev_password_id))) { @@ -991,6 +991,9 @@ int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, goto fail; } + if (p2p2) + goto skip; + switch (msg.dev_password_id) { case DEV_PW_REGISTRAR_SPECIFIED: p2p_dbg(p2p, "PIN from peer Display"); @@ -1057,7 +1060,7 @@ int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; goto fail; } - +skip: if (go && p2p_go_select_channel(p2p, dev, &status) < 0) goto fail; @@ -1128,7 +1131,7 @@ void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, { int freq; - if (p2p_process_go_neg_req(p2p, sa, data, len, rx_freq)) + if (p2p_process_go_neg_req(p2p, sa, data, len, rx_freq, false)) return; p2p_dbg(p2p, "Sending GO Negotiation Response"); @@ -1231,7 +1234,7 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, - size_t len, int rx_freq) + size_t len, int rx_freq, bool p2p2) { struct p2p_device *dev; int go = -1; @@ -1242,7 +1245,7 @@ int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR " (freq=%d)", MAC2STR(sa), rx_freq); dev = p2p_get_device(p2p, sa); - if (dev == NULL || dev->wps_method == WPS_NOT_READY || + if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) || dev != p2p->go_neg_peer) { p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, MAC2STR(sa)); @@ -1394,6 +1397,9 @@ int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, } else dev->oper_freq = 0; + if (p2p2) + goto skip; + switch (msg.dev_password_id) { case DEV_PW_REGISTRAR_SPECIFIED: p2p_dbg(p2p, "PIN from peer Display"); @@ -1449,6 +1455,7 @@ int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, goto fail; } +skip: if (go && p2p_go_select_channel(p2p, dev, &status) < 0) goto fail; @@ -1516,7 +1523,7 @@ void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, return; } - if (p2p_process_go_neg_resp(p2p, sa, data, len, rx_freq)) + if (p2p_process_go_neg_resp(p2p, sa, data, len, rx_freq, false)) return; p2p_dbg(p2p, "Sending GO Negotiation Confirm"); @@ -1545,7 +1552,7 @@ void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) + const u8 *data, size_t len, bool p2p2) { struct p2p_device *dev; struct p2p_message msg; @@ -1553,7 +1560,7 @@ void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR, MAC2STR(sa)); dev = p2p_get_device(p2p, sa); - if (dev == NULL || dev->wps_method == WPS_NOT_READY || + if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) || dev != p2p->go_neg_peer) { p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, MAC2STR(sa)); diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 95bdd19..c3dfcea 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -925,11 +925,11 @@ void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq); void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, const u8 *data, - size_t len); + size_t len, bool p2p2); int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, - size_t len, int rx_freq); + size_t len, int rx_freq, bool p2p2); int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, - size_t len, int rx_freq); + size_t len, int rx_freq, bool p2p2); int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method); void p2p_reselect_channel(struct p2p_data *p2p, -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:11 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:11 +0530 Subject: [PATCH v3 13/25] P2P: Cleanup of go-negotiation and invitation processing In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-14-git-send-email-quic_shivbara@quicinc.com> Add wrapper functions to process and prepare response for go negotiation and invitation frames. Send the response action frames in handle_ functions. Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 9 ++- src/p2p/p2p_go_neg.c | 152 ++++++++++++++++++++++++++++++++--------------- src/p2p/p2p_i.h | 45 +++++++++++--- src/p2p/p2p_invitation.c | 61 +++++++++++-------- 4 files changed, 180 insertions(+), 87 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index a66f0c4..d61f769 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1927,17 +1927,16 @@ static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, switch (data[0]) { case P2P_GO_NEG_REQ: - p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq); + p2p_handle_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_GO_NEG_RESP: - p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); + p2p_handle_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_GO_NEG_CONF: - p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1); + p2p_handle_go_neg_conf(p2p, sa, data + 1, len - 1); break; case P2P_INVITATION_REQ: - p2p_process_invitation_req(p2p, sa, data + 1, len - 1, - rx_freq); + p2p_handle_invitation_req(p2p, sa, data + 1, len - 1, rx_freq); break; case P2P_INVITATION_RESP: p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 04e5139..0308216 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -801,21 +801,19 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, } -void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) +int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq) { struct p2p_device *dev = NULL; - struct wpabuf *resp; struct p2p_message msg; u8 status = P2P_SC_FAIL_INVALID_PARAMS; int tie_breaker = 0; - int freq; p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)", MAC2STR(sa), rx_freq); if (p2p_parse(data, len, &msg)) - return; + return -1; if (!msg.capability) { p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request"); @@ -890,7 +888,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_go_neg_failed(p2p, *msg.status); p2p_parse_free(&msg); - return; + return -1; } goto fail; } @@ -968,7 +966,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) { p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent"); p2p_parse_free(&msg); - return; + return -1; } if (dev->go_neg_req_sent && @@ -976,7 +974,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent"); p2p_parse_free(&msg); - return; + return -1; } go = p2p_go_det(p2p->go_intent, *msg.go_intent); @@ -1086,7 +1084,10 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, p2p_set_state(p2p, P2P_GO_NEG); p2p_clear_timeout(p2p); dev->dialog_token = msg.dialog_token; - os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); + if (!is_zero_ether_addr(msg.intended_addr)) { + p2p_dbg(p2p, "msg.intended_addr" MACSTR, MAC2STR(msg.intended_addr)); + os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); + } p2p->go_neg_peer = dev; eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL); status = P2P_SC_SUCCESS; @@ -1095,22 +1096,13 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, fail: if (dev) dev->status = status; - resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, status, - !tie_breaker); + p2p->go_neg_resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, + status, !tie_breaker); + p2p_parse_free(&msg); - if (resp == NULL) - return; - p2p_dbg(p2p, "Sending GO Negotiation Response"); - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - wpabuf_free(resp); - return; - } + if (!p2p->go_neg_resp) + return -1; + if (status == P2P_SC_SUCCESS) { p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE; dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM; @@ -1128,13 +1120,38 @@ fail: } else p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE_FAILURE; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, - p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 100) < 0) { - p2p_dbg(p2p, "Failed to send Action frame"); + return 0; +} + +void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + int freq; + + if (p2p_process_go_neg_req(p2p, sa, data, len, rx_freq)) + return; + + p2p_dbg(p2p, "Sending GO Negotiation Response"); + + if (rx_freq > 0) + freq = rx_freq; + else + freq = p2p_channel_to_freq(p2p->cfg->reg_class, + p2p->cfg->channel); + if (freq < 0) { + p2p_dbg(p2p, "Unknown regulatory class/channel"); + return; } - wpabuf_free(resp); + if (p2p->go_neg_resp && + p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, + p2p->cfg->dev_addr, wpabuf_head(p2p->go_neg_resp), + wpabuf_len(p2p->go_neg_resp), 100) < 0) { + p2p_dbg(p2p, "Failed to send Action frame"); + } + wpabuf_free(p2p->go_neg_resp); + p2p->go_neg_resp = NULL; + return; } @@ -1213,8 +1230,8 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, } -void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) +int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq) { struct p2p_device *dev; int go = -1; @@ -1229,16 +1246,16 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, dev != p2p->go_neg_peer) { p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, MAC2STR(sa)); - return; + return -1; } if (p2p_parse(data, len, &msg)) - return; + return -1; if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) { p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore"); p2p_parse_free(&msg); - return; + return -1; } dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; p2p_update_peer_6ghz_capab(dev, &msg); @@ -1247,7 +1264,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", msg.dialog_token, dev->dialog_token); p2p_parse_free(&msg); - return; + return -1; } if (!msg.status) { @@ -1276,7 +1293,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_parse_free(&msg); - return; + return -1; } if (!msg.capability) { @@ -1446,7 +1463,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, p2p_clear_timeout(p2p); p2p_dbg(p2p, "GO Negotiation with " MACSTR, MAC2STR(sa)); - os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); + if (!is_zero_ether_addr(msg.intended_addr)) { + p2p_dbg(p2p, "msg.intended_addr" MACSTR, MAC2STR(msg.intended_addr)); + os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); + } fail: /* Store GO Negotiation Confirmation to allow retransmission */ @@ -1454,15 +1474,18 @@ fail: dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status, msg.operating_channel, go); - p2p_parse_free(&msg); if (dev->go_neg_conf == NULL) - return; - p2p_dbg(p2p, "Sending GO Negotiation Confirm"); + return -1; + + p2p->go_neg_conf = wpabuf_dup(dev->go_neg_conf); + p2p_parse_free(&msg); + if (status == P2P_SC_SUCCESS) { p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM; dev->go_state = go ? LOCAL_GO : REMOTE_GO; } else p2p->pending_action_state = P2P_NO_PENDING_ACTION; + if (rx_freq > 0) freq = rx_freq; else @@ -1471,7 +1494,39 @@ fail: dev->go_neg_conf_freq = freq; dev->go_neg_conf_sent = 0; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa, + if (status != P2P_SC_SUCCESS) { + p2p_dbg(p2p, "GO Negotiation failed"); + dev->status = status; + } + + return 0; +} + +void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq) +{ + int freq; + struct p2p_device *dev; + + dev = p2p_get_device(p2p, sa); + if (dev == NULL || dev->wps_method == WPS_NOT_READY || + dev != p2p->go_neg_peer) { + p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR, + MAC2STR(sa)); + return; + } + + if (p2p_process_go_neg_resp(p2p, sa, data, len, rx_freq)) + return; + + p2p_dbg(p2p, "Sending GO Negotiation Confirm"); + if (rx_freq > 0) + freq = rx_freq; + else + freq = dev->listen_freq; + + if (dev->go_neg_conf && + p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa, wpabuf_head(dev->go_neg_conf), wpabuf_len(dev->go_neg_conf), 50) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); @@ -1479,15 +1534,18 @@ fail: p2p->cfg->send_action_done(p2p->cfg->cb_ctx); } else dev->go_neg_conf_sent++; - if (status != P2P_SC_SUCCESS) { - p2p_dbg(p2p, "GO Negotiation failed"); - p2p_go_neg_failed(p2p, status); - } + + if (dev->status != P2P_SC_SUCCESS) + p2p_go_neg_failed(p2p, dev->status); + + wpabuf_free(p2p->go_neg_conf); + p2p->go_neg_conf = NULL; + return; } -void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len) +void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len) { struct p2p_device *dev; struct p2p_message msg; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index ef2bb9d..95bdd19 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -630,6 +630,25 @@ struct p2p_data { bool allow_6ghz; struct p2p_pairing_info *pairing_info; + /** + * go_neg_resp - GO Negotiation Response frame + */ + struct wpabuf *go_neg_resp; + + /** + * go_neg_conf - GO Negotiation Confirmation frame + */ + struct wpabuf *go_neg_conf; + + /** + * invitation_req - Invitation request frame + */ + struct wpabuf *invitation_req; + + /** + * invitation_resp - Invitation Response frame + */ + struct wpabuf *invitation_resp; }; /** @@ -901,12 +920,16 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev); int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, struct p2p_device *dev, const u8 *channel_list, size_t channel_list_len); -void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); -void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); +void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq); +void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq); +void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len); +int p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq); +int p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, + size_t len, int rx_freq); int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method); void p2p_reselect_channel(struct p2p_data *p2p, @@ -927,10 +950,14 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, struct p2p_device *dev); /* p2p_invitation.c */ -void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq); +void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq); +void p2p_handle_invitation_resp(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len); +int p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq); void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len); + const u8 *data, size_t len); int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, const u8 *go_dev_addr, int dev_pw_id); void p2p_invitation_req_cb(struct p2p_data *p2p, int success); diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 70a7f6f..8ade838 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -181,14 +181,12 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, } -void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, - const u8 *data, size_t len, int rx_freq) +int p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq) { struct p2p_device *dev; struct p2p_message msg; - struct wpabuf *resp = NULL; u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; - int freq; int go = 0; u8 group_bssid[ETH_ALEN], *bssid; int op_freq = 0; @@ -202,7 +200,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, MAC2STR(sa), rx_freq); if (p2p_parse(data, len, &msg)) - return; + return -1; dev = p2p_get_device(p2p, sa); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { @@ -385,21 +383,11 @@ fail: bssid = group_bssid; else bssid = NULL; - resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status, - bssid, reg_class, channel, channels); - - if (resp == NULL) - goto out; - - if (rx_freq > 0) - freq = rx_freq; - else - freq = p2p_channel_to_freq(p2p->cfg->reg_class, - p2p->cfg->channel); - if (freq < 0) { - p2p_dbg(p2p, "Unknown regulatory class/channel"); - goto out; - } + p2p->invitation_resp = p2p_build_invitation_resp(p2p, dev, + msg.dialog_token, + status, bssid, + reg_class, channel, + channels); /* * Store copy of invitation data to be used when processing TX status @@ -424,17 +412,38 @@ fail: } p2p->inv_status = status; p2p->inv_op_freq = op_freq; + p2p_parse_free(&msg); + return 0; +} + + +void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa, + const u8 *data, size_t len, int rx_freq) +{ + int freq; + + if (p2p_process_invitation_req(p2p, sa, data, len, rx_freq)) + return; + + if (rx_freq > 0) + freq = rx_freq; + else + freq = p2p_channel_to_freq(p2p->cfg->reg_class, + p2p->cfg->channel); + if (freq < 0) + p2p_dbg(p2p, "Unknown regulatory class/channel"); p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE; - if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, + if (p2p->invitation_resp && + p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, p2p->cfg->dev_addr, - wpabuf_head(resp), wpabuf_len(resp), 50) < 0) { + wpabuf_head(p2p->invitation_resp), + wpabuf_len(p2p->invitation_resp), 50) < 0) p2p_dbg(p2p, "Failed to send Action frame"); - } -out: - wpabuf_free(resp); - p2p_parse_free(&msg); + wpabuf_free(p2p->invitation_resp); + p2p->invitation_resp = NULL; + return; } -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:13 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:13 +0530 Subject: [PATCH v3 15/25] P2P: Encapsulate P2P2 vendor IE with size more than 255 bytes In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-16-git-send-email-quic_shivbara@quicinc.com> Add support to encapsulate vendor IE exceeding 255 bytes in go negotiation frames and action wrapper IE of pasn auth frames for p2p2. Signed-off-by: Shivani Baranwal --- src/p2p/p2p_build.c | 35 +++++++++++++ src/p2p/p2p_go_neg.c | 137 +++++++++++++++++++++++++++++---------------------- src/p2p/p2p_i.h | 2 + 3 files changed, 115 insertions(+), 59 deletions(-) diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 182af37..f505ad9 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -1022,3 +1022,38 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, return 0; } + + +struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p, + struct wpabuf *subelems, u32 ie_type) +{ + struct wpabuf *ie; + const u8 *pos, *end; + size_t len; + + if (!subelems) + return NULL; + + len = wpabuf_len(subelems) + 1000; + + ie = wpabuf_alloc(len); + if (!ie) + return NULL; + + pos = wpabuf_head(subelems); + end = pos + wpabuf_len(subelems); + + while (end > pos) { + size_t frag_len = end - pos; + + if (frag_len > 251) + frag_len = 251; + wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); + wpabuf_put_u8(ie, 4 + frag_len); + wpabuf_put_be32(ie, ie_type); + wpabuf_put_data(ie, pos, frag_len); + pos += frag_len; + } + + return ie; +} diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 58ea89c..5798018 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -138,12 +138,11 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, struct p2p_device *peer) { - struct wpabuf *buf; - u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; bool is_6ghz_capab; + struct wpabuf *buf, *buf2, *p2p_ie; #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_go_neg) @@ -153,13 +152,16 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) + buf2 = wpabuf_alloc(1000 + extra); + if (!buf2) return NULL; - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token); + p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_REQ, peer->dialog_token); + + p2p_ie = wpabuf_alloc(500); + if (!p2p_ie) + return NULL; - len = p2p_buf_add_ie_hdr(buf); group_capab = 0; if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; @@ -170,17 +172,17 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; - p2p_buf_add_capability(buf, p2p->dev_capab & + p2p_buf_add_capability(p2p_ie, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, group_capab); - p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker); - p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); - p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class, + p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | peer->tie_breaker); + p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout); + p2p_buf_add_listen_channel(p2p_ie, p2p->cfg->country, p2p->cfg->reg_class, p2p->cfg->channel); if (p2p->ext_listen_interval) - p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, + p2p_buf_add_ext_listen_timing(p2p_ie, p2p->ext_listen_period, p2p->ext_listen_interval); - p2p_buf_add_intended_addr(buf, p2p->intended_addr); + p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr); is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); if (p2p->num_pref_freq) { @@ -191,37 +193,41 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, p2p->num_pref_freq, &pref_chanlist, go); p2p_channels_dump(p2p, "channel list after filtering", &pref_chanlist); - p2p_buf_add_channel_list(buf, p2p->cfg->country, + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &pref_chanlist, is_6ghz_capab); } else { - p2p_buf_add_channel_list(buf, p2p->cfg->country, + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &p2p->channels, is_6ghz_capab); } - p2p_buf_add_device_info(buf, p2p, peer); - p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p_buf_add_device_info(p2p_ie, p2p, peer); + p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); - p2p_buf_update_ie_hdr(buf, len); - p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list, + buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE); + wpabuf_free(p2p_ie); + + p2p_buf_add_pref_channel_list(buf2, p2p->pref_freq_list, p2p->num_pref_freq); /* WPS IE with Device Password ID attribute */ pw_id = p2p_wps_method_pw_id(peer->wps_method); if (peer->oob_pw_id) pw_id = peer->oob_pw_id; - if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) { + if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) { p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request"); + wpabuf_free(buf2); wpabuf_free(buf); return NULL; } #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); + wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) - wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + buf = wpabuf_concat(buf2, buf); return buf; } @@ -292,13 +298,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, u8 dialog_token, u8 status, u8 tie_breaker) { - struct wpabuf *buf; - u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; bool is_6ghz_capab; struct p2p_channels pref_chanlist; + struct wpabuf *buf, *buf2, *p2p_ie; p2p_dbg(p2p, "Building GO Negotiation Response"); @@ -310,14 +315,17 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) + buf2 = wpabuf_alloc(1000 + extra); + if (!buf2) return NULL; - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token); + p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_RESP, dialog_token); - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); + p2p_ie = wpabuf_alloc(500); + if (!p2p_ie) + return NULL; + + p2p_buf_add_status(p2p_ie, status); group_capab = 0; if (peer && peer->go_state == LOCAL_GO) { if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { @@ -331,24 +339,25 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, if (p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; } - p2p_buf_add_capability(buf, p2p->dev_capab & + p2p_buf_add_capability(p2p_ie, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, group_capab); - p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker); - p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); + p2p_buf_add_go_intent(p2p_ie, (p2p->go_intent << 1) | tie_breaker); + p2p_buf_add_config_timeout(p2p_ie, p2p->go_timeout, p2p->client_timeout); if (p2p->override_pref_op_class) { p2p_dbg(p2p, "Override operating channel preference"); - p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country, p2p->override_pref_op_class, p2p->override_pref_channel); } else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) { p2p_dbg(p2p, "Omit Operating Channel attribute"); } else { - p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); } - p2p_buf_add_intended_addr(buf, p2p->intended_addr); + p2p_buf_add_intended_addr(p2p_ie, p2p->intended_addr); + if (p2p->num_pref_freq) { bool go = (peer && peer->go_state == LOCAL_GO) || p2p->go_intent == 15; @@ -362,12 +371,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p->allow_6ghz); } if (status || peer == NULL) { - p2p_buf_add_channel_list(buf, p2p->cfg->country, + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &pref_chanlist, false); } else if (peer->go_state == REMOTE_GO) { is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); - p2p_buf_add_channel_list(buf, p2p->cfg->country, + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &pref_chanlist, is_6ghz_capab); } else { struct p2p_channels res; @@ -376,33 +385,37 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); p2p_channels_intersect(&pref_chanlist, &peer->channels, &res); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, - is_6ghz_capab); + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res, + is_6ghz_capab); } - p2p_buf_add_device_info(buf, p2p, peer); + p2p_buf_add_device_info(p2p_ie, p2p, peer); if (peer && peer->go_state == LOCAL_GO) { - p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, + p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid, p2p->ssid_len); } - p2p_buf_update_ie_hdr(buf, len); + + buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE); + wpabuf_free(p2p_ie); /* WPS IE with Device Password ID attribute */ pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY); if (peer && peer->oob_pw_id) pw_id = peer->oob_pw_id; - if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) { + if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf2, pw_id, 0) < 0) { p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response"); + wpabuf_free(buf2); wpabuf_free(buf); return NULL; } #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); + wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) - wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + buf = wpabuf_concat(buf2, buf); return buf; } @@ -1163,12 +1176,11 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, u8 dialog_token, u8 status, const u8 *resp_chan, int go) { - struct wpabuf *buf; - u8 *len; struct p2p_channels res; u8 group_capab; size_t extra = 0; bool is_6ghz_capab; + struct wpabuf *buf, *buf2, *p2p_ie; p2p_dbg(p2p, "Building GO Negotiation Confirm"); @@ -1180,14 +1192,17 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); - buf = wpabuf_alloc(1000 + extra); - if (buf == NULL) + buf2 = wpabuf_alloc(1000 + extra); + if (!buf2) return NULL; - p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token); + p2p_buf_add_public_action_hdr(buf2, P2P_GO_NEG_CONF, dialog_token); + + p2p_ie = wpabuf_alloc(500); + if (!p2p_ie) + return NULL; - len = p2p_buf_add_ie_hdr(buf); - p2p_buf_add_status(buf, status); + p2p_buf_add_status(p2p_ie, status); group_capab = 0; if (peer->go_state == LOCAL_GO) { if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { @@ -1201,33 +1216,37 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, if (p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; } - p2p_buf_add_capability(buf, p2p->dev_capab & + p2p_buf_add_capability(p2p_ie, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, group_capab); if (go || resp_chan == NULL) - p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p_buf_add_operating_channel(p2p_ie, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); else - p2p_buf_add_operating_channel(buf, (const char *) resp_chan, + p2p_buf_add_operating_channel(p2p_ie, (const char *) resp_chan, resp_chan[3], resp_chan[4]); p2p_channels_intersect(&p2p->channels, &peer->channels, &res); is_6ghz_capab = is_p2p_6ghz_capable(p2p) && p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab); + p2p_buf_add_channel_list(p2p_ie, p2p->cfg->country, &res, is_6ghz_capab); if (go) { - p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, + p2p_buf_add_group_id(p2p_ie, p2p->cfg->dev_addr, p2p->ssid, p2p->ssid_len); } - p2p_buf_update_ie_hdr(buf, len); + + buf = p2p_encaps_p2p_vendor_ie(p2p, p2p_ie, P2P_IE_VENDOR_TYPE); + wpabuf_free(p2p_ie); #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_go_neg) - wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); + wpabuf_put_buf(buf2, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) - wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + + buf = wpabuf_concat(buf2, buf); return buf; } diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index c3dfcea..d7a5dc1 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -901,6 +901,8 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, void p2p_buf_add_pref_channel_list(struct wpabuf *buf, const struct weighted_pcl *pref_freq_list, unsigned int size); +struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p, + struct wpabuf *subelems, u32 ie_type); /* p2p_sd.c */ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:15 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:15 +0530 Subject: [PATCH v3 17/25] p2p: Add support for p2p2 set apis In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-18-git-send-email-quic_shivbara@quicinc.com> Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ src/p2p/p2p.h | 9 ++++++ wpa_supplicant/ctrl_iface.c | 40 ++++++++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 6e2a97c..ab3ccc1 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -4887,6 +4887,82 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled) } +void p2p_set_pairing_setup(struct p2p_data *p2p, int pairing_setup) +{ + p2p_dbg(p2p, "Pairing Setup: %d", pairing_setup); + p2p->cfg->pairing_config.pairing_capable = pairing_setup; + p2p->cfg->pairing_config.enable_pairing_setup = pairing_setup; + if (p2p->pairing_info) + p2p->pairing_info->enable_pairing_setup = pairing_setup; +} + + +void p2p_set_pairing_cache(struct p2p_data *p2p, int pairing_cache) +{ + p2p_dbg(p2p, "Pairing Cache: %d", pairing_cache); + p2p->cfg->pairing_config.enable_pairing_cache = pairing_cache; + if (p2p->pairing_info) + p2p->pairing_info->enable_pairing_cache = pairing_cache; +} + + +void p2p_set_pairing_verification(struct p2p_data *p2p, int pairing_verification) +{ + p2p_dbg(p2p, "Pairing Verification: %d", pairing_verification); + p2p->cfg->pairing_config.enable_pairing_verification = + pairing_verification; +} + + +void p2p_set_bootstrapmethods(struct p2p_data *p2p, int bootstrap_methods) +{ + p2p_dbg(p2p, "Bootstraping methods: 0x%x", bootstrap_methods); + p2p->cfg->pairing_config.bootstrap_methods = bootstrap_methods; + if (p2p->pairing_info) + p2p->pairing_info->supported_bootstrap = bootstrap_methods; +} + + +void p2p_set_pasn_type(struct p2p_data *p2p, u8 pasn_type) +{ + p2p_dbg(p2p, "PASN type: 0x%x", pasn_type); + p2p->cfg->pairing_config.pasn_type = pasn_type; + + memset(p2p->cfg->pairing_config.pasn_groups, 0, + sizeof(p2p->cfg->pairing_config.pasn_groups)); + + if (pasn_type & 0xc && pasn_type & 0x3) { + p2p->cfg->pairing_config.pasn_groups[0] = 20; + p2p->cfg->pairing_config.pasn_groups[1] = 19; + } else if (pasn_type & 0xc) { + p2p->cfg->pairing_config.pasn_groups[0] = 20; + } else if (pasn_type & 0x3) { + p2p->cfg->pairing_config.pasn_groups[0] = 19; + } +} + + +void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after) +{ + p2p_dbg(p2p, "Comeback after: %d", comeback_after); + p2p->cfg->comeback_after = comeback_after; +} + + +void p2p_set_reg_info(struct p2p_data *p2p, u8 val) +{ + p2p->cfg->reg_info = val; +} + + +void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val) +{ + p2p_dbg(p2p, "TWT-based P2P Power Mgmt: %s", + val ? "Enabled" : "Disabled"); + p2p->cfg->twt_power_mgmt = val; +} + + int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class, u8 *op_channel, struct wpa_freq_range_list *avoid_list, diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 1b1c19f..db2052f 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -2648,6 +2648,15 @@ int p2p_channel_to_freq(int op_class, int channel); struct wpabuf * p2p_usd_elems(struct p2p_data *p2p); void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, const u8 *peer_addr, unsigned int freq); +void p2p_set_pairing_setup(struct p2p_data *p2p, int pairing_setup); +void p2p_set_pairing_cache(struct p2p_data *p2p, int pairing_cache); +void p2p_set_pairing_verification(struct p2p_data *p2p, int pairing_verification); +void p2p_set_bootstrapmethods(struct p2p_data *p2p, int bootstrap_methods); +void p2p_set_pasn_type(struct p2p_data *p2p, u8 pasn_type); +void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after); +void p2p_set_reg_info(struct p2p_data *p2p, u8 val); +void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val); + int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq); int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, size_t len, int freq); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b223b7c..d976914 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7697,6 +7697,46 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "pairing_setup") == 0) { + p2p_set_pairing_setup(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "pairing_cache") == 0) { + p2p_set_pairing_cache(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "pairing_verification") == 0) { + p2p_set_pairing_verification(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "supported_bootstrapmethods") == 0) { + p2p_set_bootstrapmethods(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "pasn_type") == 0) { + p2p_set_pasn_type(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "comeback_after") == 0) { + p2p_set_comeback_after(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "reginfo") == 0) { + p2p_set_reg_info(wpa_s->global->p2p, atoi(param)); + return 0; + } + + if (os_strcmp(cmd, "twt_power_mgmt") == 0) { + p2p_set_twt_power_mgmt(wpa_s->global->p2p, atoi(param)); + return 0; + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:18 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:18 +0530 Subject: [PATCH v3 20/25] P2P: Add P2P2 support for autogo and client join In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-21-git-send-email-quic_shivbara@quicinc.com> Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 15 ++- src/p2p/p2p.h | 4 + src/p2p/p2p_i.h | 5 + wpa_supplicant/ctrl_iface.c | 5 +- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 2 +- wpa_supplicant/p2p_supplicant.c | 178 ++++++++++++++++++++++++---- wpa_supplicant/p2p_supplicant.h | 3 +- wpa_supplicant/wpa_supplicant_i.h | 3 + 8 files changed, 184 insertions(+), 31 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 702c90a..216abf4 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1881,6 +1881,12 @@ int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) } +void p2p_set_auto_go(struct p2p_data *p2p) +{ + p2p->auto_go = 1; +} + + void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) { struct p2p_go_neg_results res; @@ -1987,8 +1993,13 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) } #endif /* CONFIG_PASN */ - p2p_set_state(p2p, P2P_PROVISIONING); - p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); + if (p2p->auto_go && peer->p2p2) { + p2p->cfg->set_auto_go_pmk(p2p->cfg->cb_ctx, &res); + p2p->auto_go = 0; + } else { + p2p_set_state(p2p, P2P_PROVISIONING); + p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); + } } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 4759947..9962b69 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -973,6 +973,8 @@ struct p2p_config { */ void (*go_neg_completed)(void *ctx, struct p2p_go_neg_results *res); + void (*set_auto_go_pmk)(void *ctx, struct p2p_go_neg_results *res); + /** * sd_request - Callback on Service Discovery Request * @ctx: Callback context from cb_ctx @@ -2189,6 +2191,8 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p); */ int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params); +void p2p_set_auto_go(struct p2p_data *p2p); + /** * p2p_get_group_capab - Get Group Capability from P2P IE data * @p2p_ie: P2P IE(s) contents diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 7ff2c97..3e9119b 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -676,6 +676,11 @@ struct p2p_data { * invitation_resp - Invitation Response frame */ struct wpabuf *invitation_resp; + + /** + * Indicate that auto go is enabled for this device + */ + u8 auto_go; }; /** diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index daa8bef..d00cfda 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7215,6 +7215,7 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) { int freq = 0, persistent = 0, group_id = -1; + bool p2p2 = false; bool allow_6ghz = false; int vht = wpa_s->conf->p2p_go_vht; int ht40 = wpa_s->conf->p2p_go_ht40 || vht; @@ -7251,6 +7252,8 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) persistent = 1; } else if (os_strcmp(token, "allow_6ghz") == 0) { allow_6ghz = true; + } else if (os_strcmp(token, "p2p2") == 0) { + p2p2 = true; } else if (os_strncmp(token, "go_bssid=", 9) == 0) { if (hwaddr_aton(token + 9, go_bssid_buf)) return -1; @@ -7302,7 +7305,7 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) go_bssid); return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, - max_oper_chwidth, he, edmg, allow_6ghz); + max_oper_chwidth, he, edmg, allow_6ghz, p2p2); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index aad4c5b..1814b1d 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -489,7 +489,7 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, } } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, freq2, ht40, vht, max_oper_chwidth, he, edmg, - allow_6ghz)) + allow_6ghz, wpa_s->p2p2)) goto inv_args; out: diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 0befcdd..0aeb9c6 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2623,6 +2623,63 @@ bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s) } +static void wpas_set_auto_go_pmk(void *ctx, struct p2p_go_neg_results *params) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *ifs; + struct sta_info sta; + struct sae_data *sae; + struct hostapd_data *hapd; + struct hostapd_ssid *ssid = NULL; + + dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, + radio_list) { + if (ifs->current_ssid && + ifs->current_ssid->mode == WPAS_MODE_P2P_GO) + break; + } + + if (ifs && ifs->ap_iface && params->p2p2) { + + hapd = ifs->ap_iface->bss[0]; + hapd->conf->wps_state = 0; + ssid = &hapd->conf->ssid; + + if (params->akmp == WPA_KEY_MGMT_SAE) { + memset(&sta, 0, sizeof(struct sta_info)); + memcpy(sta.addr, params->peer_device_addr, ETH_ALEN); + sae = os_zalloc(sizeof(struct sae_data)); + if (!sae) { + wpa_printf(MSG_ERROR, "P2P: Mem alloc failed"); + return; + } + sta.sae = sae; + memcpy(sta.sae->pmkid, params->pmkid, PMKID_LEN); + wpa_printf(MSG_DEBUG, "P2P: Adding PMK for peer: " MACSTR + " by autonomous go", + MAC2STR(params->peer_device_addr)); + wpa_auth_pmksa_add_sae(hapd->wpa_auth, + params->peer_device_addr, + params->pmk, params->pmk_len, + params->pmkid, WPA_KEY_MGMT_SAE); + hostapd_add_pmkid(hapd, params->peer_device_addr, + params->pmk, params->pmk_len, + params->pmkid, WPA_KEY_MGMT_SAE); + memset(&sta, 0, sizeof(struct sta_info)); + os_free(sae); + } else if (params->akmp == WPA_KEY_MGMT_PASN) { + ssid->wpa_passphrase = os_strdup(params->password); + hapd->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + hapd->conf->wpa_key_mgmt = WPA_KEY_MGMT_SAE; + ssid->pt = sae_derive_pt(hapd->conf->sae_groups, ssid->ssid, + ssid->ssid_len, + (const u8 *) ssid->wpa_passphrase, + os_strlen(ssid->wpa_passphrase), + NULL); + } + } +} + static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; @@ -4882,7 +4939,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, 0); } else if (response_done) { wpas_p2p_group_add(wpa_s, 1, freq, - 0, 0, 0, 0, 0, 0, false); + 0, 0, 0, 0, 0, 0, false, + wpa_s->p2p2); } if (passwd_id == DEV_PW_P2PS_DEFAULT) { @@ -5006,7 +5064,8 @@ static int wpas_prov_disc_resp_cb(void *ctx) NULL, NULL, 0); } else { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p)); + is_p2p_allow_6ghz(wpa_s->global->p2p), + wpa_s->p2p2); } return 1; @@ -5358,6 +5417,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.send_action = wpas_send_action; p2p.send_action_done = wpas_send_action_done; p2p.go_neg_completed = wpas_go_neg_completed; + p2p.set_auto_go_pmk = wpas_set_auto_go_pmk; p2p.go_neg_req_rx = wpas_go_neg_req_rx; p2p.dev_found = wpas_dev_found; p2p.dev_lost = wpas_dev_lost; @@ -5831,7 +5891,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (scan_res) wpas_p2p_scan_res_handler(wpa_s, scan_res); - if (wpa_s->p2p_auto_pd) { + if (!wpa_s->p2p2 && wpa_s->p2p_auto_pd) { int join = wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr); if (join == 0 && @@ -5872,15 +5932,22 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, return; } - if (wpa_s->p2p_auto_join) { + if (wpa_s->p2p2 || wpa_s->p2p_auto_join) { int join = wpas_p2p_peer_go(wpa_s, wpa_s->pending_join_dev_addr); - if (join < 0) { - wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " - "running a GO -> use GO Negotiation"); - wpa_msg_global(wpa_s->p2pdev, MSG_INFO, - P2P_EVENT_FALLBACK_TO_GO_NEG - "reason=peer-not-running-GO"); + if (wpa_s->p2p2 || join < 0) { + if (join < 0) { + wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " + "running a GO -> use GO Negotiation"); + wpa_msg_global(wpa_s->p2pdev, MSG_INFO, + P2P_EVENT_FALLBACK_TO_GO_NEG + "reason=peer-not-running-GO"); + } + + if (wpa_s->p2p2) + wpa_printf(MSG_DEBUG, + "P2P2: Initiate Go Neg and provisioning " + "using PASN Authentication"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, @@ -5897,7 +5964,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p), wpa_s->p2p2, wpa_s->p2p_bootstrap, - NULL); + wpa_s->pending_join_password_len ? + wpa_s->pending_join_password : NULL); return; } @@ -6051,7 +6119,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, { int ret; struct wpa_driver_scan_params params; - struct wpabuf *wps_ie, *ies; + struct wpabuf *wps_ie = NULL, *ies; size_t ielen; int freqs[2] = { 0, 0 }; unsigned int bands; @@ -6071,13 +6139,16 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, wpa_s->p2p_join_ssid_len = 0; } - wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev, - wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0, - NULL); - if (wps_ie == NULL) { - wpas_p2p_scan_res_join(wpa_s, NULL); - return; + if (!wpa_s->p2p2) { + wpa_s->wps->dev.p2p = 1; + wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, + &wpa_s->wps->dev, + wpa_s->wps->uuid, + WPS_REQ_ENROLLEE, 0, NULL); + if (!wps_ie) { + wpas_p2p_scan_res_join(wpa_s, NULL); + return; + } } if (!freq) { @@ -6099,14 +6170,21 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, } ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { + + if (wps_ie) + ielen += wpabuf_len(wps_ie); + + ies = wpabuf_alloc(ielen); + if (!ies) { wpabuf_free(wps_ie); wpas_p2p_scan_res_join(wpa_s, NULL); return; } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); + + if (wps_ie) { + wpabuf_put_buf(ies, wps_ie); + wpabuf_free(wps_ie); + } bands = wpas_get_bands(wpa_s, freqs); p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands); @@ -6216,7 +6294,16 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN); os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr, ETH_ALEN); + if (wpa_s->pending_join_password_len) { + res.akmp = WPA_KEY_MGMT_SAE; + res.password_len = wpa_s->pending_join_password_len; + os_memcpy(res.password, wpa_s->pending_join_password, + res.password_len); + } res.wps_method = wpa_s->pending_join_wps_method; + res.p2p2 = wpa_s->p2p2; + res.cipher = WPA_CIPHER_CCMP; + if (freq && ssid && ssid_len) { res.freq = freq; res.ssid_len = ssid_len; @@ -6251,7 +6338,10 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } - wpas_start_wps_enrollee(group, &res); + if (res.p2p2) + wpas_start_gc(group, &res); + else + wpas_start_wps_enrollee(group, &res); /* * Allow a longer timeout for join-a-running-group than normal 15 @@ -6534,12 +6624,41 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, if (join || auto_join) { u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN]; + struct wpa_supplicant *ifs; if (auth) { wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to " "connect a running group from " MACSTR, MAC2STR(peer_addr)); os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN); - return ret; + + if (!wpa_s->p2p2) + return ret; + + if (is_zero_ether_addr(wpa_s->pending_interface_addr)) { + wpa_printf(MSG_DEBUG, "P2P: Interface address Invalid"); + return -1; + } + + wpa_printf(MSG_DEBUG, "P2P: own interface address for " + "authorizing join " MACSTR, + MAC2STR(wpa_s->pending_interface_addr)); + + dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, + radio_list) { + if (ifs->current_ssid == NULL || + ifs->current_ssid->mode != WPAS_MODE_P2P_GO) + continue; + + ssid = ifs->current_ssid; + } + p2p_set_auto_go(wpa_s->global->p2p); + return wpas_p2p_auth_go_neg(wpa_s, peer_addr, + wps_method, 15, + wpa_s->pending_interface_addr, + force_freq, + persistent_group, ssid, + pref_freq, bootstrap, + password); } os_memcpy(dev_addr, peer_addr, ETH_ALEN); if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr, @@ -6556,6 +6675,12 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_auto_started.usec); } wpa_s->user_initiated_pd = 1; + if (password) { + wpa_s->pending_join_password_len = os_strlen(password); + os_memcpy(wpa_s->pending_join_password, password, + os_strlen(password)); + wpa_s->pending_join_password[wpa_s->pending_join_password_len] = '\0'; + } if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method, auto_join, freq, group_ssid, group_ssid_len) < 0) @@ -7390,7 +7515,7 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, int max_oper_chwidth, int he, int edmg, - bool allow_6ghz) + bool allow_6ghz, bool p2p2) { struct p2p_go_neg_results params; int selected_freq = 0; @@ -7402,6 +7527,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, os_free(wpa_s->global->add_psk); wpa_s->global->add_psk = NULL; + wpa_s->p2p2 = p2p2; /* Make sure we are not running find during connection establishment */ wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND"); diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 61d4281..1e5f77a 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -45,7 +45,8 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq, struct wpa_ssid *ssid); int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq, int vht_center_freq2, int ht40, int vht, - int max_oper_chwidth, int he, int edmg, bool allow_6ghz); + int max_oper_chwidth, int he, int edmg, bool allow_6ghz, + bool p2p2); int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int addr_allocated, int force_freq, int neg_freq, diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 51da6ff..610072e 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1115,6 +1115,9 @@ struct wpa_supplicant { u8 pending_join_dev_addr[ETH_ALEN]; u8 p2p_bootstrap_dev_addr[ETH_ALEN]; int pending_join_wps_method; + u16 pending_join_bootstrap; + char pending_join_password[100]; + size_t pending_join_password_len; u8 p2p_join_ssid[SSID_MAX_LEN]; size_t p2p_join_ssid_len; int p2p_join_scan_count; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:20 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:20 +0530 Subject: [PATCH v3 22/25] P2P: Add support to validate DIRA and configure PMK In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-23-git-send-email-quic_shivbara@quicinc.com> When DIRA is matched, configure PMK for pairing verification of previously paired peer. --- src/ap/wpa_auth.c | 18 +++++++++++++ src/ap/wpa_auth.h | 3 +++ src/p2p/p2p.c | 39 +++++++++++++++++++++++++++ src/p2p/p2p.h | 19 ++++++++++++++ src/rsn_supp/wpa.c | 17 ++++++++++++ src/rsn_supp/wpa.h | 2 ++ wpa_supplicant/p2p_supplicant.c | 58 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 156 insertions(+) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 93f157d..20c809a 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -6557,6 +6557,24 @@ wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid); } +int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr, u8 **pmk, u16 *pmk_len, + u8 **pmkid) +{ + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = wpa_auth_pmksa_get(wpa_auth, sta_addr, NULL); + if (!pmksa) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get PMKSA for " MACSTR, + MAC2STR(sta_addr)); + return -1; + } + + *pmk = pmksa->pmk; + *pmk_len = pmksa->pmk_len; + *pmkid = pmksa->pmkid; + return 0; +} void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, struct wpa_state_machine *sm, diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index b22c419..0d621a0 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -528,6 +528,9 @@ wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); +int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr, u8 **pmk, u16 *pmk_len, + u8 **pmkid); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 216abf4..2c81ec5 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -5177,6 +5177,24 @@ int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, } +int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr, + u8 **dik_data, u16 *dik_len, u8 *cipher) +{ + struct p2p_device *dev = p2p_get_device(p2p, dev_addr); + if (!dev) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get device identity key for dev " + MACSTR, MAC2STR(dev_addr)); + return -1; + } + + *dik_data = dev->info.dik_data; + *dik_len = dev->info.dik_len; + *cipher = dev->info.dik_cipher_version; + + return 0; +} + + void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr) { os_memcpy(p2p->peer_filter, addr, ETH_ALEN); @@ -5931,6 +5949,14 @@ void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value) p2p->allow_6ghz = value; } +void p2p_validate_dira(struct p2p_data *p2p, struct p2p_device *dev, + const u8 *dira, u16 dira_len) +{ + if (p2p->cfg->validate_dira) + p2p->cfg->validate_dira(p2p->cfg->cb_ctx, p2p->cfg->dev_addr, + dev->info.p2p_device_addr, dira, + dira_len); +} struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) { @@ -6035,6 +6061,9 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, if (!ether_addr_equal(peer_addr, p2p_dev_addr)) os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN); + if (msg.dira && msg.dira_len) + p2p_validate_dira(p2p, dev, msg.dira, msg.dira_len); + p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR " dev_capab=0x%x group_capab=0x%x listen_freq=%d", MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab, @@ -6913,4 +6942,14 @@ int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, } return ret; } + + +void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, + u8 *pmk, u16 pmk_len, u8 *pmkid) +{ + pasn_initiator_pmksa_cache_add(p2p->initiator_pmksa, src, dst, pmk, + pmk_len, pmkid); + pasn_responder_pmksa_cache_add(p2p->responder_pmksa, src, dst, pmk, + pmk_len, pmkid); +} #endif diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 9962b69..6024370 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1337,6 +1337,21 @@ struct p2p_config { int freq); /** + * validate_dira - Function handler to validate dira against list of + * device identity keys available + * @ctx: Callback context from cb_ctx + * @own_addr: p2p device own address + * @peer_addr: p2p device address of the peer + * @dira: DIRA attribute present in the USD frames + * @dira_len: length of DIRA + * + * This function can be used to vaildate DIRA and configure PMK of + * paired/persistent peer from conf file. + */ + void (*validate_dira)(void *ctx, const u8 *own_addr, const u8 *peer_addr, + const u8 *dira, u16 dira_len); + + /** * pasn_send_mgmt - Function handler to transmit a Management frame * @ctx: Callback context from cb_ctx * @data : Frame to transmit @@ -2293,6 +2308,8 @@ int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, u8 *iface_addr); int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, u8 *dev_addr); +int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr, + u8 **dik_data, u16 *dik_len, u8 *cipher); void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr); @@ -2697,4 +2714,6 @@ int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data, size_t len); int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, size_t data_len, u8 acked, bool verify); +void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, + u8 *pmk, u16 pmk_len, u8 *pmkid); #endif /* P2P_H */ diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 52a4c74..3aa660d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -5547,6 +5547,23 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, akmp); } +int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, u8 **pmk, + u16 *pmk_len, u8 **pmkid) +{ + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = wpa_sm_pmksa_cache_get(sm, aa, NULL, NULL, 0); + if (!pmksa) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get PMKSA for " MACSTR, + MAC2STR(aa)); + return -1; + } + + *pmk = pmksa->pmk; + *pmk_len = pmksa->pmk_len; + *pmkid = pmksa->pmkid; + return 0; +} void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, struct rsn_pmksa_cache_entry *entry) diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index d85dd9a..2d9ed50 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -254,6 +254,8 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *pmkid, const void *network_ctx, int akmp); +int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, u8 **pmk, + u16 *pmk_len, u8 **pmkid); void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, struct rsn_pmksa_cache_entry *entry); bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 0aeb9c6..903aa42 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5152,6 +5152,63 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status, #endif /* CONFIG_PASN */ } +void wpas_validate_dira(void *ctx, const u8 *own_addr, const u8 *peer_addr, + const u8 *dira, u16 dira_len) +{ + int ret; + u8 pmk[PMK_LEN_MAX]; + u8 pmkid[PMKID_LEN]; + u8 tag[DEVICE_MAX_HASH_LEN]; + u8 dik[DEVICE_IDENTITY_KEY_LEN]; + struct wpa_dev_ik *ik = NULL; + struct wpa_supplicant *wpa_s = ctx; + u8 data[DIR_STR_LEN + DEVICE_IDENTITY_NONCE_LEN + ETH_ALEN]; + + if (dira[0] != DIRA_CIPHER_VERSION_128) { + wpa_printf(MSG_ERROR, + "DIRA cipher version unsupported, (%d)", dira[0]); + return; + } + + os_memset(tag, 0, sizeof(tag)); + os_memset(data, 0, sizeof(data)); + os_memcpy(data, "DIR", DIR_STR_LEN); + os_memcpy(&data[DIR_STR_LEN], peer_addr, ETH_ALEN); + os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], &dira[1], + DEVICE_IDENTITY_NONCE_LEN); + + for (ik = wpa_s->conf->identity; ik; ik = ik->next) { + if (ik->dik_len != DEVICE_IDENTITY_KEY_LEN || + ik->dik_cipher != DIRA_CIPHER_VERSION_128) + continue; + + hexstr2bin(ik->dik_data, dik, DEVICE_IDENTITY_KEY_LEN); + ret = hmac_sha256(dik, DEVICE_IDENTITY_KEY_LEN, data, + sizeof(data), tag); + if (ret < 0) { + wpa_printf(MSG_ERROR, "DIRA Tag derivation failed"); + return; + } + + if (os_memcmp(tag, &dira[1 + DEVICE_IDENTITY_NONCE_LEN], + DEVICE_IDENTITY_TAG_LEN) == 0) { + wpa_printf(MSG_DEBUG, "DIRA Tag Matched"); + break; + } + } + + if (!ik) + return; + + hexstr2bin(ik->pmk, pmk, ik->pmk_len); + hexstr2bin(ik->pmkid, pmkid, PMKID_LEN); + +#ifdef CONFIG_PASN + p2p_pasn_pmksa_set_pmk(wpa_s->global->p2p, own_addr, peer_addr, pmk, + ik->pmk_len, pmkid); +#endif /* CONFIG_PASN */ +} + #ifdef CONFIG_PASN static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) { @@ -5449,6 +5506,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; p2p.bootstrap_req_rx = wpas_bootstrap_req_rx; p2p.bootstrap_completed = wpas_bootstrap_completed; + p2p.validate_dira = wpas_validate_dira; #ifdef CONFIG_PASN p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mlme; p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:21 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:21 +0530 Subject: [PATCH v3 23/25] P2P: Add support to store indentity key in conf file In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-24-git-send-email-quic_shivbara@quicinc.com> When persistent is enabled, store identity key in conf file which is needed for pairing verification to invoke the persistent group. Signed-off-by: Shivani Baranwal --- wpa_supplicant/ctrl_iface.c | 3 + wpa_supplicant/p2p_supplicant.c | 161 +++++++++++++++++++++++++++++++++++++++- wpa_supplicant/p2p_supplicant.h | 7 ++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index d00cfda..5a5b9e4 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -12984,6 +12984,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) { if (wpas_p2p_lo_stop(wpa_s)) reply_len = -1; + } else if (os_strcmp(buf, "P2P_REMOVE_IDENTITY") == 0) { + if (wpas_p2p_remove_all_identity(wpa_s)) + reply_len = -1; #endif /* CONFIG_P2P */ #ifdef CONFIG_WIFI_DISPLAY } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 903aa42..249390b 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -167,6 +167,8 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s, static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_disallowed_freq(struct wpa_global *global, unsigned int freq); +static void wpas_p2p_store_go_identity(struct wpa_supplicant *wpa_s, + const u8 *go_dev_addr, const u8 *bssid); #ifdef CONFIG_PASN static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int freq); @@ -1133,6 +1135,7 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s, struct wpabuf *p2p; u8 group_capab; const u8 *addr; + int persistent; if (wpa_s->go_params) bssid = wpa_s->go_params->peer_interface_addr; @@ -1189,7 +1192,12 @@ static int wpas_p2p_persistent_group(struct wpa_supplicant *wpa_s, "go_dev_addr=" MACSTR, MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr)); - return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP); + persistent = !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP); + + if (persistent) + wpas_p2p_store_go_identity(wpa_s, go_dev_addr, bssid); + + return persistent; } @@ -3494,7 +3502,7 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && - ether_addr_equal(s->bssid, go_dev_addr) && + //ether_addr_equal(s->bssid, go_dev_addr) && s->ssid_len == ssid_len && os_memcmp(ssid, s->ssid, ssid_len) == 0) break; @@ -8568,6 +8576,107 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, go_dev_addr, persistent, pref_freq, -1, 0); } +int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s) +{ + struct wpa_dev_ik *ik; + + for (ik = wpa_s->conf->identity; ik; ik = ik->next) + wpa_config_remove_identity(wpa_s->conf, ik->id); + + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) { + wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); + return -1; + } + return 0; +} + +static void wpas_p2p_store_identity(struct wpa_supplicant *wpa_s, u8 cipher, + u8 *dik_data, u16 dik_len, u8 *pmk, + u16 pmk_len, u8 *pmkid) +{ + u8 dik[64]; + struct wpa_dev_ik *ik; + + for (ik = wpa_s->conf->identity; ik; ik = ik->next) { + if (dik_len == ik->dik_len) { + hexstr2bin(ik->dik_data, dik, dik_len); + if (os_memcmp(dik_data, dik, dik_len) == 0) { + wpa_printf(MSG_DEBUG, + "P2P: Remove previous entry of peer"); + wpa_config_remove_identity(wpa_s->conf, ik->id); + break; + } + } + } + + wpa_printf(MSG_DEBUG, "P2P: Create a new Device Identity entry"); + ik = wpa_config_add_identity(wpa_s->conf); + if (ik == NULL) + return; + + ik->dik_data = os_zalloc(dik_len * 2 + 1); + if (!ik->dik_data) + return; + ik->pmk = os_zalloc(pmk_len * 2 + 1); + if (!ik->pmk) + return; + ik->pmkid = os_zalloc(PMKID_LEN * 2 + 1); + if (!ik->pmkid) + return; + + wpa_snprintf_hex(ik->dik_data, dik_len * 2 + 1, dik_data, + dik_len); + ik->dik_len = dik_len; + ik->dik_cipher = cipher; + + wpa_snprintf_hex(ik->pmk, pmk_len * 2 + 1, pmk, pmk_len); + ik->pmk_len = pmk_len; + + wpa_snprintf_hex(ik->pmkid, PMKID_LEN * 2 + 1, pmkid, PMKID_LEN); + + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) + wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration"); +} + + +static void wpas_p2p_store_go_identity(struct wpa_supplicant *wpa_s, + const u8 *go_dev_addr, const u8 *bssid) +{ + int ret; + u8 cipher; + u16 dik_len, pmk_len; + u8 *dik_data, *pmk, *pmkid; + u8 iface_addr[ETH_ALEN]; + struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s; + + if (!wpa_s->p2p2) + return; + + ret = p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, go_dev_addr, + &dik_data, &dik_len, &cipher); + if (ret) + return; + + ret = p2p_get_interface_addr(p2p_wpa_s->global->p2p, go_dev_addr, + iface_addr); + if (ret) { + wpa_printf(MSG_DEBUG, "P2P: Fetch PMK from go bssid" + "(bssid " MACSTR ")", MAC2STR(bssid)); + memcpy(iface_addr, bssid, ETH_ALEN); + } + ret = wpa_sm_pmksa_get_pmk(wpa_s->wpa, iface_addr, &pmk, &pmk_len, + &pmkid); + if (ret) + return; + + wpa_printf(MSG_DEBUG, "P2P: Storing Device identity of " + "client (Interface Addr " MACSTR ")", MAC2STR(iface_addr)); + wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk, + pmk_len, pmkid); +} + void wpas_p2p_completed(struct wpa_supplicant *wpa_s) { @@ -9393,6 +9502,52 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, } +static void wpas_p2p_store_client_identity(struct wpa_supplicant *wpa_s, + const u8 *addr) +{ + int ret; + u8 cipher; + u16 dik_len, pmk_len; + u8 *dik_data, *pmk, *pmkid; + u8 iface_addr[ETH_ALEN]; + struct hostapd_data *hapd; + struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s; + + if (!wpa_s->p2p2) + return; + + hapd = wpa_s->ap_iface->bss[0]; + if (!hapd) + return; + + ret = p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, addr, + &dik_data, &dik_len, &cipher); + if (ret) + return; + + wpa_printf(MSG_DEBUG, "P2P: Fetch PMK from client" + "(Device Addr " MACSTR ")", MAC2STR(addr)); + ret = wpa_auth_pmksa_get_pmk(hapd->wpa_auth, addr, &pmk, &pmk_len, + &pmkid); + if (ret) { + wpa_printf(MSG_DEBUG, "P2P: Fetch PMK from client" + "(Iface Addr " MACSTR ")", MAC2STR(iface_addr)); + ret = p2p_get_interface_addr(p2p_wpa_s->global->p2p, addr, + iface_addr); + if (ret) + return; + ret = wpa_auth_pmksa_get_pmk(hapd->wpa_auth, iface_addr, &pmk, + &pmk_len, &pmkid); + if (ret) + return; + } + + wpa_printf(MSG_DEBUG, "P2P: Storing Device identity of " + "client (Device Addr " MACSTR ")", MAC2STR(addr)); + wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk, + pmk_len, pmkid); +} + void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr) { @@ -9434,6 +9589,8 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, wpa_s->global->p2p_go_wait_client.sec = 0; if (addr == NULL) return; + + wpas_p2p_store_client_identity(wpa_s, addr); wpas_p2p_add_persistent_group_client(wpa_s, addr); } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 1e5f77a..c9e9c78 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -233,6 +233,7 @@ struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s); int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len, int freq); +int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s); #else /* CONFIG_P2P */ static inline int @@ -370,6 +371,12 @@ wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, return 0; } +static inline int +wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s) +{ + return 0; +} + #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:19 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:19 +0530 Subject: [PATCH v3 21/25] P2P: Add device identity block to p2p_supplicant.conf In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-22-git-send-email-quic_shivbara@quicinc.com> Add device identity block to store dik, pmk, pmikd, cipher version. This persistent data is used during pairing verification of previously paired peers. Signed-off-by: Shivani Baranwal --- wpa_supplicant/config.c | 132 +++++++++++++++++++++++++++++++++++++++++++ wpa_supplicant/config.h | 62 ++++++++++++++++++++ wpa_supplicant/config_file.c | 96 +++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index d0957eb..f9d34b2 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3027,6 +3027,7 @@ void wpa_config_free(struct wpa_config *config) { struct wpa_ssid *ssid, *prev = NULL; struct wpa_cred *cred, *cprev; + struct wpa_dev_ik *identity, *iprev; int i; ssid = config->ssid; @@ -3043,6 +3044,13 @@ void wpa_config_free(struct wpa_config *config) wpa_config_free_cred(cprev); } + identity = config->identity; + while (identity) { + iprev = identity; + identity = identity->next; + wpa_config_free_identity(iprev); + } + wpa_config_flush_blobs(config); wpabuf_free(config->wps_vendor_ext_m1); @@ -4105,6 +4113,60 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return -1; } +int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var, + const char *value, int line) +{ + char *val; + size_t len; + + if (os_strcmp(var, "dik_cipher") == 0) { + identity->dik_cipher = atoi(value); + return 0; + } + + if (os_strcmp(var, "dik_len") == 0) { + identity->dik_len = atoi(value); + return 0; + } + + val = wpa_config_parse_string(value, &len); + if (val == NULL) { + wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " + "value '%s'.", line, var, value); + return -1; + } + + if (os_strcmp(var, "dik_data") == 0) { + os_free(identity->dik_data); + identity->dik_data = val; + return 0; + } + + if (os_strcmp(var, "pmk_len") == 0) { + identity->pmk_len = atoi(value); + return 0; + } + + if (os_strcmp(var, "pmk") == 0) { + os_free(identity->pmk); + identity->pmk = val; + return 0; + } + if (os_strcmp(var, "pmkid") == 0) { + os_free(identity->pmkid); + identity->pmkid = val; + return 0; + } + + if (line) { + wpa_printf(MSG_ERROR, "Line %d: unknown identity field '%s'.", + line, var); + } + + os_free(val); + + return -1; +} static char * alloc_int_str(int val) { @@ -5763,3 +5825,73 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) return ret; } + +void wpa_config_free_identity(struct wpa_dev_ik *identity) +{ + os_free(identity->dik_data); + os_free(identity->pmk); + os_free(identity->pmkid); + os_free(identity); +} + +/** + * wpa_config_add_identity - Add a new device identity with empty configuration + * @config: Configuration data from wpa_config_read() + * Returns: The new device identity or %NULL if operation failed + */ +struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config) +{ + int id; + struct wpa_dev_ik *identity, *last = NULL; + + id = -1; + identity = config->identity; + while (identity) { + if (identity->id > id) + id = identity->id; + last = identity; + identity = identity->next; + } + id++; + + identity = os_zalloc(sizeof(*identity)); + if (identity == NULL) + return NULL; + identity->id = id; + if (last) + last->next = identity; + else + config->identity = identity; + + return identity; +} + +/** + * wpa_config_remove_identity - Remove a configured identity based on id + * @config: Configuration data from wpa_config_read() + * @id: Unique network id to search for + * Returns: 0 on success, or -1 if the network was not found + */ +int wpa_config_remove_identity(struct wpa_config *config, int id) +{ + struct wpa_dev_ik *identity, *prev = NULL; + + identity = config->identity; + while (identity) { + if (id == identity->id) + break; + prev = identity; + identity = identity->next; + } + + if (identity == NULL) + return -1; + + if (prev) + prev->next = identity->next; + else + config->identity = identity->next; + + wpa_config_free_identity(identity); + return 0; +} diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 6b8f0cb..3333125 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -417,6 +417,57 @@ struct wpa_cred { int sim_num; }; +struct wpa_dev_ik { + /** + * next - Next device Identity in the list + * + * This pointer can be used to iterate over all device Indetity keys. + * The head of this list is stored in the dev_ik field of struct + * wpa_config. + */ + struct wpa_dev_ik *next; + + /** + * id - Unique id for the credential + * + * This identifier is used as a unique identifier for each identity + * block when using the control interface. Each identity is allocated + * an id when it is being created, either when reading the + * configuration file or when a new identity is added through the + * control interface. + */ + int id; + + /** + * dik_cipher - Device Identity key cipher version + */ + int dik_cipher; + + /** + * dik_len - Device Identity key length + */ + int dik_len; + + /** + * dik_data - Device Identity key which is unique for the device + */ + char *dik_data; + + /** + * pmk_len - PMK length + */ + int pmk_len; + + /** + * pmk - pmk associated of previous connection with the given device + */ + char *pmk; + + /** + * pmkid - pmkid of previous connection with the given device + */ + char *pmkid; +}; #define CFG_CHANGED_DEVICE_NAME BIT(0) #define CFG_CHANGED_CONFIG_METHODS BIT(1) @@ -1823,6 +1874,12 @@ struct wpa_config { /* length of DevIK */ size_t dik_len; + /** + * identity - Head of the list of peer device identities + * + * This is the head for the list of all the paired devices. + */ + struct wpa_dev_ik *identity; }; @@ -1867,6 +1924,8 @@ int wpa_config_remove_cred(struct wpa_config *config, int id); void wpa_config_free_cred(struct wpa_cred *cred); int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line); +int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var, + const char *value, int line); char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var); struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, @@ -1919,5 +1978,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, * Each configuration backend needs to implement this function. */ int wpa_config_write(const char *name, struct wpa_config *config); +void wpa_config_free_identity(struct wpa_dev_ik *identity); +struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config); +int wpa_config_remove_identity(struct wpa_config *config, int id); #endif /* CONFIG_H */ diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 68aed57..f79b301 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -296,6 +296,60 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f, #endif /* CONFIG_NO_CONFIG_BLOBS */ +static struct wpa_dev_ik * wpa_config_read_identity(FILE *f, int *line, int id) +{ + struct wpa_dev_ik *identity; + int errors = 0, end = 0; + char buf[256], *pos, *pos2; + + wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new identity block", *line); + identity = os_zalloc(sizeof(*identity)); + if (identity == NULL) + return NULL; + identity->id = id; + + while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { + if (os_strcmp(pos, "}") == 0) { + end = 1; + break; + } + + pos2 = os_strchr(pos, '='); + if (pos2 == NULL) { + wpa_printf(MSG_ERROR, "Line %d: Invalid identity line " + "'%s'.", *line, pos); + errors++; + continue; + } + + *pos2++ = '\0'; + if (*pos2 == '"') { + if (os_strchr(pos2 + 1, '"') == NULL) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "quotation '%s'.", *line, pos2); + errors++; + continue; + } + } + + if (wpa_config_set_identity(identity, pos, pos2, *line) < 0) + errors++; + } + + if (!end) { + wpa_printf(MSG_ERROR, "Line %d: identity block was not " + "terminated properly.", *line); + errors++; + } + + if (errors) { + wpa_config_free_identity(identity); + identity = NULL; + } + + return identity; +} + struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, bool ro) { @@ -304,9 +358,11 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, int errors = 0, line = 0; struct wpa_ssid *ssid, *tail, *head; struct wpa_cred *cred, *cred_tail, *cred_head; + struct wpa_dev_ik *identity, *identity_tail, *identity_head; struct wpa_config *config; static int id = 0; static int cred_id = 0; + static int identity_id = 0; if (name == NULL) return NULL; @@ -325,6 +381,9 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, cred_tail = cred_head = config->cred; while (cred_tail && cred_tail->next) cred_tail = cred_tail->next; + identity_tail = identity_head = config->identity; + while (identity_tail && identity_tail->next) + identity_tail = identity_tail->next; wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name); f = fopen(name, "r"); @@ -383,6 +442,20 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, continue; } #endif /* CONFIG_NO_CONFIG_BLOBS */ + } else if (os_strcmp(pos, "identity={") == 0) { + identity = wpa_config_read_identity(f, &line, identity_id++); + if (identity == NULL) { + wpa_printf(MSG_ERROR, "Line %d: failed to " + "parse identity block.", line); + errors++; + continue; + } + if (identity_head == NULL) { + identity_head = identity_tail = identity; + } else { + identity_tail->next = identity; + identity_tail = identity; + } } else if (wpa_config_process_global(config, pos, line) < 0) { wpa_printf(MSG_ERROR, "Line %d: Invalid configuration " "line '%s'.", line, pos); @@ -396,6 +469,7 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, config->ssid = head; wpa_config_debug_dump_networks(config); config->cred = cred_head; + config->identity = identity_head; #ifndef WPA_IGNORE_CONFIG_ERRORS if (errors) { @@ -1075,6 +1149,21 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) cred->imsi_privacy_attr); } +static void wpa_config_write_identity(FILE *f, struct wpa_dev_ik *dev_ik) +{ + fprintf(f, "\tdik_cipher=%d\n", dev_ik->dik_cipher); + + fprintf(f, "\tdik_len=%d\n", dev_ik->dik_len); + if (dev_ik->dik_data) + fprintf(f, "\tdik_data=\"%s\"\n", dev_ik->dik_data); + + fprintf(f, "\tpmk_len=%d\n", dev_ik->pmk_len); + if (dev_ik->pmk) + fprintf(f, "\tpmk=\"%s\"\n", dev_ik->pmk); + + if (dev_ik->pmkid) + fprintf(f, "\tpmkid=\"%s\"\n", dev_ik->pmkid); +} #ifndef CONFIG_NO_CONFIG_BLOBS static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob) @@ -1646,6 +1735,7 @@ int wpa_config_write(const char *name, struct wpa_config *config) FILE *f; struct wpa_ssid *ssid; struct wpa_cred *cred; + struct wpa_dev_ik *dev_ik; #ifndef CONFIG_NO_CONFIG_BLOBS struct wpa_config_blob *blob; #endif /* CONFIG_NO_CONFIG_BLOBS */ @@ -1700,6 +1790,12 @@ int wpa_config_write(const char *name, struct wpa_config *config) fprintf(f, "}\n"); } + for (dev_ik = config->identity; dev_ik; dev_ik = dev_ik->next) { + fprintf(f, "\nidentity={\n"); + wpa_config_write_identity(f, dev_ik); + fprintf(f, "}\n"); + } + #ifndef CONFIG_NO_CONFIG_BLOBS for (blob = config->blobs; blob; blob = blob->next) { ret = wpa_config_write_blob(f, blob); -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:16 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:16 +0530 Subject: [PATCH v3 18/25] Add p2p2 support for group formation on successful negotiation In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-19-git-send-email-quic_shivbara@quicinc.com> Add support for Group formation and connection between p2p go and p2p client on successful go negotiation. Signed-off-by: Shivani Baranwal --- src/ap/ap_drv_ops.c | 23 +++++ src/ap/ap_drv_ops.h | 5 ++ src/ap/ieee802_11.c | 15 ++++ src/ap/ieee802_11.h | 2 + src/ap/wpa_auth_ie.c | 17 ++++ src/p2p/p2p.c | 59 +++++++++++-- src/p2p/p2p.h | 22 ++++- src/p2p/p2p_group.c | 50 ++++++++++- src/p2p/p2p_i.h | 2 + wpa_supplicant/p2p_supplicant.c | 180 +++++++++++++++++++++++++++++++++++----- 10 files changed, 346 insertions(+), 29 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index c473491..e22efeb 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -1250,3 +1250,26 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd, return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms); } #endif /* CONFIG_PASN */ + +int hostapd_drv_add_pmkid(struct hostapd_data *hapd, + struct wpa_pmkid_params *params) +{ + if (!hapd->driver || !hapd->driver->add_pmkid || !hapd->drv_priv) + return 0; + return hapd->driver->add_pmkid(hapd->drv_priv, params); +} + +int hostapd_drv_remove_pmkid(struct hostapd_data *hapd, + struct wpa_pmkid_params *params) +{ + if (!hapd->driver || !hapd->driver->remove_pmkid || !hapd->drv_priv) + return 0; + return hapd->driver->remove_pmkid(hapd->drv_priv, params); +} + +int hostapd_drv_flush_pmkid(struct hostapd_data *hapd) +{ + if (!hapd->driver || !hapd->driver->flush_pmkid || !hapd->drv_priv) + return 0; + return hapd->driver->flush_pmkid(hapd->drv_priv); +} diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index d7e79c8..de7c4af 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -148,6 +148,11 @@ int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd, u32 cipher, u8 key_len, const u8 *key, u8 ltf_keyseed_len, const u8 *ltf_keyseed, u32 action); +int hostapd_drv_add_pmkid(struct hostapd_data *hapd, + struct wpa_pmkid_params *params); +int hostapd_drv_remove_pmkid(struct hostapd_data *hapd, + struct wpa_pmkid_params *params); +int hostapd_drv_flush_pmkid(struct hostapd_data *hapd); #include "drivers/driver.h" diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 3c5a8dd..5973056 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -8295,4 +8295,19 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, return eid; } + +int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk, + size_t pmk_len, const u8 *pmkid, int akmp) +{ + struct wpa_pmkid_params params; + + os_memset(¶ms, 0, sizeof(params)); + params.bssid = bssid; + params.pmkid = pmkid; + params.pmk = pmk; + params.pmk_len = pmk_len; + + return hostapd_drv_add_pmkid(hapd, ¶ms); +} + #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index dd4995f..b1a3edf 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -263,5 +263,7 @@ int hostapd_process_assoc_ml_info(struct hostapd_data *hapd, const u8 *ies, size_t ies_len, bool reassoc, int tx_link_status, bool offload); +int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk, + size_t pmk_len, const u8 *pmkid, int akmp); #endif /* IEEE802_11_H */ diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 43d9c1d..bd1bd64 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -499,6 +499,9 @@ static u32 rsnxe_capab(struct wpa_auth_config *conf, int key_mgmt) #endif /* CONFIG_SAE_PK */ } + // FIXME: Should not set it by default + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); + if (conf->secure_ltf) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); if (conf->secure_rtt) @@ -1251,6 +1254,20 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, pmkid = sm->pmksa->pmkid; break; } + + if (!is_zero_ether_addr(sm->p2p_dev_addr)) { + wpa_hexdump(MSG_DEBUG, "RSN IE: P2P DEV PMKID", + &data.pmkid[i * PMKID_LEN], PMKID_LEN); + sm->pmksa = + pmksa_cache_auth_get(wpa_auth->pmksa, + sm->p2p_dev_addr, + &data.pmkid[i * PMKID_LEN]); + if (sm->pmksa) { + pmkid = sm->pmksa->pmkid; + break; + } + } + } for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && i < data.num_pmkid; i++) { diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index ab3ccc1..8f3d76e 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -253,6 +253,7 @@ void p2p_go_neg_failed(struct p2p_data *p2p, int status) os_memset(&res, 0, sizeof(res)); res.status = status; + res.p2p2 = peer->p2p2; os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN); p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); @@ -1072,7 +1073,8 @@ static void p2p_search(struct p2p_data *p2p) res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, pw_id, p2p->include_6ghz); + p2p->find_dev_id, pw_id, p2p->include_6ghz, + false); if (res < 0) { p2p_dbg(p2p, "Scan request schedule failed"); p2p_continue_find(p2p); @@ -1299,7 +1301,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, DEV_PW_DEFAULT, - p2p->include_6ghz); + p2p->include_6ghz, false); break; } /* fall through */ @@ -1307,13 +1309,15 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT, p2p->include_6ghz); + DEV_PW_DEFAULT, p2p->include_6ghz, + false); break; case P2P_FIND_ONLY_SOCIAL: res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0, p2p->num_req_dev_types, p2p->req_dev_types, dev_id, - DEV_PW_DEFAULT, p2p->include_6ghz); + DEV_PW_DEFAULT, p2p->include_6ghz, + false); break; default: return -1; @@ -1861,6 +1865,16 @@ int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) } p2p->ssid_set = 0; + params->cipher = WPA_CIPHER_CCMP; + if (p2p->cfg->pairing_config.pasn_type & 0xc) + params->cipher |= WPA_CIPHER_GCMP_256; + + if (params->p2p2) { + params->password_len = p2p->cfg->dev_password_len; + memcpy(params->password, p2p->cfg->dev_password, + p2p->cfg->dev_password_len); + } + p2p_random(params->passphrase, p2p->cfg->passphrase_len); params->passphrase[p2p->cfg->passphrase_len] = '\0'; return 0; @@ -1934,8 +1948,43 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) peer->go_neg_conf = NULL; #ifdef CONFIG_PASN - if (peer->p2p2 && peer->pasn) + if (peer->p2p2 && peer->pasn) { + res.p2p2 = peer->p2p2; + res.akmp = peer->pasn->akmp; + res.cipher = peer->pasn->cipher; + + if (res.akmp == WPA_KEY_MGMT_PASN) { + if (go) { + res.password_len = p2p->cfg->dev_password_len; + memcpy(res.password, p2p->cfg->dev_password, + res.password_len); + } else { + if (!peer->info.password_len) { + p2p_dbg(p2p, "Password Invalid for P2P2 group formation"); + return; + } + res.password_len = peer->info.password_len; + memcpy(res.password, peer->info.password, + res.password_len); + } + } else if (res.akmp == WPA_KEY_MGMT_SAE) { + res.password_len = peer->password_len; + memcpy(res.password, peer->password, res.password_len); + if (peer->role == P2P_ROLE_PAIRING_INITIATOR) { + pasn_initiator_pmksa_cache_get(peer->pasn->pmksa, + peer->pasn->peer_addr, + res.pmkid, res.pmk, + &res.pmk_len); + } else { + pasn_responder_pmksa_cache_get(peer->pasn->pmksa, + peer->pasn->peer_addr, + res.pmkid, res.pmk, + &res.pmk_len); + } + } + wpa_pasn_reset(peer->pasn); + } #endif /* CONFIG_PASN */ p2p_set_state(p2p, P2P_PROVISIONING); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index db2052f..65e2e0d 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -11,6 +11,7 @@ #include "common/ieee802_11_defs.h" #include "wps/wps.h" +#include "common/wpa_common.h" #define DEVICE_IDENTITY_KEY_MAX_LEN 64 #define DEVICE_IDENTITY_KEY_LEN 16 @@ -181,6 +182,22 @@ struct p2p_go_neg_results { * peer_config_timeout - Peer configuration timeout (in 10 msec units) */ unsigned int peer_config_timeout; + + bool p2p2; + + int akmp; + + int cipher; + + u8 pmkid[PMKID_LEN]; + + u8 pmk[PMK_LEN_MAX]; + + size_t pmk_len; + + char password[100]; + + size_t password_len; }; struct p2ps_provision { @@ -779,7 +796,7 @@ struct p2p_config { int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id, - bool include_6ghz); + bool include_6ghz, bool p2p2); /** * send_probe_resp - Transmit a Probe Response frame @@ -1993,6 +2010,7 @@ struct p2p_group_config { * p2p_group_init - Initialize P2P group * @p2p: P2P module context from p2p_init() * @config: P2P group configuration (will be freed by p2p_group_deinit()) + * @p2p2: parameter to indicate that the group formed using p2p2 * Returns: Pointer to private data or %NULL on failure * * This function is used to initialize per-group P2P module context. Currently, @@ -2000,7 +2018,7 @@ struct p2p_group_config { * create an instance of this per-group information. */ struct p2p_group * p2p_group_init(struct p2p_data *p2p, - struct p2p_group_config *config); + struct p2p_group_config *config, bool p2p2); /** * p2p_group_deinit - Deinitialize P2P group diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index c036f92..4822c28 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -40,11 +40,12 @@ struct p2p_group { int beacon_update; struct wpabuf *noa; struct wpabuf *wfd_ie; + bool p2p2; }; struct p2p_group * p2p_group_init(struct p2p_data *p2p, - struct p2p_group_config *config) + struct p2p_group_config *config, bool p2p2) { struct p2p_group *group, **groups; @@ -62,6 +63,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p, p2p->groups = groups; group->p2p = p2p; + group->p2p2 = p2p2; group->cfg = config; group->group_formation = 1; group->beacon_update = 1; @@ -205,11 +207,28 @@ static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems) } +struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p, + struct wpabuf *p2p2_ie, int freq) +{ + u8 *len; + + wpabuf_put_u8(p2p2_ie, WLAN_EID_VENDOR_SPECIFIC); + len = wpabuf_put(p2p2_ie, 1); + wpabuf_put_be32(p2p2_ie, P2P2_IE_VENDOR_TYPE); + wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header"); + p2p_buf_add_pcea(p2p2_ie, p2p); + *len = (u8 *)wpabuf_put(p2p2_ie, 0) - len - 1; + + return p2p2_ie; +} + + static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) { struct wpabuf *ie; u8 *len; size_t extra = 0; + struct wpabuf *p2p2_ie; #ifdef CONFIG_WIFI_DISPLAY if (group->p2p->wfd_ie_beacon) @@ -220,7 +239,7 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); - ie = wpabuf_alloc(257 + extra); + ie = wpabuf_alloc(500 + extra); if (ie == NULL) return NULL; @@ -240,6 +259,15 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) p2p_group_add_noa(ie, group->noa); p2p_buf_update_ie_hdr(ie, len); + if (group->p2p2) { + p2p2_ie = wpabuf_alloc(255); + if (!p2p2_ie) + return NULL; + + p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq); + ie = wpabuf_concat(p2p2_ie, ie); + } + return ie; } @@ -443,6 +471,7 @@ void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf) static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { struct wpabuf *p2p_subelems, *ie; + struct wpabuf *p2p2_ie; p2p_subelems = wpabuf_alloc(500); if (p2p_subelems == NULL) @@ -474,7 +503,14 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) ie = wpabuf_concat(wfd, ie); } #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p2) { + p2p2_ie = wpabuf_alloc(255); + if (!p2p2_ie) + return NULL; + p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq); + ie = wpabuf_concat(p2p2_ie, ie); + } return ie; } @@ -648,6 +684,7 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) struct wpabuf *resp; u8 *rlen; size_t extra = 0; + struct wpabuf *p2p2_ie; #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) @@ -683,6 +720,15 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) p2p_buf_add_status(resp, status); p2p_buf_update_ie_hdr(resp, rlen); + if (group->p2p2) { + p2p2_ie = wpabuf_alloc(255); + if (!p2p2_ie) + return NULL; + + p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq); + resp = wpabuf_concat(p2p2_ie, resp); + } + return resp; } diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index e0d2ee0..440ed1f 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -926,6 +926,8 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, unsigned int size); struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p, struct wpabuf *subelems, u32 ie_type); +struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p, + struct wpabuf *p2p2_ie, int freq); /* p2p_sd.c */ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 0cffb99..71aaeba 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -426,11 +426,11 @@ static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s, static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, unsigned int num_req_dev_types, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id, - bool include_6ghz) + bool include_6ghz, bool p2p2) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_scan_params *params = NULL; - struct wpabuf *wps_ie, *ies; + struct wpabuf *wps_ie = NULL, *ies; unsigned int num_channels = 0; int social_channels_freq[] = { 2412, 2437, 2462, 60480 }; size_t ielen; @@ -459,11 +459,16 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; wpa_s->wps->dev.p2p = 1; - wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, - wpa_s->wps->uuid, WPS_REQ_ENROLLEE, - num_req_dev_types, req_dev_types); - if (wps_ie == NULL) - goto fail; + + if (!p2p2) { + wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev, + wpa_s->wps->uuid, + WPS_REQ_ENROLLEE, + num_req_dev_types, + req_dev_types); + if (wps_ie == NULL) + goto fail; + } /* * In case 6 GHz channels are requested as part of the P2P scan, only @@ -514,13 +519,20 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, } ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); - ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen); - if (ies == NULL) { + + if (wps_ie) + ielen += wpabuf_len(wps_ie); + + ies = wpabuf_alloc(ielen); + if (!ies) { wpabuf_free(wps_ie); goto fail; } - wpabuf_put_buf(ies, wps_ie); - wpabuf_free(wps_ie); + + if (wps_ie) { + wpabuf_put_buf(ies, wps_ie); + wpabuf_free(wps_ie); + } bands = wpas_get_bands(wpa_s, params->freqs); p2p_scan_ie(wpa_s->global->p2p, ies, dev_id, bands); @@ -1757,6 +1769,80 @@ static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s, return 0; } +static void wpas_start_gc(struct wpa_supplicant *wpa_s, + struct p2p_go_neg_results *res) +{ + struct wpa_ssid *ssid; + + if (!res->ssid_len) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: SSID info not present"); + return; + } + + wpa_s->group_formation_reported = 0; + wpa_printf(MSG_DEBUG, "P2P: Start connect for peer " MACSTR + " dev_addr " MACSTR, + MAC2STR(res->peer_interface_addr), + MAC2STR(res->peer_device_addr)); + wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start connect for SSID", + res->ssid, res->ssid_len); + wpa_supplicant_ap_deinit(wpa_s); + wpas_copy_go_neg_results(wpa_s, res); + + ssid = wpa_config_add_network(wpa_s->conf); + if (ssid == NULL) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Could not add network for Client"); + return; + } + os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN); + wpa_config_set_network_defaults(ssid); + ssid->temporary = 1; + ssid->p2p_group = 1; + + ssid->ssid = os_zalloc(res->ssid_len); + if (!ssid->ssid) + return; + + ssid->ssid_len = res->ssid_len; + os_memcpy(ssid->ssid, res->ssid, ssid->ssid_len); + + memcpy(ssid->bssid, res->peer_interface_addr, ETH_ALEN); + + if (res->akmp == WPA_KEY_MGMT_PASN) { + ssid->auth_alg = WPA_AUTH_ALG_SAE; + ssid->sae_password = os_strdup(res->password); + } else if (res->akmp == WPA_KEY_MGMT_SAE) { + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->sae_password = os_strdup(res->password); + wpa_sm_set_pmk(wpa_s->wpa, res->pmk, res->pmk_len, + res->pmkid, res->peer_interface_addr); + } + + if (res->psk_set) { + os_memcpy(ssid->psk, res->psk, 32); + ssid->psk_set = 1; + } + ssid->proto = WPA_PROTO_RSN; + ssid->key_mgmt = WPA_KEY_MGMT_SAE; + ssid->pairwise_cipher = WPA_CIPHER_CCMP; + ssid->group_cipher = WPA_CIPHER_CCMP; + if (res->cipher) { + ssid->pairwise_cipher |= res->cipher; + } + ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; + ssid->disabled = 0; + wpa_s->show_group_started = 1; + wpa_s->p2p_in_invitation = 1; + wpa_s->p2p_go_group_formation_completed = 0; + wpa_s->global->p2p_group_formation = wpa_s; + + wpa_s->current_ssid = ssid; + wpa_supplicant_update_scan_results(wpa_s, res->peer_interface_addr); + wpa_supplicant_select_network(wpa_s, ssid); +} + static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) @@ -1892,6 +1978,9 @@ static void p2p_go_configured(void *ctx, void *data) struct wpa_supplicant *wpa_s = ctx; struct p2p_go_neg_results *params = data; struct wpa_ssid *ssid; + struct sta_info sta; + struct sae_data *sae; + struct hostapd_data *hapd; wpa_s->ap_configured_cb = NULL; wpa_s->ap_configured_cb_ctx = NULL; @@ -1901,6 +1990,26 @@ static void p2p_go_configured(void *ctx, void *data) "P2P: p2p_go_configured() called with wpa_s->go_params == NULL"); return; } + if (wpa_s->ap_iface && params->p2p2 && + params->akmp == WPA_KEY_MGMT_SAE) { + hapd = wpa_s->ap_iface->bss[0]; + memset(&sta, 0, sizeof(struct sta_info)); + memcpy(sta.addr, params->peer_device_addr, ETH_ALEN); + sae = os_zalloc(sizeof(struct sae_data)); + if (sae) { + sta.sae = sae; + memcpy(sta.sae->pmkid, params->pmkid, PMKID_LEN); + wpa_auth_pmksa_add_sae(hapd->wpa_auth, + params->peer_device_addr, + params->pmk, params->pmk_len, + params->pmkid, WPA_KEY_MGMT_SAE); + hostapd_add_pmkid(hapd, params->peer_device_addr, + params->pmk, params->pmk_len, + params->pmkid, WPA_KEY_MGMT_SAE); + memset(&sta, 0, sizeof(struct sta_info)); + os_free(sae); + } + } p2p_go_save_group_common_freqs(wpa_s, params); p2p_go_dump_common_freqs(wpa_s); @@ -1967,13 +2076,21 @@ static void p2p_go_configured(void *ctx, void *data) return; } - wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning"); if (wpa_supplicant_ap_mac_addr_filter(wpa_s, params->peer_interface_addr)) { wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address " "filtering"); return; } + + if (params->p2p2) { + wpas_group_formation_completed(wpa_s, 1, 0); + wpa_printf(MSG_DEBUG, "P2P2: Group formation completed, " + "First connection in progress"); + goto out; + } + + wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning"); if (params->wps_method == WPS_PBC) { wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr, params->peer_device_addr); @@ -1994,6 +2111,7 @@ static void p2p_go_configured(void *ctx, void *data) } else if (wpa_s->p2p_pin[0]) wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr, wpa_s->p2p_pin, NULL, 0, 0); +out: os_free(wpa_s->go_params); wpa_s->go_params = NULL; } @@ -2076,9 +2194,9 @@ int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s, } -static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, - struct p2p_go_neg_results *params, - int group_formation) +static void wpas_start_go(struct wpa_supplicant *wpa_s, + struct p2p_go_neg_results *params, + int group_formation, bool p2p2) { struct wpa_ssid *ssid; @@ -2173,6 +2291,21 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, wpa_config_update_psk(ssid); ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity; + if (p2p2) { + if (params->akmp == WPA_KEY_MGMT_SAE) + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + else + ssid->auth_alg |= WPA_AUTH_ALG_SAE; + + ssid->key_mgmt = WPA_KEY_MGMT_SAE; + ssid->sae_password = os_strdup(params->password); + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; + wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + if (params->cipher) { + ssid->pairwise_cipher |= params->cipher; + } + } + wpa_s->ap_configured_cb = p2p_go_configured; wpa_s->ap_configured_cb_ctx = wpa_s; wpa_s->ap_configured_cb_data = wpa_s->go_params; @@ -2387,6 +2520,7 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go) wpa_s->global->pending_group_iface_for_p2ps = 0; wpas_p2p_clone_config(group_wpa_s, wpa_s); + group_wpa_s->p2p2 = wpa_s->p2p2; if (wpa_s->conf->p2p_interface_random_mac_addr) { if (wpa_drv_set_mac_addr(group_wpa_s, @@ -2569,12 +2703,18 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin, sizeof(group_wpa_s->p2p_pin)); group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method; + group_wpa_s->p2p2 = res->p2p2; + group_wpa_s->p2p_bootstrap = wpa_s->p2p_bootstrap; } + if (res->role_go) { - wpas_start_wps_go(group_wpa_s, res, 1); + wpas_start_go(group_wpa_s, res, 1, res->p2p2); } else { os_get_reltime(&group_wpa_s->scan_min_time); - wpas_start_wps_enrollee(group_wpa_s, res); + if (res->p2p2) + wpas_start_gc(group_wpa_s, res); + else + wpas_start_wps_enrollee(group_wpa_s, res); } wpa_s->global->p2p_long_listen = 0; @@ -7190,7 +7330,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, return -1; if (freq > 0) wpa_s->p2p_go_no_pri_sec_switch = 1; - wpas_start_wps_go(wpa_s, ¶ms, 0); + wpas_start_go(wpa_s, ¶ms, 0, wpa_s->p2p2); return 0; } @@ -7407,7 +7547,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS); wpa_s->p2p_first_connection_timeout = connection_timeout; - wpas_start_wps_go(wpa_s, ¶ms, 0); + wpas_start_go(wpa_s, ¶ms, 0, wpa_s->p2p2); return 0; } @@ -7489,7 +7629,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start) != 0; - group = p2p_group_init(wpa_s->global->p2p, cfg); + group = p2p_group_init(wpa_s->global->p2p, cfg, wpa_s->p2p2); if (group == NULL) os_free(cfg); if (ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:22 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:22 +0530 Subject: [PATCH v3 24/25] P2P: Add support to get PASN PTK In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-25-git-send-email-quic_shivbara@quicinc.com> Signed-off-by: Shivani Baranwal --- src/common/wpa_common.c | 2 ++ src/common/wpa_common.h | 1 + src/p2p/p2p.c | 54 +++++++++++++++++++++++++++++++++++++++-- src/p2p/p2p.h | 8 ++++++ src/p2p/p2p_i.h | 10 ++++++++ wpa_supplicant/ctrl_iface.c | 23 ++++++++++++++++++ wpa_supplicant/p2p_supplicant.c | 11 +++++++++ wpa_supplicant/p2p_supplicant.h | 8 ++++++ 8 files changed, 115 insertions(+), 2 deletions(-) diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 28f478c..ef8a0fa 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -582,6 +582,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, ptk->kek2_len = 0; ptk->kck2_len = 0; + ptk->ptk_len = ptk_len; os_memset(tmp, 0, sizeof(tmp)); os_memset(data, 0, data_len); return 0; @@ -1555,6 +1556,7 @@ int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len, ptk->kdk, ptk->kdk_len); } + ptk->ptk_len = ptk_len; forced_memzero(tmp, sizeof(tmp)); ret = 0; err: diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 8f77d38..63196bc 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -270,6 +270,7 @@ struct wpa_ptk { size_t kck2_len; size_t kek2_len; size_t kdk_len; + size_t ptk_len; size_t ltf_keyseed_len; int installed; /* 1 if key has already been installed to driver */ }; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 2c81ec5..59a15a8 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -3064,6 +3064,11 @@ void p2p_group_formation_failed(struct p2p_data *p2p) p2p_clear_go_neg(p2p); } +void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val) +{ + p2p->cfg->store_pasn_ptk = val; +} + bool is_p2p_6ghz_disabled(struct p2p_data *p2p) { @@ -6875,6 +6880,7 @@ int p2p_handle_pasn_auth(struct p2p_data *p2p, struct p2p_device *dev, p2p_dbg(p2p, "P2P PASN Responder: Handle PASN Auth3 failed"); return -1; } + p2p_pasn_store_ptk(p2p, &pasn->ptk); if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq, auth_transaction)) { p2p_dbg(p2p, "P2P PASN Responder: Handle Auth3 action wrapper failed"); @@ -6930,12 +6936,12 @@ int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, return -1; } ret = wpa_pasn_auth_rx(pasn, (const u8 *)mgmt, len, &pasn_data); - forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); - if (ret < 0) { p2p_dbg(p2p, "P2P PASN: wpa_pasn_auth_rx failed"); dev->role = P2P_ROLE_IDLE; } + p2p_pasn_store_ptk(p2p, &pasn->ptk); + forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); } else { ret = p2p_handle_pasn_auth(p2p, dev, mgmt, len, freq); @@ -6952,4 +6958,48 @@ void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, pasn_responder_pmksa_cache_add(p2p->responder_pmksa, src, dst, pmk, pmk_len, pmkid); } + + +void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk) +{ + u8 *pos; + + if (!p2p->cfg->store_pasn_ptk) + return; + + if (ptk->ptk_len > sizeof(p2p->pasn_ptk)) { + p2p_dbg(p2p, "P2P PASN PTK exceeds: (len=%ld)", ptk->ptk_len); + return; + } + + pos = p2p->pasn_ptk; + p2p->pasn_ptk_len = ptk->ptk_len; + if (ptk->kck_len) { + os_memcpy(pos, ptk->kck, ptk->kck_len); + pos += ptk->kck_len; + } + if (ptk->kek_len) { + os_memcpy(pos, ptk->kek, ptk->kek_len); + pos += ptk->kek_len; + } + if (ptk->tk_len) { + os_memcpy(pos, ptk->tk, ptk->tk_len); + pos += ptk->tk_len; + } + if (ptk->kdk_len) { + os_memcpy(pos, ptk->kdk, ptk->kdk_len); + pos += ptk->kdk_len; + } +} + + +int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len) +{ + if (!p2p || !p2p->cfg->store_pasn_ptk || !p2p->pasn_ptk_len) + return -1; + + *buf_len = p2p->pasn_ptk_len; + *buf = p2p->pasn_ptk; + return 0; +} #endif diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 6024370..5d798a0 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -752,6 +752,11 @@ struct p2p_config { void *cb_ctx; /** + * store pasn ptk, Used for certification mode + */ + bool store_pasn_ptk; + + /** * debug_print - Debug print * @ctx: Callback context from cb_ctx * @level: Debug verbosity level (MSG_*) @@ -2716,4 +2721,7 @@ int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, size_t data_len, u8 acked, bool verify); void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, u8 *pmk, u16 pmk_len, u8 *pmkid); +void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val); +void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk); +int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len); #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 3e9119b..32a8421 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -681,6 +681,16 @@ struct p2p_data { * Indicate that auto go is enabled for this device */ u8 auto_go; + + /** + * pasn ptk of recent auth when store_pasn_ptk enabled + */ + u8 pasn_ptk[128]; + + /** + * pasn ptk length + */ + size_t pasn_ptk_len; }; /** diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 5a5b9e4..9c9e9a7 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7748,6 +7748,11 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "store_pasn_ptk") == 0) { + p2p_set_store_pasn_ptk(wpa_s->global->p2p, atoi(param)); + return 0; + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); @@ -10905,6 +10910,20 @@ static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s) #endif /* CONFIG_AP */ } +#ifdef CONFIG_PASN + +static int p2p_ctrl_get_pasn_ptk(struct wpa_supplicant *wpa_s, char *buf, + size_t buflen) +{ + const u8 *ptk; + size_t ptk_len; + + if (wpas_p2p_get_pasn_ptk(wpa_s, &ptk, &ptk_len)) + return -1; + return wpa_snprintf_hex(buf, buflen, ptk, ptk_len); +} + +#endif // CONFIG_PASN #ifdef CONFIG_PMKSA_CACHE_EXTERNAL @@ -12918,6 +12937,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) { reply_len = p2p_get_passphrase(wpa_s, reply, reply_size); +#ifdef CONFIG_PASN + } else if (os_strcmp(buf, "P2P_GET_PASNPTK") == 0) { + reply_len = p2p_ctrl_get_pasn_ptk(wpa_s, reply, reply_size); +#endif /* CONFIG_PASN */ } else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) { reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply, reply_size); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 249390b..394beef 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -11159,4 +11159,15 @@ int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, return -2; return p2p_pasn_auth_rx(p2p, mgmt, len, freq); } + + +int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, + size_t *ptk_len) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + + if (wpa_s->global->p2p_disabled || !p2p) + return -2; + return p2p_pasn_get_ptk(p2p, ptk, ptk_len); +} #endif /* CONFIG_PASN */ diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index c9e9c78..3dcc9e3 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -234,6 +234,8 @@ int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len, int freq); int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s); +int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, + size_t *ptk_len); #else /* CONFIG_P2P */ static inline int @@ -377,6 +379,12 @@ wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s) return 0; } +static inline int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, + const u8 **ptk, size_t *ptk_len) +{ + return 0; +} + #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:17 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:17 +0530 Subject: [PATCH v3 19/25] p2p: Add support for Invitation using pairing verification In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-20-git-send-email-quic_shivbara@quicinc.com> Signed-off-by: Shivani Baranwal --- src/p2p/p2p.c | 124 +++++++++++++++++++- src/p2p/p2p.h | 18 ++- src/p2p/p2p_i.h | 16 ++- src/p2p/p2p_invitation.c | 100 ++++++++++++++-- wpa_supplicant/ctrl_iface.c | 12 +- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 8 +- wpa_supplicant/p2p_supplicant.c | 175 +++++++++++++++++++++++++--- wpa_supplicant/p2p_supplicant.h | 6 +- 8 files changed, 415 insertions(+), 44 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 8f3d76e..702c90a 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -3996,7 +3996,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, p2p_invitation_req_cb(p2p, success); break; case P2P_PENDING_INVITATION_RESPONSE: - p2p_invitation_resp_cb(p2p, success); + p2p_invitation_resp_cb(p2p, dst, success); break; case P2P_PENDING_DEV_DISC_REQUEST: p2p_dev_disc_req_cb(p2p, success); @@ -4296,7 +4296,7 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p) p2p->cfg->invitation_result( p2p->cfg->cb_ctx, -1, NULL, NULL, p2p->invite_peer->info.p2p_device_addr, - 0, 0); + 0, 0, NULL, NULL, 0); } p2p_set_state(p2p, P2P_IDLE); } @@ -6206,6 +6206,117 @@ void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev, pasn->freq = freq; } +int get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr) +{ + int freq; + struct p2p_device *dev; + + if (!peer_addr) { + p2p_dbg(p2p, "peer address NULL"); + return -1; + } + + dev = p2p_get_device(p2p, peer_addr); + if (!dev) { + p2p_dbg(p2p, "Peer not known"); + return -1; + } + + freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; + if (freq <= 0) + freq = dev->oob_go_neg_freq; + if (freq <= 0) { + p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " + MACSTR, MAC2STR(dev->info.p2p_device_addr)); + return -1; + } + return freq; +} + +int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr, + int freq, enum p2p_invite_role role, + const u8 *bssid, const u8 *ssid, size_t ssid_len, + unsigned int force_freq, const u8 *go_dev_addr, + unsigned int pref_freq) +{ + struct pasn_data *pasn; + struct p2p_device *dev; + struct wpabuf *extra_ies, *req; + int ret = 0; + + if (!peer_addr) { + p2p_dbg(p2p, "peer address NULL"); + return -1; + } + + dev = p2p_get_device(p2p, peer_addr); + if (!dev) { + p2p_dbg(p2p, "Peer not known"); + return -1; + } + + if (p2p_invite(p2p, peer_addr, role, bssid, ssid, ssid_len, force_freq, + go_dev_addr, 1, pref_freq, -1, 1)) { + p2p_dbg(p2p, "p2p_invite failed"); + return -1; + } + + dev->role = P2P_ROLE_PAIRING_INITIATOR; + p2p_pasn_initialize(p2p, dev, peer_addr, freq, true); + pasn = dev->pasn; + + req = p2p_build_invitation_req(p2p, dev, go_dev_addr, -1); + if (!req) + return -1; + + p2p_set_state(p2p, P2P_INVITE); + p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST; + p2p->invite_peer = dev; + dev->invitation_reqs++; + + extra_ies = wpabuf_alloc(1500); + if (!extra_ies) { + wpabuf_free(req); + p2p_dbg(p2p, "Mem alloc failed for extra ies"); + return -1; + } + + if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) { + p2p_dbg(p2p, "prepare pasn extra ies failed"); + ret = -1; + goto out; + } + + pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies)); + if (!pasn->extra_ies) { + p2p_dbg(p2p, "Mem alloc failed for pasn extra ies"); + ret = -1; + goto out; + } + + os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies), + wpabuf_len(extra_ies)); + pasn->extra_ies_len = wpabuf_len(extra_ies); + + /* Start PASN Verify */ + if (wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid, + pasn->akmp, pasn->cipher, pasn->group, pasn->freq, + NULL, 0, NULL, 0, NULL)) { + p2p_dbg(p2p, "p2p pasn verify failed"); + ret = -1; + } else { + dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK; + } +out: + if (pasn->extra_ies) { + os_free((u8 *)pasn->extra_ies); + pasn->extra_ies = NULL; + pasn->extra_ies_len = 0; + } + wpabuf_free(req); + wpabuf_free(extra_ies); + return ret; +} int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq) { @@ -6370,7 +6481,8 @@ int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p, p2p_handle_go_neg_conf(p2p, mgmt->sa, data + 1, data_len - 1, true); } else { - p2p_invitation_resp_cb(p2p, P2P_SEND_ACTION_SUCCESS); + p2p_invitation_resp_cb(p2p, mgmt->sa, + P2P_SEND_ACTION_SUCCESS); } } p2p_parse_free(&msg); @@ -6631,7 +6743,7 @@ done: } int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, - size_t data_len, u8 acked) + size_t data_len, u8 acked, bool verify) { int ret = 0; struct p2p_device *dev; @@ -6664,7 +6776,9 @@ int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, if (ret != 1) return ret; - if (dev == p2p->go_neg_peer) + if (verify && dev == p2p->invite_peer) + p2p_start_invitation_connect(p2p, dev); + else if (dev == p2p->go_neg_peer) p2p_go_complete(p2p, dev); return 0; diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 65e2e0d..4759947 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1127,7 +1127,8 @@ struct p2p_config { void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid, const u8 *ssid, size_t ssid_len, const u8 *go_dev_addr, u8 status, - int op_freq); + int op_freq, u8 *pmkid, u8 *pmk, + size_t pmk_len); /** * invitation_result - Callback on Invitation result @@ -1148,7 +1149,8 @@ struct p2p_config { */ void (*invitation_result)(void *ctx, int status, const u8 *bssid, const struct p2p_channels *channels, - const u8 *addr, int freq, int peer_oper_freq); + const u8 *addr, int freq, int peer_oper_freq, + u8 *pmkid, u8 *pmk, size_t pmk_len); /** * go_connected - Check whether we are connected to a GO @@ -1693,12 +1695,14 @@ enum p2p_invite_role { * force_freq == 0) * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover * case or -1 if not used + * @p2p2: Operating in p2p2 mode * Returns: 0 on success, -1 on failure */ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, const u8 *bssid, const u8 *ssid, size_t ssid_len, unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq, int dev_pw_id); + int persistent_group, unsigned int pref_freq, int dev_pw_id, + bool p2p2); /** * p2p_presence_req - Request GO presence @@ -2675,12 +2679,18 @@ void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after); void p2p_set_reg_info(struct p2p_data *p2p, u8 val); void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val); +int get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr); int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq); +int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr, + int freq, enum p2p_invite_role role, + const u8 *bssid, const u8 *ssid, size_t ssid_len, + unsigned int force_freq, const u8 *go_dev_addr, + unsigned int pref_freq); int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, size_t len, int freq); int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr); int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data, size_t len); int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, - size_t data_len, u8 acked); + size_t data_len, u8 acked, bool verify); #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 440ed1f..7ff2c97 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -201,6 +201,16 @@ struct p2p_device { /* device role */ enum p2p_role role; + + /** + * Invitation params for P2P2 + */ + u8 inv_reject; + u8 inv_status; + int inv_freq; + int inv_peer_oper_freq; + u8 inv_bssid[ETH_ALEN]; + struct p2p_channels *inv_channels; }; struct p2p_sd_query { @@ -979,6 +989,9 @@ void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg, struct p2p_device *dev); /* p2p_invitation.c */ +struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, + struct p2p_device *peer, + const u8 *go_dev_addr, int dev_pw_id); void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq); void p2p_handle_invitation_resp(struct p2p_data *p2p, const u8 *sa, @@ -990,7 +1003,8 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, const u8 *go_dev_addr, int dev_pw_id); void p2p_invitation_req_cb(struct p2p_data *p2p, int success); -void p2p_invitation_resp_cb(struct p2p_data *p2p, int success); +void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *dst, int success); +void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev); /* p2p_dev_disc.c */ void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 8ade838..19785d4 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -13,12 +13,15 @@ #include "common/wpa_ctrl.h" #include "p2p_i.h" #include "p2p.h" +#include "crypto/sha256.h" +#include "crypto/sha384.h" +#include "common/sae.h" +#include "pasn/pasn_common.h" -static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, - struct p2p_device *peer, - const u8 *go_dev_addr, - int dev_pw_id) +struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, + struct p2p_device *peer, + const u8 *go_dev_addr, int dev_pw_id) { struct wpabuf *buf; u8 *len; @@ -100,7 +103,7 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); - if (dev_pw_id >= 0) { + if (dev_pw_id >= 0 && !peer->p2p2) { /* WSC IE in Invitation Request for NFC static handover */ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); } @@ -120,6 +123,7 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, u8 *len; size_t extra = 0; + p2p_dbg(p2p, "Building Invitation Response "); #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; if (wfd_ie && group_bssid) { @@ -453,6 +457,7 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, struct p2p_device *dev; struct p2p_message msg; struct p2p_channels intersection, *channels = NULL; + struct p2p_channels *p2p2_channels = NULL; p2p_dbg(p2p, "Received Invitation Response from " MACSTR, MAC2STR(sa)); @@ -532,14 +537,17 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, #endif /* CONFIG_P2P_STRICT */ /* Try to survive without peer channel list */ channels = &p2p->channels; + p2p2_channels = channels; } else if (!msg.channel_list) { /* Non-success cases are not required to include Channel List */ channels = &p2p->channels; + p2p2_channels = channels; } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev, msg.channel_list, msg.channel_list_len) < 0) { p2p_dbg(p2p, "No common channels found"); p2p_parse_free(&msg); + dev->inv_reject = 1; return; } else { p2p_channels_intersect(&p2p->channels, &dev->channels, @@ -547,6 +555,7 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, channels = &intersection; } + if (p2p->cfg->invitation_result) { int peer_oper_freq = 0; int freq = p2p_channel_to_freq(p2p->op_reg_class, @@ -568,18 +577,70 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, */ p2p_check_pref_chan(p2p, 0, dev, &msg); + if (dev->p2p2) { + dev->inv_freq = freq; + dev->inv_status = *msg.status; + dev->inv_channels = p2p2_channels; + dev->inv_peer_oper_freq = peer_oper_freq; + if (msg.group_bssid) + os_memcpy(dev->inv_bssid, msg.group_bssid, ETH_ALEN); + goto out; + } + p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status, msg.group_bssid, channels, sa, - freq, peer_oper_freq); + freq, peer_oper_freq, NULL, NULL, + 0); } + p2p_clear_timeout(p2p); + p2p_set_state(p2p, P2P_IDLE); + p2p->invite_peer = NULL; + +out: p2p_parse_free(&msg); +} + + +#ifdef CONFIG_PASN +void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev) +{ + size_t pmk_len = 0; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN_MAX]; + struct p2p_channels intersection; + + if (!p2p || !dev || dev->inv_reject || !dev->pasn) + return; + + if (!dev->inv_channels) { + p2p_channels_intersect(&p2p->channels, &dev->channels, + &intersection); + dev->inv_channels = &intersection; + } + + pasn_initiator_pmksa_cache_get(dev->pasn->pmksa, dev->pasn->peer_addr, + pmkid, pmk, &pmk_len); + + wpa_pasn_reset(dev->pasn); + p2p_dbg(p2p, "P2P Invitation connect: msg status %d", dev->inv_status); + if (p2p->cfg->invitation_result) + p2p->cfg->invitation_result(p2p->cfg->cb_ctx, dev->inv_status, + dev->inv_bssid, dev->inv_channels, + dev->info.p2p_device_addr, + dev->inv_freq, + dev->inv_peer_oper_freq, pmkid, + pmk, pmk_len); + + /* Reset pmk and pmkid from RAM */ + memset(pmkid, 0, sizeof(pmkid)); + memset(pmk, 0, sizeof(pmk)); p2p_clear_timeout(p2p); p2p_set_state(p2p, P2P_IDLE); p2p->invite_peer = NULL; } - +#endif /* CONFIG_PASN */ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, const u8 *go_dev_addr, int dev_pw_id) @@ -649,8 +710,19 @@ void p2p_invitation_req_cb(struct p2p_data *p2p, int success) } -void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) +void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *peer, int success) { + size_t pmk_len = 0; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN_MAX]; + struct p2p_device *dev; + + dev = p2p_get_device(p2p, peer); + if (dev && dev->pasn) + pasn_responder_pmksa_cache_get(dev->pasn->pmksa, + dev->pasn->peer_addr, pmkid, + pmk, &pmk_len); + p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success); p2p->cfg->send_action_done(p2p->cfg->cb_ctx); @@ -664,15 +736,20 @@ void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) p2p->inv_ssid, p2p->inv_ssid_len, p2p->inv_go_dev_addr, p2p->inv_status, - p2p->inv_op_freq); + p2p->inv_op_freq, pmkid, pmk, + pmk_len); } + /* Reset pmk and pmkid from RAM */ + memset(pmkid, 0, sizeof(pmkid)); + memset(pmk, 0, sizeof(pmk)); } int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, const u8 *bssid, const u8 *ssid, size_t ssid_len, unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq, int dev_pw_id) + int persistent_group, unsigned int pref_freq, int dev_pw_id, + bool p2p2) { struct p2p_device *dev; @@ -740,5 +817,8 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, os_memcpy(p2p->inv_ssid, ssid, ssid_len); p2p->inv_ssid_len = ssid_len; p2p->inv_persistent = persistent_group; + if (p2p2) + return 0; + return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id); } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index d976914..daa8bef 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7073,6 +7073,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0; int edmg; bool allow_6ghz; + bool p2p2; id = atoi(cmd); pos = os_strstr(cmd, " peer="); @@ -7129,9 +7130,11 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) if (allow_6ghz && chwidth == 40) max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ; + p2p2 = os_strstr(cmd, "p2p2") != NULL; + return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, max_oper_chwidth, pref_freq, he, edmg, - allow_6ghz); + allow_6ghz, p2p2); } @@ -7186,6 +7189,9 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, int he, int edmg, bool allow_6ghz, const u8 *go_bssid) { + size_t pmk_len = 0; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN_MAX]; struct wpa_ssid *ssid; ssid = wpa_config_get_network(wpa_s->conf, id); @@ -7196,11 +7202,13 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return -1; } + /* FIXME Fetch pmk, pmkid from p2p_supplicant.conf */ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, freq, vht_center_freq2, ht40, vht, vht_chwidth, he, edmg, NULL, 0, 0, allow_6ghz, 0, - go_bssid); + go_bssid, NULL, pmkid, pmk, + pmk_len); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 65bd478..aad4c5b 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -367,6 +367,9 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, int he = wpa_s->conf->p2p_go_he; int edmg = wpa_s->conf->p2p_go_edmg; int max_oper_chwidth, chwidth = 0, freq2 = 0; + size_t pmk_len = 0; + u8 pmkid[PMKID_LEN]; + u8 pmk[PMK_LEN_MAX]; dbus_message_iter_init(message, &iter); @@ -477,7 +480,8 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, freq2, ht40, vht, max_oper_chwidth, he, edmg, NULL, 0, 0, allow_6ghz, - retry_limit, go_bssid)) { + retry_limit, go_bssid, NULL, pmkid, + pmk, pmk_len)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); @@ -866,7 +870,7 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, goto err; if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0, - 0, 0, 0, false) < 0) { + 0, 0, 0, false, 0) < 0) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 71aaeba..0befcdd 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -39,7 +39,8 @@ #include "wifi_display.h" #include "crypto/random.h" - +#include "ap/ieee802_11.h" +#include "ap/wpa_auth.h" /* * How many times to try to scan to find the GO before giving up on join @@ -1736,13 +1737,22 @@ static void wpas_send_action_done(void *ctx) #ifdef CONFIG_PASN struct wpa_p2p_pasn_auth_work { u8 peer_addr[ETH_ALEN]; - bool verify; int freq; + bool verify; + int force_freq; + int pref_freq; + enum p2p_invite_role role; + u8 *ssid; + size_t ssid_len; + u8 bssid[ETH_ALEN]; + u8 go_dev_addr[ETH_ALEN]; }; static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork) { + if (awork->ssid) + os_free(awork->ssid); os_free(awork); } @@ -3522,7 +3532,8 @@ accept_inv: static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, const u8 *ssid, size_t ssid_len, const u8 *go_dev_addr, u8 status, - int op_freq) + int op_freq, u8 *pmkid, u8 *pmk, + size_t pmk_len) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; @@ -3562,7 +3573,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s->conf->p2p_go_edmg, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0, - NULL); + bssid, sa, pmkid, pmk, pmk_len); } else if (bssid) { wpa_s->user_initiated_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, @@ -3680,12 +3691,20 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s, static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, const struct p2p_channels *channels, const u8 *peer, int neg_freq, - int peer_oper_freq) + int peer_oper_freq, u8 *pmkid, u8 *pmk, + size_t pmk_len) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid; int freq; +#ifdef CONFIG_PASN + if (wpa_s->p2p_pasn_auth_work) { + wpas_p2p_pasn_cancel_auth_work(wpa_s); + wpa_s->p2p_pasn_auth_work = NULL; + } +#endif /* CONFIG_PASN */ + if (bssid) { wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT "status=%d " MACSTR, @@ -3793,7 +3812,7 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0, - NULL); + bssid, peer, pmkid, pmk, pmk_len); } @@ -4859,7 +4878,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : - 0, 0, false, 0, NULL); + 0, 0, false, 0, NULL, NULL, NULL, NULL, + 0); } else if (response_done) { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, false); @@ -4982,7 +5002,8 @@ static int wpas_prov_disc_resp_cb(void *ctx) NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL); + is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL, NULL, + NULL, NULL, 0); } else { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); @@ -5075,10 +5096,13 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status, #ifdef CONFIG_PASN static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) { + int ret = 0; struct wpa_supplicant *wpa_s = work->wpa_s; struct wpa_p2p_pasn_auth_work *awork = work->ctx; struct p2p_data *p2p = wpa_s->global->p2p; const u8 *peer_addr = NULL; + const u8 *bssid = NULL; + const u8 *go_dev_addr = NULL; if (deinit) { if (!work->started) { @@ -5091,7 +5115,22 @@ static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) if (!is_zero_ether_addr(awork->peer_addr)) peer_addr = awork->peer_addr; - if (p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq)) { + if (!is_zero_ether_addr(awork->bssid)) + bssid = awork->bssid; + if (!is_zero_ether_addr(awork->go_dev_addr)) + go_dev_addr = awork->go_dev_addr; + + + if (awork->verify) + ret = p2p_initiate_pasn_verify(p2p, peer_addr, awork->freq, + awork->role, bssid, awork->ssid, + awork->ssid_len, + awork->force_freq, go_dev_addr, + awork->pref_freq); + else + ret = p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq); + + if (ret) { wpa_printf(MSG_DEBUG, "P2P PASN: Failed to start PASN authentication"); goto fail; @@ -5109,6 +5148,59 @@ fail: radio_work_done(work); } +static int wpas_p2p_initiate_pasn_verify(struct wpa_supplicant *wpa_s, + const u8 *peer, + enum p2p_invite_role role, + const u8 *bssid, const u8 *ssid, + size_t ssid_len, + unsigned int force_freq, + const u8 *go_dev_addr, + unsigned int pref_freq) +{ + int freq; + struct wpa_p2p_pasn_auth_work *awork; + + wpas_p2p_pasn_cancel_auth_work(wpa_s); + wpa_s->p2p_pasn_auth_work = NULL; + + freq = get_listen_freq(wpa_s->global->p2p, peer); + if (freq == -1) + return -1; + + awork = os_zalloc(sizeof(*awork)); + if (!awork) + return -1; + + awork->verify = 1; + awork->role = role; + awork->freq = freq; + awork->force_freq = force_freq; + awork->pref_freq = pref_freq; + os_memcpy(awork->peer_addr, peer, ETH_ALEN); + if (go_dev_addr) + os_memcpy(awork->go_dev_addr, go_dev_addr, ETH_ALEN); + if (bssid) + os_memcpy(awork->bssid, bssid, ETH_ALEN); + if (ssid_len) { + awork->ssid = os_zalloc(ssid_len); + if (!awork->ssid) { + os_free(awork); + return -1; + } + memcpy(awork->ssid, ssid, ssid_len); + awork->ssid_len = ssid_len; + } + + if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1, + wpas_p2p_pasn_auth_start_cb, awork) < 0) { + wpas_p2p_pasn_free_auth_work(awork); + return -1; + } + + wpa_printf(MSG_DEBUG, "P2P PASN: Auth work successfully added"); + return 0; +} + static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int freq) { @@ -5166,8 +5258,12 @@ int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, size_t data_len, u8 acked) { struct p2p_data *p2p = wpa_s->global->p2p; + struct wpa_p2p_pasn_auth_work *awork; - return p2p_pasn_auth_tx_status(p2p, data, data_len, acked); + awork = wpa_s->p2p_pasn_auth_work->ctx; + + return p2p_pasn_auth_tx_status(p2p, data, data_len, acked, + awork->verify); } #endif @@ -6897,6 +6993,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, params->max_oper_chwidth = max_oper_chwidth; params->vht_center_freq2 = vht_center_freq2; params->edmg = edmg; + params->p2p2 = wpa_s->p2p2; freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(struct wpa_used_freq_data)); @@ -7339,7 +7436,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, struct wpa_ssid *params, int addr_allocated, int freq, int force_scan, int retry_limit, - const u8 *go_bssid) + const u8 *go_bssid, bool p2p2, u8 *pmkid, + u8 *pmk, size_t pmk_len) { struct wpa_ssid *ssid; int other_iface_found = 0; @@ -7397,6 +7495,20 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, os_memcpy(ssid->bssid, go_bssid, ETH_ALEN); } + if (p2p2) { + ssid->key_mgmt = WPA_KEY_MGMT_SAE; + ssid->auth_alg = WPA_AUTH_ALG_OPEN; + ssid->sae_password = "12345678"; + wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; + ssid->disabled = 0; + + if (pmk && pmk_len && pmkid) + wpa_sm_set_pmk(wpa_s->wpa, pmk, pmk_len, pmkid, + ssid->bssid); + wpa_s->current_ssid = ssid; + } + wpa_s->show_group_started = 1; wpa_s->p2p_in_invitation = 1; wpa_s->p2p_retry_limit = retry_limit; @@ -7444,7 +7556,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, const struct p2p_channels *channels, int connection_timeout, int force_scan, bool allow_6ghz, int retry_limit, - const u8 *go_bssid) + const u8 *go_bssid, const u8 *dev_addr, + u8 *pmkid, u8 *pmk, size_t pmk_len) { struct p2p_go_neg_results params; int go = 0, freq; @@ -7513,7 +7626,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, } return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq, - force_scan, retry_limit, go_bssid); + force_scan, retry_limit, go_bssid, + wpa_s->p2p2, pmkid, pmk, pmk_len); } else { return -1; } @@ -7540,6 +7654,15 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, params.ssid_len = ssid->ssid_len; params.persistent_group = 1; + if (wpa_s->p2p2 && pmk_len && pmk && pmkid) { + memcpy(params.peer_device_addr, dev_addr, ETH_ALEN); + memcpy(params.pmkid, pmkid, PMKID_LEN); + memcpy(params.pmk, pmk, pmk_len); + params.pmk_len = pmk_len; + params.akmp = WPA_KEY_MGMT_SAE; + params.p2p2 = true; + } + wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1); if (wpa_s == NULL) return -1; @@ -8077,7 +8200,7 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int vht_center_freq2, int ht40, int vht, int max_chwidth, - int pref_freq, int he, int edmg, bool allow_6ghz) + int pref_freq, int he, int edmg, bool allow_6ghz, bool p2p2) { enum p2p_invite_role role; u8 *bssid = NULL; @@ -8103,6 +8226,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->p2p_go_max_oper_chwidth = max_chwidth; wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2; wpa_s->p2p_go_edmg = !!edmg; + wpa_s->p2p2 = p2p2; if (ssid->mode == WPAS_MODE_P2P_GO) { role = P2P_INVITE_ROLE_GO; if (peer_addr == NULL) { @@ -8125,7 +8249,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, bssid = wpa_s->own_addr; } else { role = P2P_INVITE_ROLE_CLIENT; - peer_addr = ssid->bssid; + if (!wpa_s->p2p2) + peer_addr = ssid->bssid; } wpa_s->pending_invite_ssid_id = ssid->id; @@ -8156,9 +8281,23 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, */ wpas_p2p_stop_find_oper(wpa_s); +#ifdef CONFIG_PASN + if (p2p2) { + if (wpas_p2p_initiate_pasn_verify(wpa_s, peer_addr, role, bssid, + ssid->ssid, ssid->ssid_len, + force_freq, go_dev_addr, + pref_freq) < 0) { + if (wpa_s->create_p2p_iface) + wpas_p2p_remove_pending_group_interface(wpa_s); + return -1; + } + return 0; + } +#endif /* CONFIG_PASN */ + return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, - 1, pref_freq, -1); + 1, pref_freq, -1, 0); } @@ -8242,7 +8381,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, - go_dev_addr, persistent, pref_freq, -1); + go_dev_addr, persistent, pref_freq, -1, 0); } @@ -9743,7 +9882,7 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr, ssid->ssid, ssid->ssid_len, ssid->frequency, wpa_s->global->p2p_dev_addr, persistent, 0, - wpa_s->p2pdev->p2p_oob_dev_pw_id); + wpa_s->p2pdev->p2p_oob_dev_pw_id, 0); } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 5612d83..61d4281 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -54,7 +54,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, const struct p2p_channels *channels, int connection_timeout, int force_scan, bool allow_6ghz, int retry_limit, - const u8 *go_bssid); + const u8 *go_bssid, const u8 *dev_addr, + u8 *pmkid, u8 *pmk, size_t pmk_len); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); enum wpas_p2p_prov_disc_use { @@ -122,7 +123,8 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq, int vht_center_freq2, int ht40, int vht, int max_chwidth, - int pref_freq, int he, int edmg, bool allow_6ghz); + int pref_freq, int he, int edmg, bool allow_6ghz, + bool p2p2); int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, const u8 *peer_addr, const u8 *go_dev_addr, bool allow_6ghz); -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:23 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:23 +0530 Subject: [PATCH v3 25/25] P2P: Add support for Assited DFS for P2P2 GO in 5GHz In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-26-git-send-email-quic_shivbara@quicinc.com> Signed-off-by: Shivani Baranwal --- src/ap/hostapd.c | 15 ++++- src/ap/hostapd.h | 3 + src/ap/hw_features.c | 3 +- src/common/ieee802_11_common.c | 14 ++--- src/common/ieee802_11_defs.h | 9 +++ src/p2p/p2p.c | 125 +++++++++++++++++++++++++++++++++++++- src/p2p/p2p.h | 22 +++++++ src/p2p/p2p_build.c | 44 ++++++++++++++ src/p2p/p2p_go_neg.c | 68 +++++++++++++++++++++ src/p2p/p2p_group.c | 11 ++++ src/p2p/p2p_i.h | 20 ++++++ src/p2p/p2p_parse.c | 9 +++ src/p2p/p2p_utils.c | 50 +++++++++++++++ wpa_supplicant/ap.c | 1 + wpa_supplicant/config.c | 2 + wpa_supplicant/config.h | 2 + wpa_supplicant/ctrl_iface.c | 5 ++ wpa_supplicant/events.c | 11 ++++ wpa_supplicant/p2p_supplicant.c | 52 ++++++++++++++-- wpa_supplicant/p2p_supplicant.h | 7 +++ wpa_supplicant/wpa_supplicant_i.h | 1 + 21 files changed, 458 insertions(+), 16 deletions(-) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a0ac3a8..3cb132c 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2495,8 +2495,17 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, iface->conf->channel, iface->freq); #ifdef NEED_AP_MLME - /* Handle DFS only if it is not offloaded to the driver */ - if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + if (iface->assisted_dfs_go) { + if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + wpa_printf(MSG_DEBUG, + "Fail: Offload not supported for assisted DFS P2P GO"); + goto fail; + } + // FIXME: Check with shivani if this is correct or not + wpa_printf(MSG_DEBUG, + "Request for Assisted DFS P2P GO"); + } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + /* Handle DFS only if it is not offloaded to the driver */ /* Check DFS */ res = hostapd_handle_dfs(iface); if (res <= 0) { @@ -2645,7 +2654,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, } if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && - !res_dfs_offload) { + !res_dfs_offload && !iface->assisted_dfs_go) { /* * If freq is DFS, and DFS is offloaded to the driver, then wait * for CAC to complete. diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dcf395c..66239dc 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -711,6 +711,9 @@ struct hostapd_iface { bool is_no_ir; bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */ + + /* P2P GO in assisted DFS mode */ + bool assisted_dfs_go; }; /* hostapd.c */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index c455660..23b193b 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -142,7 +142,8 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } else if (((feature->channels[j].flag & HOSTAPD_CHAN_RADAR) && !(iface->drv_flags & - WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || + WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + !iface->assisted_dfs_go) || (feature->channels[j].flag & HOSTAPD_CHAN_NO_IR)) { feature->channels[j].flag |= diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index b16564d..2c22016 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2066,7 +2066,7 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, */ int is_dfs_global_op_class(u8 op_class) { - return (op_class >= 118) && (op_class <= 123); + return (op_class >= 118) && (op_class <= 130); } @@ -2422,12 +2422,12 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP }, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index db1033a..7a46e77 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1754,6 +1754,7 @@ enum p2p_attr_id { P2P_ATTR_FEATURE_CAPABILITY = 27, P2P_ATTR_PERSISTENT_GROUP = 28, P2P_ATTR_CAPABILITY_EXTENSION = 29, + P2P_ATTR_WLAN_AP_INFORMATION = 30, P2P_ATTR_DEVICE_IDENTITY_KEY = 31, P2P_ATTR_DEVICE_IDENTITY_RESOLUTION = 32, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING = 33, @@ -3106,6 +3107,14 @@ struct ieee80211_s1g_beacon_compat { le32 tsf_completion; } STRUCT_PACKED; +struct ieee80211_dfs_ap_info_list { + u8 flag; + u8 bssid[ETH_ALEN]; + u8 country[3]; + u8 op_class; + u8 op_chan; +}; + #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 59a15a8..7cd1768 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1431,7 +1431,15 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p, p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d", force_freq, pref_freq, go); - if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) { + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, freq, 0, 0)) { + if (ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_80MHZ, + &op_class, &op_channel) == NUM_HOSTAPD_MODES) { + p2p_dbg(p2p, "Unsupported frequency %u MHz", freq); + return -1; + } + } else if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) { p2p_dbg(p2p, "Unsupported frequency %u MHz", freq); return -1; } @@ -1570,6 +1578,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, unsigned int force_freq, unsigned int pref_freq, int go) { + struct p2p_channels p2p_chanlist; + p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d", force_freq, pref_freq, go); if (force_freq || pref_freq) { @@ -1579,6 +1589,18 @@ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, } else { p2p_prepare_channel_best(p2p); } + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + p2p_dfs_channel_filter(p2p, &p2p->channels, p2p->dfs_ap_list, + p2p->num_dfs_ap, &p2p_chanlist); + p2p_channels_dump(p2p, "channel list after filtering DFS " + " channels with WLAN AP info attr channles", + &p2p_chanlist); + p2p_copy_channels(&p2p->channels, &p2p_chanlist, p2p->allow_6ghz); + } + p2p_channels_dump(p2p, "prepared channels", &p2p->channels); if (go) p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq); @@ -2806,6 +2828,20 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, p2p_buf_add_device_info(tmp, p2p, peer); p2p_buf_update_ie_hdr(tmp, lpos); + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, p2p->op_reg_class, + p2p->op_channel) && + !is_p2p_dfs_owner(p2p)) { + struct wpabuf *p2p2_ie; + + p2p2_ie = wpabuf_alloc(255); + if (!p2p2_ie) + return -1; + + p2p_group_build_p2p2_ie(p2p, p2p2_ie, 0); + tmp = wpabuf_concat(p2p2_ie, tmp); + } + tmplen = wpabuf_len(tmp); if (tmplen > len) res = -1; @@ -3077,6 +3113,91 @@ bool is_p2p_6ghz_disabled(struct p2p_data *p2p) return false; } + +bool is_p2p_dfs_chan_enabled(struct p2p_data *p2p) +{ + if (p2p) + return p2p->cfg->dfs_chan_enable; + return false; +} + + +bool is_p2p_dfs_owner(struct p2p_data *p2p) +{ + if (p2p) + return p2p->cfg->dfs_owner; + return false; +} + + +void p2p_remove_wlan_ap_info(struct p2p_data *p2p, u8 val) +{ + p2p->cfg->remove_wlan_ap_info = val; +} + + +struct ieee80211_dfs_ap_info_list * p2p_dfs_get_ap_info(struct p2p_data *p2p, + const u8 *bssid) +{ + size_t i; + + if (!p2p->dfs_ap_list) + return NULL; + + for (i = 0; i < p2p->num_dfs_ap; i++) { + struct ieee80211_dfs_ap_info_list *dfs_ap = + &p2p->dfs_ap_list[i]; + if (ether_addr_equal(dfs_ap->bssid, bssid)) + return dfs_ap; + } + return NULL; +} + + +void p2p_update_dfs_ap_info(struct p2p_data *p2p, const u8 *bssid, int freq, + int flag, bool disconnect_evt) +{ + struct ieee80211_dfs_ap_info_list *dfs_ap; + + dfs_ap = p2p_dfs_get_ap_info(p2p, bssid); + + if (dfs_ap) { + wpa_printf(MSG_DEBUG, "Update the existing DFS AP info"); + } else { + dfs_ap = os_realloc_array(p2p->dfs_ap_list, p2p->num_dfs_ap + 1, + sizeof(struct ieee80211_dfs_ap_info_list)); + if (!dfs_ap) { + wpa_printf(MSG_DEBUG, "Unable to allocate dfs_ap memory"); + return; + } + + p2p->dfs_ap_list = dfs_ap; + dfs_ap = &p2p->dfs_ap_list[p2p->num_dfs_ap]; + p2p->num_dfs_ap++; + os_memset(dfs_ap, 0, sizeof(*dfs_ap)); + } + + if (disconnect_evt) + dfs_ap->flag = 0; + + /* skip if flag is already set by assoc event */ + if (!dfs_ap->flag) + dfs_ap->flag = flag; + + os_memcpy(dfs_ap->bssid, bssid, ETH_ALEN); + + //TO-DO: update country string correctly + dfs_ap->country[0] = 0; + dfs_ap->country[1] = 0; + + dfs_ap->country[2] = 0x04; + ieee80211_freq_to_channel_ext(freq, 0, + CONF_OPER_CHWIDTH_80MHZ, + &dfs_ap->op_class, + &dfs_ap->op_chan); +} + + int p2p_pairing_info_init(struct p2p_data *p2p) { struct p2p_pairing_info *pairing_info; @@ -3231,6 +3352,8 @@ void p2p_deinit(struct p2p_data *p2p) os_free(p2p->no_go_freq.range); p2p_service_flush_asp(p2p); p2p_pairing_info_deinit(p2p); + if (p2p->dfs_ap_list) + os_free(p2p->dfs_ap_list); os_free(p2p); } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 5d798a0..b40fef6 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -735,6 +735,11 @@ struct p2p_config { bool dfs_owner; /** + * dfs_chan_enable - Enable p2p Go to operate on dfs channel + */ + bool dfs_chan_enable; + + /** * twt_power_mgmt - Enable TWT based power mgmt for P2P */ bool twt_power_mgmt; @@ -745,6 +750,10 @@ struct p2p_config { */ u16 comeback_after; + /** + * remove_wlan_ap_info - Flag not to include wlan ap info in frames + */ + u8 remove_wlan_ap_info; /** * cb_ctx - Context to use with callback functions @@ -1387,6 +1396,14 @@ struct p2p_config { * Returns: 0 on success, -1 on failure */ int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len); + + /** + * + * is_p2p_dfs_chan - DFS channel check + * + * To check if a channel is DFS channel or not. + */ + int (*is_p2p_dfs_chan)(void *ctx, int freq, int op_class, int op_chan); }; @@ -2724,4 +2741,9 @@ void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val); void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk); int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len); +bool is_p2p_dfs_chan_enabled(struct p2p_data *p2p); +bool is_p2p_dfs_owner(struct p2p_data *p2p); +void p2p_remove_wlan_ap_info(struct p2p_data *p2p, u8 val); +void p2p_update_dfs_ap_info(struct p2p_data *p2p, const u8 *bssid, int freq, + int flag, bool disconnect_evt); #endif /* P2P_H */ diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index f505ad9..c76918c 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -1057,3 +1057,47 @@ struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p, return ie; } + +void p2p_buf_add_wlan_ap_info(struct wpabuf *buf, + struct ieee80211_dfs_ap_info_list *dfs_ap_list, + size_t list_size) +{ + u8 *len; + size_t i, size; + + if (!list_size) + return; + + wpabuf_put_u8(buf, P2P_ATTR_WLAN_AP_INFORMATION); + /* IE length to be filled */ + len = wpabuf_put(buf, 2); + + for (i = 0; i < list_size; i++) { + if (dfs_ap_list[i].flag != 1) + continue; + + wpabuf_put_u8(buf, dfs_ap_list[i].flag); + wpabuf_put_data(buf, dfs_ap_list[i].bssid, ETH_ALEN); + wpabuf_put_data(buf, dfs_ap_list[i].country, 3); + wpabuf_put_u8(buf, dfs_ap_list[i].op_class); + wpabuf_put_u8(buf, dfs_ap_list[i].op_chan); + } + + if (list_size > 4) + size = 4; + else + size = list_size; + + for (i = 0; i < size; i++) { + if (dfs_ap_list[i].flag == 1) + continue; + wpabuf_put_u8(buf, dfs_ap_list[i].flag); + wpabuf_put_data(buf, dfs_ap_list[i].bssid, ETH_ALEN); + wpabuf_put_data(buf, dfs_ap_list[i].country, 3); + wpabuf_put_u8(buf, dfs_ap_list[i].op_class); + wpabuf_put_u8(buf, dfs_ap_list[i].op_chan); + } + + /* Update attribute length */ + WPA_PUT_LE16(len, (u8 *)wpabuf_put(buf, 0) - len - 2); +} diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 1f6923d..3129d78 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -138,6 +138,7 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, struct p2p_device *peer) { + u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; @@ -227,6 +228,15 @@ struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } buf = wpabuf_concat(buf2, buf); return buf; @@ -298,6 +308,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, u8 dialog_token, u8 status, u8 tie_breaker) { + u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; @@ -415,6 +426,15 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } buf = wpabuf_concat(buf2, buf); return buf; @@ -1089,6 +1109,24 @@ skip: */ p2p_check_pref_chan(p2p, go, dev, &msg); + if (msg.wlan_ap_info) { + u8 *pos = (u8 *)msg.wlan_ap_info, match = 0, i; + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, + p2p->op_channel)) { + for (i = 0; i < msg.wlan_ap_info_len; i += 12) { + if (*(pos + 10) == p2p->op_reg_class && + *(pos + 11) == p2p->op_channel) { + match = 1; + break; + } + } + if (match == 0) + goto fail; + } + } + if (msg.config_timeout) { dev->go_timeout = msg.config_timeout[0]; dev->client_timeout = msg.config_timeout[1]; @@ -1176,6 +1214,7 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, u8 dialog_token, u8 status, const u8 *resp_chan, int go) { + u8 *len; struct p2p_channels res; u8 group_capab; size_t extra = 0; @@ -1246,6 +1285,15 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } + buf = wpabuf_concat(buf2, buf); return buf; @@ -1485,6 +1533,26 @@ skip: if (go) p2p_check_pref_chan(p2p, go, dev, &msg); + if (msg.wlan_ap_info) { + u16 match = 0, i; + const u8 *pos = msg.wlan_ap_info; + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, + p2p->op_channel)) { + for (i = 0; i < msg.wlan_ap_info_len; i += 12) { + if (*(pos + 10) == p2p->op_reg_class && + *(pos + 11) == p2p->op_channel) { + match = 1; + break; + } + } + if (match == 0) + goto fail; + } + } + p2p_set_state(p2p, P2P_GO_NEG); p2p_clear_timeout(p2p); diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index 4822c28..d07f41e 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -217,6 +217,17 @@ struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p, wpabuf_put_be32(p2p2_ie, P2P2_IE_VENDOR_TYPE); wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header"); p2p_buf_add_pcea(p2p2_ie, p2p); + if (p2p->cfg->remove_wlan_ap_info) + goto out; + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, freq, p2p->op_reg_class, + p2p->op_channel) && + !is_p2p_dfs_owner(p2p)) { + p2p_buf_add_wlan_ap_info(p2p2_ie, p2p->dfs_ap_list, + p2p->num_dfs_ap); + } +out: *len = (u8 *)wpabuf_put(p2p2_ie, 0) - len - 1; return p2p2_ie; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 32a8421..54de28b 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -691,6 +691,16 @@ struct p2p_data { * pasn ptk length */ size_t pasn_ptk_len; + + /** + * list of DFS APs + */ + struct ieee80211_dfs_ap_info_list *dfs_ap_list; + + /** + * num of DFS APs + */ + size_t num_dfs_ap; }; /** @@ -809,6 +819,9 @@ struct p2p_message { const u8 *dira; size_t dira_len; + + const u8 *wlan_ap_info; + size_t wlan_ap_info_len; }; @@ -1079,6 +1092,13 @@ void p2p_pref_channel_filter(const struct p2p_channels *a, void p2p_sd_query_cb(struct p2p_data *p2p, int success); void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev, const u8 *addr, int freq, bool verify); +void p2p_dfs_channel_filter(struct p2p_data *p2p, + const struct p2p_channels *p2p_chan, + const struct ieee80211_dfs_ap_info_list *ap_list, + size_t num_dfs_ap, struct p2p_channels *res); +void p2p_buf_add_wlan_ap_info(struct wpabuf *buf, + struct ieee80211_dfs_ap_info_list *dfs_ap_list, + size_t list_size); void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) PRINTF_FORMAT(2, 3); diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index de2a43f..d863b72 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -457,6 +457,15 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, msg->dira_len = len; wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len); break; + case P2P_ATTR_WLAN_AP_INFORMATION: + if (len < 1) { + wpa_printf(MSG_DEBUG, "P2P: Too short WLAN AP info (length %d)", + len); + return -1; + } + msg->wlan_ap_info = data; + msg->wlan_ap_info_len = len; + break; default: wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " "(length %d)", id, len); diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index c1f0084..35cbb16 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -611,3 +611,53 @@ void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan, res_reg->reg_class = reg->reg_class; } } + + +static int +p2p_check_dfs_channel(int channel, u8 op_class, + const struct ieee80211_dfs_ap_info_list *ap_list, + unsigned int num_dfs_ap) +{ + unsigned int i; + + for (i = 0; i < num_dfs_ap; i++) { + if (op_class == ap_list[i].op_class && + channel == ap_list[i].op_chan) + return 0; + } + return -1; +} + + +void p2p_dfs_channel_filter(struct p2p_data *p2p, + const struct p2p_channels *p2p_chan, + const struct ieee80211_dfs_ap_info_list *ap_list, + size_t num_dfs_ap, struct p2p_channels *res) +{ + size_t i, j; + + os_memset(res, 0, sizeof(*res)); + + for (i = 0; i < p2p_chan->reg_classes; i++) { + const struct p2p_reg_class *reg = &p2p_chan->reg_class[i]; + struct p2p_reg_class *res_reg = &res->reg_class[i]; + + for (j = 0; j < reg->channels; j++) { + if (p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + reg->reg_class, + reg->channel[j]) && + p2p_check_dfs_channel(reg->channel[j], + reg->reg_class, ap_list, + num_dfs_ap) < 0) + continue; + + res_reg->channel[res_reg->channels++] = + reg->channel[j]; + } + + if (res_reg->channels == 0) + continue; + res->reg_classes++; + res_reg->reg_class = reg->reg_class; + } +} diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 69a0e5e..9ca266a 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1072,6 +1072,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_len = wpa_s->extended_capa_len; hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs; + hapd_iface->assisted_dfs_go = wpa_s->assisted_dfs_go; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index f9d34b2..da37d88 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -5549,6 +5549,8 @@ static const struct global_parse_data global_fields[] = { { FUNC(p2p_device_persistent_mac_addr), 0 }, { INT(p2p_interface_random_mac_addr), 0 }, { INT(p2p_6ghz_disable), 0 }, + { INT(p2p_dfs_chan_enable), 0 }, + { INT(p2p_dfs_owner), 0 }, #endif /* CONFIG_P2P */ { FUNC(country), CFG_CHANGED_COUNTRY }, { INT(bss_max_count), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 3333125..11b83f9 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -909,6 +909,8 @@ struct wpa_config { int p2p_optimize_listen_chan; int p2p_6ghz_disable; + int p2p_dfs_chan_enable; + int p2p_dfs_owner; struct wpabuf *wps_vendor_ext_m1; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 9c9e9a7..556f203 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7753,6 +7753,11 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "remove_wlan_ap_info") == 0) { + p2p_remove_wlan_ap_info(wpa_s->global->p2p, atoi(param)); + return 0; + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 1c7992e..d70cb88 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -391,6 +391,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) sme_clear_on_disassoc(wpa_s); wpa_s->current_bss = NULL; wpa_s->assoc_freq = 0; + wpa_s->assisted_dfs_go = 0; if (bssid_changed) wpas_notify_bssid_changed(wpa_s); @@ -2588,6 +2589,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_notify_scan_done(wpa_s, 1); + wpas_p2p_update_dfs_ap_info_list(wpa_s, scan_res); if (ap) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode"); #ifdef CONFIG_AP @@ -3799,6 +3801,12 @@ no_pfs: } wpa_s->assoc_freq = data->assoc_info.freq; + if (ieee80211_is_dfs(wpa_s->assoc_freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) { + wpa_s->assisted_dfs_go = 1; + p2p_update_dfs_ap_info(wpa_s->global->p2p, bssid, + wpa_s->assoc_freq, 1, 0); + } #ifndef CONFIG_NO_ROBUST_AV wpas_handle_assoc_resp_qos_mgmt(wpa_s, data->assoc_info.resp_ies, @@ -4728,6 +4736,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, wpa_sm_notify_disassoc(wpa_s->wpa); ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE); + p2p_update_dfs_ap_info(wpa_s->global->p2p, bssid, + wpa_s->assoc_freq, 0, 1); + if (locally_generated) wpa_s->disconnect_reason = -reason_code; else diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 394beef..22778c4 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2539,6 +2539,7 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go) wpas_p2p_clone_config(group_wpa_s, wpa_s); group_wpa_s->p2p2 = wpa_s->p2p2; + group_wpa_s->assisted_dfs_go = wpa_s->assisted_dfs_go; if (wpa_s->conf->p2p_interface_random_mac_addr) { if (wpa_drv_set_mac_addr(group_wpa_s, @@ -4234,8 +4235,11 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, const struct oper_class_map *o = &global_op_class[op]; unsigned int ch; struct p2p_reg_class *reg = NULL, *cli_reg = NULL; + bool check_dfs_supported = + (is_p2p_dfs_chan_enabled(wpa_s->global->p2p) && + is_dfs_global_op_class(o->op_class)); - if (o->p2p == NO_P2P_SUPP || + if ((!check_dfs_supported && o->p2p == NO_P2P_SUPP) || (is_6ghz_op_class(o->op_class) && p2p_disable_6ghz)) continue; @@ -4253,10 +4257,11 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, if ((o->op_class >= 128 && o->op_class <= 130) && ch < 149 && ch + o->inc > 149) ch = 149; - + //FIXME + wpa_s->p2p_go_allow_dfs = 1; res = wpas_p2p_verify_channel(wpa_s, mode, o->op_class, ch, o->bw); - if (res == ALLOWED) { + if (res == ALLOWED || (res == RADAR && check_dfs_supported)) { if (reg == NULL) { if (cla == P2P_MAX_REG_CLASSES) continue; @@ -5449,6 +5454,19 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) } +static int wpas_p2p_dfs_chan(void *ctx, int freq, int op_class, int op_chan) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (freq == 0) + freq = ieee80211_chan_to_freq(NULL, op_class, op_chan); + if (ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes)) + return 1; + + return 0; +} + + /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() @@ -5520,6 +5538,11 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies; p2p.pasn_parse_encrypted_data = wpas_p2p_pasn_parse_encrypted_data; #endif /* CONFIG_PASN */ + p2p.is_p2p_dfs_chan = wpas_p2p_dfs_chan; + // FIXME: Dont hardcode dfs_chan_enable +// p2p.dfs_chan_enable = wpa_s->conf->p2p_dfs_chan_enable; + p2p.dfs_chan_enable = 1; + p2p.dfs_owner = wpa_s->conf->p2p_dfs_owner; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); p2p.dev_name = wpa_s->conf->device_name; @@ -6460,7 +6483,7 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, else ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq); if (!ret) { - if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + if (is_p2p_dfs_chan_enabled(wpa_s->global->p2p) && ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes)) { /* @@ -11171,3 +11194,24 @@ int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, return p2p_pasn_get_ptk(p2p, ptk, ptk_len); } #endif /* CONFIG_PASN */ + +void wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + size_t i; + + for (i = 0; i < scan_res->num; i++) { + if (!ieee80211_is_dfs(scan_res->res[i]->freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) + continue; + if (scan_res->res[i]->flags & BIT(5)) { + p2p_update_dfs_ap_info(wpa_s->global->p2p, + scan_res->res[i]->bssid, + scan_res->res[i]->freq, 1, 0); + } else { + p2p_update_dfs_ap_info(wpa_s->global->p2p, + scan_res->res[i]->bssid, + scan_res->res[i]->freq, 0, 0); + } + } +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 3dcc9e3..aafe647 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -236,6 +236,8 @@ int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s); int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, size_t *ptk_len); +void wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res); #else /* CONFIG_P2P */ static inline int @@ -385,6 +387,11 @@ static inline int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, return 0; } +static inline void +wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ +} #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 610072e..e153530 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1606,6 +1606,7 @@ struct wpa_supplicant { bool last_scan_all_chan; bool last_scan_non_coloc_6ghz; bool support_6ghz; + u8 assisted_dfs_go; struct wpa_signal_info last_signal_info; -- 2.7.4 From quic_shivbara at quicinc.com Mon Aug 5 02:33:14 2024 From: quic_shivbara at quicinc.com (Shivani Baranwal) Date: Mon, 5 Aug 2024 15:03:14 +0530 Subject: [PATCH v3 16/25] P2P: Add support for GO negotiation wrapped in PASN auth frame In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: <1722850403-8852-17-git-send-email-quic_shivbara@quicinc.com> Add P2P2 support for GO negotiation wrapped in PASN authentication frames as a action wrapper attribute. Signed-off-by: Shivani Baranwal --- src/ap/ieee802_11.c | 16 +- src/common/ieee802_11_common.c | 4 + src/common/ieee802_11_common.h | 2 + src/common/ieee802_11_defs.h | 2 + src/p2p/p2p.c | 808 +++++++++++++++++++++++++++++++++++++- src/p2p/p2p.h | 85 ++++ src/p2p/p2p_go_neg.c | 4 +- src/p2p/p2p_i.h | 27 ++ src/p2p/p2p_parse.c | 20 + src/p2p/p2p_pd.c | 6 + src/pasn/pasn_common.h | 7 + src/pasn/pasn_initiator.c | 50 ++- src/pasn/pasn_responder.c | 20 +- wpa_supplicant/events.c | 56 ++- wpa_supplicant/p2p_supplicant.c | 161 +++++++- wpa_supplicant/p2p_supplicant.h | 11 +- wpa_supplicant/pasn_supplicant.c | 5 + wpa_supplicant/wpa_supplicant_i.h | 5 + 18 files changed, 1260 insertions(+), 29 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 38fcba5..3c5a8dd 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2487,6 +2487,10 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd, fils->erp_resp = erp_resp; ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL, WLAN_STATUS_SUCCESS); + if (sta->pasn->frame) { + wpabuf_free(sta->pasn->frame); + sta->pasn->frame = NULL; + } fils->erp_resp = NULL; if (ret) { @@ -2800,6 +2804,8 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta, const struct ieee80211_mgmt *mgmt, size_t len, u16 trans_seq, u16 status) { + int ret; + if (hapd->conf->wpa != WPA_PROTO_RSN) { wpa_printf(MSG_INFO, "PASN: RSN is not configured"); return; @@ -2831,9 +2837,15 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta, hapd_initialize_pasn(hapd, sta); hapd_pasn_update_params(hapd, sta, mgmt, len); - if (handle_auth_pasn_1(sta->pasn, hapd->own_addr, - sta->addr, mgmt, len) < 0) + ret = handle_auth_pasn_1(sta->pasn, hapd->own_addr, sta->addr, + mgmt, len); + if (sta->pasn->frame) { + wpabuf_free(sta->pasn->frame); + sta->pasn->frame = NULL; + } + if (ret < 0) ap_free_sta(hapd, sta); + } else if (trans_seq == 3) { if (!sta->pasn) { wpa_printf(MSG_DEBUG, diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 2d4540b..b16564d 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -413,6 +413,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->mbssid_known_bss = pos; elems->mbssid_known_bss_len = elen; break; + case WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT: + elems->pasn_encrypted_ie = pos; + elems->pasn_encrypted_ie_len = elen; + break; default: if (show_errors) { wpa_printf(MSG_MSGDUMP, diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index e4321b5..7ca99f3 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -66,6 +66,7 @@ struct ieee802_11_elems { const u8 *vendor_vht; const u8 *p2p; const u8 *p2p2_ie; + const u8 *pasn_encrypted_ie; const u8 *wfd; const u8 *link_id; const u8 *interworking; @@ -141,6 +142,7 @@ struct ieee802_11_elems { u8 vendor_vht_len; u8 p2p_len; u8 p2p2_ie_len; + u8 pasn_encrypted_ie_len; u8 wfd_len; u8 interworking_len; u8 qos_map_set_len; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 0e88797..db1033a 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -524,6 +524,7 @@ #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 #define WLAN_EID_EXT_QOS_CHARACTERISTICS 113 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114 +#define WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT 140 /* Extended Capabilities field */ #define WLAN_EXT_CAPAB_20_40_COEX 0 @@ -616,6 +617,7 @@ #define WLAN_RSNX_CAPAB_SECURE_RTT 9 #define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10 #define WLAN_RSNX_CAPAB_URNM_MFPR 15 +#define WLAN_RSNX_CAPAB_KEK 18 #define WLAN_RSNX_CAPAB_SSID_PROTECTION 21 /* Multiple BSSID element subelements */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 01490e2..6e2a97c 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -15,10 +15,14 @@ #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "crypto/sha256.h" +#include "crypto/sha384.h" #include "crypto/crypto.h" #include "wps/wps_i.h" #include "p2p_i.h" #include "p2p.h" +#include "common/sae.h" +#include "pasn/pasn_common.h" +#include "crypto/aes_wrap.h" static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx); @@ -242,6 +246,11 @@ void p2p_go_neg_failed(struct p2p_data *p2p, int status) peer->go_neg_conf = NULL; p2p->go_neg_peer = NULL; +#ifdef CONFIG_PASN + if (peer->p2p2 && peer->pasn) + wpa_pasn_reset(peer->pasn); +#endif /* CONFIG_PASN */ + os_memset(&res, 0, sizeof(res)); res.status = status; os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); @@ -959,6 +968,14 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) dev->bootstrap_params = NULL; } +#ifdef CONFIG_PASN + if (dev->pasn) { + wpa_pasn_reset(dev->pasn); + pasn_data_deinit(dev->pasn); + dev->pasn = NULL; + } +#endif /* CONFIG_PASN */ + wpabuf_free(dev->info.wfd_subelems); wpabuf_free(dev->info.vendor_elems); wpabuf_free(dev->go_neg_conf); @@ -1861,8 +1878,13 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) os_memset(&res, 0, sizeof(res)); res.role_go = go; + + if (is_zero_ether_addr(peer->interface_addr)) + os_memcpy(peer->interface_addr, peer->intended_addr, ETH_ALEN); + os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); - os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN); + os_memcpy(res.peer_interface_addr, peer->interface_addr, ETH_ALEN); + res.wps_method = peer->wps_method; if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) { if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN) @@ -1911,6 +1933,11 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) wpabuf_free(peer->go_neg_conf); peer->go_neg_conf = NULL; +#ifdef CONFIG_PASN + if (peer->p2p2 && peer->pasn) + wpa_pasn_reset(peer->pasn); +#endif /* CONFIG_PASN */ + p2p_set_state(p2p, P2P_PROVISIONING); p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); } @@ -3012,7 +3039,18 @@ int p2p_pairing_info_init(struct p2p_data *p2p) os_memcpy(pairing_info->dev_ik.dik_data, p2p->cfg->pairing_config.dik_data, p2p->cfg->pairing_config.dik_len); + + if (!p2p->cfg->dev_password_len) { + p2p->cfg->dev_password_len = 10; + p2p_random(p2p->cfg->dev_password, p2p->cfg->dev_password_len); + p2p->cfg->dev_password[p2p->cfg->dev_password_len] = '\0'; + } + p2p->pairing_info = pairing_info; +#ifdef CONFIG_PASN + p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init(); + p2p->responder_pmksa = pasn_responder_pmksa_cache_init(); +#endif /* CONFIG_PASN */ return 0; } @@ -3086,6 +3124,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) void p2p_pairing_info_deinit(struct p2p_data *p2p) { +#ifdef CONFIG_PASN + pasn_initiator_pmksa_cache_deinit(p2p->initiator_pmksa); + pasn_responder_pmksa_cache_deinit(p2p->responder_pmksa); +#endif /* CONFIG_PASN */ os_free(p2p->pairing_info); } @@ -4975,8 +5017,11 @@ int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, u8 *iface_addr) { struct p2p_device *dev = p2p_get_device(p2p, dev_addr); - if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) + if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get interface addr from dev addr " + MACSTR, MAC2STR(dev_addr)); return -1; + } os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN); return 0; } @@ -4986,8 +5031,11 @@ int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, u8 *dev_addr) { struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr); - if (dev == NULL) + if (!dev) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get device addr from iface addr " + MACSTR, MAC2STR(iface_addr)); return -1; + } os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN); return 0; } @@ -5862,3 +5910,757 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, p2p_parse_free(&msg); } + +#ifdef CONFIG_PASN +int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p, struct wpabuf *extra_ies, + struct wpabuf *frame) +{ + struct wpabuf *buf, *buf2; + + buf = wpabuf_alloc(1500); + if (!buf) { + p2p_dbg(p2p, "Mem alloc failed for buf"); + return -1; + } + + /* P2P Capability Extension attribute */ + p2p_buf_add_pcea(buf, p2p); + + if (frame) { + p2p_dbg(p2p, "P2P: Added Action frame wrapper"); + wpabuf_put_u8(buf, P2P_ATTR_ACTION_FRAME_WRAPPER); + wpabuf_put_le16(buf, wpabuf_len(frame)); + wpabuf_put_buf(buf, frame); + } + + buf2 = p2p_encaps_p2p_vendor_ie(p2p, buf, P2P2_IE_VENDOR_TYPE); + wpabuf_free(buf); + + wpabuf_put_buf(extra_ies, buf2); + wpabuf_free(buf2); + + return 0; +} + +struct wpabuf *p2p_pairing_generate_rsnxe(int akmp) +{ + u32 capab; + size_t flen = 0; + struct wpabuf *buf; + + capab = BIT(WLAN_RSNX_CAPAB_KEK); + + if (akmp == WPA_KEY_MGMT_SAE) + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); + + while (capab >> flen * 8) + flen++; + + buf = wpabuf_alloc(2 + flen); + if (!buf) { + wpa_printf(MSG_ERROR, "Memory allocation failed"); + return NULL; + } + + if (wpabuf_tailroom(buf) < 2 + flen) { + wpa_printf(MSG_ERROR, "wpabuf tail room small"); + wpabuf_free(buf); + return NULL; + } + capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ + + wpa_printf(MSG_DEBUG, "RSNXE capabilities: %04x", capab); + wpabuf_put_u8(buf, WLAN_EID_RSNX); + wpabuf_put_u8(buf, flen); + while (flen--) { + wpabuf_put_u8(buf, (capab & 0xff)); + capab = capab >> 8; + } + return buf; +} + +/* sae password id to derive pt */ +#define P2P_PAIRING_SSID "516F9A020000" + +void p2p_pairing_set_password(struct pasn_data *pasn, const char *passphrase, + u32 len) +{ + const u8 *pairing_ssid; + size_t pairing_ssid_len; + + if (!passphrase) { + wpa_printf(MSG_ERROR, "p2p pairing password NULL"); + return; + } + + pairing_ssid = (const u8 *)(P2P_PAIRING_SSID); + pairing_ssid_len = strlen(P2P_PAIRING_SSID); + pasn->pt = sae_derive_pt(pasn->pasn_groups, pairing_ssid, + pairing_ssid_len, (const u8 *)passphrase, len, + NULL); + /* Set passpharse for Pairing Responder to validate PASN auth1 frame*/ + pasn->password = passphrase; +} + +void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev, + const u8 *addr, int freq, bool verify) +{ + struct pasn_data *pasn; + struct wpabuf *rsnxe; + + if (!p2p || !dev) + return; + + if (dev->pasn) + wpa_pasn_reset(dev->pasn); + else + dev->pasn = pasn_data_init(); + + pasn = dev->pasn; + + os_memcpy(pasn->own_addr, p2p->cfg->dev_addr, ETH_ALEN); + os_memcpy(pasn->peer_addr, addr, ETH_ALEN); + + if (dev->role == P2P_ROLE_PAIRING_INITIATOR) + memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN); + else + memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN); + + pasn->noauth = 1; + + if ((p2p->cfg->pairing_config.pasn_type & 0xc) && + (dev->info.pairing_config.pasn_type & 0xc)) { + pasn->group = 20; + pasn->cipher = WPA_CIPHER_GCMP_256; + pasn->kek_len = WPA_KEK_256; + pasn->pasn_groups = p2p->cfg->pairing_config.pasn_groups; + } else { + pasn->group = 19; + pasn->cipher = WPA_CIPHER_CCMP; + pasn->kek_len = WPA_KEK_128; + } + + if (dev->password_len) { + pasn->akmp = WPA_KEY_MGMT_SAE; + p2p_pairing_set_password(pasn, dev->password, + dev->password_len); + pasn->rsnxe_capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); + } else if (verify) { + pasn->akmp = WPA_KEY_MGMT_SAE; + } else { + pasn->akmp = WPA_KEY_MGMT_PASN; + } + + pasn->rsn_pairwise = pasn->cipher; + pasn->wpa_key_mgmt = pasn->akmp; + + rsnxe = p2p_pairing_generate_rsnxe(pasn->akmp); + if (rsnxe) { + pasn->rsnxe_ie = os_zalloc(wpabuf_len(rsnxe)); + if (!pasn->rsnxe_ie) { + p2p_dbg(p2p, "Mem alloc failed for pasn rsnxe ie"); + wpabuf_free(rsnxe); + return; + } + os_memcpy((u8 *)pasn->rsnxe_ie, wpabuf_head_u8(rsnxe), + wpabuf_len(rsnxe)); + pasn->rsnxe_ie_len = wpabuf_len(rsnxe); + wpabuf_free(rsnxe); + } + + if (dev->role == P2P_ROLE_PAIRING_INITIATOR) + pasn->pmksa = p2p->initiator_pmksa; + else + pasn->pmksa = p2p->responder_pmksa; + + pasn->cb_ctx = p2p->cfg->cb_ctx; + pasn->send_mgmt = p2p->cfg->pasn_send_mgmt; + pasn->update_extra_ies = p2p->cfg->pasn_update_extra_ies; + pasn->parse_encrypted_data = p2p->cfg->pasn_parse_encrypted_data; + + pasn->freq = freq; +} + + +int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq) +{ + struct pasn_data *pasn; + struct p2p_device *dev; + struct wpabuf *extra_ies, *req; + int ret = 0; + + if (!addr) { + p2p_dbg(p2p, "peer address NULL"); + return -1; + } + + dev = p2p_get_device(p2p, addr); + if (!dev) { + p2p_dbg(p2p, "Peer not known"); + return -1; + } + + dev->role = P2P_ROLE_PAIRING_INITIATOR; + p2p_pasn_initialize(p2p, dev, addr, freq, false); + pasn = dev->pasn; + + pasn_initiator_pmksa_cache_remove(pasn->pmksa, (u8 *)addr); + + /* FIXME: Added to resolve listen freq issue resulting in GO Neg no + * common channel failure + */ + p2p->cfg->reg_class = p2p->op_reg_class; + p2p->cfg->channel = p2p->op_channel; + + req = p2p_build_go_neg_req(p2p, dev); + if (!req) + return -1; + + p2p->go_neg_peer = dev; + dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE; + + extra_ies = wpabuf_alloc(1500); + if (!extra_ies) { + wpabuf_free(req); + p2p_dbg(p2p, "Mem alloc failed for extra ies"); + return -1; + } + + if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) { + p2p_dbg(p2p, "prepare pasn extra ies failed"); + ret = -1; + goto out; + } + + pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies)); + if (!pasn->extra_ies) { + p2p_dbg(p2p, "Mem alloc failed for pasn extra ies"); + ret = -1; + goto out; + } + + os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies), + wpabuf_len(extra_ies)); + pasn->extra_ies_len = wpabuf_len(extra_ies); + + /* Start PASN Auth */ + if (wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid, + pasn->akmp, pasn->cipher, pasn->group, pasn->freq, + NULL, 0, NULL, 0, NULL)) { + p2p_dbg(p2p, "p2p pasn start failed"); + ret = -1; + } +out: + if (pasn->extra_ies) { + os_free((u8 *)pasn->extra_ies); + pasn->extra_ies = NULL; + pasn->extra_ies_len = 0; + } + wpabuf_free(req); + wpabuf_free(extra_ies); + return ret; +} + + +int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p, + struct p2p_device *dev, + const struct ieee80211_mgmt *mgmt, + size_t len, int freq, int trans_seq) +{ + const u8 *ies; + size_t ies_len; + size_t data_len = 0; + const u8 *data = NULL; + struct p2p_message msg; + + ies = mgmt->u.auth.variable; + ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable); + + os_memset(&msg, 0, sizeof(msg)); + if (p2p_parse_ies(ies, ies_len, &msg)) { + p2p_dbg(p2p, "Failed to parse P2P IE from auth frame"); + p2p_parse_free(&msg); + return -1; + } + + if (msg.action_frame_wrapper && msg.action_frame_wrapper_len) { + data = msg.action_frame_wrapper; + data_len = msg.action_frame_wrapper_len; + if (data[0] == WLAN_ACTION_PUBLIC && + data[1] == WLAN_PA_VENDOR_SPECIFIC) { + data += 2; + data_len -= 2; + if (data_len < 4 || + WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE) { + p2p_parse_free(&msg); + return -1; + } + data += 4; + data_len -= 4; + } else { + p2p_dbg(p2p, "Invalid category in action frame wrapper in Auth %d", + trans_seq); + p2p_parse_free(&msg); + return -1; + } + } + + if (trans_seq == 1) { + if (data && data[0] == P2P_INVITATION_REQ) { + p2p_process_invitation_req(p2p, mgmt->sa, data + 1, + data_len - 1, freq); + if (!p2p->invitation_resp) + p2p_dbg(p2p, "No Invitation Response found"); + + dev->role = P2P_ROLE_PAIRING_RESPONDER; + p2p_pasn_initialize(p2p, dev, mgmt->sa, freq, true); + dev->pasn->action_frame_wrapper = p2p->invitation_resp; + } else if (data && data[0] == P2P_GO_NEG_REQ) { + p2p_process_go_neg_req(p2p, mgmt->sa, data + 1, + data_len - 1, freq, true); + if (!p2p->go_neg_resp) + p2p_dbg(p2p, "No GO Neg Response found"); + dev->pasn->action_frame_wrapper = p2p->go_neg_resp; + } else { + p2p_dbg(p2p, "Invalid action frame wrapper in Auth1"); + } + } else if (trans_seq == 2) { + if (data && data[0] == P2P_INVITATION_RESP) { + p2p_process_invitation_resp(p2p, mgmt->sa, data + 1, + data_len - 1); + dev->pasn->action_frame_wrapper = NULL; + } else if (data && data[0] == P2P_GO_NEG_RESP) { + p2p_process_go_neg_resp(p2p, mgmt->sa, data + 1, + data_len - 1, freq, true); + if (!p2p->go_neg_conf) + p2p_dbg(p2p, "No GO Neg confirm found"); + dev->pasn->action_frame_wrapper = p2p->go_neg_conf; + /* FIXME: If go neg resp is with failure status, + how go_neg_failed is indicated to host */ + } else { + p2p_dbg(p2p, "Invalid action frame wrapper in Auth2"); + } + } else if (trans_seq == 3) { + if (data && data[0] == P2P_GO_NEG_CONF) { + p2p_handle_go_neg_conf(p2p, mgmt->sa, data + 1, + data_len - 1, true); + } else { + p2p_invitation_resp_cb(p2p, P2P_SEND_ACTION_SUCCESS); + } + } + p2p_parse_free(&msg); + return 0; +} + + +static void p2p_pasn_add_encrypted_element(struct p2p_data *p2p, + struct p2p_device *dev, + struct wpabuf *buf) +{ + int ret; + struct pasn_data *pasn; + struct wpabuf *p2p2_ie; + u8 *len, *dika_len, *p2p2_ie_len; + u8 *pos, *key_data, *encrypted_data; + u16 key_data_len, pad_len = 0; + + if (!p2p || !dev || !dev->pasn) + return; + + pasn = dev->pasn; + + if (dev->req_bootstrap_method != P2P_PBMA_OPPORTUNISTIC && + !p2p->pairing_info->enable_pairing_cache) + return; + + p2p2_ie = wpabuf_alloc(100); + if (!p2p2_ie) { + p2p_dbg(p2p, "Mem alloc failed for p2p2 IE"); + return; + } + + p2p2_ie_len = p2p_buf_add_p2p2_ie_hdr(p2p2_ie); + + if (p2p->pairing_info->enable_pairing_cache) { + wpabuf_put_u8(p2p2_ie, P2P_ATTR_DEVICE_IDENTITY_KEY); + dika_len = wpabuf_put(p2p2_ie, 2); + + wpabuf_put_u8(p2p2_ie, DIRA_CIPHER_VERSION_128); + wpabuf_put_data(p2p2_ie, p2p->pairing_info->dev_ik.dik_data, + p2p->pairing_info->dev_ik.dik_len); + wpabuf_put_be32(p2p2_ie, p2p->pairing_info->dev_ik.expiration); + + WPA_PUT_LE16(dika_len, + (u8 *)wpabuf_put(p2p2_ie, 0) - dika_len - 2); + } + + if (dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC && + p2p->cfg->dev_password_len) { + wpabuf_put_u8(p2p2_ie, P2P_ATTR_PASSWORD); + wpabuf_put_le16(p2p2_ie, p2p->cfg->dev_password_len); + wpabuf_put_data(p2p2_ie, p2p->cfg->dev_password, + p2p->cfg->dev_password_len); + } + + p2p_buf_update_p2p2_ie_hdr(p2p2_ie, p2p2_ie_len); + + key_data = (u8 *)wpabuf_head(p2p2_ie); + key_data_len = wpabuf_len(p2p2_ie); + + pad_len = key_data_len % 8; + + if (pad_len) { + pad_len = 8 - pad_len; + pos = key_data + key_data_len; + *pos++ = 0xdd; + } + key_data_len += pad_len + 8; + + encrypted_data = os_malloc(key_data_len); + if (!encrypted_data) { + p2p_dbg(p2p, "P2P PASN: Mem alloc failed for encrypted data"); + wpabuf_free(p2p2_ie); + return; + } + ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len, + (key_data_len - 8) / 8, key_data, encrypted_data); + if (ret) { + p2p_dbg(p2p, "P2P PASN: AES upwrap failed, ret=%d", ret); + goto out; + } + + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + len = wpabuf_put(buf, 1); + + wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_ELEMENT); + + wpabuf_put_data(buf, encrypted_data, key_data_len); + *len = (u8 *)wpabuf_put(buf, 0) - len - 1; + +out: + os_free(encrypted_data); + wpabuf_free(p2p2_ie); +} + + +int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr) +{ + int ret = -1; + struct p2p_device *dev; + struct pasn_data *pasn; + struct wpabuf *extra_ies; + + if (!p2p) + return -1; + + dev = p2p_get_device(p2p, (u8 *)peer_addr); + if (!dev || !dev->pasn) { + p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR, + MAC2STR(peer_addr)); + return -1; + } + pasn = dev->pasn; + + extra_ies = wpabuf_alloc(1500); + if (!extra_ies) { + p2p_dbg(p2p, "Mem alloc failed for extra ies"); + goto out; + } + + if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, + pasn->action_frame_wrapper)) { + p2p_dbg(p2p, "prepare pasn extra ies failed"); + goto out; + } + + p2p_pasn_add_encrypted_element(p2p, dev, extra_ies); + + pasn->extra_ies = os_zalloc(wpabuf_len(extra_ies)); + if (!pasn->extra_ies) { + p2p_dbg(p2p, "Mem alloc failed for pasn extra ies"); + goto out; + } + + os_memcpy((u8 *)pasn->extra_ies, wpabuf_head_u8(extra_ies), + wpabuf_len(extra_ies)); + pasn->extra_ies_len = wpabuf_len(extra_ies); + ret = 0; + +out: + wpabuf_free(extra_ies); + wpabuf_free(pasn->action_frame_wrapper); + pasn->action_frame_wrapper = NULL; + + return ret; +} + + +int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data, + size_t len) +{ + int ret = -1; + u8 attr_id; + u8 *buf, *pos; + u16 rem_len, attr_len; + struct p2p_device *dev; + struct pasn_data *pasn; + struct ieee802_11_elems elems; + const struct ieee80211_mgmt *mgmt = + (const struct ieee80211_mgmt *) data; + + if (!p2p) + return -1; + + dev = p2p_get_device(p2p, (u8 *)mgmt->sa); + if (!dev || !dev->pasn) { + p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR, + MAC2STR(mgmt->sa)); + return -1; + } + + if (ieee802_11_parse_elems(mgmt->u.auth.variable, + len - offsetof(struct ieee80211_mgmt, + u.auth.variable), + &elems, 0) == ParseFailed) { + p2p_dbg(p2p, "P2P PASN: Failed parsing Authentication frame"); + return -1; + } + + if (!elems.pasn_encrypted_ie || !elems.pasn_encrypted_ie_len) { + p2p_dbg(p2p, "P2P PASN: No encrypted IEs"); + return 0; + } + + pasn = dev->pasn; + rem_len = elems.pasn_encrypted_ie_len; + + buf = os_zalloc(rem_len); + if (!buf) { + p2p_dbg(p2p, "Mem alloc failed for buf"); + return -1; + } + + ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, (rem_len - 8) / 8, + elems.pasn_encrypted_ie, buf); + if (ret) { + p2p_dbg(p2p, "P2P PASN: AES unwrap failed, ret=%d", ret); + goto done; + } + + pos = buf; + if (pos[0] != WLAN_EID_VENDOR_SPECIFIC || + WPA_GET_BE32(&pos[2]) != P2P2_IE_VENDOR_TYPE) { + p2p_dbg(p2p, "P2P PASN: P2P2 IE not present"); + goto done; + } + + pos += 6; + rem_len -= 6; + + while (rem_len > 2) { + attr_id = *pos++; + attr_len = WPA_GET_LE16(pos); + + pos += 2; + rem_len -= 3; + switch (attr_id) { + case P2P_ATTR_DEVICE_IDENTITY_KEY: + if (rem_len < 13) { + p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len); + goto done; + } + dev->info.dik_cipher_version = *pos++; + rem_len--; + if (dev->info.dik_cipher_version == 0) { + memcpy(dev->info.dik_data, pos, 16); + dev->info.dik_len = 16; + pos += 16; + rem_len -= 16; + } else { + p2p_dbg(p2p, "P2P PASN: Invalid cipher"); + goto done; + } + dev->info.dik_lifetime = WPA_GET_BE32(pos); + pos += 4; + rem_len -= 4; + break; + case P2P_ATTR_PASSWORD: + if (rem_len < 1) { + p2p_dbg(p2p, "P2P PASN: Invalid rem len %d", rem_len); + goto done; + } + dev->info.password_len = attr_len; + memset(dev->info.password, 0, + sizeof(dev->info.password)); + memcpy(dev->info.password, pos, attr_len); + break; + default: + p2p_dbg(p2p, "Invalid Attr ID: %d", attr_id); + break; + } + } + ret = 0; +done: + os_free(buf); + return ret; +} + +int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, + size_t data_len, u8 acked) +{ + int ret = 0; + struct p2p_device *dev; + struct pasn_data *pasn; + const struct ieee80211_mgmt *mgmt = + (const struct ieee80211_mgmt *) data; + + if (!p2p) + return -1; + + dev = p2p_get_device(p2p, (u8 *)mgmt->da); + if (!dev || !dev->pasn) { + p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR, + MAC2STR(mgmt->da)); + return -1; + } + + pasn = dev->pasn; + + ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked); + if (ret != 1 && acked == 0 && pasn->frame) { + return pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(pasn->frame), + wpabuf_len(pasn->frame), 0, pasn->freq, + 1000); + } else if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } + + if (ret != 1) + return ret; + + if (dev == p2p->go_neg_peer) + p2p_go_complete(p2p, dev); + + return 0; +} + +int p2p_handle_pasn_auth(struct p2p_data *p2p, struct p2p_device *dev, + const struct ieee80211_mgmt *mgmt, size_t len, + int freq) +{ + struct pasn_data *pasn; + u16 auth_alg, auth_transaction, status_code; + + if (!p2p || !dev || !dev->pasn) + return -1; + + if (os_memcmp(mgmt->da, p2p->cfg->dev_addr, ETH_ALEN) != 0) { + p2p_dbg(p2p, "P2P PASN Responder: Not our frame"); + return -1; + } + + pasn = dev->pasn; + auth_alg = le_to_host16(mgmt->u.auth.auth_alg); + status_code = le_to_host16(mgmt->u.auth.status_code); + + auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); + + if (status_code != WLAN_STATUS_SUCCESS && + status_code != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { + p2p_dbg(p2p, "P2P PASN: Authentication rejected - status=%u", + status_code); + return -1; + } + + if (auth_alg != WLAN_AUTH_PASN || auth_transaction == 2) { + p2p_dbg(p2p, "P2P PASN Responder: Not PASN frame " + " or Unexpected auth frame, auth_alg = %d", + auth_alg); + return -1; + } + if (auth_transaction == 1) { + if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq, + auth_transaction)) { + p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 action wrapper failed"); + return -1; + } + if (handle_auth_pasn_1(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt, + len) < 0) { + p2p_dbg(p2p, "P2P PASN Responder: Handle Auth1 failed"); + return -1; + } + } else if (auth_transaction == 3) { + if (handle_auth_pasn_3(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt, + len) < 0) { + p2p_dbg(p2p, "P2P PASN Responder: Handle PASN Auth3 failed"); + return -1; + } + if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq, + auth_transaction)) { + p2p_dbg(p2p, "P2P PASN Responder: Handle Auth3 action wrapper failed"); + memset(dev->info.dik_data, 0, + sizeof(dev->info.dik_data)); + memset(dev->info.password, 0, + sizeof(dev->info.password)); + dev->info.password_len = 0; + return -1; + } + forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); + } + return 0; +} + + +int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, + size_t len, int freq) +{ + int ret = 0; + u8 auth_transaction; + struct p2p_device *dev; + struct pasn_data *pasn; + struct wpa_pasn_params_data pasn_data; + + dev = p2p_get_device(p2p, (u8 *)mgmt->sa); + if (!dev) { + p2p_dbg(p2p, "P2P PASN: Peer not found" MACSTR, + MAC2STR(mgmt->sa)); + return -1; + } + + if (!dev->pasn) { + p2p_dbg(p2p, "P2P PASN: uninitialized"); + return -1; + } + + pasn = dev->pasn; + + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } + + pasn_register_callbacks(pasn, p2p->cfg->cb_ctx, + p2p->cfg->pasn_send_mgmt, NULL); + auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); + + if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) { + if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq, + auth_transaction)) { + p2p_dbg(p2p, "P2P PASN Initiator: Handle Auth2 action wrapper failed"); + return -1; + } + ret = wpa_pasn_auth_rx(pasn, (const u8 *)mgmt, len, &pasn_data); + forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); + + if (ret < 0) { + p2p_dbg(p2p, "P2P PASN: wpa_pasn_auth_rx failed"); + dev->role = P2P_ROLE_IDLE; + } + + } else { + ret = p2p_handle_pasn_auth(p2p, dev, mgmt, len, freq); + } + return ret; +} +#endif diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index c9bc12f..1b1c19f 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -372,6 +372,11 @@ struct p2p_pairing_config { /* length of DevIK */ size_t dik_len; + + /** + * The set of supported PASN groups + */ + int pasn_groups[4]; }; @@ -479,6 +484,36 @@ struct p2p_peer_info { * p2p_pairing_config - P2P Pairing configuration */ struct p2p_pairing_config pairing_config; + + /** + * cipher version for Device Identity key generation + */ + u8 dik_cipher_version; + + /** + * Device Identity key which is unique for a device + */ + u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN]; + + /** + * Device Identity key length + */ + u16 dik_len; + + /** + * Device Identity key lifetime + */ + u32 dik_lifetime; + + /** + * password used during group formation post opportunistic pasn auth + */ + char password[100]; + + /** + * password length. Non zero if valid + */ + u16 password_len; }; enum p2p_prov_disc_status { @@ -658,6 +693,16 @@ struct p2p_config { unsigned int passphrase_len; /** + * password used during group formation post opportunistic pasn auth + */ + char dev_password[100]; + + /** + * password length. Non zero if valid + */ + u16 dev_password_len; + + /** * p2p_pairing_config - P2P Pairing configuration */ struct p2p_pairing_config pairing_config; @@ -1269,6 +1314,38 @@ struct p2p_config { */ void (*bootstrap_completed)(void *ctx, const u8 *addr, int status, int freq); + + /** + * pasn_send_mgmt - Function handler to transmit a Management frame + * @ctx: Callback context from cb_ctx + * @data : Frame to transmit + * @data_len: Length of frame to transmit + * @noack : No ack flag + * @freq: Frequency in MHz for the channel on which to transmit + * @wait: How many milliseconds to wait for a response frame + * Returns: 0 on success, -1 on failure + */ + int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, unsigned int wait); + + /** + * pasn_update_extra_ies - Function handler to update protocol specific + * IEs in pasn auth frames + * @ctx: Callback context from cb_ctx + * @peer_addr : peer mac address + * Returns: 0 on success, -1 on failure + */ + int (*pasn_update_extra_ies)(void *ctx, const u8 *peer_addr); + + /** + * pasn_parse_encrypted_data - Function handler to parse encrypted data + * with KEK received in pasn auth frames + * @ctx: Callback context from cb_ctx + * @data : data to be decrypted + * @len: length of encrypted data + * Returns: 0 on success, -1 on failure + */ + int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len); }; @@ -2571,4 +2648,12 @@ int p2p_channel_to_freq(int op_class, int channel); struct wpabuf * p2p_usd_elems(struct p2p_data *p2p); void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, const u8 *peer_addr, unsigned int freq); +int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq); +int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, + size_t len, int freq); +int p2p_pasn_update_extra_ies(struct p2p_data *p2p, const u8 *peer_addr); +int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data, + size_t len); +int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, + size_t data_len, u8 acked); #endif /* P2P_H */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 5798018..1f6923d 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -135,8 +135,8 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) } -static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, - struct p2p_device *peer) +struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, + struct p2p_device *peer) { u8 group_capab; size_t extra = 0; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index d7a5dc1..e0d2ee0 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -37,6 +37,13 @@ enum p2p_go_state { }; +/* Enumeration for P2P device current role */ +enum p2p_role { + P2P_ROLE_IDLE = 0, + P2P_ROLE_PAIRING_INITIATOR, + P2P_ROLE_PAIRING_RESPONDER, +}; + /** * struct bootstrap_params - P2P Device bootstrap request params */ @@ -188,6 +195,12 @@ struct p2p_device { * password length. Non zero if valid */ u16 password_len; + + /* pasn data structure */ + struct pasn_data *pasn; + + /* device role */ + enum p2p_role role; }; struct p2p_sd_query { @@ -630,6 +643,10 @@ struct p2p_data { bool allow_6ghz; struct p2p_pairing_info *pairing_info; + /*p2p pairing initiator pmksa cache list */ + struct rsn_pmksa_cache *initiator_pmksa; + /* p2p pairing responder pmksa cache list */ + struct rsn_pmksa_cache *responder_pmksa; /** * go_neg_resp - GO Negotiation Response frame */ @@ -761,6 +778,12 @@ struct p2p_message { const u8 *pbma_info; size_t pbma_info_len; + + const u8 *action_frame_wrapper; + size_t action_frame_wrapper_len; + + const u8 *dira; + size_t dira_len; }; @@ -919,6 +942,8 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev); /* p2p_go_neg.c */ +struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, + struct p2p_device *peer); int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, struct p2p_device *dev, const u8 *channel_list, size_t channel_list_len); @@ -1021,6 +1046,8 @@ void p2p_pref_channel_filter(const struct p2p_channels *a, struct p2p_channels *res, bool go); void p2p_sd_query_cb(struct p2p_data *p2p, int success); +void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev, + const u8 *addr, int freq, bool verify); void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) PRINTF_FORMAT(2, 3); diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index a70e180..de2a43f 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -437,6 +437,26 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, msg->pbma_info_len = len; wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len); break; + case P2P_ATTR_ACTION_FRAME_WRAPPER: + if (len < 2) { + wpa_printf(MSG_DEBUG, "P2P: Too short Action frame (length %d)", + len); + return -1; + } + msg->action_frame_wrapper = data; + msg->action_frame_wrapper_len = len; + wpa_printf(MSG_DEBUG, "P2P: * Action frame wrapper (length=%u)", len); + break; + case P2P_ATTR_DEVICE_IDENTITY_RESOLUTION: + if (len < 2) { + wpa_printf(MSG_DEBUG, "P2P: Too short DIRA (length %d)", + len); + return -1; + } + msg->dira = data; + msg->dira_len = len; + wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len); + break; default: wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " "(length %d)", id, len); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 56022ff..f1856d2 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -824,6 +824,12 @@ static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p, wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap); + if (status == P2P_SC_SUCCESS) { + dev->role = P2P_ROLE_PAIRING_RESPONDER; +#ifdef CONFIG_PASN + p2p_pasn_initialize(p2p, dev, sa, rx_freq, false); +#endif /* CONFIG_PASN */ + } out: /* * Send PD Bootstrapping Response for the PD Request diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h index e3ff746..8eb3bce 100644 --- a/src/pasn/pasn_common.h +++ b/src/pasn/pasn_common.h @@ -55,6 +55,7 @@ struct pasn_data { int rsn_pairwise; u16 rsnxe_capab; const u8 *rsnxe_ie; + size_t rsnxe_ie_len; bool custom_pmkid_valid; u8 custom_pmkid[PMKID_LEN]; @@ -130,6 +131,8 @@ struct pasn_data { struct os_reltime last_comeback_key_update; u16 comeback_idx; u16 *comeback_pending_idx; + struct wpabuf *action_frame_wrapper; + struct wpabuf *frame; /** * send_mgmt - Function handler to transmit a Management frame @@ -151,6 +154,10 @@ struct pasn_data { */ int (*validate_custom_pmkid)(void *ctx, const u8 *addr, const u8 *pmkid); + + int (*update_extra_ies)(void *ctx, const u8 *peer_addr); + + int (*parse_encrypted_data)(void *ctx, const u8 *data, size_t len); }; /* Initiator */ diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c index dbcc91a..9d97895 100644 --- a/src/pasn/pasn_initiator.c +++ b/src/pasn/pasn_initiator.c @@ -646,7 +646,10 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn, if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) goto fail; - wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab); + if (pasn->rsnxe_ie) + wpabuf_put_data(buf, pasn->rsnxe_ie, pasn->rsnxe_ie_len); + else + wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab); wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len); @@ -675,11 +678,13 @@ fail: } -static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn) +static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn, + const u8 *mgmt, size_t len) { struct wpabuf *buf, *wrapped_data_buf = NULL; u8 mic[WPA_PASN_MAX_MIC_LEN]; - u8 mic_len, data_len; + u8 mic_len; + size_t data_len; const u8 *data; u8 *ptr; u8 wrapped_data; @@ -713,6 +718,11 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct pasn_data *pasn) wpabuf_free(wrapped_data_buf); wrapped_data_buf = NULL; + if (pasn->update_extra_ies && pasn->cb_ctx) + pasn->update_extra_ies(pasn->cb_ctx, pasn->peer_addr); + + wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len); + /* Add the MIC */ mic_len = pasn_mic_len(pasn->akmp, pasn->cipher); wpabuf_put_u8(buf, WLAN_EID_MIC); @@ -806,13 +816,25 @@ void wpa_pasn_reset(struct pasn_data *pasn) pasn->derive_kdk = false; pasn->rsn_ie = NULL; pasn->rsn_ie_len = 0; - pasn->rsnxe_ie = NULL; pasn->custom_pmkid_valid = false; + if (pasn->rsnxe_ie) { + os_free((u8 *)pasn->rsnxe_ie); + pasn->rsnxe_ie = NULL; + pasn->rsnxe_ie_len = 0; + } if (pasn->extra_ies) { os_free((u8 *) pasn->extra_ies); pasn->extra_ies = NULL; } + if (pasn->action_frame_wrapper) { + wpabuf_free(pasn->action_frame_wrapper); + pasn->action_frame_wrapper = NULL; + } + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } } @@ -982,17 +1004,21 @@ static int wpas_pasn_send_auth_1(struct pasn_data *pasn, const u8 *own_addr, wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame"); goto fail; } + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(frame), wpabuf_len(frame), 0, pasn->freq, 1000); - wpabuf_free(frame); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame"); + wpabuf_free(frame); goto fail; } - + pasn->frame = frame; return 0; fail: @@ -1382,21 +1408,29 @@ int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len, wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame"); - frame = wpas_pasn_build_auth_3(pasn); + if (pasn->parse_encrypted_data && pasn->cb_ctx) + pasn->parse_encrypted_data(pasn->cb_ctx, data, len); + + frame = wpas_pasn_build_auth_3(pasn, data, len); if (!frame) { wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame"); goto fail; } + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(frame), wpabuf_len(frame), 0, pasn->freq, 100); - wpabuf_free(frame); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame"); + wpabuf_free(frame); goto fail; } + pasn->frame = frame; wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK"); pasn->status = WLAN_STATUS_SUCCESS; diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c index c75ba87..e5216a0 100644 --- a/src/pasn/pasn_responder.c +++ b/src/pasn/pasn_responder.c @@ -473,7 +473,7 @@ static void handle_auth_pasn_comeback(struct pasn_data *pasn, "PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr)); ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), - wpabuf_len(buf), 0, 0, 0); + wpabuf_len(buf), 0, pasn->freq, 0); if (ret) wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); @@ -561,6 +561,9 @@ int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr, if (rsnxe_ie) wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]); + if (pasn->update_extra_ies && pasn->cb_ctx) + pasn->update_extra_ies(pasn->cb_ctx, peer_addr); + wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len); /* Add the mic */ @@ -636,14 +639,20 @@ done: wpa_printf(MSG_DEBUG, "PASN: Building frame 2: success; resp STA=" MACSTR, MAC2STR(peer_addr)); + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), - wpabuf_len(buf), 0, 0, 0); - if (ret) + wpabuf_len(buf), 0, pasn->freq, 0); + if (ret) { wpa_printf(MSG_INFO, "send_auth_reply: Send failed"); + goto fail; + } wpabuf_free(rsn_buf); - wpabuf_free(buf); + pasn->frame = buf; return ret; fail: wpabuf_free(wrapped_data_buf); @@ -1079,6 +1088,9 @@ int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr, wpabuf_free(wrapped_data); } + if (pasn->parse_encrypted_data && pasn->cb_ctx) + pasn->parse_encrypted_data(pasn->cb_ctx, (const u8 *) mgmt, len); + wpa_printf(MSG_INFO, "PASN: Success handling transaction == 3. Store PTK"); return 0; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 46e7cf1..1c7992e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -6093,6 +6093,37 @@ static void wpas_link_reconfig(struct wpa_supplicant *wpa_s) } +#ifdef CONFIG_PASN +int wpas_pasn_auth(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, size_t len, int freq) +{ + int ret = 0; + struct ieee802_11_elems elems; + + if (len < 24) { + wpa_printf(MSG_DEBUG, "nl80211: Too short management frame"); + return -2; + } + + if (ieee802_11_parse_elems(mgmt->u.auth.variable, + len - offsetof(struct ieee80211_mgmt, + u.auth.variable), + &elems, 1) == ParseFailed) { + wpa_printf(MSG_DEBUG, + "PASN: Failed parsing Authentication frame"); + return -2; + } + + if (!elems.p2p2_ie || !elems.p2p2_ie_len) + ret = wpas_pasn_auth_rx(wpa_s, mgmt, len); + else + ret = wpas_p2p_pasn_auth_rx(wpa_s, mgmt, len, freq); + + return ret; +} +#endif /* CONFIG_PASN */ + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -6323,11 +6354,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_WNM */ #ifdef CONFIG_PASN if (data->tx_status.type == WLAN_FC_TYPE_MGMT && - data->tx_status.stype == WLAN_FC_STYPE_AUTH && - wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data, - data->tx_status.data_len, - data->tx_status.ack) == 0) - break; + data->tx_status.stype == WLAN_FC_STYPE_AUTH) { + if (!wpa_s->pasn_auth_work && + wpa_s->p2p_pasn_auth_work) { + if (wpas_p2p_pasn_auth_tx_status(wpa_s, + data->tx_status.data, + data->tx_status.data_len, + data->tx_status.ack) == 0) + break; + } else { + if (wpas_pasn_auth_tx_status(wpa_s, + data->tx_status.data, + data->tx_status.data_len, + data->tx_status.ack) == 0) + break; + } + } #endif /* CONFIG_PASN */ #ifdef CONFIG_AP if (wpa_s->ap_iface == NULL) { @@ -6599,8 +6641,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #ifdef CONFIG_PASN if (stype == WLAN_FC_STYPE_AUTH && - wpas_pasn_auth_rx(wpa_s, mgmt, - data->rx_mgmt.frame_len) != -2) + wpas_pasn_auth(wpa_s, mgmt, data->rx_mgmt.frame_len, + data->rx_mgmt.freq) != -2) break; #endif /* CONFIG_PASN */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 6e7cf8f..0cffb99 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -40,6 +40,7 @@ #include "crypto/random.h" + /* * How many times to try to scan to find the GO before giving up on join * request. @@ -165,7 +166,10 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s, static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx); static int wpas_p2p_disallowed_freq(struct wpa_global *global, unsigned int freq); - +#ifdef CONFIG_PASN +static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int freq); +#endif /* CONFIG_PASN */ static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode) { @@ -1717,6 +1721,29 @@ static void wpas_send_action_done(void *ctx) offchannel_send_action_done(wpa_s); } +#ifdef CONFIG_PASN +struct wpa_p2p_pasn_auth_work { + u8 peer_addr[ETH_ALEN]; + bool verify; + int freq; +}; + + +static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork) +{ + os_free(awork); +} + + +static void wpas_p2p_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "P2P PASN: Cancel p2p-pasn-start-auth work"); + + /* Remove pending/started work */ + radio_remove_works(wpa_s, "p2p-pasn-start-auth", 0); +} +#endif /* CONFIG_PASN */ + static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *params) @@ -2392,6 +2419,12 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; +#ifdef CONFIG_PASN + if (wpa_s->p2p_pasn_auth_work) { + wpas_p2p_pasn_cancel_auth_work(wpa_s); + wpa_s->p2p_pasn_auth_work = NULL; + } +#endif /* CONFIG_PASN */ wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out"); wpas_p2p_group_formation_failed(wpa_s, 0); } @@ -2456,6 +2489,12 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = 0; } +#ifdef CONFIG_PASN + if (wpa_s->p2p_pasn_auth_work) { + wpas_p2p_pasn_cancel_auth_work(wpa_s); + wpa_s->p2p_pasn_auth_work = NULL; + } +#endif /* CONFIG_PASN */ if (res->status) { wpa_msg_global(wpa_s, MSG_INFO, @@ -4888,8 +4927,109 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status, if (status) return; +#ifdef CONFIG_PASN + wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq); +#endif /* CONFIG_PASN */ +} + +#ifdef CONFIG_PASN +static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpa_p2p_pasn_auth_work *awork = work->ctx; + struct p2p_data *p2p = wpa_s->global->p2p; + const u8 *peer_addr = NULL; + + if (deinit) { + if (!work->started) { + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->p2pdev, NULL); + } + os_free(awork); + return; + } + + if (!is_zero_ether_addr(awork->peer_addr)) + peer_addr = awork->peer_addr; + if (p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq)) { + wpa_printf(MSG_DEBUG, + "P2P PASN: Failed to start PASN authentication"); + goto fail; + } + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->p2pdev, NULL); + eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, + wpas_p2p_group_formation_timeout, + wpa_s->p2pdev, NULL); + wpa_s->p2p_pasn_auth_work = work; + return; +fail: + wpas_p2p_pasn_free_auth_work(awork); + work->ctx = NULL; + radio_work_done(work); } +static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int freq) +{ + struct wpa_p2p_pasn_auth_work *awork; + + wpas_p2p_pasn_cancel_auth_work(wpa_s); + wpa_s->p2p_pasn_auth_work = NULL; + + awork = os_zalloc(sizeof(*awork)); + if (!awork) + return -1; + + awork->freq = freq; + os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN); + + if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1, + wpas_p2p_pasn_auth_start_cb, awork) < 0) { + wpas_p2p_pasn_free_auth_work(awork); + return -1; + } + + wpa_printf(MSG_DEBUG, "P2P PASN: Auth work successfully added"); + return 0; +} + +static int wpas_p2p_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, + unsigned int wait) +{ + struct wpa_supplicant *wpa_s = ctx; + + return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait); +} + + +static int wpas_p2p_pasn_update_extra_ies(void *ctx, const u8 *peer_addr) +{ + struct wpa_supplicant *wpa_s = ctx; + struct p2p_data *p2p = wpa_s->global->p2p; + + return p2p_pasn_update_extra_ies(p2p, peer_addr); +} + + +static int wpas_p2p_pasn_parse_encrypted_data(void *ctx, const u8 *data, + size_t len) +{ + struct wpa_supplicant *wpa_s = ctx; + struct p2p_data *p2p = wpa_s->global->p2p; + + return p2p_pasn_parse_encrypted_data(p2p, data, len); +} + +int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, + size_t data_len, u8 acked) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + + return p2p_pasn_auth_tx_status(p2p, data, data_len, acked); +} +#endif int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) { @@ -5013,7 +5153,11 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; p2p.bootstrap_req_rx = wpas_bootstrap_req_rx; p2p.bootstrap_completed = wpas_bootstrap_completed; - +#ifdef CONFIG_PASN + p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mlme; + p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies; + p2p.pasn_parse_encrypted_data = wpas_p2p_pasn_parse_encrypted_data; +#endif /* CONFIG_PASN */ os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); p2p.dev_name = wpa_s->conf->device_name; @@ -10383,3 +10527,16 @@ void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf, return; p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq); } + +#ifdef CONFIG_PASN +int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, size_t len, + int freq) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + + if (wpa_s->global->p2p_disabled || !p2p) + return -2; + return p2p_pasn_auth_rx(p2p, mgmt, len, freq); +} +#endif /* CONFIG_PASN */ diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index a2cb78d..5612d83 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -227,7 +227,9 @@ int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq, int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s); int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s); struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s); - +int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, size_t len, + int freq); #else /* CONFIG_P2P */ static inline int @@ -358,6 +360,13 @@ static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s) return NULL; } +static inline int +wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, + const struct ieee80211_mgmt *mgmt, size_t len, int freq) +{ + return 0; +} + #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c index 89edad4..f4a3bb2 100644 --- a/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant/pasn_supplicant.c @@ -806,6 +806,11 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, if (!wpa_s->pasn_auth_work) return -2; + if (pasn->frame) { + wpabuf_free(pasn->frame); + pasn->frame = NULL; + } + pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL); ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data); if (ret == 0) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 35f541f..51da6ff 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1593,6 +1593,9 @@ struct wpa_supplicant { struct wpa_radio_work *pasn_auth_work; unsigned int pasn_count; struct pasn_auth *pasn_params; +#ifdef CONFIG_P2P + struct wpa_radio_work *p2p_pasn_auth_work; +#endif /* CONFIG_P2P */ #endif /* CONFIG_PASN */ bool is_6ghz_enabled; @@ -2028,5 +2031,7 @@ int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid, void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf, u16 buf_len, const u8 *peer_addr, unsigned int freq); +int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, + size_t data_len, u8 acked); #endif /* WPA_SUPPLICANT_I_H */ -- 2.7.4 From j at w1.fi Mon Aug 5 10:25:21 2024 From: j at w1.fi (Jouni Malinen) Date: Mon, 5 Aug 2024 20:25:21 +0300 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: <20240801165143.3212598-3-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-3-quic_adisi@quicinc.com> Message-ID: On Thu, Aug 01, 2024 at 10:21:39PM +0530, Aditya Kumar Singh wrote: > With MLO, each link have socket created with "_link" under > the control interface directory. > > Introduce a MLD level socket - "" as well under the same control > interface directory. This socket can be used to pass the command to its > partner links directly instead of using the link level socket. Link ID > needs to be passed with the command. > > The structure of the command is - > " LINKID " That feels quite problematic since "LINKID" could occur in a valid command, e.g., when setting a string parameter. This "LINKID " part would likely need to be a prefix instead of postfix for the command to make this more robust. > diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c > +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, > + /* Check if link id is provided in the command or not */ > + link_cmd = os_strstr(buf, "LINKID"); > + if (link_cmd) { > + /* Trim the link id part now */ > + *(link_cmd - 1) = '\0'; That needs bounds checking.. The received command could start with "LINKID" and that -1 would make this write before the start of the buffer. Though, my comment above will likely make this not applicable, but anyway, all commands received from the control interface needs to be fully verified to be valid to avoid security issues. > + } else if (os_strcmp(buf, "ATTACH") == 0) { > + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, NULL)) > + reply_len = -1; > + } else if (os_strncmp(buf, "ATTACH ", 7) == 0) { > + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, buf + 7)) > + reply_len = -1; > + } else if (os_strcmp(buf, "DETACH") == 0) { > + if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) > + reply_len = -1; Is there a plan to use those hostapd_mld_ctrl_iface_{attach,detach}() functions for something else than for wrapping a call to ctrl_iface_{attach,detach}()? I would simply call the existing functions directly instead of going through that minimal wrapper function. > +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, > + os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); > + buf[len - 1] = '\0'; Instead of hardcoding \0 termination, it would be better to explicitly check the os_snprintf() return value with os_snprintf_error() to catch all truncation cases. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Mon Aug 5 10:31:46 2024 From: j at w1.fi (Jouni Malinen) Date: Mon, 5 Aug 2024 20:31:46 +0300 Subject: [PATCH v3 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240801165143.3212598-2-quic_adisi@quicinc.com> References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-2-quic_adisi@quicinc.com> Message-ID: On Thu, Aug 01, 2024 at 10:21:38PM +0530, Aditya Kumar Singh wrote: > diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c > @@ -54,7 +54,11 @@ static void usage(void) > +#ifdef CONFIG_IEEE80211BE > + "usage: hostapd_cli [-p] [-i] [-l] [-hvBr] " > +#else > "usage: hostapd_cli [-p] [-i] [-hvBr] " > +#endif /* CONFIG_IEEE80211BE */ Please avoid duplicated versions by splitting that into "usage: hostapd_cli [-p] [-i] " #ifdef CONFIG_IEEE80211BE "[-l] " #endif /* CONFIG_IEEE80211BE */ "[-hvBr] " > +#ifdef CONFIG_IEEE80211BE > + " -l Link ID of the interface in case of Multi-Link\n" > + " Operation\n" That "Operation" fits fine into the end of the previous printed line.. > @@ -2205,19 +2214,26 @@ static void hostapd_cli_action(struct wpa_ctrl *ctrl) > eloop_unregister_read_sock(fd); > } > > - > int main(int argc, char *argv[]) Please no unrelated whitespace cleanup (especially when it is actually incorrect for the coding style used in hostap.git). > +#ifdef CONFIG_IEEE80211BE > + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); > +#else > c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); > +#endif /* CONFIG_IEEE80211BE */ Please avoid duplicated things. I would go with that CONFIG_IEEE80211BE case for both since the default case in the switch will handle that fine as-is. > @@ -2252,6 +2268,16 @@ int main(int argc, char *argv[]) > +#ifdef CONFIG_IEEE80211BE > + case 'l': > + link_id = atoi(optarg); > + os_memset(buf, '\0', sizeof(buf)); > + os_snprintf(buf, sizeof(buf), "%s_%s%d", > + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, link_id); No os_memset() is needed before os_snprintf(), but use of os_snprintf_error() would be recommended. > diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c > +static void hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) > +{ > +#ifdef CONFIG_IEEE80211BE > + os_memset(hapd->ctrl_sock_iface, '\0', > + sizeof(hapd->ctrl_sock_iface)); > + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, > + sizeof(hapd->ctrl_sock_iface)); No os_memset() before os_strlcpy().. > + if (hapd->conf->mld_ap) { > + char buf[128]; > + > + os_memset(buf, '\0', sizeof(buf)); > + os_snprintf(buf, sizeof(buf), "%s_%s%d", > + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, > + hapd->mld_link_id); > + os_memset(hapd->ctrl_sock_iface, '\0', > + sizeof(hapd->ctrl_sock_iface)); > + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); No os_memset() before os_snprintf()/os_strlcpy(). That last sizeof(buf) is very wrong for the os_strlcpy().. It is supposed to be the size of the target buffer. This could result in buffer overflow.. Why is that buf[] stack buffer used here? Couldn't this simply os_snprintf() to hapd->ctrl_sock_iface? Instead of first writing the non-mld_ap value into hapd->ctrl_sock_iface and then overwriting it, this would be cleaner by having if-else.. > diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h > @@ -476,6 +476,7 @@ struct hostapd_data { > struct hostapd_mld *mld; > struct dl_list link; > u8 mld_link_id; > + char ctrl_sock_iface[IFNAMSIZ + 1]; Is that large enough to include the "_link" + ID part? -- Jouni Malinen PGP id EFC895FA From j at w1.fi Mon Aug 5 10:45:33 2024 From: j at w1.fi (Jouni Malinen) Date: Mon, 5 Aug 2024 20:45:33 +0300 Subject: [PATCH v2 0/2] MLO related fixes for scan/ACS In-Reply-To: <20240621053439.379657-1-quic_adisi@quicinc.com> References: <20240621053439.379657-1-quic_adisi@quicinc.com> Message-ID: On Fri, Jun 21, 2024 at 11:04:37AM +0530, Aditya Kumar Singh wrote: > Do some fixes in scan handling with MLO. > > Aditya Kumar Singh (2): > nl80211: fix scan request and its related events handling with MLO > nl80211: fix simultaneous scanning failure in case of MLO For some reason, this was set to the "superseded" state in patchwork, but I think that was an error since I could not find any sign of an update on this v2. In any case, I did apply these now with some cleanup. -- Jouni Malinen PGP id EFC895FA From quic_adisi at quicinc.com Mon Aug 5 21:37:40 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 6 Aug 2024 10:07:40 +0530 Subject: [PATCH v3 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-2-quic_adisi@quicinc.com> Message-ID: <27cde08f-9032-428a-ae58-a5b4f2f202bc@quicinc.com> On 8/5/24 23:01, Jouni Malinen wrote: > On Thu, Aug 01, 2024 at 10:21:38PM +0530, Aditya Kumar Singh wrote: > >> diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c >> @@ -54,7 +54,11 @@ static void usage(void) >> +#ifdef CONFIG_IEEE80211BE >> + "usage: hostapd_cli [-p] [-i] [-l] [-hvBr] " >> +#else >> "usage: hostapd_cli [-p] [-i] [-hvBr] " >> +#endif /* CONFIG_IEEE80211BE */ > > Please avoid duplicated versions by splitting that into > > "usage: hostapd_cli [-p] [-i] " > #ifdef CONFIG_IEEE80211BE > "[-l] " > #endif /* CONFIG_IEEE80211BE */ > "[-hvBr] " > Sure will do. > >> +#ifdef CONFIG_IEEE80211BE >> + " -l Link ID of the interface in case of Multi-Link\n" >> + " Operation\n" > > That "Operation" fits fine into the end of the previous printed line.. Okay. > >> @@ -2205,19 +2214,26 @@ static void hostapd_cli_action(struct wpa_ctrl *ctrl) >> eloop_unregister_read_sock(fd); >> } >> >> - >> int main(int argc, char *argv[]) > > Please no unrelated whitespace cleanup (especially when it is actually > incorrect for the coding style used in hostap.git). Got it. This came accidentally. Thanks for pointing it out. > >> +#ifdef CONFIG_IEEE80211BE >> + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); >> +#else >> c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); >> +#endif /* CONFIG_IEEE80211BE */ > > Please avoid duplicated things. I would go with that CONFIG_IEEE80211BE > case for both since the default case in the switch will handle that fine > as-is. > Sure, got it. >> @@ -2252,6 +2268,16 @@ int main(int argc, char *argv[]) >> +#ifdef CONFIG_IEEE80211BE >> + case 'l': >> + link_id = atoi(optarg); >> + os_memset(buf, '\0', sizeof(buf)); >> + os_snprintf(buf, sizeof(buf), "%s_%s%d", >> + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, link_id); > > No os_memset() is needed before os_snprintf(), but use of > os_snprintf_error() would be recommended. Okay. > >> diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c >> +static void hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) >> +{ >> +#ifdef CONFIG_IEEE80211BE >> + os_memset(hapd->ctrl_sock_iface, '\0', >> + sizeof(hapd->ctrl_sock_iface)); >> + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, >> + sizeof(hapd->ctrl_sock_iface)); > > No os_memset() before os_strlcpy().. Got it. > >> + if (hapd->conf->mld_ap) { >> + char buf[128]; >> + >> + os_memset(buf, '\0', sizeof(buf)); >> + os_snprintf(buf, sizeof(buf), "%s_%s%d", >> + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, >> + hapd->mld_link_id); >> + os_memset(hapd->ctrl_sock_iface, '\0', >> + sizeof(hapd->ctrl_sock_iface)); >> + os_strlcpy(hapd->ctrl_sock_iface, buf, sizeof(buf)); > > No os_memset() before os_snprintf()/os_strlcpy(). > > That last sizeof(buf) is very wrong for the os_strlcpy().. It is > supposed to be the size of the target buffer. This could result in > buffer overflow.. > > Why is that buf[] stack buffer used here? Couldn't this simply > os_snprintf() to hapd->ctrl_sock_iface? > > Instead of first writing the non-mld_ap value into hapd->ctrl_sock_iface > and then overwriting it, this would be cleaner by having if-else.. Sure will move to to if-else. Thanks for the suggestion. > >> diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h >> @@ -476,6 +476,7 @@ struct hostapd_data { >> struct hostapd_mld *mld; >> struct dl_list link; >> u8 mld_link_id; >> + char ctrl_sock_iface[IFNAMSIZ + 1]; > > Is that large enough to include the "_link" + ID part? Oops! Nope, typically tested with interface names not going beyond 6-7 chars. But ideally this should be be "IFNAMSIZ + 7+ 1". Thanks for pointing this out. Thanks for your review Jouni. I will address these and send next version for review. -- Aditya From quic_adisi at quicinc.com Mon Aug 5 22:28:05 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 6 Aug 2024 10:58:05 +0530 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-3-quic_adisi@quicinc.com> Message-ID: <0f510593-2f11-4185-b68d-6ab300844e78@quicinc.com> On 8/5/24 22:55, Jouni Malinen wrote: > On Thu, Aug 01, 2024 at 10:21:39PM +0530, Aditya Kumar Singh wrote: >> With MLO, each link have socket created with "_link" under >> the control interface directory. >> >> Introduce a MLD level socket - "" as well under the same control >> interface directory. This socket can be used to pass the command to its >> partner links directly instead of using the link level socket. Link ID >> needs to be passed with the command. >> >> The structure of the command is - >> " LINKID " > > That feels quite problematic since "LINKID" could occur in a valid > command, e.g., when setting a string parameter. This "LINKID " > part would likely need to be a prefix instead of postfix for the command > to make this more robust. > Sure will move to prefix. Thanks for the suggestion. >> diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c > >> +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, > >> + /* Check if link id is provided in the command or not */ >> + link_cmd = os_strstr(buf, "LINKID"); >> + if (link_cmd) { >> + /* Trim the link id part now */ >> + *(link_cmd - 1) = '\0'; > > That needs bounds checking.. The received command could start with > "LINKID" and that -1 would make this write before the start of the > buffer. Though, my comment above will likely make this not applicable, > but anyway, all commands received from the control interface needs to be > fully verified to be valid to avoid security issues. Sure got it. > >> + } else if (os_strcmp(buf, "ATTACH") == 0) { >> + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, NULL)) >> + reply_len = -1; >> + } else if (os_strncmp(buf, "ATTACH ", 7) == 0) { >> + if (hostapd_mld_ctrl_iface_attach(mld, from, fromlen, buf + 7)) >> + reply_len = -1; >> + } else if (os_strcmp(buf, "DETACH") == 0) { >> + if (hostapd_mld_ctrl_iface_detach(mld, from, fromlen)) >> + reply_len = -1; > > Is there a plan to use those hostapd_mld_ctrl_iface_{attach,detach}() > functions for something else than for wrapping a call to > ctrl_iface_{attach,detach}()? I would simply call the existing functions > directly instead of going through that minimal wrapper function. > I don't have any plans as of now. Sure, I will directly call the functions instead of the wrapper. >> +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, > >> + os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); >> + buf[len - 1] = '\0'; > > Instead of hardcoding \0 termination, it would be better to explicitly > check the os_snprintf() return value with os_snprintf_error() to catch > all truncation cases. Sure will do. -- Aditya From quic_adisi at quicinc.com Mon Aug 5 23:17:27 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 6 Aug 2024 11:47:27 +0530 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-3-quic_adisi@quicinc.com> Message-ID: On 8/5/24 22:55, Jouni Malinen wrote: > Is there a plan to use those hostapd_mld_ctrl_iface_{attach,detach}() > functions for something else than for wrapping a call to > ctrl_iface_{attach,detach}()? I would simply call the existing functions > directly instead of going through that minimal wrapper function. Now that I see, this was done in order to have similar naming link for non-AP MLD. Please see hostapd_ctrl_iface_attach(). So similarly, for MLD as well the wrapper is introduced. Do you still want to remove the wrapper? -- Aditya From mhs at emlogic.no Tue Aug 6 01:31:37 2024 From: mhs at emlogic.no (Morten Hauke Solvang) Date: Tue, 6 Aug 2024 08:31:37 +0000 Subject: wpa_supplicant can generate configs which it can't read back Message-ID: Hi, I believe this commit introduces a bug: https://w1.fi/cgit/hostap/commit/src/utils/config.c?id=aca4d4963a65e49614ed8cd52836a2619775c1f6 Take for example this password: secret"#123 If you configure this password using wpa_cli, and save to a config file: wpa_cli set_network 0 psk '"secret"#123"' wpa_cli save_config It generates a config file which looks something like this: network={ psk="secret"#123" } When restarting supplicant (or doing wpa_cli reconfigure), supplicant fails to read this config back, because wpa_config_get_line uses strchr in a loop to find pairs of quotes, and checks if the # is inside a pair of quotes: end of string | v psk="secret"#123" ^ ^^^^^ | comment start of string But this doesn't match the way quotes are interpreted by the rest of the parser! If we look at wpa_config_parse_str which calls wpa_config_parse_string, it strips the leftmost and rightmost quote (using strrchr). end of string | v psk="secret"#123" ^ | start of string (Of course, wpa_config_parse_string never gets to see anything past the #, since wpa_config_get_line already has discarded that part of the string, since it thought it was a comment). I'd suggest reverting the commit mentioned above. Alternatively, if the config format needs to support comments containing quotes, the config format maybe needs to be changed to escape quotes inside quotes (instead of using strrchr)? Best regards, Morten Solvang From jintaolin at chromium.org Wed Aug 7 14:48:01 2024 From: jintaolin at chromium.org (Jintao Lin) Date: Wed, 7 Aug 2024 21:48:01 +0000 Subject: [PATCH] p2p: consult driver capabilities before setting HE bit in GO's conf Message-ID: <20240807214801.2030506-1-jintaolin@chromium.org> p2p_go_he could be set to 1 in the global config file while the device might only has a VHT WiFi nic. Consult driver capabilities before setting the HE bit for the GO's conf so that latter AP configuration does not fail due to wrong AP configuration, like hostapd_get_oper_centr_freq_seg0_idx. This config bit is checked and set in wpa_supplicant_conf_ap_ht. Thus there is no need to override this bit specifically for GO. Signed-off-by: Jintao Lin --- wpa_supplicant/ap.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 69a0e5ee1..729277907 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -540,12 +540,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, conf->supported_rates = list; } -#ifdef CONFIG_IEEE80211AX - if (ssid->mode == WPAS_MODE_P2P_GO || - ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) - conf->ieee80211ax = ssid->he; -#endif /* CONFIG_IEEE80211AX */ - bss->isolate = !wpa_s->conf->p2p_intra_bss; bss->extended_key_id = wpa_s->conf->extended_key_id; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; -- 2.46.0.rc2.264.g509ed76dc8-goog From benjamin at sipsolutions.net Mon Aug 5 10:41:14 2024 From: benjamin at sipsolutions.net (Benjamin Berg) Date: Mon, 05 Aug 2024 19:41:14 +0200 Subject: [PATCH 08/16] WNM: Move driver MBO transition rejection into wnm_is_bss_excluded In-Reply-To: References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-9-benjamin@sipsolutions.net> Message-ID: Hi, looks like I initially only replied in private by accident. On Fri, 2024-08-02 at 13:30 +0300, Jouni Malinen wrote: > On Mon, Apr 29, 2024 at 01:51:49PM +0200, benjamin at sipsolutions.net?wrote: > > Change the logic a bit to not directly use the result of the > > wpa_drv_get_bss_trans_status call and instead use the same selection > > logic as usual but taking into account the driver rejections. > > > > This changes the logic in minor ways. The main change is that this > > aligns the ordering of BSSs to be identical in all cases. More > > precisely, we'll select the best BSS as found by find_better_target. > > > > Beyond that, it also means that in the case of an non-abridged BTM > > request we'll also consider candidates that were found through the scan > > and not in the neighbor report. In this case, the driver will not have a > > chance to reject them. > > This feels a bit scary especially if the updated design has not actually > been tested with a driver that uses the driver-based mechanism for > updating candidate lists (which I'm assuming has not been done here). Yes, it is a bit scary. Honestly, I am not able to test the code. Maybe I missed it, but I didn't even find a driver that provides the nl80211 API. > And there is something strange here: > > > diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c > > ?#ifdef CONFIG_MBO > > -static struct wpa_bss * > > -get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, > > +static void > > +fetch_drv_mbo_candidate_info(struct wpa_supplicant *wpa_s, > > ? ???? enum mbo_transition_reject_reason *reason) > > ?{ > > > + if (nei->preference_present && nei->preference == 0) > > ? continue; > > + > > + /* FIXME: Should we go through wpa_scan_res_match? */ > > Well, that is not the strange part, but again, something that makes me > unhappy about applying this without full testing. > > > +#else > > +static void > > +fetch_drv_mbo_transition_candidate_info(struct wpa_supplicant *wpa_s) > > +{ > > ?} > > ?#endif /* CONFIG_MBO */ > > That is the strange part.. What was that supposed to be? That same > function with empty payload? Now the function name is different and so > is the list of arguments. This would obviously not work without > CONFIG_MBO defined. Oops, yep, looks like I messed up the function rename and such. > If this is just to skip the functionality within the function, defining > the function once with the actually body within #ifdef CONFIG_MBO would > be much cleaner. Sure, that makes sense! Benjamin From benjamin at sipsolutions.net Mon Aug 5 10:41:14 2024 From: benjamin at sipsolutions.net (Benjamin Berg) Date: Mon, 05 Aug 2024 19:41:14 +0200 Subject: [PATCH 08/16] WNM: Move driver MBO transition rejection into wnm_is_bss_excluded In-Reply-To: References: <20240429115157.211073-1-benjamin@sipsolutions.net> <20240429115157.211073-9-benjamin@sipsolutions.net> Message-ID: Hi, looks like I initially only replied in private by accident. On Fri, 2024-08-02 at 13:30 +0300, Jouni Malinen wrote: > On Mon, Apr 29, 2024 at 01:51:49PM +0200, benjamin at sipsolutions.net?wrote: > > Change the logic a bit to not directly use the result of the > > wpa_drv_get_bss_trans_status call and instead use the same selection > > logic as usual but taking into account the driver rejections. > > > > This changes the logic in minor ways. The main change is that this > > aligns the ordering of BSSs to be identical in all cases. More > > precisely, we'll select the best BSS as found by find_better_target. > > > > Beyond that, it also means that in the case of an non-abridged BTM > > request we'll also consider candidates that were found through the scan > > and not in the neighbor report. In this case, the driver will not have a > > chance to reject them. > > This feels a bit scary especially if the updated design has not actually > been tested with a driver that uses the driver-based mechanism for > updating candidate lists (which I'm assuming has not been done here). Yes, it is a bit scary. Honestly, I am not able to test the code. Maybe I missed it, but I didn't even find a driver that provides the nl80211 API. > And there is something strange here: > > > diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c > > ?#ifdef CONFIG_MBO > > -static struct wpa_bss * > > -get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, > > +static void > > +fetch_drv_mbo_candidate_info(struct wpa_supplicant *wpa_s, > > ? ???? enum mbo_transition_reject_reason *reason) > > ?{ > > > + if (nei->preference_present && nei->preference == 0) > > ? continue; > > + > > + /* FIXME: Should we go through wpa_scan_res_match? */ > > Well, that is not the strange part, but again, something that makes me > unhappy about applying this without full testing. > > > +#else > > +static void > > +fetch_drv_mbo_transition_candidate_info(struct wpa_supplicant *wpa_s) > > +{ > > ?} > > ?#endif /* CONFIG_MBO */ > > That is the strange part.. What was that supposed to be? That same > function with empty payload? Now the function name is different and so > is the list of arguments. This would obviously not work without > CONFIG_MBO defined. Oops, yep, looks like I messed up the function rename and such. > If this is just to skip the functionality within the function, defining > the function once with the actually body within #ifdef CONFIG_MBO would > be much cleaner. Sure, that makes sense! Benjamin From jintaolin at chromium.org Fri Aug 9 11:10:34 2024 From: jintaolin at chromium.org (Jintao Lin) Date: Fri, 9 Aug 2024 18:10:34 +0000 Subject: [PATCH] nl80211: nullptr check for link before use Message-ID: <20240809181034.1539857-1-jintaolin@chromium.org> bss->flink could be nullptr when wpa_driver_nl80211_del_beacon is called if wpa_driver_nl80211_drv_init fails early and jump to wpa_driver_nl80211_deinit with bss->flink unset. Signed-off-by: Jintao Lin --- src/drivers/driver_nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 12fe4d12d..5deca7bc2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -3071,7 +3071,7 @@ static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss, struct wpa_driver_nl80211_data *drv = bss->drv; struct i802_link *link = nl80211_get_link(bss, link_id); - if (!link->beacon_set) + if (!link || !link->beacon_set) return 0; wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)", -- 2.46.0.76.ge559c4bf1a-goog From j at w1.fi Sat Aug 10 00:37:41 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 10 Aug 2024 10:37:41 +0300 Subject: [PATCH] eap: fix the duplicated registration of eap server In-Reply-To: References: Message-ID: On Mon, Aug 05, 2024 at 03:16:08AM +0000, Maochen Wang wrote: > Fix the duplicated registration of eap server method, as on Zephyr OS, > hostapd and supplicant are running in same task, when hostapd enabled, > eap_server_register_methods() will also call the eap server related > functions, which leads to the duplicated registration of eap server > method. So this is somehow building both hostapd/*.c and wpa_supplicant/*.c code into a single binary? I'd expect that to fail due to conflicting symbols, so this needs some other changes as well and those do not exist in hostap.git.. > diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c > +#ifndef HOSTAPD > #ifdef EAP_SERVER_IDENTITY That feels strange from hostap.git view point. There is nothing there that would result in HOSTAPD being defined when compiling wpa_supplicant/*.c. If this is needed for some custom builds that have modified the way the process is initiated using changes that do not exist in hostap.git, it would seem cleaner to keep this change in those out-of-hostap.git changes as well. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 10 00:49:10 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 10 Aug 2024 10:49:10 +0300 Subject: [PATCH] hostapd: Rename event handling functions in hostapd for In-Reply-To: References: Message-ID: On Thu, Jun 13, 2024 at 06:32:01AM +0000, Hui Bai wrote: > On Zephyr, both wpa_supplicant and hostapd are supported. One compilation error was found due to function name conflict. > Both wpa_supplicant and hostapd has its own global event and event handlers with same name: > wpa_supplicant_event > wpa_supplicant_event_global > > To fix the compilation error, rename above functions in hostapd for Zephyr as below: > hostapd_event > hostapd_event_global This does not look like something that would really work at all in hostap.git, i.e., this is based on something that has other changes and as such, I'm not sure why this particular change should be in hostap.git. Those functions have the same name for a reason, i.e., those are the functions that are called from the driver interface code for either hostapd or wpa_supplicant. If there is need to make this work with both hostapd and wpa_supplicant somehow linked into a single binary, the driver wrappers would need changes. For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and wpa_supplicant_event_global as function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 10 00:58:55 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 10 Aug 2024 10:58:55 +0300 Subject: [PATCH 1/1] hostapd: Avoid EAPOL trigger in reassoc path for AP, in case of 4way HS offload In-Reply-To: References: Message-ID: On Fri, May 24, 2024 at 12:00:27PM +0530, Vinayak Yadawad wrote: > Currently avoiding of EAPOL exchange for AP with 4way HS offload is > handled only in new STA assoc path. Current change avoids complete > authentication trigger in case of AP reassoc path as well. Do you really mean association path and reassociation path here? The current implementation in hostapd_new_assoc_sta() should be used both when processing an Association Request frame and when processing a Reassociation Request frame. > diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c > @@ -2708,8 +2717,20 @@ SM_STATE(WPA_PTK, PTKSTART) > SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); > + > + wpa_auth_get_drv_flags(sm->wpa_auth, &drv_flags, &drv_flags2); > + ap_4way_hs_offload = !!(drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK); > + if (ap_4way_hs_offload) { > + /* 4way HS offloaded to driver no need of EAPOL */ > + wpa_printf(MSG_INFO, "Avoid EAPOL in case of 4way HS offload"); > + return; > + } This on the other hand would address other reasons to start 4-way handshake than association or reassociation. For example, rekeying of the PTK would be such a case. This might be a reasonable thing to do, but that commit message makes the intent of this change quite unclear. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 10 01:13:45 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 10 Aug 2024 11:13:45 +0300 Subject: [PATCH] nl80211: nullptr check for link before use In-Reply-To: <20240809181034.1539857-1-jintaolin@chromium.org> References: <20240809181034.1539857-1-jintaolin@chromium.org> Message-ID: On Fri, Aug 09, 2024 at 06:10:34PM +0000, Jintao Lin wrote: > bss->flink could be nullptr when wpa_driver_nl80211_del_beacon is called > if wpa_driver_nl80211_drv_init fails early and jump to > wpa_driver_nl80211_deinit with bss->flink unset. Thanks, applied. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Sat Aug 10 01:30:36 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 10 Aug 2024 11:30:36 +0300 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> Message-ID: On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: > wpa_supplicant 2.11 on Linux's 6.9.y / 6.10.y brcmfmac driver runs in > authentication timeouts with WPA2-PSK and WPA3-SAE. This was reported > with Apple silicon devices using Fedora Asahi remix with a patched > driver as well as other devices without additional brcmfmac patches. See > https://bugzilla.redhat.com/show_bug.cgi?id=2302577 for some reports. > > I've bisected this to > https://w1.fi/cgit/hostap/commit/?id=41638606054a09867fe3f9a2b5523aa4678cbfa5 > "Mark authorization completed on driver indication during 4-way HS > offload". Reverting this commit on top of hostap_2_11 properly > authenticates the connections. Looking at that change and the code it > looks clearly broken to to me. As far as I can see is > `assoc_info.authorized` for the nl80211 driver only set when > QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED is set (in main, I did not > check older revisions). This doesn't seem appropriate to expect this on > chipsets from different vendors. This commit is from Broadcom to fix some race conditions with the 4-way handshake offload which I'm assuming is for a Broadcom driver.. Whether that is for brcmfmac is unknown to me, though. It looks like the goal here was to move completion of the connection from the association event to EVENT_PORT_AUTHORIZED, i.e., the NL80211_CMD_PORT_AUTHORIZED event from the driver. Is that event not delivered by brcmfmac? I did not see any full wpa_supplicant debug logs for these issues based on a quick look, so I could not check that myself. > A revert looks to me like a possible/proper fix. I can send that later > if no alternative materializes. I'm inclined to revert this if it is indeed the case that NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the upstream driver and this commit was tested only with some non-upstream versions. -- Jouni Malinen PGP id EFC895FA From j at jannau.net Sat Aug 10 02:17:33 2024 From: j at jannau.net (Janne Grunau) Date: Sat, 10 Aug 2024 11:17:33 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> Message-ID: Hej, On Sat, Aug 10, 2024, at 10:30, Jouni Malinen wrote: > On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: >> wpa_supplicant 2.11 on Linux's 6.9.y / 6.10.y brcmfmac driver runs in >> authentication timeouts with WPA2-PSK and WPA3-SAE. This was reported >> with Apple silicon devices using Fedora Asahi remix with a patched >> driver as well as other devices without additional brcmfmac patches. >> See https://bugzilla.redhat.com/show_bug.cgi?id=2302577 for some >> reports. >> >> I've bisected this to >> https://w1.fi/cgit/hostap/commit/?id=41638606054a09867fe3f9a2b5523aa4678cbfa5 >> "Mark authorization completed on driver indication during 4-way HS >> offload". Reverting this commit on top of hostap_2_11 properly >> authenticates the connections. Looking at that change and the code it >> looks clearly broken to to me. As far as I can see is >> `assoc_info.authorized` for the nl80211 driver only set when >> QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED is set (in main, I did not >> check older revisions). This doesn't seem appropriate to expect this >> on chipsets from different vendors. > > This commit is from Broadcom to fix some race conditions with the 4- > way handshake offload which I'm assuming is for a Broadcom driver.. > Whether that is for brcmfmac is unknown to me, though. > > It looks like the goal here was to move completion of the connection > from the association event to EVENT_PORT_AUTHORIZED, i.e., the > NL80211_CMD_PORT_AUTHORIZED event from the driver. Is that event not > delivered by brcmfmac? I did not see any full wpa_supplicant debug > logs for these issues based on a quick look, so I could not check > that myself. The following place in brcmf_bss_roaming_done() is the only place where NL80211_CMD_PORT_AUTHORIZED event is posted. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c#n6402 In my initial analysis I missed that the NL80211_CMD_PORT_AUTHORIZED is delivered directly to wpa_supplicant. >> A revert looks to me like a possible/proper fix. I can send that >> later if no alternative materializes. > > I'm inclined to revert this if it is indeed the case that > NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the upstream > driver and this commit was tested only with some non-upstream > versions. I intend extend the upstream kernel driver to post NL80211_CMD_PORT_AUTHORIZED after successful connection with authentication offload. I expect that the change will be accepted for the stable kernel. Infineon/Cypress have non-upstream patches for the brcmfmac driver which implement it already. A revert in wpa_supplicant might be still appropriate until exteded kernel drivers are deployed. The wpa_supplicant Fedora package carries the revert as patch: https://src.fedoraproject.org/rpms/wpa_supplicant/c/c2eac195adadd2c48b04f8752cc46b12a351e69c thanks, Janne From taavieomae at gmail.com Sat Aug 10 02:50:25 2024 From: taavieomae at gmail.com (=?UTF-8?Q?Taavi_Eom=C3=A4e?=) Date: Sat, 10 Aug 2024 12:50:25 +0300 Subject: [PATCH] Scan other networks first to unlock 5GHz bands on Intel cards In-Reply-To: References: <5TLtkCSwaUx-RqmmGmjkvZYDuOoygMMyJo5CGL76zpDSc4DrPeUsskBfK_dfts8Uxl5Rk4BqrZD1L6uQKsSJWPSlNj__T7dHdz7zzVPo_J8=@protonmail.com> Message-ID: <0a918425-c030-471c-9335-e3d0bfa4a903@gmail.com> Hi, Not the?submitter of the patch, but I think this is needed because of Intel's Location Aware Regulatory (LAR). If a scan is not done beforehand, all 5GHz channels are marked as NO-IR. This is incredibly inconvenient, but indeed a quirk with Intel cards. There's also an open Bugzilla ticket about it: https://bugzilla.kernel.org/show_bug.cgi?id=206469 It also has the nasty side-effect of making 6GHz APs practically impossible to start. On 03/08/2024 11:55, Jouni Malinen wrote: > On Wed, Jul 17, 2024 at 07:56:04PM +0000, Pedro Goncalves (developer account) wrote: >> Subject: [PATCH] For intel Wi-Fi cards, force to scan other wireless networks so the drive is able to set the correct region - master >> >> Signed-off-by: Pedro Goncalves > This would need much more detailed commit message to justify why this is > needed and why this is appropriate behavior. How is this specific to > Intel cards? Why would an AP be allowed to operate on the 5 GHz band > based on just a single scan if it was not allowed to do so without that > scan? > >> Index: src/ap/hostapd.h >> IDEA additional info: >> Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP >> <+>UTF-8 >> =================================================================== >> diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h > And this format is pretty strange and requires manual operations to > apply with 'git am'. > From arend.vanspriel at broadcom.com Sat Aug 10 03:43:43 2024 From: arend.vanspriel at broadcom.com (Arend Van Spriel) Date: Sat, 10 Aug 2024 12:43:43 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> Message-ID: <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> On August 10, 2024 11:17:56 AM "Janne Grunau" wrote: > Hej, > > On Sat, Aug 10, 2024, at 10:30, Jouni Malinen wrote: >> On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: >>> wpa_supplicant 2.11 on Linux's 6.9.y / 6.10.y brcmfmac driver runs in >>> authentication timeouts with WPA2-PSK and WPA3-SAE. This was reported >>> with Apple silicon devices using Fedora Asahi remix with a patched >>> driver as well as other devices without additional brcmfmac patches. >>> See https://bugzilla.redhat.com/show_bug.cgi?id=2302577 for some >>> reports. >>> >>> I've bisected this to >>> https://w1.fi/cgit/hostap/commit/?id=41638606054a09867fe3f9a2b5523aa4678cbfa5 >>> "Mark authorization completed on driver indication during 4-way HS >>> offload". Reverting this commit on top of hostap_2_11 properly >>> authenticates the connections. Looking at that change and the code it >>> looks clearly broken to to me. As far as I can see is >>> `assoc_info.authorized` for the nl80211 driver only set when >>> QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED is set (in main, I did not >>> check older revisions). This doesn't seem appropriate to expect this >>> on chipsets from different vendors. >> >> This commit is from Broadcom to fix some race conditions with the 4- >> way handshake offload which I'm assuming is for a Broadcom driver.. >> Whether that is for brcmfmac is unknown to me, though. >> >> It looks like the goal here was to move completion of the connection >> from the association event to EVENT_PORT_AUTHORIZED, i.e., the >> NL80211_CMD_PORT_AUTHORIZED event from the driver. Is that event not >> delivered by brcmfmac? I did not see any full wpa_supplicant debug >> logs for these issues based on a quick look, so I could not check >> that myself. I was surprised to see this was coming from Broadcom. I did not yet contact the author for more details. >> > > The following place in brcmf_bss_roaming_done() is the only place where > NL80211_CMD_PORT_AUTHORIZED event is posted. > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c#n6402 Right. This seems to be added exclusively for Fast BSS transition scenario. > > In my initial analysis I missed that the NL80211_CMD_PORT_AUTHORIZED is > delivered directly to wpa_supplicant. > >>> A revert looks to me like a possible/proper fix. I can send that >>> later if no alternative materializes. >> >> I'm inclined to revert this if it is indeed the case that >> NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the upstream >> driver and this commit was tested only with some non-upstream >> versions. > > I intend extend the upstream kernel driver to post > NL80211_CMD_PORT_AUTHORIZED after successful connection with > authentication offload. I expect that the change will be accepted for > the stable kernel. Infineon/Cypress have non-upstream patches for the > brcmfmac driver which implement it already. Do you have a reference to see what they have done? > A revert in wpa_supplicant might be still appropriate until exteded > kernel drivers are deployed. The wpa_supplicant Fedora package carries > the revert as patch: > https://src.fedoraproject.org/rpms/wpa_supplicant/c/c2eac195adadd2c48b04f8752cc46b12a351e69 Agree that revert makes most sense here. So what upstream drivers use WPA offload. Only brcmsmac and QCA drivers? Regards, Arend From arend.vanspriel at broadcom.com Sat Aug 10 04:15:19 2024 From: arend.vanspriel at broadcom.com (Arend Van Spriel) Date: Sat, 10 Aug 2024 13:15:19 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> Message-ID: <1913bfffd70.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> On August 10, 2024 12:43:43 PM Arend Van Spriel wrote: > On August 10, 2024 11:17:56 AM "Janne Grunau" wrote: > >> Hej, >> >> On Sat, Aug 10, 2024, at 10:30, Jouni Malinen wrote: >>> On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: >>>> wpa_supplicant 2.11 on Linux's 6.9.y / 6.10.y brcmfmac driver runs in >>>> authentication timeouts with WPA2-PSK and WPA3-SAE. This was reported >>>> with Apple silicon devices using Fedora Asahi remix with a patched >>>> driver as well as other devices without additional brcmfmac patches. >>>> See https://bugzilla.redhat.com/show_bug.cgi?id=2302577 for some >>>> reports. >>>> >>>> I've bisected this to >>>> https://w1.fi/cgit/hostap/commit/?id=41638606054a09867fe3f9a2b5523aa4678cbfa5 >>>> "Mark authorization completed on driver indication during 4-way HS >>>> offload". Reverting this commit on top of hostap_2_11 properly >>>> authenticates the connections. Looking at that change and the code it >>>> looks clearly broken to to me. As far as I can see is >>>> `assoc_info.authorized` for the nl80211 driver only set when >>>> QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED is set (in main, I did not >>>> check older revisions). This doesn't seem appropriate to expect this >>>> on chipsets from different vendors. >>> >>> This commit is from Broadcom to fix some race conditions with the 4- >>> way handshake offload which I'm assuming is for a Broadcom driver.. >>> Whether that is for brcmfmac is unknown to me, though. >>> >>> It looks like the goal here was to move completion of the connection >>> from the association event to EVENT_PORT_AUTHORIZED, i.e., the >>> NL80211_CMD_PORT_AUTHORIZED event from the driver. Is that event not >>> delivered by brcmfmac? I did not see any full wpa_supplicant debug >>> logs for these issues based on a quick look, so I could not check >>> that myself. > > I was surprised to see this was coming from Broadcom. I did not yet contact > the author for more details. > >>> >> >> The following place in brcmf_bss_roaming_done() is the only place where >> NL80211_CMD_PORT_AUTHORIZED event is posted. >> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c#n6402 > > Right. This seems to be added exclusively for Fast BSS transition scenario. > >> >> In my initial analysis I missed that the NL80211_CMD_PORT_AUTHORIZED is >> delivered directly to wpa_supplicant. >> >>>> A revert looks to me like a possible/proper fix. I can send that >>>> later if no alternative materializes. >>> >>> I'm inclined to revert this if it is indeed the case that >>> NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the upstream >>> driver and this commit was tested only with some non-upstream >>> versions. >> >> I intend extend the upstream kernel driver to post >> NL80211_CMD_PORT_AUTHORIZED after successful connection with >> authentication offload. I expect that the change will be accepted for >> the stable kernel. Infineon/Cypress have non-upstream patches for the >> brcmfmac driver which implement it already. > > Do you have a reference to see what they have done? > >> A revert in wpa_supplicant might be still appropriate until exteded >> kernel drivers are deployed. The wpa_supplicant Fedora package carries >> the revert as patch: >> https://src.fedoraproject.org/rpms/wpa_supplicant/c/c2eac195adadd2c48b04f8752cc46b12a351e69 > > Agree that revert makes most sense here. So what upstream drivers use WPA > offload. Only brcmsmac and QCA drivers? Obviously mean brcmfmac here. Autocorrect is mostly wrong ;-) Regards, Arend From j at jannau.net Sat Aug 10 05:02:20 2024 From: j at jannau.net (Janne Grunau) Date: Sat, 10 Aug 2024 14:02:20 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> Message-ID: <81485c0a-dbf0-4e07-abb9-22fb8d671839@app.fastmail.com> Hej, On Sat, Aug 10, 2024, at 12:43, Arend Van Spriel wrote: > On August 10, 2024 11:17:56 AM "Janne Grunau" wrote: >> On Sat, Aug 10, 2024, at 10:30, Jouni Malinen wrote: >>> On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: >> >>>> A revert looks to me like a possible/proper fix. I can send that >>>> later if no alternative materializes. >>> >>> I'm inclined to revert this if it is indeed the case that >>> NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the >>> upstream driver and this commit was tested only with some non- >>> upstream versions. >> >> I intend extend the upstream kernel driver to post >> NL80211_CMD_PORT_AUTHORIZED after successful connection with >> authentication offload. I expect that the change will be accepted for >> the stable kernel. Infineon/Cypress have non-upstream patches for the >> brcmfmac driver which implement it already. > > Do you have a reference to see what they have done? I was misremembering their implementation. They removed NL80211_CMD_PORT_AUTHORIZED and instead added "authorized" fields to struct cfg80211_connect_resp_params and struct cfg80211_roam_info. Those fields are then used to set NL80211_ATTR_PORT_AUTHORIZED. This is annotated as reserved and as far as I can see unused in upstream Linux and hostap. That means the patched Infineon/Cypress driver is broken as well. Probably not relevant since they patch hostap as well. Looking at the RTM/v6.1.19-hedorah branch of https://github.com/Infineon/ifx-wireless-drivers (214 mostly brcmfmac commits on top of Linux v6.1.19). 1. "nl80211: add authorized flag to CONNECT event" https://github.com/Infineon/ifx-wireless-drivers/commit/f7fb21f980b743e319cee406719e18ca0fd6784e 2. "brcmfmac: set authorized flag in CONNECT event for PMK caching" https://github.com/Infineon/ifx-wireless-drivers/commit/a665defa7e67b1d5f5735a55643014374e5f53d0 For roaming they do same and revert the NL80211_CMD_PORT_AUTHORIZED 1. "nl80211: add authorized flag back to ROAM event" https://github.com/Infineon/ifx-wireless-drivers/commit/d2262fb0a08124153c9549d2cd0e6f9c04d946e9 2. "brcmfmac: set authorized flag in ROAM event for offload FT roaming" https://github.com/Infineon/ifx-wireless-drivers/commit/3099d355af9914753927f913b14f62318a33ab55 >> A revert in wpa_supplicant might be still appropriate until exteded >> kernel drivers are deployed. The wpa_supplicant Fedora package >> carries the revert as patch: >> https://src.fedoraproject.org/rpms/wpa_supplicant/c/c2eac195adadd2c48b04f8752cc46b12a351e69 > > Agree that revert makes most sense here. So what upstream drivers use > WPA offload. Only brcmsmac and QCA drivers? It might be only brcmfmac, at least that's the only driver match for NL80211_EXT_FEATURE_SAE_OFFLOAD / NL80211_EXT_FEATURE_SAE_OFFLOAD_AP regards, Janne From arend.vanspriel at broadcom.com Sat Aug 10 06:13:46 2024 From: arend.vanspriel at broadcom.com (Arend Van Spriel) Date: Sat, 10 Aug 2024 15:13:46 +0200 Subject: wpa_supplicant 2.11 breaks WPA2-PSK / WPA3-SAE authentication on Linux' brcmfmac In-Reply-To: <81485c0a-dbf0-4e07-abb9-22fb8d671839@app.fastmail.com> References: <92fe4dd4-21a4-4559-8441-32ef86672de6@app.fastmail.com> <1913be30f30.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> <81485c0a-dbf0-4e07-abb9-22fb8d671839@app.fastmail.com> Message-ID: <1913c6c7310.279b.9b12b7fc0a3841636cfb5e919b41b954@broadcom.com> On August 10, 2024 2:02:43 PM "Janne Grunau" wrote: > Hej, > > On Sat, Aug 10, 2024, at 12:43, Arend Van Spriel wrote: >> On August 10, 2024 11:17:56 AM "Janne Grunau" wrote: >>> On Sat, Aug 10, 2024, at 10:30, Jouni Malinen wrote: >>>> On Sun, Aug 04, 2024 at 02:23:56PM +0200, Janne Grunau wrote: >>> >>>>> A revert looks to me like a possible/proper fix. I can send that >>>>> later if no alternative materializes. >>>> >>>> I'm inclined to revert this if it is indeed the case that >>>> NL80211_CMD_PORT_AUTHORIZED is not delivered reliably by the >>>> upstream driver and this commit was tested only with some non- >>>> upstream versions. >>> >>> I intend extend the upstream kernel driver to post >>> NL80211_CMD_PORT_AUTHORIZED after successful connection with >>> authentication offload. I expect that the change will be accepted for >>> the stable kernel. Infineon/Cypress have non-upstream patches for the >>> brcmfmac driver which implement it already. >> >> Do you have a reference to see what they have done? > > I was misremembering their implementation. They removed > NL80211_CMD_PORT_AUTHORIZED and instead added "authorized" fields to > struct cfg80211_connect_resp_params and struct cfg80211_roam_info. Those > fields are then used to set NL80211_ATTR_PORT_AUTHORIZED. This is > annotated as reserved and as far as I can see unused in upstream Linux > and hostap. That means the patched Infineon/Cypress driver is broken as > well. Probably not relevant since they patch hostap as well. > > Looking at the RTM/v6.1.19-hedorah branch of > https://github.com/Infineon/ifx-wireless-drivers (214 mostly brcmfmac > commits on top of Linux v6.1.19). > 1. "nl80211: add authorized flag to CONNECT event" > https://github.com/Infineon/ifx-wireless-drivers/commit/f7fb21f980b743e319cee406719e18ca0fd6784e > 2. "brcmfmac: set authorized flag in CONNECT event for PMK caching" > https://github.com/Infineon/ifx-wireless-drivers/commit/a665defa7e67b1d5f5735a55643014374e5f53d0 > > For roaming they do same and revert the NL80211_CMD_PORT_AUTHORIZED > 1. "nl80211: add authorized flag back to ROAM event" > https://github.com/Infineon/ifx-wireless-drivers/commit/d2262fb0a08124153c9549d2cd0e6f9c04d946e9 > 2. "brcmfmac: set authorized flag in ROAM event for offload FT roaming" > https://github.com/Infineon/ifx-wireless-drivers/commit/3099d355af9914753927f913b14f62318a33ab55 > >>> A revert in wpa_supplicant might be still appropriate until exteded >>> kernel drivers are deployed. The wpa_supplicant Fedora package >>> carries the revert as patch: >>> https://src.fedoraproject.org/rpms/wpa_supplicant/c/c2eac195adadd2c48b04f8752cc46b12a351e69 >> >> Agree that revert makes most sense here. So what upstream drivers use >> WPA offload. Only brcmsmac and QCA drivers? > > It might be only brcmfmac, at least that's the only driver match for > NL80211_EXT_FEATURE_SAE_OFFLOAD / NL80211_EXT_FEATURE_SAE_OFFLOAD_AP But the issue was not just with SAE or was it. I thought I saw someone mentioning WPA2-PSK was not working with wpa_sup 2.11 and assumed for the same reason. So for the NL80211_EXT_FEATURE_4WAY_HANDSHAKE_* flavors. Regards, Arend From gang.li_1 at nxp.com Mon Aug 12 00:50:53 2024 From: gang.li_1 at nxp.com (Gang Li) Date: Mon, 12 Aug 2024 07:50:53 +0000 Subject: SAE: reduce loop iterations of PWE derivation Message-ID: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-SAE-reduce-loop-iterations-of-PWE-derivation.patch Type: application/octet-stream Size: 1071 bytes Desc: 0001-SAE-reduce-loop-iterations-of-PWE-derivation.patch URL: From j at w1.fi Mon Aug 12 01:41:57 2024 From: j at w1.fi (Jouni Malinen) Date: Mon, 12 Aug 2024 11:41:57 +0300 Subject: SAE: reduce loop iterations of PWE derivation In-Reply-To: References: Message-ID: On Mon, Aug 12, 2024 at 07:50:53AM +0000, Gang Li wrote: > For low-performance processors, reduce the number of loop iterations > for PWE derivation to reduce the time to generate PWE. > Add CONFIG_SAE_PWE_NS macro to enable it. That would reintroduce the widely reported side-channel attacks against SAE. If you want to do that and understand the consequences, that is your choice, but I won't promote that in hostap.git. An appropriate way to avoid the iterations is to upgrade to using the direct hash-to-element mechanism with SAE. That avoids this loop completely. -- Jouni Malinen PGP id EFC895FA From gang.li_1 at nxp.com Mon Aug 12 02:03:22 2024 From: gang.li_1 at nxp.com (Gang Li) Date: Mon, 12 Aug 2024 09:03:22 +0000 Subject: [EXT] Re: SAE: reduce loop iterations of PWE derivation In-Reply-To: References: Message-ID: Hi Jouni Malinen, Yes, I understand the consequences. A few STAs may not support the Hash-to-Element (H2E) WPA3 SAE method, then it needs to use Hunting-and-Pecking (HnP) method. But it takes a long time to generate PWE, causing authentication failure. So reduce loop iterations of PWE derivation, and add CONFIG_SAE_PWE_NS macro, disable by default. It is up to the user to decide whether to enable it. Best Regards, Gang Li -----Original Message----- From: Jouni Malinen Sent: 2024?8?12? 16:42 To: Gang Li Cc: hostap at lists.infradead.org Subject: [EXT] Re: SAE: reduce loop iterations of PWE derivation Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button On Mon, Aug 12, 2024 at 07:50:53AM +0000, Gang Li wrote: > For low-performance processors, reduce the number of loop iterations > for PWE derivation to reduce the time to generate PWE. > Add CONFIG_SAE_PWE_NS macro to enable it. That would reintroduce the widely reported side-channel attacks against SAE. If you want to do that and understand the consequences, that is your choice, but I won't promote that in hostap.git. An appropriate way to avoid the iterations is to upgrade to using the direct hash-to-element mechanism with SAE. That avoids this loop completely. -- Jouni Malinen PGP id EFC895FA From hui.bai at nxp.com Mon Aug 12 03:05:40 2024 From: hui.bai at nxp.com (Hui Bai) Date: Mon, 12 Aug 2024 10:05:40 +0000 Subject: [EXT] Re: [PATCH] hostapd: Rename event handling functions in hostapd for In-Reply-To: References: Message-ID: Hi Jouni Malinen, Currently on Zephyr, we are using Monolithic build, which means both wpa_supplicant and hostapd files will be built into one single binary. I didn't quite get your idea of using function pointers to the driver interface. But based on my understanding, even I take your suggestions, the redefinition build error will still occurred with Monolithic build. Regards, Hui Bai -----Original Message----- From: Jouni Malinen Sent: Saturday, August 10, 2024 3:49 PM To: Hui Bai Cc: hostap at lists.infradead.org Subject: [EXT] Re: [PATCH] hostapd: Rename event handling functions in hostapd for Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button On Thu, Jun 13, 2024 at 06:32:01AM +0000, Hui Bai wrote: > On Zephyr, both wpa_supplicant and hostapd are supported. One compilation error was found due to function name conflict. > Both wpa_supplicant and hostapd has its own global event and event handlers with same name: > wpa_supplicant_event > wpa_supplicant_event_global > > To fix the compilation error, rename above functions in hostapd for Zephyr as below: > hostapd_event > hostapd_event_global This does not look like something that would really work at all in hostap.git, i.e., this is based on something that has other changes and as such, I'm not sure why this particular change should be in hostap.git. Those functions have the same name for a reason, i.e., those are the functions that are called from the driver interface code for either hostapd or wpa_supplicant. If there is need to make this work with both hostapd and wpa_supplicant somehow linked into a single binary, the driver wrappers would need changes. For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and wpa_supplicant_event_global as function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Mon Aug 12 12:04:04 2024 From: j at w1.fi (Jouni Malinen) Date: Mon, 12 Aug 2024 22:04:04 +0300 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-3-quic_adisi@quicinc.com> Message-ID: On Tue, Aug 06, 2024 at 11:47:27AM +0530, Aditya Kumar Singh wrote: > On 8/5/24 22:55, Jouni Malinen wrote: > > Is there a plan to use those hostapd_mld_ctrl_iface_{attach,detach}() > > functions for something else than for wrapping a call to > > ctrl_iface_{attach,detach}()? I would simply call the existing functions > > directly instead of going through that minimal wrapper function. > > Now that I see, this was done in order to have similar naming link for > non-AP MLD. Please see hostapd_ctrl_iface_attach(). So similarly, for MLD as > well the wrapper is introduced. Do you still want to remove the wrapper? hostapd_ctrl_iface_attach() used to contain the implementation and that ended up being a minimal wrapper when the function was shared for multiple purposes in commit 89b781bc89ef ("hostapd: Use common functions for ctrl_iface"). It was never cleaned up, but I guess better late than never.. So yes, I think the one-liner wrapper should be removed if there is no plan on extending it (and independently of that, the existing one-liner wrappers from that commit could be removed). -- Jouni Malinen PGP id EFC895FA From quic_adisi at quicinc.com Mon Aug 12 21:11:11 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 09:41:11 +0530 Subject: [PATCH v3 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: References: <20240801165143.3212598-1-quic_adisi@quicinc.com> <20240801165143.3212598-3-quic_adisi@quicinc.com> Message-ID: <47d09fa8-1f5a-43d1-bf48-60aedced31d1@quicinc.com> On 8/13/24 00:34, Jouni Malinen wrote: > On Tue, Aug 06, 2024 at 11:47:27AM +0530, Aditya Kumar Singh wrote: >> On 8/5/24 22:55, Jouni Malinen wrote: >>> Is there a plan to use those hostapd_mld_ctrl_iface_{attach,detach}() >>> functions for something else than for wrapping a call to >>> ctrl_iface_{attach,detach}()? I would simply call the existing functions >>> directly instead of going through that minimal wrapper function. >> >> Now that I see, this was done in order to have similar naming link for >> non-AP MLD. Please see hostapd_ctrl_iface_attach(). So similarly, for MLD as >> well the wrapper is introduced. Do you still want to remove the wrapper? > > hostapd_ctrl_iface_attach() used to contain the implementation and that > ended up being a minimal wrapper when the function was shared for > multiple purposes in commit 89b781bc89ef ("hostapd: Use common functions > for ctrl_iface"). It was never cleaned up, but I guess better late than > never.. So yes, I think the one-liner wrapper should be removed if there > is no plan on extending it (and independently of that, the existing > one-liner wrappers from that commit could be removed). > :) Sure, got it, will do as suggested. -- Aditya From quic_adisi at quicinc.com Mon Aug 12 21:41:33 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:33 +0530 Subject: [PATCH v4 0/6] MLO control socket changes Message-ID: <20240813044139.3632734-1-quic_adisi@quicinc.com> Control socket for each link BSS of MLD currently needs to be in a separate directory since interface name is same for all links in an AP MLD. Hence once the first link comes up, rest of links will not come up if using the same control interface directory. Hence, introduce link level sockets. Each link will use socket with name "_link" under given control interface directory. Also, introduce a MLD level socket with name "" in the same directory. This will help to route the commands to underlying links if required as well as it will keep backwards compatibility with other applications trying to find "" file in the control interface directory. Aditya Kumar Singh (5): ctrl_iface: MLO: introduce MLD level socket hostapd_cli: MLO: pass 'LINKID' in the command hostapd_cli: MLO: add status command for MLD socket tests: MLO: use link ID to access control sockets tests: MLO: add MLD socket connectivity test case Karthikeyan Kathirvel (1): ctrl_iface: create link based hapd control sockets --- v4: * Moved LINKID as prefix in MLD level socket command. * os_snprintf() and os_snprintf_error() usage wherever needed. * CONFIG_IEEE8021BE guard usage changes to avoid duplicate statements. v3: * Email correction in [0] and [6]. v2: * Rebased on ToT. No conflicts in [1-4]. * Fixed newly added EHT MLO and RSN Override sim test cases. [5/6] --- hostapd/ctrl_iface.c | 384 ++++++++++++++++++++++++++++++- hostapd/ctrl_iface.h | 4 + hostapd/hostapd_cli.c | 70 +++++- hostapd/main.c | 5 + src/ap/hostapd.c | 39 ++++ src/ap/hostapd.h | 11 + src/common/wpa_ctrl.c | 54 +++++ src/common/wpa_ctrl.h | 7 + tests/hwsim/hostapd.py | 27 ++- tests/hwsim/mld.py | 36 +++ tests/hwsim/test_eht.py | 126 +++++++++- tests/hwsim/test_rsn_override.py | 2 + 12 files changed, 740 insertions(+), 25 deletions(-) create mode 100644 tests/hwsim/mld.py base-commit: 43943ea5b31fb84bcb3b01f0d85d301a28e66e4c -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:34 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:34 +0530 Subject: [PATCH v4 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-2-quic_adisi@quicinc.com> From: Karthikeyan Kathirvel Create link based control sockets to access the link based commands through hostapd_cli. This will create the link interfaces in the name of wlan_link Example: To fetch link 0 status from wlan0, below command can be used - $ hostapd_cli -i wlan0 -l 0 status On failure of link/interface selection, below error will be observed $ hostapd_cli -i wlan0 -l 2 status Failed to connect to hostapd - wpa_ctrl_open: No such file or directory Signed-off-by: Karthikeyan Kathirvel Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 16 ++++++++++++++-- hostapd/hostapd_cli.c | 31 ++++++++++++++++++++++++++++--- src/ap/hostapd.c | 28 ++++++++++++++++++++++++++++ src/ap/hostapd.h | 5 +++++ src/common/wpa_ctrl.h | 4 ++++ 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 85eb35675495..f28707f9a15f 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4727,18 +4727,26 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { char *buf; size_t len; + char *ctrl_sock_iface; + +#ifdef CONFIG_IEEE80211BE + ctrl_sock_iface = hapd->ctrl_sock_iface; +#else + ctrl_sock_iface = hapd->conf->iface; +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->ctrl_interface == NULL) return NULL; len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; + os_strlen(ctrl_sock_iface) + 2; + buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); + hapd->conf->ctrl_interface, ctrl_sock_iface); buf[len - 1] = '\0'; return buf; } @@ -4909,7 +4917,11 @@ fail: #endif /* ANDROID */ if (os_strlen(hapd->conf->ctrl_interface) + 1 + +#ifdef CONFIG_IEEE80211BE + os_strlen(hapd->ctrl_sock_iface) >= sizeof(addr.sun_path)) +#else os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) +#endif /* CONFIG_IEEE80211BE */ goto fail; s = socket(PF_UNIX, SOCK_DGRAM, 0); diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index eb8a38350bd1..e0e5c9097c66 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -54,7 +54,11 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" - "usage: hostapd_cli [-p] [-i] [-hvBr] " + "usage: hostapd_cli [-p] [-i] " +#ifdef CONFIG_IEEE80211BE + "[-l] " +#endif /* CONFIG_IEEE80211BE */ + "[-hvBr] " "[-a] \\\n" " [-P] [-G] [command..]\n" "\n" @@ -74,7 +78,11 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n"); + " socket path)\n" +#ifdef CONFIG_IEEE80211BE + " -l Link ID of the interface in case of Multi-Link Operation\n" +#endif /* CONFIG_IEEE80211BE */ + "\n"); print_help(stderr, NULL); } @@ -2212,12 +2220,16 @@ int main(int argc, char *argv[]) int c; int daemonize = 0; int reconnect = 0; +#ifdef CONFIG_IEEE80211BE + int ret, link_id = -1; + char buf[300]; +#endif /* CONFIG_IEEE80211BE */ if (os_program_init()) return -1; for (;;) { - c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); if (c < 0) break; switch (c) { @@ -2252,6 +2264,19 @@ int main(int argc, char *argv[]) case 's': client_socket_dir = optarg; break; +#ifdef CONFIG_IEEE80211BE + case 'l': + link_id = atoi(optarg); + ret = os_snprintf(buf, sizeof(buf), "%s_%s%d", + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, + link_id); + if (os_snprintf_error(sizeof(buf), ret)) + return -1; + + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); + break; +#endif /* CONFIG_IEEE80211BE */ default: usage(); return -1; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index bf40f389d6d5..bf076916dadf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1824,12 +1824,36 @@ int hostapd_set_acl(struct hostapd_data *hapd) } +static int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + int ret; + + if (hapd->conf->mld_ap) { + ret = os_snprintf(hapd->ctrl_sock_iface, + sizeof(hapd->ctrl_sock_iface), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + if (os_snprintf_error(sizeof(hapd->ctrl_sock_iface), ret)) + return -1; + } else { + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + } +#endif /* CONFIG_IEEE80211BE */ + return 0; +} + + static int start_ctrl_iface_bss(struct hostapd_data *hapd) { if (!hapd->iface->interfaces || !hapd->iface->interfaces->ctrl_iface_init) return 0; + if (hostapd_set_ctrl_sock_iface(hapd)) + return -1; + if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", @@ -1850,6 +1874,10 @@ static int start_ctrl_iface(struct hostapd_iface *iface) for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; + + if (hostapd_set_ctrl_sock_iface(hapd)) + return -1; + if (iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 898dc0d75b93..071e1146c4cc 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -495,6 +495,11 @@ struct hostapd_data { /* Cached partner info for ML probe response */ struct mld_link_info partner_links[MAX_NUM_MLD_LINKS]; + /* 5 chars for "_link", 2 chars for . So in total, + * additionally 7 characters required. + */ + char ctrl_sock_iface[IFNAMSIZ + 7 + 1]; + #ifdef CONFIG_TESTING_OPTIONS u8 eht_mld_link_removal_count; #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f6142501e440..865ac6d91052 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -674,4 +674,8 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); } #endif +#ifdef CONFIG_IEEE80211BE +#define WPA_CTRL_IFACE_LINK_NAME "link" +#endif /* CONFIG_IEEE80211BE */ + #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:35 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:35 +0530 Subject: [PATCH v4 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-3-quic_adisi@quicinc.com> With MLO, each link have socket created with "_link" under the control interface directory. Introduce a MLD level socket - "" as well under the same control interface directory. This socket can be used to pass the command to its partner links directly instead of using the link level socket. Link ID needs to be passed with the command in a prefix way. If no Link ID is provided then first link ID is selected. The structure of the command is - "LINKID " Directory looks something like this - $ ls /var/run/hostapd/ wlan0 wlan0_link0 wlan0_link1 wlan0 here is the MLD level socket. Rest are each link level. This would also help to maintain backwards compatibility with applications which looks for under the control interface directory.` Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 322 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.h | 4 + hostapd/main.c | 5 + src/ap/hostapd.c | 11 ++ src/ap/hostapd.h | 6 + 5 files changed, 348 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index f28707f9a15f..fe46c37a7930 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4722,6 +4722,328 @@ done: } +#ifdef CONFIG_IEEE80211BE +#ifndef CONFIG_CTRL_IFACE_UDP +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, + char *buf, char *reply, + int reply_size, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct hostapd_data *link_hapd, *link_itr; + int reply_len, link_id = -1; + char cmd[4096]; + bool found = false; + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + /* Check if link id is provided in the command or not */ + if (sscanf(buf, "LINKID %d %s", &link_id, cmd) == 2) { + if (link_id < 0 || link_id >= 15) { + os_memcpy(reply, "INVALID LINK ID\n", 16); + reply_len = 16; + return reply_len; + } + + link_hapd = mld->fbss; + if (!link_hapd) { + os_memcpy(reply, "NO LINKS ACTIVE\n", 16); + reply_len = 16; + return reply_len; + } + + for_each_mld_link(link_itr, link_hapd) { + if (link_itr->mld_link_id == link_id) { + found = true; + break; + } + } + + if (!found) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + return reply_len; + } + + link_hapd = link_itr; + } else { + link_hapd = mld->fbss; + os_strlcpy(cmd, buf, sizeof(cmd)); + } + + if (os_strcmp(cmd, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); + reply_len = 5; + } else if (os_strcmp(cmd, "ATTACH") == 0) { + if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, NULL)) + reply_len = -1; + } else if (os_strncmp(cmd, "ATTACH ", 7) == 0) { + if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, cmd + 7)) + reply_len = -1; + } else if (os_strcmp(cmd, "DETACH") == 0) { + if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen)) + reply_len = -1; + } else { + if (link_id == -1) + wpa_printf(MSG_DEBUG, + "Link ID not provided, using first link BSS (if available)"); + + if (!link_hapd) + reply_len = -1; + else + reply_len = + hostapd_ctrl_iface_receive_process(link_hapd, + cmd, + reply, + reply_size, + from, + fromlen); + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + return reply_len; +} + + +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct hostapd_mld *mld = eloop_ctx; + char buf[4096]; + int res; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + char *reply, *pos = buf; + const int reply_size = 4096; + int reply_len; + int level = MSG_DEBUG; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s", + strerror(errno)); + return; + } + buf[res] = '\0'; + + reply = os_malloc(reply_size); + if (reply == NULL) { + if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + return; + } + + if (os_strcmp(pos, "PING") == 0) + level = MSG_EXCESSIVE; + + wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res); + + reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos, + reply, reply_size, + &from, fromlen); + + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + os_free(reply); +} + + +static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld) +{ + size_t len; + char *buf; + int ret; + + if (!mld->ctrl_interface) + return NULL; + + len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2; + + buf = os_malloc(len); + if (buf == NULL) + return NULL; + + ret = os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); + if (os_snprintf_error(len, ret)) { + os_free(buf); + return NULL; + } + + return buf; +} +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct sockaddr_un addr; + int s = -1; + char *fname = NULL; + + if (!mld) + return -1; + + if (mld->ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!", + mld->name); + return 0; + } + + dl_list_init(&mld->ctrl_dst); + + if (mld->ctrl_interface == NULL) + return 0; + + if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); + goto fail; + } + } + + if (os_strlen(mld->ctrl_interface) + 1 + + os_strlen(mld->name) >= sizeof(addr.sun_path)) + goto fail; + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ + addr.sun_family = AF_UNIX; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname == NULL) + goto fail; + + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + + wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name); + + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); + goto fail; + } + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < + 0) { + wpa_printf(MSG_ERROR, + "hostapd-ctrl-iface: bind(PF_UNIX): %s", + strerror(errno)); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); + goto fail; + } + os_free(fname); + + mld->ctrl_sock = s; + + if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld, + NULL) < 0) + return -1; + + return 0; + +fail: + if (s >= 0) + close(s); + if (fname) { + unlink(fname); + os_free(fname); + } + return -1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + return 0; +} + + +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct wpa_ctrl_dst *dst, *prev; + + if (mld->ctrl_sock > -1) { + char *fname; + eloop_unregister_read_sock(mld->ctrl_sock); + close(mld->ctrl_sock); + mld->ctrl_sock = -1; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname) + unlink(fname); + os_free(fname); + + if (mld->ctrl_interface && + rmdir(mld->ctrl_interface) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "MLD Control interface " + "directory not empty - leaving it " + "behind"); + } else { + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + mld->ctrl_interface, + strerror(errno)); + } + } + } + + dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst, + list) + os_free(dst); +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + os_free(mld->ctrl_interface); +} +#endif /* CONFIG_IEEE80211BE */ + + #ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h index 3341a66bdc6c..ec5a95be785c 100644 --- a/hostapd/ctrl_iface.h +++ b/hostapd/ctrl_iface.h @@ -14,6 +14,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd); void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); +#ifdef CONFIG_IEEE80211BE +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld); +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld); +#endif /* CONFIG_IEEE80211BE */ #else /* CONFIG_NO_CTRL_IFACE */ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { diff --git a/hostapd/main.c b/hostapd/main.c index be156ee60b25..512cd892bdec 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -752,6 +752,7 @@ static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) if (!interfaces->mld[i]) continue; + interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]); os_free(interfaces->mld[i]); interfaces->mld[i] = NULL; } @@ -797,6 +798,10 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; +#ifdef CONFIG_IEEE80211BE + interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init; + interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit; +#endif /* CONFIG_IEEE80211BE */ dl_list_init(&interfaces.global_ctrl_dst); #ifdef CONFIG_ETH_P_OUI dl_list_init(&interfaces.eth_p_oui); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index bf076916dadf..bde974ae0a19 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3115,9 +3115,18 @@ static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); dl_list_init(&mld->links); + mld->ctrl_sock = -1; + mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface); wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + /* + * Initialize MLD control interfaces early to allow external monitoring of + * link setup operations. + */ + if (interfaces->mld_ctrl_iface_init(mld)) + goto fail; + hapd->mld = mld; hostapd_mld_ref_inc(mld); hostapd_bss_alloc_link_id(hapd); @@ -3177,6 +3186,8 @@ static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) if (!remove && !forced_remove) continue; + interfaces->mld_ctrl_iface_deinit(mld); + wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name, forced_remove ? " (forced)" : ""); os_free(mld); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 071e1146c4cc..1bc34e9e1a4b 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -97,6 +97,8 @@ struct hapd_interfaces { #ifdef CONFIG_IEEE80211BE struct hostapd_mld **mld; size_t mld_count; + int (*mld_ctrl_iface_init)(struct hostapd_mld *mld); + void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld); #endif /* CONFIG_IEEE80211BE */ }; @@ -542,6 +544,10 @@ struct hostapd_mld { struct hostapd_data *fbss; struct dl_list links; /* List head of all affiliated links */ + + int ctrl_sock; + struct dl_list ctrl_dst; + char *ctrl_interface; /* directory for UNIX domain sockets */ }; #define HOSTAPD_MLD_MAX_REF_COUNT 0xFF -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:36 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:36 +0530 Subject: [PATCH v4 3/6] hostapd_cli: MLO: pass 'LINKID' in the command In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-4-quic_adisi@quicinc.com> MLD level socket can take 'LINKID '. Add changes to pass this via hostapd_cli. User needs to give "link_id=" in post fix fashion in the command in order to pass this link_id from cli. For example - $ hostapd_cli -i wlan0 status link_id=0 | grep freq= freq=2437 $ hostapd_cli -i wlan0 ... Interactive mode > ping PONG > > status link_id=0 Command for 'LINKID 0' state=ENABLED phy=phy0 freq=2437 ... Signed-off-by: Aditya Kumar Singh --- hostapd/hostapd_cli.c | 39 +++++++++++++++++++++++++++++++ src/common/wpa_ctrl.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/common/wpa_ctrl.h | 3 +++ 3 files changed, 96 insertions(+) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index e0e5c9097c66..73a29d80b409 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1961,6 +1961,45 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); } else { +#ifdef CONFIG_IEEE80211BE + char *pos, *end; + int i, j, link_id; + bool link_found = false; + + wpa_ctrl_reset_mld_link(ctrl); + i = 0; + + while (i < argc) { + pos = os_strstr(argv[i], "link_id="); + if (!pos) { + i++; + continue; + } + + pos = pos + 8; + link_id = strtol(pos, &end, 10); + + if (link_id < 0 || link_id >= 15) { + printf("Invalid link ID '%d'\n", link_id); + return; + } + + link_found = true; + + /* remove this link_id= from the arguements */ + for (j = i + 1; j < argc; j++) + argv[j - 1] = argv[j]; + + argc--; + i = 0; + } + + if (link_found) { + wpa_ctrl_set_mld_link(ctrl, link_id); + printf("Command for '%s'\n", + wpa_ctrl_get_mld_link(ctrl)); + } +#endif /* CONFIG_IEEE80211BE */ match->handler(ctrl, argc - 1, &argv[1]); } } diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 7e197f094fd1..d0c174c05d48 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -72,6 +72,13 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +#ifdef CONFIG_IEEE80211BE + /* 'LINKID ' - 7 chars including space + * 'XX' - Two chars max for link id + * Total required 10 chars at least + */ + char link_id_str[10]; +#endif /* CONFIG_IEEE80211BE */ }; @@ -488,6 +495,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, fd_set rfds; const char *_cmd; char *cmd_buf = NULL; + char *link_cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP @@ -510,6 +518,28 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, _cmd_len = cmd_len; } +#ifdef CONFIG_IEEE80211BE + if (os_strlen(ctrl->link_id_str)) { + char *pos; + + _cmd_len = _cmd_len + 1 + os_strlen(ctrl->link_id_str); + link_cmd_buf = os_malloc(_cmd_len); + if (link_cmd_buf == NULL) { + if (cmd_buf) + os_free(cmd_buf); + return -1; + } + + pos = link_cmd_buf; + os_strlcpy(pos, _cmd, _cmd_len); + pos += os_strlen(_cmd); + *pos++ = ' '; + os_memcpy(pos, ctrl->link_id_str, os_strlen(ctrl->link_id_str)); + _cmd = link_cmd_buf; + wpa_ctrl_reset_mld_link(ctrl); + } +#endif /* CONFIG_IEEE80211BE */ + errno = 0; started_at.sec = 0; started_at.usec = 0; @@ -535,9 +565,11 @@ retry_send: } send_err: os_free(cmd_buf); + os_free(link_cmd_buf); return -1; } os_free(cmd_buf); + os_free(link_cmd_buf); os_get_reltime(&ending_at); ending_at.sec += 10; @@ -773,4 +805,26 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_IEEE80211BE +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl) +{ + os_memset(ctrl->link_id_str, '\0', sizeof(ctrl->link_id_str)); +} + + +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id) +{ + os_snprintf(ctrl->link_id_str, sizeof(ctrl->link_id_str), + "LINKID %d", link_id); +} + + +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl) +{ + return ctrl->link_id_str; +} +#endif /* CONFIG_IEEE80211BE */ + + #endif /* CONFIG_CTRL_IFACE */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 865ac6d91052..d1ce1dd299f4 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -676,6 +676,9 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); #ifdef CONFIG_IEEE80211BE #define WPA_CTRL_IFACE_LINK_NAME "link" +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl); +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id); +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl); #endif /* CONFIG_IEEE80211BE */ #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:37 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:37 +0530 Subject: [PATCH v4 4/6] hostapd_cli: MLO: add status command for MLD socket In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-5-quic_adisi@quicinc.com> Add MLD level 'status' command. Currently each link level socket has got 'status' command. When the same is passed on MLD level socket without any link id, it routes it to first BSS of the MLD if available. Handle this now properly. If link id is not passed then it will be treated as MLD level status command. $ hostapd_cli -i wlan0 .... Interactive mode > status name=wlan0 mld_address=AA:BB:CC:DD:EE:FF num_links=2 LINK INFORMATION link_id=0 link_addr=AA:BB:CC:DD:EE:EE link_id=1 link_addr=AA:BB:CC:DD:FF:FF Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index fe46c37a7930..e868b826d040 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4724,6 +4724,49 @@ done: #ifdef CONFIG_IEEE80211BE #ifndef CONFIG_CTRL_IFACE_UDP +int hostapd_ctrl_mld_iface_status(struct hostapd_mld *mld, char *buf, + size_t buflen) +{ + struct hostapd_data *link_hapd; + int len = 0, ret; + + ret = os_snprintf(buf + len, buflen - len, + "name=%s\n" + "mld_address=" MACSTR "\n" + "num_links=%d\n", + mld->name, MAC2STR(mld->mld_addr), mld->num_links); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + if (!mld->fbss) { + ret = os_snprintf(buf + len, buflen - len, + "\n No Link information present\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, + "LINK INFORMATION\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + dl_list_for_each(link_hapd, &mld->links, struct hostapd_data, link) { + ret = os_snprintf(buf + len, buflen - len, + "link_id=%d\n" + "link_addr=" MACSTR "\n", + link_hapd->mld_link_id, MAC2STR(link_hapd->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + return len; +} + + static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, char *buf, char *reply, int reply_size, @@ -4784,6 +4827,9 @@ static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, } else if (os_strcmp(cmd, "DETACH") == 0) { if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen)) reply_len = -1; + } else if (os_strcmp(buf, "STATUS") == 0 && link_id == -1){ + reply_len = hostapd_ctrl_mld_iface_status(mld, reply, + reply_size); } else { if (link_id == -1) wpa_printf(MSG_DEBUG, -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:38 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:38 +0530 Subject: [PATCH v4 5/6] tests: MLO: use link ID to access control sockets In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-6-quic_adisi@quicinc.com> With MLO, each BSS will create sockets under the given ctrl_iface directory with the socket name being '_link'. Make necessary changes in MLO related test cases so that it can access the new socket and proceed further as expected. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/hostapd.py | 27 +++++++--- tests/hwsim/test_eht.py | 92 +++++++++++++++++++++++++++----- tests/hwsim/test_rsn_override.py | 2 + 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index 73819941b53a..8ed80588b2ee 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -165,15 +165,21 @@ class HostapdGlobal: class Hostapd: def __init__(self, ifname, bssidx=0, hostname=None, ctrl=hapd_ctrl, - port=8877, remote_cli=False): + port=8877, remote_cli=False, link=None): self.hostname = hostname self.host = remotehost.Host(hostname, ifname) self.ifname = ifname self.remote_cli = remote_cli if hostname is None: - self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.dbg = ifname + if link is None: + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + else: + ifname = ifname + "_link" + link + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname else: if remote_cli: self.ctrl = RemoteCtrl(ctrl, port, hostname=hostname, @@ -784,6 +790,13 @@ def add_mld_link(apdev, params): hostname = None port = 8878 + if "link_id" not in params: + raise Exception("Link ID not passed in param") + + link_id = params["link_id"] + # Delete the 'link_id' key from params or else it will be added in config + del params["link_id"] + hapd_global = HostapdGlobal(apdev) confname, ctrl_iface = cfg_mld_link_file(ifname, params) hapd_global.send_file(confname, confname) @@ -793,7 +806,8 @@ def add_mld_link(apdev, params): if str(e) == "Could not add hostapd link": raise utils.HwsimSkip("No MLO support in hostapd") port = hapd_global.get_ctrl_iface_port(ifname) - hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) + hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port, + link=link_id) if not hapd.ping(): raise Exception("Could not ping hostapd") return hapd @@ -1067,9 +1081,6 @@ def cfg_mld_link_file(ifname, params): fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') f = os.fdopen(fd, 'w') - if idx != 0: - ctrl_iface="/var/run/hostapd_%d" % idx - f.write("ctrl_interface=%s\n" % ctrl_iface) f.write("driver=nl80211\n") f.write("ieee80211n=1\n") diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index bde2b0e08148..3defa4e58d66 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -305,10 +305,12 @@ def test_eht_mld_discovery(dev, apdev): ssid = "mld_ap" link0_params = {"ssid": ssid, "hw_mode": "g", - "channel": "1"} + "channel": "1", + "link_id": "0"} link1_params = {"ssid": ssid, "hw_mode": "g", - "channel": "2"} + "channel": "2", + "link_id": "1"} hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) @@ -390,12 +392,14 @@ def _eht_mld_owe_two_links(dev, apdev, second_link_disabled=False, ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' if second_link_disabled: params['mld_indicate_disabled'] = '1' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) # Check legacy client connection @@ -448,6 +452,7 @@ def test_eht_mld_sae_single_link(dev, apdev): ssid = "mld_ap_sae_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='2') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -474,10 +479,12 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1", key_mgmt="SAE", mfp="2", pwe='1', beacon_prot=beacon_prot, bridge=bridge) + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -572,6 +579,7 @@ def test_eht_mld_sae_ext_one_link(dev, apdev): passphrase = 'qwertyuiop' ssid = "mld_ap_sae_ext_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -595,10 +603,12 @@ def test_eht_mld_sae_ext_two_links(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -618,10 +628,12 @@ def test_eht_mld_sae_legacy_client(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -658,10 +670,12 @@ def test_eht_mld_sae_transition(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -694,10 +708,12 @@ def test_eht_mld_ptk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_ptk_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -734,10 +750,12 @@ def test_eht_mld_gtk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_group_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -774,10 +792,12 @@ def test_eht_ml_probe_req(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -816,10 +836,14 @@ def test_eht_mld_connect_probes(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -861,10 +885,14 @@ def test_eht_tx_link_rejected_connect_other(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -891,10 +919,14 @@ def test_eht_all_links_rejected(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("mld_connect_bssid_pref", "00:11:22:33:44:01") wpas.set("sae_pwe", "1") @@ -934,10 +966,13 @@ def test_eht_connect_invalid_link(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, link_params) # We scan for both APs, then try to connect to link 0, but only the @@ -969,9 +1004,12 @@ def test_eht_mld_link_removal(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1021,10 +1059,12 @@ def test_eht_mld_bss_trans_mgmt_link_removal_imminent(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1073,10 +1113,12 @@ def test_eht_ap_mld_proto(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1461,10 +1503,14 @@ def test_eht_mld_gas(dev, apdev): params['venue_group'] = "7" params['venue_type'] = "1" params['venue_name'] = "eng:Example venue" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) bssid0 = hapd0.own_addr() params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) bssid1 = hapd1.own_addr() @@ -1497,9 +1543,13 @@ def test_eht_mld_dpp_responder_while_assoc(dev, apdev): ssid = "owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1525,9 +1575,13 @@ def _eht_mld_disconnect(dev, apdev, disassoc=True): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1582,6 +1636,7 @@ def test_eht_mld_non_pref_chan(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1670,6 +1725,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): params["bss_transition"] = "1" params["mbo"] = "1" params["rrm_beacon_report"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1685,6 +1741,8 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): other_ssid = "other" params = eht_mld_ap_wpa2_params(other_ssid, key_mgmt="OWE", mfp="2") params["channel"] = '6' + params['link_id'] = '0' + hapd1 = eht_mld_enable_ap(hapd1_iface, params) # Issue a beacon request for the second AP @@ -1724,6 +1782,8 @@ def test_eht_mld_legacy_stas(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) for i in range(3): @@ -1763,6 +1823,8 @@ def test_eht_mld_and_mlds(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1828,9 +1890,13 @@ def test_eht_mlo_csa(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1928,7 +1994,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, params['sae_pwe'] = "2" params['group_mgmt_cipher'] = "AES-128-CMAC" params['beacon_prot'] = "1" - params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel) + params["ctrl_interface"] = "/var/run/hostapd/" params["bssid"] = bssid_regex % (i + 1) if rnr: @@ -1936,7 +2002,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, append_bss_conf_to_file(f, ifname, params, first=(i == 0)) - hapds.append([ifname, params["ctrl_interface"], i]) + hapds.append([ifname, i]) f.close() @@ -1981,15 +2047,15 @@ def get_mld_devs(hapd_iface, count, prefix, rnr=False): start_ap(prefix, fname1 + " " + fname2) - hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], - bssidx=hapds1[0][2]) - hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1], - bssidx=hapds2[0][2]) + hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], bssidx=hapds1[0][1], + link="0") + hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], bssidx=hapds2[0][1], + link="1") - hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1], - bssidx=hapds1[1][2]) - hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1], - bssidx=hapds2[1][2]) + hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], bssidx=hapds1[1][1], + link="0") + hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], bssidx=hapds2[1][1], + link="1") if not hapd_mld1_link0.ping(): raise Exception("Could not ping hostapd") @@ -2168,11 +2234,13 @@ def test_eht_mlo_color_change(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') params['he_bss_color'] = '42' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' params['he_bss_color'] = '24' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) diff --git a/tests/hwsim/test_rsn_override.py b/tests/hwsim/test_rsn_override.py index 6733102e7ba4..9ffcad1032d4 100644 --- a/tests/hwsim/test_rsn_override.py +++ b/tests/hwsim/test_rsn_override.py @@ -141,6 +141,7 @@ def run_rsn_override_mld(dev, apdev, mixed): params['sae_groups'] = '19 20' params['sae_require_mfp'] = '1' params['sae_pwe'] = '2' + params['link_id'] = '0' if not mixed: params['rsn_override_key_mgmt'] = 'SAE' params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY' @@ -166,6 +167,7 @@ def run_rsn_override_mld(dev, apdev, mixed): hapd0 = eht_mld_enable_ap(hapd_iface, params) params1['channel'] = '6' + params1['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params1) wpas.set("sae_pwe", "1") -- 2.34.1 From quic_adisi at quicinc.com Mon Aug 12 21:41:39 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 10:11:39 +0530 Subject: [PATCH v4 6/6] tests: MLO: add MLD socket connectivity test case In-Reply-To: <20240813044139.3632734-1-quic_adisi@quicinc.com> References: <20240813044139.3632734-1-quic_adisi@quicinc.com> Message-ID: <20240813044139.3632734-7-quic_adisi@quicinc.com> Add simple test case to bring up a 2 link MLD and get the status of each link via the MLD level socket. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/mld.py | 36 ++++++++++++++++++++++++++++++++++++ tests/hwsim/test_eht.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/hwsim/mld.py diff --git a/tests/hwsim/mld.py b/tests/hwsim/mld.py new file mode 100644 index 000000000000..af6695e601df --- /dev/null +++ b/tests/hwsim/mld.py @@ -0,0 +1,36 @@ +# Python class for controlling Multi Link Device +# Copyright (c) 2024, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import logging +import wpaspy + +logger = logging.getLogger() +hapd_ctrl = '/var/run/hostapd' + +class Multi_Link_Device: + def __init__(self, ifname, ctrl=hapd_ctrl, port=8877): + self.ifname = ifname + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + + def close_ctrl(self): + self.ctrl.close() + self.ctrl = None + + def request(self, cmd): + logger.debug(self.dbg + ": MLD CTRL: " + cmd) + return self.ctrl.request(cmd) + + def ping(self): + return "PONG" in self.request("PING") + +def get_mld_obj(ifname, ctrl=hapd_ctrl, port=8877): + mld = Multi_Link_Device(ifname, ctrl, port) + if not mld.ping(): + raise Exception("Could not ping MLD %s" % ifname) + + return mld diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index 3defa4e58d66..bb2444638a1d 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -17,6 +17,7 @@ from tshark import run_tshark from test_gas import hs20_ap_params from test_dpp import check_dpp_capab, wait_auth_success from test_rrm import build_beacon_request, run_req_beacon, BeaconReport +import mld def eht_verify_wifi_version(dev): status = dev.get_status() @@ -2283,3 +2284,36 @@ def test_eht_mlo_color_change(dev, apdev): hapd0.dump_monitor() hapd1.dump_monitor() + +def test_eht_mld_socket_connectivity(dev, apdev): + """EHT MLD Socket Connectivity""" + with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \ + HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface): + + ssid = "mld_ap" + link0_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "1", + "link_id": "0"} + link1_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "2", + "link_id": "1"} + + hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) + hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) + + mld_dev = mld.get_mld_obj(hapd_iface) + + # Check status of each link + res = str(mld_dev.request("LINKID 0 STATUS")) + if "state" not in res: + raise Exception("Failed to get link 0 status via MLD socket") + + logger.info("LINK 0 STATUS: \n" + res) + + res = mld_dev.request("LINKID 1 STATUS") + if "state" not in res: + raise Exception("Failed to get link 1 status via MLD socket") + + logger.info("LINK 1 STATUS: \n" + res) -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:46 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:46 +0530 Subject: [PATCH v5 0/6] MLO control socket changes Message-ID: <20240813083852.3945773-1-quic_adisi@quicinc.com> Control socket for each link BSS of MLD currently needs to be in a separate directory since interface name is same for all links in an AP MLD. Hence once the first link comes up, rest of links will not come up if using the same control interface directory. Hence, introduce link level sockets. Each link will use socket with name "_link" under given control interface directory. Also, introduce a MLD level socket with name "" in the same directory. This will help to route the commands to underlying links if required as well as it will keep backwards compatibility with other applications trying to find "" file in the control interface directory. Aditya Kumar Singh (5): ctrl_iface: MLO: introduce MLD level socket hostapd_cli: MLO: pass 'LINKID' in the command hostapd_cli: MLO: add status command for MLD socket tests: MLO: use link ID to access control sockets tests: MLO: add MLD socket connectivity test case Karthikeyan Kathirvel (1): ctrl_iface: create link based hapd control sockets --- v5: * When moving LINKID from postfix to prefix, handling the same via cli was missed, fixed that in [3]. * No changes in other patches. v4: * Moved LINKID as prefix in MLD level socket command. * os_snprintf() and os_snprintf_error() usage wherever needed. * CONFIG_IEEE8021BE guard usage changes to avoid duplicate statements. v3: * Email correction in [0] and [6]. v2: * Rebased on ToT. No conflicts in [1-4]. * Fixed newly added EHT MLO and RSN Override sim test cases. [5/6] --- hostapd/ctrl_iface.c | 384 ++++++++++++++++++++++++++++++- hostapd/ctrl_iface.h | 4 + hostapd/hostapd_cli.c | 70 +++++- hostapd/main.c | 5 + src/ap/hostapd.c | 39 ++++ src/ap/hostapd.h | 11 + src/common/wpa_ctrl.c | 63 +++++ src/common/wpa_ctrl.h | 7 + tests/hwsim/hostapd.py | 27 ++- tests/hwsim/mld.py | 36 +++ tests/hwsim/test_eht.py | 126 +++++++++- tests/hwsim/test_rsn_override.py | 2 + 12 files changed, 749 insertions(+), 25 deletions(-) create mode 100644 tests/hwsim/mld.py base-commit: 43943ea5b31fb84bcb3b01f0d85d301a28e66e4c -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:47 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:47 +0530 Subject: [PATCH v5 1/6] ctrl_iface: create link based hapd control sockets In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-2-quic_adisi@quicinc.com> From: Karthikeyan Kathirvel Create link based control sockets to access the link based commands through hostapd_cli. This will create the link interfaces in the name of wlan_link Example: To fetch link 0 status from wlan0, below command can be used - $ hostapd_cli -i wlan0 -l 0 status On failure of link/interface selection, below error will be observed $ hostapd_cli -i wlan0 -l 2 status Failed to connect to hostapd - wpa_ctrl_open: No such file or directory Signed-off-by: Karthikeyan Kathirvel Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 16 ++++++++++++++-- hostapd/hostapd_cli.c | 31 ++++++++++++++++++++++++++++--- src/ap/hostapd.c | 28 ++++++++++++++++++++++++++++ src/ap/hostapd.h | 5 +++++ src/common/wpa_ctrl.h | 4 ++++ 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 85eb35675495..f28707f9a15f 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4727,18 +4727,26 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { char *buf; size_t len; + char *ctrl_sock_iface; + +#ifdef CONFIG_IEEE80211BE + ctrl_sock_iface = hapd->ctrl_sock_iface; +#else + ctrl_sock_iface = hapd->conf->iface; +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->ctrl_interface == NULL) return NULL; len = os_strlen(hapd->conf->ctrl_interface) + - os_strlen(hapd->conf->iface) + 2; + os_strlen(ctrl_sock_iface) + 2; + buf = os_malloc(len); if (buf == NULL) return NULL; os_snprintf(buf, len, "%s/%s", - hapd->conf->ctrl_interface, hapd->conf->iface); + hapd->conf->ctrl_interface, ctrl_sock_iface); buf[len - 1] = '\0'; return buf; } @@ -4909,7 +4917,11 @@ fail: #endif /* ANDROID */ if (os_strlen(hapd->conf->ctrl_interface) + 1 + +#ifdef CONFIG_IEEE80211BE + os_strlen(hapd->ctrl_sock_iface) >= sizeof(addr.sun_path)) +#else os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) +#endif /* CONFIG_IEEE80211BE */ goto fail; s = socket(PF_UNIX, SOCK_DGRAM, 0); diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index eb8a38350bd1..e0e5c9097c66 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -54,7 +54,11 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" - "usage: hostapd_cli [-p] [-i] [-hvBr] " + "usage: hostapd_cli [-p] [-i] " +#ifdef CONFIG_IEEE80211BE + "[-l] " +#endif /* CONFIG_IEEE80211BE */ + "[-hvBr] " "[-a] \\\n" " [-P] [-G] [command..]\n" "\n" @@ -74,7 +78,11 @@ static void usage(void) " -B run a daemon in the background\n" " -i Interface to listen on (default: first " "interface found in the\n" - " socket path)\n\n"); + " socket path)\n" +#ifdef CONFIG_IEEE80211BE + " -l Link ID of the interface in case of Multi-Link Operation\n" +#endif /* CONFIG_IEEE80211BE */ + "\n"); print_help(stderr, NULL); } @@ -2212,12 +2220,16 @@ int main(int argc, char *argv[]) int c; int daemonize = 0; int reconnect = 0; +#ifdef CONFIG_IEEE80211BE + int ret, link_id = -1; + char buf[300]; +#endif /* CONFIG_IEEE80211BE */ if (os_program_init()) return -1; for (;;) { - c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); + c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v"); if (c < 0) break; switch (c) { @@ -2252,6 +2264,19 @@ int main(int argc, char *argv[]) case 's': client_socket_dir = optarg; break; +#ifdef CONFIG_IEEE80211BE + case 'l': + link_id = atoi(optarg); + ret = os_snprintf(buf, sizeof(buf), "%s_%s%d", + ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME, + link_id); + if (os_snprintf_error(sizeof(buf), ret)) + return -1; + + os_free(ctrl_ifname); + ctrl_ifname = os_strdup(buf); + break; +#endif /* CONFIG_IEEE80211BE */ default: usage(); return -1; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index bf40f389d6d5..bf076916dadf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1824,12 +1824,36 @@ int hostapd_set_acl(struct hostapd_data *hapd) } +static int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + int ret; + + if (hapd->conf->mld_ap) { + ret = os_snprintf(hapd->ctrl_sock_iface, + sizeof(hapd->ctrl_sock_iface), "%s_%s%d", + hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME, + hapd->mld_link_id); + if (os_snprintf_error(sizeof(hapd->ctrl_sock_iface), ret)) + return -1; + } else { + os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, + sizeof(hapd->ctrl_sock_iface)); + } +#endif /* CONFIG_IEEE80211BE */ + return 0; +} + + static int start_ctrl_iface_bss(struct hostapd_data *hapd) { if (!hapd->iface->interfaces || !hapd->iface->interfaces->ctrl_iface_init) return 0; + if (hostapd_set_ctrl_sock_iface(hapd)) + return -1; + if (hapd->iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", @@ -1850,6 +1874,10 @@ static int start_ctrl_iface(struct hostapd_iface *iface) for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; + + if (hostapd_set_ctrl_sock_iface(hapd)) + return -1; + if (iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface for %s", diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 898dc0d75b93..071e1146c4cc 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -495,6 +495,11 @@ struct hostapd_data { /* Cached partner info for ML probe response */ struct mld_link_info partner_links[MAX_NUM_MLD_LINKS]; + /* 5 chars for "_link", 2 chars for . So in total, + * additionally 7 characters required. + */ + char ctrl_sock_iface[IFNAMSIZ + 7 + 1]; + #ifdef CONFIG_TESTING_OPTIONS u8 eht_mld_link_removal_count; #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f6142501e440..865ac6d91052 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -674,4 +674,8 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); } #endif +#ifdef CONFIG_IEEE80211BE +#define WPA_CTRL_IFACE_LINK_NAME "link" +#endif /* CONFIG_IEEE80211BE */ + #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:48 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:48 +0530 Subject: [PATCH v5 2/6] ctrl_iface: MLO: introduce MLD level socket In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-3-quic_adisi@quicinc.com> With MLO, each link have socket created with "_link" under the control interface directory. Introduce a MLD level socket - "" as well under the same control interface directory. This socket can be used to pass the command to its partner links directly instead of using the link level socket. Link ID needs to be passed with the command in a prefix way. If no Link ID is provided then first link ID is selected. The structure of the command is - "LINKID " Directory looks something like this - $ ls /var/run/hostapd/ wlan0 wlan0_link0 wlan0_link1 wlan0 here is the MLD level socket. Rest are each link level. This would also help to maintain backwards compatibility with applications which looks for under the control interface directory.` Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 322 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.h | 4 + hostapd/main.c | 5 + src/ap/hostapd.c | 11 ++ src/ap/hostapd.h | 6 + 5 files changed, 348 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index f28707f9a15f..fe46c37a7930 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4722,6 +4722,328 @@ done: } +#ifdef CONFIG_IEEE80211BE +#ifndef CONFIG_CTRL_IFACE_UDP +static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, + char *buf, char *reply, + int reply_size, + struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct hostapd_data *link_hapd, *link_itr; + int reply_len, link_id = -1; + char cmd[4096]; + bool found = false; + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + /* Check if link id is provided in the command or not */ + if (sscanf(buf, "LINKID %d %s", &link_id, cmd) == 2) { + if (link_id < 0 || link_id >= 15) { + os_memcpy(reply, "INVALID LINK ID\n", 16); + reply_len = 16; + return reply_len; + } + + link_hapd = mld->fbss; + if (!link_hapd) { + os_memcpy(reply, "NO LINKS ACTIVE\n", 16); + reply_len = 16; + return reply_len; + } + + for_each_mld_link(link_itr, link_hapd) { + if (link_itr->mld_link_id == link_id) { + found = true; + break; + } + } + + if (!found) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + return reply_len; + } + + link_hapd = link_itr; + } else { + link_hapd = mld->fbss; + os_strlcpy(cmd, buf, sizeof(cmd)); + } + + if (os_strcmp(cmd, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); + reply_len = 5; + } else if (os_strcmp(cmd, "ATTACH") == 0) { + if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, NULL)) + reply_len = -1; + } else if (os_strncmp(cmd, "ATTACH ", 7) == 0) { + if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, cmd + 7)) + reply_len = -1; + } else if (os_strcmp(cmd, "DETACH") == 0) { + if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen)) + reply_len = -1; + } else { + if (link_id == -1) + wpa_printf(MSG_DEBUG, + "Link ID not provided, using first link BSS (if available)"); + + if (!link_hapd) + reply_len = -1; + else + reply_len = + hostapd_ctrl_iface_receive_process(link_hapd, + cmd, + reply, + reply_size, + from, + fromlen); + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + return reply_len; +} + + +static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct hostapd_mld *mld = eloop_ctx; + char buf[4096]; + int res; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + char *reply, *pos = buf; + const int reply_size = 4096; + int reply_len; + int level = MSG_DEBUG; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s", + strerror(errno)); + return; + } + buf[res] = '\0'; + + reply = os_malloc(reply_size); + if (reply == NULL) { + if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + return; + } + + if (os_strcmp(pos, "PING") == 0) + level = MSG_EXCESSIVE; + + wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res); + + reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos, + reply, reply_size, + &from, fromlen); + + if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, + fromlen) < 0) { + wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s", + strerror(errno)); + } + os_free(reply); +} + + +static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld) +{ + size_t len; + char *buf; + int ret; + + if (!mld->ctrl_interface) + return NULL; + + len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2; + + buf = os_malloc(len); + if (buf == NULL) + return NULL; + + ret = os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name); + if (os_snprintf_error(len, ret)) { + os_free(buf); + return NULL; + } + + return buf; +} +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct sockaddr_un addr; + int s = -1; + char *fname = NULL; + + if (!mld) + return -1; + + if (mld->ctrl_sock > -1) { + wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!", + mld->name); + return 0; + } + + dl_list_init(&mld->ctrl_dst); + + if (mld->ctrl_interface == NULL) + return 0; + + if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", + strerror(errno)); + goto fail; + } + } + + if (os_strlen(mld->ctrl_interface) + 1 + + os_strlen(mld->name) >= sizeof(addr.sun_path)) + goto fail; + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ + addr.sun_family = AF_UNIX; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname == NULL) + goto fail; + + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + + wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name); + + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + wpa_printf(MSG_ERROR, + "Could not unlink existing ctrl_iface socket '%s': %s", + fname, strerror(errno)); + goto fail; + } + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < + 0) { + wpa_printf(MSG_ERROR, + "hostapd-ctrl-iface: bind(PF_UNIX): %s", + strerror(errno)); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", + strerror(errno)); + goto fail; + } + os_free(fname); + + mld->ctrl_sock = s; + + if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld, + NULL) < 0) + return -1; + + return 0; + +fail: + if (s >= 0) + close(s); + if (fname) { + unlink(fname); + os_free(fname); + } + return -1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + return 0; +} + + +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld) +{ +#ifndef CONFIG_CTRL_IFACE_UDP + struct wpa_ctrl_dst *dst, *prev; + + if (mld->ctrl_sock > -1) { + char *fname; + eloop_unregister_read_sock(mld->ctrl_sock); + close(mld->ctrl_sock); + mld->ctrl_sock = -1; + + fname = hostapd_mld_ctrl_iface_path(mld); + if (fname) + unlink(fname); + os_free(fname); + + if (mld->ctrl_interface && + rmdir(mld->ctrl_interface) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "MLD Control interface " + "directory not empty - leaving it " + "behind"); + } else { + wpa_printf(MSG_ERROR, + "rmdir[ctrl_interface=%s]: %s", + mld->ctrl_interface, + strerror(errno)); + } + } + } + + dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst, + list) + os_free(dst); +#endif /* !CONFIG_CTRL_IFACE_UDP */ + + os_free(mld->ctrl_interface); +} +#endif /* CONFIG_IEEE80211BE */ + + #ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) { diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h index 3341a66bdc6c..ec5a95be785c 100644 --- a/hostapd/ctrl_iface.h +++ b/hostapd/ctrl_iface.h @@ -14,6 +14,10 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd); void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); +#ifdef CONFIG_IEEE80211BE +int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld); +void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld); +#endif /* CONFIG_IEEE80211BE */ #else /* CONFIG_NO_CTRL_IFACE */ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { diff --git a/hostapd/main.c b/hostapd/main.c index be156ee60b25..512cd892bdec 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -752,6 +752,7 @@ static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) if (!interfaces->mld[i]) continue; + interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]); os_free(interfaces->mld[i]); interfaces->mld[i] = NULL; } @@ -797,6 +798,10 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; +#ifdef CONFIG_IEEE80211BE + interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init; + interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit; +#endif /* CONFIG_IEEE80211BE */ dl_list_init(&interfaces.global_ctrl_dst); #ifdef CONFIG_ETH_P_OUI dl_list_init(&interfaces.eth_p_oui); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index bf076916dadf..bde974ae0a19 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3115,9 +3115,18 @@ static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); dl_list_init(&mld->links); + mld->ctrl_sock = -1; + mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface); wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + /* + * Initialize MLD control interfaces early to allow external monitoring of + * link setup operations. + */ + if (interfaces->mld_ctrl_iface_init(mld)) + goto fail; + hapd->mld = mld; hostapd_mld_ref_inc(mld); hostapd_bss_alloc_link_id(hapd); @@ -3177,6 +3186,8 @@ static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) if (!remove && !forced_remove) continue; + interfaces->mld_ctrl_iface_deinit(mld); + wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name, forced_remove ? " (forced)" : ""); os_free(mld); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 071e1146c4cc..1bc34e9e1a4b 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -97,6 +97,8 @@ struct hapd_interfaces { #ifdef CONFIG_IEEE80211BE struct hostapd_mld **mld; size_t mld_count; + int (*mld_ctrl_iface_init)(struct hostapd_mld *mld); + void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld); #endif /* CONFIG_IEEE80211BE */ }; @@ -542,6 +544,10 @@ struct hostapd_mld { struct hostapd_data *fbss; struct dl_list links; /* List head of all affiliated links */ + + int ctrl_sock; + struct dl_list ctrl_dst; + char *ctrl_interface; /* directory for UNIX domain sockets */ }; #define HOSTAPD_MLD_MAX_REF_COUNT 0xFF -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:49 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:49 +0530 Subject: [PATCH v5 3/6] hostapd_cli: MLO: pass 'LINKID' in the command In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-4-quic_adisi@quicinc.com> MLD level socket can take 'LINKID '. Add changes to pass this via hostapd_cli. User needs to give "link_id=" in post fix fashion in the command in order to pass this link_id from cli. For example - $ hostapd_cli -i wlan0 status link_id=0 | grep freq= freq=2437 $ hostapd_cli -i wlan0 ... Interactive mode > ping PONG > > status link_id=0 Command for 'LINKID 0' state=ENABLED phy=phy0 freq=2437 ... Signed-off-by: Aditya Kumar Singh --- hostapd/hostapd_cli.c | 39 +++++++++++++++++++++++++++ src/common/wpa_ctrl.c | 63 +++++++++++++++++++++++++++++++++++++++++++ src/common/wpa_ctrl.h | 3 +++ 3 files changed, 105 insertions(+) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index e0e5c9097c66..73a29d80b409 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1961,6 +1961,45 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); } else { +#ifdef CONFIG_IEEE80211BE + char *pos, *end; + int i, j, link_id; + bool link_found = false; + + wpa_ctrl_reset_mld_link(ctrl); + i = 0; + + while (i < argc) { + pos = os_strstr(argv[i], "link_id="); + if (!pos) { + i++; + continue; + } + + pos = pos + 8; + link_id = strtol(pos, &end, 10); + + if (link_id < 0 || link_id >= 15) { + printf("Invalid link ID '%d'\n", link_id); + return; + } + + link_found = true; + + /* remove this link_id= from the arguements */ + for (j = i + 1; j < argc; j++) + argv[j - 1] = argv[j]; + + argc--; + i = 0; + } + + if (link_found) { + wpa_ctrl_set_mld_link(ctrl, link_id); + printf("Command for '%s'\n", + wpa_ctrl_get_mld_link(ctrl)); + } +#endif /* CONFIG_IEEE80211BE */ match->handler(ctrl, argc - 1, &argv[1]); } } diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 7e197f094fd1..9d050ad687fb 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -72,6 +72,13 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE HANDLE pipe; #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +#ifdef CONFIG_IEEE80211BE + /* 'LINKID ' - 7 chars including space + * 'XX' - Two chars max for link id + * Total required 10 chars at least + */ + char link_id_str[10]; +#endif /* CONFIG_IEEE80211BE */ }; @@ -488,6 +495,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, fd_set rfds; const char *_cmd; char *cmd_buf = NULL; + char *link_cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP @@ -510,6 +518,37 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, _cmd_len = cmd_len; } +#ifdef CONFIG_IEEE80211BE + if (os_strlen(ctrl->link_id_str)) { + char *pos; + size_t link_cmd_len; + + link_cmd_len = _cmd_len + 1 + os_strlen(ctrl->link_id_str) + 1; + link_cmd_buf = os_malloc(link_cmd_len); + if (!link_cmd_buf) { + os_free(cmd_buf); + return -1; + } + + pos = link_cmd_buf; + /* Expected format is - 'LINKID ' + * + * Copy 'LINKID ' part + */ + os_memcpy(pos, ctrl->link_id_str, os_strlen(ctrl->link_id_str)); + pos += os_strlen(ctrl->link_id_str); + /* space */ + *pos++ = ' '; + /* Copy actual command */ + os_memcpy(pos, _cmd, _cmd_len); + pos += _cmd_len; + + wpa_ctrl_reset_mld_link(ctrl); + _cmd = link_cmd_buf; + _cmd_len = link_cmd_len; + } +#endif /* CONFIG_IEEE80211BE */ + errno = 0; started_at.sec = 0; started_at.usec = 0; @@ -535,9 +574,11 @@ retry_send: } send_err: os_free(cmd_buf); + os_free(link_cmd_buf); return -1; } os_free(cmd_buf); + os_free(link_cmd_buf); os_get_reltime(&ending_at); ending_at.sec += 10; @@ -773,4 +814,26 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_IEEE80211BE +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl) +{ + os_memset(ctrl->link_id_str, '\0', sizeof(ctrl->link_id_str)); +} + + +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id) +{ + os_snprintf(ctrl->link_id_str, sizeof(ctrl->link_id_str), + "LINKID %d", link_id); +} + + +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl) +{ + return ctrl->link_id_str; +} +#endif /* CONFIG_IEEE80211BE */ + + #endif /* CONFIG_CTRL_IFACE */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 865ac6d91052..d1ce1dd299f4 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -676,6 +676,9 @@ char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl); #ifdef CONFIG_IEEE80211BE #define WPA_CTRL_IFACE_LINK_NAME "link" +void wpa_ctrl_reset_mld_link(struct wpa_ctrl *ctrl); +void wpa_ctrl_set_mld_link(struct wpa_ctrl *ctrl, int link_id); +char *wpa_ctrl_get_mld_link(struct wpa_ctrl *ctrl); #endif /* CONFIG_IEEE80211BE */ #endif /* WPA_CTRL_H */ -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:50 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:50 +0530 Subject: [PATCH v5 4/6] hostapd_cli: MLO: add status command for MLD socket In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-5-quic_adisi@quicinc.com> Add MLD level 'status' command. Currently each link level socket has got 'status' command. When the same is passed on MLD level socket without any link id, it routes it to first BSS of the MLD if available. Handle this now properly. If link id is not passed then it will be treated as MLD level status command. $ hostapd_cli -i wlan0 .... Interactive mode > status name=wlan0 mld_address=AA:BB:CC:DD:EE:FF num_links=2 LINK INFORMATION link_id=0 link_addr=AA:BB:CC:DD:EE:EE link_id=1 link_addr=AA:BB:CC:DD:FF:FF Signed-off-by: Aditya Kumar Singh --- hostapd/ctrl_iface.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index fe46c37a7930..e868b826d040 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -4724,6 +4724,49 @@ done: #ifdef CONFIG_IEEE80211BE #ifndef CONFIG_CTRL_IFACE_UDP +int hostapd_ctrl_mld_iface_status(struct hostapd_mld *mld, char *buf, + size_t buflen) +{ + struct hostapd_data *link_hapd; + int len = 0, ret; + + ret = os_snprintf(buf + len, buflen - len, + "name=%s\n" + "mld_address=" MACSTR "\n" + "num_links=%d\n", + mld->name, MAC2STR(mld->mld_addr), mld->num_links); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + if (!mld->fbss) { + ret = os_snprintf(buf + len, buflen - len, + "\n No Link information present\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + ret = os_snprintf(buf + len, buflen - len, + "LINK INFORMATION\n"); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + dl_list_for_each(link_hapd, &mld->links, struct hostapd_data, link) { + ret = os_snprintf(buf + len, buflen - len, + "link_id=%d\n" + "link_addr=" MACSTR "\n", + link_hapd->mld_link_id, MAC2STR(link_hapd->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + return len; +} + + static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, char *buf, char *reply, int reply_size, @@ -4784,6 +4827,9 @@ static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld, } else if (os_strcmp(cmd, "DETACH") == 0) { if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen)) reply_len = -1; + } else if (os_strcmp(buf, "STATUS") == 0 && link_id == -1){ + reply_len = hostapd_ctrl_mld_iface_status(mld, reply, + reply_size); } else { if (link_id == -1) wpa_printf(MSG_DEBUG, -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:51 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:51 +0530 Subject: [PATCH v5 5/6] tests: MLO: use link ID to access control sockets In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-6-quic_adisi@quicinc.com> With MLO, each BSS will create sockets under the given ctrl_iface directory with the socket name being '_link'. Make necessary changes in MLO related test cases so that it can access the new socket and proceed further as expected. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/hostapd.py | 27 +++++++--- tests/hwsim/test_eht.py | 92 +++++++++++++++++++++++++++----- tests/hwsim/test_rsn_override.py | 2 + 3 files changed, 101 insertions(+), 20 deletions(-) diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index 73819941b53a..8ed80588b2ee 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -165,15 +165,21 @@ class HostapdGlobal: class Hostapd: def __init__(self, ifname, bssidx=0, hostname=None, ctrl=hapd_ctrl, - port=8877, remote_cli=False): + port=8877, remote_cli=False, link=None): self.hostname = hostname self.host = remotehost.Host(hostname, ifname) self.ifname = ifname self.remote_cli = remote_cli if hostname is None: - self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) - self.dbg = ifname + if link is None: + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + else: + ifname = ifname + "_link" + link + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.mon = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname else: if remote_cli: self.ctrl = RemoteCtrl(ctrl, port, hostname=hostname, @@ -784,6 +790,13 @@ def add_mld_link(apdev, params): hostname = None port = 8878 + if "link_id" not in params: + raise Exception("Link ID not passed in param") + + link_id = params["link_id"] + # Delete the 'link_id' key from params or else it will be added in config + del params["link_id"] + hapd_global = HostapdGlobal(apdev) confname, ctrl_iface = cfg_mld_link_file(ifname, params) hapd_global.send_file(confname, confname) @@ -793,7 +806,8 @@ def add_mld_link(apdev, params): if str(e) == "Could not add hostapd link": raise utils.HwsimSkip("No MLO support in hostapd") port = hapd_global.get_ctrl_iface_port(ifname) - hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port) + hapd = Hostapd(ifname, hostname=hostname, ctrl=ctrl_iface, port=port, + link=link_id) if not hapd.ping(): raise Exception("Could not ping hostapd") return hapd @@ -1067,9 +1081,6 @@ def cfg_mld_link_file(ifname, params): fd, fname = tempfile.mkstemp(dir='/tmp', prefix=conf + '-') f = os.fdopen(fd, 'w') - if idx != 0: - ctrl_iface="/var/run/hostapd_%d" % idx - f.write("ctrl_interface=%s\n" % ctrl_iface) f.write("driver=nl80211\n") f.write("ieee80211n=1\n") diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index bde2b0e08148..3defa4e58d66 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -305,10 +305,12 @@ def test_eht_mld_discovery(dev, apdev): ssid = "mld_ap" link0_params = {"ssid": ssid, "hw_mode": "g", - "channel": "1"} + "channel": "1", + "link_id": "0"} link1_params = {"ssid": ssid, "hw_mode": "g", - "channel": "2"} + "channel": "2", + "link_id": "1"} hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) @@ -390,12 +392,14 @@ def _eht_mld_owe_two_links(dev, apdev, second_link_disabled=False, ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' if second_link_disabled: params['mld_indicate_disabled'] = '1' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) # Check legacy client connection @@ -448,6 +452,7 @@ def test_eht_mld_sae_single_link(dev, apdev): ssid = "mld_ap_sae_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='2') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -474,10 +479,12 @@ def run_eht_mld_sae_two_links(dev, apdev, beacon_prot="1", key_mgmt="SAE", mfp="2", pwe='1', beacon_prot=beacon_prot, bridge=bridge) + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -572,6 +579,7 @@ def test_eht_mld_sae_ext_one_link(dev, apdev): passphrase = 'qwertyuiop' ssid = "mld_ap_sae_ext_single_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) @@ -595,10 +603,12 @@ def test_eht_mld_sae_ext_two_links(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -618,10 +628,12 @@ def test_eht_mld_sae_legacy_client(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -658,10 +670,12 @@ def test_eht_mld_sae_transition(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -694,10 +708,12 @@ def test_eht_mld_ptk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_ptk_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -734,10 +750,12 @@ def test_eht_mld_gtk_rekey(dev, apdev): key_mgmt="SAE-EXT-KEY SAE WPA-PSK WPA-PSK-SHA256", mfp="1") params['wpa_group_rekey'] = '5' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -774,10 +792,12 @@ def test_eht_ml_probe_req(dev, apdev): ssid = "mld_ap_sae_two_link" params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE-EXT-KEY") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) @@ -816,10 +836,14 @@ def test_eht_mld_connect_probes(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -861,10 +885,14 @@ def test_eht_tx_link_rejected_connect_other(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("sae_pwe", "1") @@ -891,10 +919,14 @@ def test_eht_all_links_rejected(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, link_params) wpas.set("mld_connect_bssid_pref", "00:11:22:33:44:01") wpas.set("sae_pwe", "1") @@ -934,10 +966,13 @@ def test_eht_connect_invalid_link(dev, apdev, params): key_mgmt="SAE", pwe='2') link_params['channel'] = '1' link_params['bssid'] = '00:11:22:33:44:01' + link_params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, link_params) link_params['channel'] = '6' link_params['bssid'] = '00:11:22:33:44:02' + link_params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, link_params) # We scan for both APs, then try to connect to link 0, but only the @@ -969,9 +1004,12 @@ def test_eht_mld_link_removal(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1021,10 +1059,12 @@ def test_eht_mld_bss_trans_mgmt_link_removal_imminent(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1073,10 +1113,12 @@ def test_eht_ap_mld_proto(dev, apdev): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd0_iface, params) @@ -1461,10 +1503,14 @@ def test_eht_mld_gas(dev, apdev): params['venue_group'] = "7" params['venue_type'] = "1" params['venue_name'] = "eng:Example venue" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) bssid0 = hapd0.own_addr() params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) bssid1 = hapd1.own_addr() @@ -1497,9 +1543,13 @@ def test_eht_mld_dpp_responder_while_assoc(dev, apdev): ssid = "owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1525,9 +1575,13 @@ def _eht_mld_disconnect(dev, apdev, disassoc=True): ssid = "mld_ap_owe_two_link" params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd0_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd0_iface, params) wpas.connect(ssid, scan_freq="2412 2437", key_mgmt="OWE", @@ -1582,6 +1636,7 @@ def test_eht_mld_non_pref_chan(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, key_mgmt="OWE", mfp="2") params["bss_transition"] = "1" params["mbo"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1670,6 +1725,7 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): params["bss_transition"] = "1" params["mbo"] = "1" params["rrm_beacon_report"] = "1" + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd0_iface, params) @@ -1685,6 +1741,8 @@ def test_eht_mld_rrm_beacon_req(dev, apdev): other_ssid = "other" params = eht_mld_ap_wpa2_params(other_ssid, key_mgmt="OWE", mfp="2") params["channel"] = '6' + params['link_id'] = '0' + hapd1 = eht_mld_enable_ap(hapd1_iface, params) # Issue a beacon request for the second AP @@ -1724,6 +1782,8 @@ def test_eht_mld_legacy_stas(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) for i in range(3): @@ -1763,6 +1823,8 @@ def test_eht_mld_and_mlds(dev, apdev): mfp="2", pwe='2') params['rsn_pairwise'] = "CCMP GCMP-256" params['sae_groups'] = "19 20" + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1828,9 +1890,13 @@ def test_eht_mlo_csa(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') + params['link_id'] = '0' + hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' + params['link_id'] = '1' + hapd1 = eht_mld_enable_ap(hapd_iface, params) wpas.set("sae_pwe", "1") @@ -1928,7 +1994,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, params['sae_pwe'] = "2" params['group_mgmt_cipher'] = "AES-128-CMAC" params['beacon_prot'] = "1" - params["ctrl_interface"] = "/var/run/hostapd/chan_" + str(channel) + params["ctrl_interface"] = "/var/run/hostapd/" params["bssid"] = bssid_regex % (i + 1) if rnr: @@ -1936,7 +2002,7 @@ def get_config(iface, count, ssid, passphrase, channel, bssid_regex, append_bss_conf_to_file(f, ifname, params, first=(i == 0)) - hapds.append([ifname, params["ctrl_interface"], i]) + hapds.append([ifname, i]) f.close() @@ -1981,15 +2047,15 @@ def get_mld_devs(hapd_iface, count, prefix, rnr=False): start_ap(prefix, fname1 + " " + fname2) - hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], ctrl=hapds1[0][1], - bssidx=hapds1[0][2]) - hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], ctrl=hapds2[0][1], - bssidx=hapds2[0][2]) + hapd_mld1_link0 = hostapd.Hostapd(ifname=hapds1[0][0], bssidx=hapds1[0][1], + link="0") + hapd_mld1_link1 = hostapd.Hostapd(ifname=hapds2[0][0], bssidx=hapds2[0][1], + link="1") - hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], ctrl=hapds1[1][1], - bssidx=hapds1[1][2]) - hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], ctrl=hapds2[1][1], - bssidx=hapds2[1][2]) + hapd_mld2_link0 = hostapd.Hostapd(ifname=hapds1[1][0], bssidx=hapds1[1][1], + link="0") + hapd_mld2_link1 = hostapd.Hostapd(ifname=hapds2[1][0], bssidx=hapds2[1][1], + link="1") if not hapd_mld1_link0.ping(): raise Exception("Could not ping hostapd") @@ -2168,11 +2234,13 @@ def test_eht_mlo_color_change(dev, apdev): params = eht_mld_ap_wpa2_params(ssid, passphrase, key_mgmt="SAE", mfp="2", pwe='1') params['he_bss_color'] = '42' + params['link_id'] = '0' hapd0 = eht_mld_enable_ap(hapd_iface, params) params['channel'] = '6' params['he_bss_color'] = '24' + params['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params) diff --git a/tests/hwsim/test_rsn_override.py b/tests/hwsim/test_rsn_override.py index 6733102e7ba4..9ffcad1032d4 100644 --- a/tests/hwsim/test_rsn_override.py +++ b/tests/hwsim/test_rsn_override.py @@ -141,6 +141,7 @@ def run_rsn_override_mld(dev, apdev, mixed): params['sae_groups'] = '19 20' params['sae_require_mfp'] = '1' params['sae_pwe'] = '2' + params['link_id'] = '0' if not mixed: params['rsn_override_key_mgmt'] = 'SAE' params['rsn_override_key_mgmt_2'] = 'SAE-EXT-KEY' @@ -166,6 +167,7 @@ def run_rsn_override_mld(dev, apdev, mixed): hapd0 = eht_mld_enable_ap(hapd_iface, params) params1['channel'] = '6' + params1['link_id'] = '1' hapd1 = eht_mld_enable_ap(hapd_iface, params1) wpas.set("sae_pwe", "1") -- 2.34.1 From quic_adisi at quicinc.com Tue Aug 13 01:38:52 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Tue, 13 Aug 2024 14:08:52 +0530 Subject: [PATCH v5 6/6] tests: MLO: add MLD socket connectivity test case In-Reply-To: <20240813083852.3945773-1-quic_adisi@quicinc.com> References: <20240813083852.3945773-1-quic_adisi@quicinc.com> Message-ID: <20240813083852.3945773-7-quic_adisi@quicinc.com> Add simple test case to bring up a 2 link MLD and get the status of each link via the MLD level socket. Signed-off-by: Aditya Kumar Singh --- tests/hwsim/mld.py | 36 ++++++++++++++++++++++++++++++++++++ tests/hwsim/test_eht.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/hwsim/mld.py diff --git a/tests/hwsim/mld.py b/tests/hwsim/mld.py new file mode 100644 index 000000000000..af6695e601df --- /dev/null +++ b/tests/hwsim/mld.py @@ -0,0 +1,36 @@ +# Python class for controlling Multi Link Device +# Copyright (c) 2024, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import logging +import wpaspy + +logger = logging.getLogger() +hapd_ctrl = '/var/run/hostapd' + +class Multi_Link_Device: + def __init__(self, ifname, ctrl=hapd_ctrl, port=8877): + self.ifname = ifname + self.ctrl = wpaspy.Ctrl(os.path.join(ctrl, ifname)) + self.dbg = ifname + + def close_ctrl(self): + self.ctrl.close() + self.ctrl = None + + def request(self, cmd): + logger.debug(self.dbg + ": MLD CTRL: " + cmd) + return self.ctrl.request(cmd) + + def ping(self): + return "PONG" in self.request("PING") + +def get_mld_obj(ifname, ctrl=hapd_ctrl, port=8877): + mld = Multi_Link_Device(ifname, ctrl, port) + if not mld.ping(): + raise Exception("Could not ping MLD %s" % ifname) + + return mld diff --git a/tests/hwsim/test_eht.py b/tests/hwsim/test_eht.py index 3defa4e58d66..bb2444638a1d 100644 --- a/tests/hwsim/test_eht.py +++ b/tests/hwsim/test_eht.py @@ -17,6 +17,7 @@ from tshark import run_tshark from test_gas import hs20_ap_params from test_dpp import check_dpp_capab, wait_auth_success from test_rrm import build_beacon_request, run_req_beacon, BeaconReport +import mld def eht_verify_wifi_version(dev): status = dev.get_status() @@ -2283,3 +2284,36 @@ def test_eht_mlo_color_change(dev, apdev): hapd0.dump_monitor() hapd1.dump_monitor() + +def test_eht_mld_socket_connectivity(dev, apdev): + """EHT MLD Socket Connectivity""" + with HWSimRadio(use_mlo=True) as (hapd_radio, hapd_iface), \ + HWSimRadio(use_mlo=True) as (wpas_radio, wpas_iface): + + ssid = "mld_ap" + link0_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "1", + "link_id": "0"} + link1_params = {"ssid": ssid, + "hw_mode": "g", + "channel": "2", + "link_id": "1"} + + hapd0 = eht_mld_enable_ap(hapd_iface, link0_params) + hapd1 = eht_mld_enable_ap(hapd_iface, link1_params) + + mld_dev = mld.get_mld_obj(hapd_iface) + + # Check status of each link + res = str(mld_dev.request("LINKID 0 STATUS")) + if "state" not in res: + raise Exception("Failed to get link 0 status via MLD socket") + + logger.info("LINK 0 STATUS: \n" + res) + + res = mld_dev.request("LINKID 1 STATUS") + if "state" not in res: + raise Exception("Failed to get link 1 status via MLD socket") + + logger.info("LINK 1 STATUS: \n" + res) -- 2.34.1 From chaitanya.mgit at gmail.com Tue Aug 13 02:16:59 2024 From: chaitanya.mgit at gmail.com (Krishna Chaitanya) Date: Tue, 13 Aug 2024 14:46:59 +0530 Subject: [EXT] Re: [PATCH] hostapd: Rename event handling functions in hostapd for In-Reply-To: References: Message-ID: On Mon, Aug 12, 2024 at 3:39?PM Hui Bai wrote: > > Hi Jouni Malinen, > > Currently on Zephyr, we are using Monolithic build, which means both wpa_supplicant and hostapd files will be built into one single binary. > I didn't quite get your idea of using function pointers to the driver interface. But based on my understanding, even I take your suggestions, the redefinition build error will still occurred with Monolithic build. > > Regards, > Hui Bai > > -----Original Message----- > From: Jouni Malinen > Sent: Saturday, August 10, 2024 3:49 PM > To: Hui Bai > Cc: hostap at lists.infradead.org > Subject: [EXT] Re: [PATCH] hostapd: Rename event handling functions in hostapd for > > Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button > > > On Thu, Jun 13, 2024 at 06:32:01AM +0000, Hui Bai wrote: > > On Zephyr, both wpa_supplicant and hostapd are supported. One compilation error was found due to function name conflict. > > Both wpa_supplicant and hostapd has its own global event and event handlers with same name: > > wpa_supplicant_event > > wpa_supplicant_event_global > > > > To fix the compilation error, rename above functions in hostapd for Zephyr as below: > > hostapd_event > > hostapd_event_global > > This does not look like something that would really work at all in hostap.git, i.e., this is based on something that has other changes and as such, I'm not sure why this particular change should be in hostap.git. > > Those functions have the same name for a reason, i.e., those are the functions that are called from the driver interface code for either hostapd or wpa_supplicant. If there is need to make this work with both hostapd and wpa_supplicant somehow linked into a single binary, the driver wrappers would need changes. For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and wpa_supplicant_event_global as function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. > somehow linked into a single binary, This and a couple of other patches related to single binary using both hostap and wpa_supplicant are in the context of an embedded OS (ZephyrRTOS) where there are only threads and no processes. So, hostapd and WPA supplicant run in separate threads and belong to the same binary and we see conflicts in that case. > For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and > wpa_supplicant_event_global as function pointers to the driver interface and using those function > pointers instead of direct calls. That is something that I could consider applying to hostap.git. I guess what Jouni is proposing is something like below, where we can register both a global and per-interface event callback and both AP and STA interfaces can register their own callback using per-interface callbacks. diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f39ea6560..64a6c169c 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2550,6 +2550,9 @@ enum nested_attr { NESTED_ATTR_UNSPECIFIED = 2, }; + +typedef void (*wpa_event_callback)(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); /** * struct wpa_driver_ops - Driver interface API definition * @@ -2937,7 +2940,7 @@ struct wpa_driver_ops { * use init2() function instead of init() to get the pointer to global * data available to per-interface initializer. */ - void * (*global_init)(void *ctx); + void * (*global_init)(void *ctx, wpa_event_callback cb); /** * global_deinit - Global driver deinitialization @@ -2959,7 +2962,8 @@ struct wpa_driver_ops { * This function can be used instead of init() if the driver wrapper * uses global data. */ - void * (*init2)(void *ctx, const char *ifname, void *global_priv); + void * (*init2)(void *ctx, const char *ifname, void *global_priv, + wpa_event_callback cb); /** * get_interfaces - Get information about available interfaces From Doug.Smith at ezurio.com Thu Aug 15 11:49:51 2024 From: Doug.Smith at ezurio.com (Doug Smith) Date: Thu, 15 Aug 2024 18:49:51 +0000 Subject: wpa_supplicant 2.11 - thick-mac open AP won't pass data packets Message-ID: All, Apologies in advance if this has already been addressed. Found an issue using wpa_supplicant 2.11 (built with CONFIG_AP support) configured as an open AP. After a station connects to the AP, data packets are not passed -- pings fail. The issue occurs with a thick-mac radio due to the WPA_STA_AUTHORIZED flag not being pushed. When the station connects, the AP handles the assoc event in wpa_supplicant_event_assoc():, and calls hostapd_notif_assoc():. hostapd_notif_assoc call hostapd_set_sta_flags() to push the flags -- unfortunately the AUTHORIZED flag hasn't been set yet. The AUTHORIZED flag isn't set until hostapd_new_assoc_sta() is called a few lines later. hostapd_new_assoc_sta(): calls ap_sta_set_authorized() for the open AP -- unfortunately the flag isn't pushed. One possible fix is to push the flag as follows: diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index c8ec1d624..d4a73510d 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -4042,6 +4042,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, * been authorized. */ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) { ap_sta_set_authorized(hapd, sta, 1); + // fix no ping -- push the authorized flag + hostapd_set_sta_flags(hapd, sta); os_get_reltime(&sta->connected_time); accounting_sta_start(hapd, sta); } Regards, Doug THE INFORMATION CONTAINED IN THIS DOCUMENT IS OF A PROPRIETARY NATURE AND IS INTENDED TO BE KEPT CONFIDENTIAL BETWEEN THE SENDER AND THE INTENDED RECIPIENT. IT MAY NOT BE REPRODUCED OR USED WITHOUT EXPRESS WRITTEN PERMISSION OF EZURIO From alex.gavin at candelatech.com Thu Aug 15 21:32:37 2024 From: alex.gavin at candelatech.com (Alex Gavin) Date: Thu, 15 Aug 2024 21:32:37 -0700 Subject: hostapd AX Client Association Issue w/ 6GHz 320MHz AP Message-ID: <9353656c-ef90-4f55-9b48-d1d130aa2eb8@candelatech.com> To Whom It May Concern: When testing a mt7996-based 6GHz 320MHz AP on a custom 6.10.3+ kernel and recent upstream hostapd (commit 70b8f64), AX clients will not associate. However, BE clients will associate. Separately, all AX and BE clients will associate when the AP is configured to 160MHz. In all cases, the clients are configured to the 6GHz BSSID. The following is a selection from the configuration file when configuring the AP for 320MHz operation: ieee80211be=1 channel=37 op_class=137 he_oper_centr_freq_seg0_idx=31 eht_oper_centr_freq_seg0_idx=31 he_6ghz_reg_pwr_type=0 With this configuration, the 'Channel Width' in the 'Control' field is set to '0' (20 MHz). This is located in the '6GHz Operation Information' section of the 'HE Operation' IE. Beacons from other 320MHz-configured APs (e.g. ASUS RT-BE96U, Netgear RS700S) show the 'Channel Width' field set to '3' (160MHz or 80+80MHz). Digging into the beacon creation code for this IE, 'center_idx_to_bw_6ghz()' returns '4' for 320MHz operation. This overflows the two bit 'Channel Width' field, setting 'Channel Width' field to 0 (also setting the 'Duplicate Beacon' field to '1'). With the following hacked changes, I am able to associate AX clients again: diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index a2deda6c4..8b00abad1 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -252,7 +252,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) * bits 3-5: Regulatory Info */ /* Channel Width */ - if (seg1) + if (seg1 || oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) control = 3; else control = center_idx_to_bw_6ghz(seg0); Can someone double check this partial configuration? I'm happy to provide the full config if needed. If the config is correct, I am happy to submit this as a proper patch with any needed modifications. Best, -- Alex Gavin Candela Technologies, USA (PST/GMT-8) Please CC support at candelatech.com on support topics. From quic_adisi at quicinc.com Fri Aug 16 00:51:50 2024 From: quic_adisi at quicinc.com (Aditya Kumar Singh) Date: Fri, 16 Aug 2024 13:21:50 +0530 Subject: hostapd AX Client Association Issue w/ 6GHz 320MHz AP In-Reply-To: <9353656c-ef90-4f55-9b48-d1d130aa2eb8@candelatech.com> References: <9353656c-ef90-4f55-9b48-d1d130aa2eb8@candelatech.com> Message-ID: <48b85496-a640-4978-bd97-c732b1bfbc53@quicinc.com> On 8/16/24 10:02, Alex Gavin wrote: > To Whom It May Concern: > > When testing a mt7996-based 6GHz 320MHz AP on a custom 6.10.3+ kernel > and recent upstream hostapd (commit 70b8f64), AX clients will not associate. > However, BE clients will associate. Separately, all AX and BE clients will associate > when the AP is configured to 160MHz. In all cases, the clients are configured to > the 6GHz BSSID. > > The following is a selection from the configuration file when configuring the AP > for 320MHz operation: > > ieee80211be=1 > channel=37 > op_class=137 > he_oper_centr_freq_seg0_idx=31 This seem wrong? HE does not support 320 bandwidth and hence the idx should be w.r.t to 160 which should be 47. > eht_oper_centr_freq_seg0_idx=31 This is fine. > he_6ghz_reg_pwr_type=0 > > With this configuration, the 'Channel Width' in the 'Control' field is set to > '0' (20 MHz). This is located in the '6GHz Operation Information' section of > the 'HE Operation' IE. Beacons from other 320MHz-configured APs (e.g. ASUS RT-BE96U, > Netgear RS700S) show the 'Channel Width' field set to '3' (160MHz or 80+80MHz). > > Digging into the beacon creation code for this IE, 'center_idx_to_bw_6ghz()' returns '4' > for 320MHz operation. This overflows the two bit 'Channel Width' field, setting > 'Channel Width' field to 0 (also setting the 'Duplicate Beacon' field to '1'). > > With the following hacked changes, I am able to associate AX clients again: > > diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c > index a2deda6c4..8b00abad1 100644 > --- a/src/ap/ieee802_11_he.c > +++ b/src/ap/ieee802_11_he.c > @@ -252,7 +252,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) > * bits 3-5: Regulatory Info > */ > /* Channel Width */ > - if (seg1) > + if (seg1 || oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) > control = 3; > else > control = center_idx_to_bw_6ghz(seg0); So here it will go to center_idx_to_bw_6ghz with value 47 which should return 3 which is what is expected. > > Can someone double check this partial configuration? I'm happy to provide the full config > if needed. If the config is correct, I am happy to submit this as a proper patch with any > needed modifications. > > Best, -- Aditya From vinayak.yadawad at broadcom.com Fri Aug 16 02:58:09 2024 From: vinayak.yadawad at broadcom.com (Vinayak Yadawad) Date: Fri, 16 Aug 2024 15:28:09 +0530 Subject: [PATCH 1/1] hostapd: Avoid EAPOL trigger in reassoc path for AP, in case of 4way HS offload In-Reply-To: References: Message-ID: Hi Jouni, >Do you really mean association path and reassociation path here? The >current implementation in hostapd_new_assoc_sta() should be used both >when processing an Association Request frame and when processing a >Reassociation Request frame. The fix is meant for a case where assoc event is received by the AP from an already associated STA (without deauth in between). wpa_auth_sta_associated handles both reassoc and assoc case differently and the 4way HS offload case is getting skipped for reassoc case. This change should have been in common path. Let me check whether I can handle the same in SM_STATE(WPA_PTK, PTKSTART). Regards, Vinayak On Sat, Aug 10, 2024 at 1:29?PM Jouni Malinen wrote: > > On Fri, May 24, 2024 at 12:00:27PM +0530, Vinayak Yadawad wrote: > > Currently avoiding of EAPOL exchange for AP with 4way HS offload is > > handled only in new STA assoc path. Current change avoids complete > > authentication trigger in case of AP reassoc path as well. > > Do you really mean association path and reassociation path here? The > current implementation in hostapd_new_assoc_sta() should be used both > when processing an Association Request frame and when processing a > Reassociation Request frame. > > > diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c > > @@ -2708,8 +2717,20 @@ SM_STATE(WPA_PTK, PTKSTART) > > SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); > > + > > + wpa_auth_get_drv_flags(sm->wpa_auth, &drv_flags, &drv_flags2); > > + ap_4way_hs_offload = !!(drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK); > > + if (ap_4way_hs_offload) { > > + /* 4way HS offloaded to driver no need of EAPOL */ > > + wpa_printf(MSG_INFO, "Avoid EAPOL in case of 4way HS offload"); > > + return; > > + } > > This on the other hand would address other reasons to start 4-way > handshake than association or reassociation. For example, rekeying of > the PTK would be such a case. This might be a reasonable thing to do, > but that commit message makes the intent of this change quite unclear. > > -- > Jouni Malinen PGP id EFC895FA -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 4218 bytes Desc: S/MIME Cryptographic Signature URL: From alex.gavin at candelatech.com Sun Aug 18 11:05:40 2024 From: alex.gavin at candelatech.com (Alex Gavin) Date: Sun, 18 Aug 2024 11:05:40 -0700 Subject: hostapd AX Client Association Issue w/ 6GHz 320MHz AP In-Reply-To: <48b85496-a640-4978-bd97-c732b1bfbc53 () quicinc ! com> References: <48b85496-a640-4978-bd97-c732b1bfbc53 () quicinc ! com> Message-ID: On 8/16/24 12:59 AM, Aditya Kumar Singh wrote: > On 8/16/24 10:02, Alex Gavin wrote: >> The following is a selection from the configuration file when configuring the AP >> for 320MHz operation: >> >> ieee80211be=1 >> channel=37 >> op_class=137 >> he_oper_centr_freq_seg0_idx=31 > > This seem wrong? HE does not support 320 bandwidth and hence the idx > should be w.r.t to 160 which should be 47. > Thank you for the quick reply and for pointing this out. I missed this in the config file documentation. Changing the 'he_oper_centr_freq_seg0_idx' value as you suggested addressed the issue. >> With the following hacked changes, I am able to associate AX clients again: >> >> diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c >> index a2deda6c4..8b00abad1 100644 >> --- a/src/ap/ieee802_11_he.c >> +++ b/src/ap/ieee802_11_he.c >> @@ -252,7 +252,7 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) >> * bits 3-5: Regulatory Info >> */ >> /* Channel Width */ >> - if (seg1) >> + if (seg1 || oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) >> control = 3; >> else >> control = center_idx_to_bw_6ghz(seg0); > > So here it will go to center_idx_to_bw_6ghz with value 47 which should > return 3 which is what is expected. > Understood. -- Alex Gavin Candela Technologies, USA (PST/GMT-8) Please CC support at candelatech.com on support topics. From frank.ye at nxp.com Tue Aug 20 23:05:02 2024 From: frank.ye at nxp.com (Fengming Ye) Date: Wed, 21 Aug 2024 06:05:02 +0000 Subject: [PATCH] hostapd: Rename event handling functions in hostapd for In-Reply-To: References: Message-ID: > Those functions have the same name for a reason, i.e., those are the functions that are called from the driver interface code for either hostapd or wpa_supplicant. If there is need to make this work with both hostapd and wpa_supplicant somehow linked into a single binary, the driver wrappers would need changes. For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and wpa_supplicant_event_global as function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. Hi Jouni, Thanks for the suggestion. RTOS platform is using wpa_supplicant and hostapd in monolithic image. Are you planning to support this case? We read your suggestion and it will be a huge change containing all the driver wrappers. As hostap maintainer, you may be more proper to add this feature's framework. And we can implement driver zephyr to support this feature. Is that okay to you? Best regards, Fengming Ye -----Original Message----- From: Krishna Chaitanya Sent: Tuesday, August 13, 2024 5:17 PM To: Hui Bai Cc: Jouni Malinen ; hostap at lists.infradead.org Subject: Re: [EXT] Re: [PATCH] hostapd: Rename event handling functions in hostapd for Caution: This is an external email. Please take care when clicking links or opening attachments. When in doubt, report the message using the 'Report this email' button On Mon, Aug 12, 2024 at 3:39?PM Hui Bai wrote: > > Hi Jouni Malinen, > > Currently on Zephyr, we are using Monolithic build, which means both wpa_supplicant and hostapd files will be built into one single binary. > I didn't quite get your idea of using function pointers to the driver interface. But based on my understanding, even I take your suggestions, the redefinition build error will still occurred with Monolithic build. > > Regards, > Hui Bai > > -----Original Message----- > From: Jouni Malinen > Sent: Saturday, August 10, 2024 3:49 PM > To: Hui Bai > Cc: hostap at lists.infradead.org > Subject: [EXT] Re: [PATCH] hostapd: Rename event handling functions in > hostapd for > > Caution: This is an external email. Please take care when clicking > links or opening attachments. When in doubt, report the message using > the 'Report this email' button > > > On Thu, Jun 13, 2024 at 06:32:01AM +0000, Hui Bai wrote: > > On Zephyr, both wpa_supplicant and hostapd are supported. One compilation error was found due to function name conflict. > > Both wpa_supplicant and hostapd has its own global event and event handlers with same name: > > wpa_supplicant_event > > wpa_supplicant_event_global > > > > To fix the compilation error, rename above functions in hostapd for Zephyr as below: > > hostapd_event > > hostapd_event_global > > This does not look like something that would really work at all in hostap.git, i.e., this is based on something that has other changes and as such, I'm not sure why this particular change should be in hostap.git. > > Those functions have the same name for a reason, i.e., those are the functions that are called from the driver interface code for either hostapd or wpa_supplicant. If there is need to make this work with both hostapd and wpa_supplicant somehow linked into a single binary, the driver wrappers would need changes. For that, the cleaner way of updating the design would be by registering wpa_supplicant_event and wpa_supplicant_event_global as function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. > somehow linked into a single binary, This and a couple of other patches related to single binary using both hostap and wpa_supplicant are in the context of an embedded OS (ZephyrRTOS) where there are only threads and no processes. So, hostapd and WPA supplicant run in separate threads and belong to the same binary and we see conflicts in that case. > For that, the cleaner way of updating the design would be by > registering wpa_supplicant_event and wpa_supplicant_event_global as > function pointers to the driver interface and using those function pointers instead of direct calls. That is something that I could consider applying to hostap.git. I guess what Jouni is proposing is something like below, where we can register both a global and per-interface event callback and both AP and STA interfaces can register their own callback using per-interface callbacks. diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f39ea6560..64a6c169c 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2550,6 +2550,9 @@ enum nested_attr { NESTED_ATTR_UNSPECIFIED = 2, }; + +typedef void (*wpa_event_callback)(void *ctx, enum wpa_event_type event, + union wpa_event_data *data); /** * struct wpa_driver_ops - Driver interface API definition * @@ -2937,7 +2940,7 @@ struct wpa_driver_ops { * use init2() function instead of init() to get the pointer to global * data available to per-interface initializer. */ - void * (*global_init)(void *ctx); + void * (*global_init)(void *ctx, wpa_event_callback cb); /** * global_deinit - Global driver deinitialization @@ -2959,7 +2962,8 @@ struct wpa_driver_ops { * This function can be used instead of init() if the driver wrapper * uses global data. */ - void * (*init2)(void *ctx, const char *ifname, void *global_priv); + void * (*init2)(void *ctx, const char *ifname, void *global_priv, + wpa_event_callback cb); /** * get_interfaces - Get information about available interfaces From jsoloveckis at maxlinear.com Wed Aug 21 00:34:49 2024 From: jsoloveckis at maxlinear.com (Jurijs Soloveckis) Date: Wed, 21 Aug 2024 07:34:49 +0000 Subject: [PATCH] Multi-AP: wpa_supplicant: added support for VLAN ID and Multi-AP profile parsing Message-ID: For Multi-AP traffic separation requirement, wpa_supplicant parses 802.1Q Multi-AP sub-element and reports: - VLAN ID of the AP it connects to. - Multi-AP profile of the AP it connects to. Signed-off-by: Jurijs Soloveckis --- wpa_supplicant/config_ssid.h | 7 +++++++ wpa_supplicant/events.c | 12 ++++++++++++ wpa_supplicant/wpa_supplicant.c | 7 +++++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index d64c30508..48e4a1da0 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -1192,6 +1192,13 @@ struct wpa_ssid { */ int multi_ap_profile; + /** + * multi_ap_primary_vlanid - Multi-AP Primary VLAN ID (Multi-AP Specification v2.0) + * 0 = VLAN ID not set + * 1-4094 = VLAN ID + */ + u16 multi_ap_primary_vlanid; + /** * beacon_prot - Whether Beacon protection is enabled * diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 724f2413f..d80b65add 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3093,6 +3093,7 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, { struct ieee802_11_elems elems; struct multi_ap_params multi_ap; + struct wpa_ssid *ssid = wpa_s->current_ssid; u16 status; wpa_s->multi_ap_ie = 0; @@ -3112,6 +3113,17 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, wpa_s->multi_ap_fronthaul = !!(multi_ap.capability & MULTI_AP_FRONTHAUL_BSS); wpa_s->multi_ap_ie = 1; + + if (!ssid) + return; + + ssid->multi_ap_primary_vlanid = 0; + + if (wpa_s->multi_ap_backhaul) { + ssid->multi_ap_profile = multi_ap.profile; + if (ssid->multi_ap_backhaul_sta) + ssid->multi_ap_primary_vlanid = multi_ap.vlanid; + } } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 81858327b..c29fb562c 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1114,11 +1114,14 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to " - MACSTR " completed [id=%d id_str=%s%s]%s", + MACSTR " completed [id=%d id_str=%s%s]%s" + " multi_ap_profile=%d multi_ap_primary_vlanid=%d", MAC2STR(wpa_s->bssid), ssid ? ssid->id : -1, ssid && ssid->id_str ? ssid->id_str : "", - fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr); + fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr, + ssid ? ssid->multi_ap_profile : 0, + ssid ? ssid->multi_ap_primary_vlanid : 0); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ wpas_clear_temp_disabled(wpa_s, ssid, 1); wpa_s->consecutive_conn_failures = 0; -- 2.17.1 From geomatsi at gmail.com Wed Aug 21 14:03:41 2024 From: geomatsi at gmail.com (Sergey Matyukevich) Date: Thu, 22 Aug 2024 00:03:41 +0300 Subject: [PATCH] macsec_linux: hardware offload requires Linux headers >= v5.7 Message-ID: <20240821210348.1665468-1-geomatsi@gmail.com> Hardware offload in Linux macsec driver is enabled in compile time if libnl version is >= v3.6. This is not sufficient for successful build since enum 'macsec_offload' has been added to Linux header if_link.h in kernels v5.6 and v5.7, see commits: - https://github.com/torvalds/linux/commit/21114b7feec29e4425a3ac48a037569c016a46c8 - https://github.com/torvalds/linux/commit/76564261a7db80c5f5c624e0122a28787f266bdf New libnl with older Linux headers is a valid combination. This is how hostapd build failure has been detected by Buildroot autobuilder, see: - http://autobuild.buildroot.net/results/b59d5bc5bd17683a3a1e3577c40c802e81911f84/ Extend compile time condition for the enablement of the macsec hardware offload adding Linux headers version check. Fixes: 40c139664439 ("macsec_linux: Add support for MACsec hardware offload") Signed-off-by: Sergey Matyukevich --- src/drivers/driver_macsec_linux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c index c86715498..9ad24183e 100644 --- a/src/drivers/driver_macsec_linux.c +++ b/src/drivers/driver_macsec_linux.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "utils/common.h" @@ -32,7 +33,7 @@ #define UNUSED_SCI 0xffffffffffffffff -#if LIBNL_VER_NUM >= LIBNL_VER(3, 6) +#if (LIBNL_VER_NUM >= LIBNL_VER(3, 6) && LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)) #define LIBNL_HAS_OFFLOAD #endif -- 2.45.2 From neustradamus at hotmail.com Thu Aug 22 22:31:38 2024 From: neustradamus at hotmail.com (* Neustradamus *) Date: Fri, 23 Aug 2024 05:31:38 +0000 Subject: hostapd/wpa_supplicant - new release v2.11 In-Reply-To: References: Message-ID: Dear Jouni, Thanks a lot for this new version "2.11 (2024-07-20)" of hostap/wpa_supplicant which arrives several years after the 2.10 (2022-01-16) with CVE fixes. A lot of people have requested it since a long time like me. We hope more releases now and minor releases at each CVE, security is very important. Regards, Neustradamus ________________________________________ From: Hostap on behalf of Jouni Malinen Sent: Saturday, July 20, 2024 20:38 To: hostap at lists.infradead.org Subject: hostapd/wpa_supplicant - new release v2.11 New versions of wpa_supplicant and hostapd were just released and are now available from https://w1.fi/ This release follows the v2.x style with the release being made directly from the main branch and the main branch moving now to 2.12 development. There has been quite a few new features and fixes since the 2.10 release. The following ChangeLog entries highlight some of the main changes: hostapd: * Wi-Fi Easy Connect - add support for DPP release 3 - allow Configurator parameters to be provided during config exchange * HE/IEEE 802.11ax/Wi-Fi 6 - various fixes * EHT/IEEE 802.11be/Wi-Fi 7 - add preliminary support * SAE: add support for fetching the password from a RADIUS server * support OpenSSL 3.0 API changes * support background radar detection and CAC with some additional drivers * support RADIUS ACL/PSK check during 4-way handshake (wpa_psk_radius=3) * EAP-SIM/AKA: support IMSI privacy * improve 4-way handshake operations - use Secure=1 in message 3 during PTK rekeying * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases to avoid interoperability issues * support new SAE AKM suites with variable length keys * support new AKM for 802.1X/EAP with SHA384 * extend PASN support for secure ranging * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) - this is based on additional details being added in the IEEE 802.11 standard - the new implementation is not backwards compatible * improved ACS to cover additional channel types/bandwidths * extended Multiple BSSID support * fix beacon protection with FT protocol (incorrect BIGTK was provided) * support unsynchronized service discovery (USD) * add preliminary support for RADIUS/TLS * add support for explicit SSID protection in 4-way handshake (a mitigation for CVE-2023-52424; disabled by default for now, can be enabled with ssid_protection=1) * fix SAE H2E rejected groups validation to avoid downgrade attacks * use stricter validation for some RADIUS messages * a large number of other fixes, cleanup, and extensions wpa_supplicant: * Wi-Fi Easy Connect - add support for DPP release 3 - allow Configurator parameters to be provided during config exchange * MACsec - add support for GCM-AES-256 cipher suite - remove incorrect EAP Session-Id length constraint - add hardware offload support for additional drivers * HE/IEEE 802.11ax/Wi-Fi 6 - support BSS color updates - various fixes * EHT/IEEE 802.11be/Wi-Fi 7 - add preliminary support * support OpenSSL 3.0 API changes * improve EAP-TLS support for TLSv1.3 * EAP-SIM/AKA: support IMSI privacy * improve mitigation against DoS attacks when PMF is used * improve 4-way handshake operations - discard unencrypted EAPOL frames in additional cases - use Secure=1 in message 2 during PTK rekeying * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases to avoid interoperability issues * support new SAE AKM suites with variable length keys * support new AKM for 802.1X/EAP with SHA384 * improve cross-AKM roaming with driver-based SME/BSS selection * PASN - extend support for secure ranging - allow PASN implementation to be used with external programs for Wi-Fi Aware * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) - this is based on additional details being added in the IEEE 802.11 standard - the new implementation is not backwards compatible, but PMKSA caching with FT-EAP was, and still is, disabled by default * support a pregenerated MAC (mac_addr=3) as an alternative mechanism for using per-network random MAC addresses * EAP-PEAP: require Phase 2 authentication by default (phase2_auth=1) to improve security for still unfortunately common invalid configurations that do not set ca_cert * extend SCS support for QoS Characteristics * extend MSCS support * support unsynchronized service discovery (USD) * add support for explicit SSID protection in 4-way handshake (a mitigation for CVE-2023-52424; disabled by default for now, can be enabled with ssid_protection=1) - in addition, verify SSID after key setup when beacon protection is used * fix SAE H2E rejected groups validation to avoid downgrade attacks * a large number of other fixes, cleanup, and extensions git-shortlog for 2.10 -> 2.11: There were 2295 commits, so the list would be a too long for this email. Anyway, if you are interested in the details, they are available in the hostap.git repository. diffstat has following to say about the changes: 534 files changed, 85965 insertions(+), 16847 deletions(-) -- Jouni Malinen PGP id EFC895FA _______________________________________________ Hostap mailing list Hostap at lists.infradead.org http://lists.infradead.org/mailman/listinfo/hostap From chin-ran.lo at nxp.com Fri Aug 23 02:41:16 2024 From: chin-ran.lo at nxp.com (Chin-Ran Lo) Date: Fri, 23 Aug 2024 09:41:16 +0000 Subject: [PATCH v7 1/2] Add the similar USD APIs to dbus control interface that other apps can use the functions In-Reply-To: References: Message-ID: >From 9e243e683d16cf07387dced941dca56287bc5fee Mon Sep 17 00:00:00 2001 From: "Lo,Chin-Ran" Date: Mon, 15 Jul 2024 14:01:11 +0800 Subject: [v7 1/2] USD: Move control interface events to notify.c This separates the control interface specific generation of a text event message away from the main implementation of USD and makes it more convenient to add support for other control interface mechanisms like dbus. Signed-off-by: Lo,Chin-Ran --- Changelog since v6: * Separate dbus parameters as its individual type * Add the missing method, nan-update-publish * Add the missing signal parameters: FSD, FSD-GAS * Add the NANReplied event. * Add the information to doc/dbus.doxygen wpa_supplicant/nan_usd.c | 65 ++++-------------------- wpa_supplicant/notify.c | 104 +++++++++++++++++++++++++++++++++++++++ wpa_supplicant/notify.h | 23 +++++++++ 3 files changed, 137 insertions(+), 55 deletions(-) diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c index 657b302c1..6efc70fa7 100644 --- a/wpa_supplicant/nan_usd.c +++ b/wpa_supplicant/nan_usd.c @@ -13,6 +13,7 @@ #include "wpa_supplicant_i.h" #include "offchannel.h" #include "driver_i.h" +#include "notify.h" #include "nan_usd.h" @@ -241,19 +242,10 @@ wpas_nan_de_discovery_result(void *ctx, int subscribe_id, const u8 *peer_addr, bool fsd, bool fsd_gas) { struct wpa_supplicant *wpa_s = 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(wpa_s, 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); + wpas_notify_nan_discovery_result(wpa_s, srv_proto_type, subscribe_id, + peer_publish_id, peer_addr, fsd, + fsd_gas, ssi, ssi_len); } @@ -263,34 +255,9 @@ static void wpas_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr, const u8 *ssi, size_t ssi_len) { struct wpa_supplicant *wpa_s = 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(wpa_s, 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"; + wpas_notify_nan_replied(wpa_s, srv_proto_type, publish_id, + peer_subscribe_id, peer_addr, ssi, ssi_len); } @@ -299,9 +266,7 @@ static void wpas_nan_de_publish_terminated(void *ctx, int publish_id, { struct wpa_supplicant *wpa_s = ctx; - wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED - "publish_id=%d reason=%s", - publish_id, nan_reason_txt(reason)); + wpas_notify_nan_publish_terminated(wpa_s, publish_id, reason); } @@ -310,9 +275,7 @@ static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id, { struct wpa_supplicant *wpa_s = ctx; - wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED - "subscribe_id=%d reason=%s", - subscribe_id, nan_reason_txt(reason)); + wpas_notify_nan_subscribe_terminated(wpa_s, subscribe_id, reason); } @@ -321,17 +284,9 @@ static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id, const u8 *peer_addr) { struct wpa_supplicant *wpa_s = 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(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); - os_free(ssi_hex); + wpas_notify_nan_receive(wpa_s, id, peer_instance_id, peer_addr, + ssi, ssi_len); } diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 745234dda..7a1222f37 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/wpa_ctrl.h" +#include "common/nan_de.h" #include "config.h" #include "wpa_supplicant_i.h" #include "wps_supplicant.h" @@ -1036,3 +1037,106 @@ void wpas_notify_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, wpas_dbus_signal_hs20_t_c_acceptance(wpa_s, url); } #endif /* CONFIG_HS20 */ + + +#ifdef CONFIG_NAN_USD + +void wpas_notify_nan_discovery_result(struct wpa_supplicant *wpa_s, + enum nan_service_protocol_type + srv_proto_type, + int subscribe_id, int peer_publish_id, + const u8 *peer_addr, + bool fsd, bool fsd_gas, + const u8 *ssi, size_t ssi_len) +{ + 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(wpa_s, 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); +} + + +void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s, + enum nan_service_protocol_type srv_proto_type, + int publish_id, int peer_subscribe_id, + const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ + 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(wpa_s, 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); +} + + +void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id, + int peer_instance_id, const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ + 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(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); + 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"; +} + + +void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s, + int publish_id, + enum nan_de_reason reason) +{ + wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED + "publish_id=%d reason=%s", + publish_id, nan_reason_txt(reason)); +} + + +void wpas_notify_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, + int subscribe_id, + enum nan_de_reason reason) +{ + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED + "subscribe_id=%d reason=%s", + subscribe_id, nan_reason_txt(reason)); +} + +#endif /* CONFIG_NAN_USD */ diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 2a0cf097a..31463c15c 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -17,6 +17,8 @@ struct wps_event_fail; struct tls_cert_data; struct wpa_cred; struct rsn_pmksa_cache_entry; +enum nan_de_reason; +enum nan_service_protocol_type; int wpas_notify_supplicant_initialized(struct wpa_global *global); void wpas_notify_supplicant_deinitialized(struct wpa_global *global); @@ -171,5 +173,26 @@ void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s, void wpas_notify_signal_change(struct wpa_supplicant *wpa_s); void wpas_notify_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url); +void wpas_notify_nan_discovery_result(struct wpa_supplicant *wpa_s, + enum nan_service_protocol_type + srv_proto_type, + int subscribe_id, int peer_publish_id, + const u8 *peer_addr, + bool fsd, bool fsd_gas, + const u8 *ssi, size_t ssi_len); +void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s, + enum nan_service_protocol_type srv_proto_type, + int publish_id, int peer_subscribe_id, + const u8 *peer_addr, + 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 *ssi, size_t ssi_len); +void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s, + int publish_id, + enum nan_de_reason reason); +void wpas_notify_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, + int subscribe_id, + enum nan_de_reason reason); #endif /* NOTIFY_H */ -- 2.21.0.windows.1 From chin-ran.lo at nxp.com Fri Aug 23 02:41:19 2024 From: chin-ran.lo at nxp.com (Chin-Ran Lo) Date: Fri, 23 Aug 2024 09:41:19 +0000 Subject: [PATCH v7 2/2] Add the similar USD APIs to dbus control interface that other apps can use the functions In-Reply-To: References: Message-ID: >From 31c6a62ed5a2bab21a3a98466c2f5b20ed704657 Mon Sep 17 00:00:00 2001 From: "Lo,Chin-Ran" Date: Mon, 15 Jul 2024 14:01:11 +0800 Subject: [v7 2/2] dbus: Add API for USD USD had a control interface commands and events defined for it. Extend this by providing similar USD APIs through the dbus control interface. Signed-off-by: Lo,Chin-Ran --- doc/dbus.doxygen | 71 ++++ src/common/nan_de.h | 2 +- wpa_supplicant/dbus/dbus_new.c | 339 +++++++++++++++ wpa_supplicant/dbus/dbus_new.h | 56 +++ wpa_supplicant/dbus/dbus_new_handlers.c | 533 ++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new_handlers.h | 14 + wpa_supplicant/dbus/dbus_new_helpers.h | 24 ++ wpa_supplicant/notify.c | 16 + 8 files changed, 1054 insertions(+), 1 deletion(-) diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen index 4c5f5f9e9..a1f075a25 100644 --- a/doc/dbus.doxygen +++ b/doc/dbus.doxygen @@ -412,6 +412,77 @@ fi.w1.wpa_supplicant1.CreateInterface.
Invalid entries were found in the passed argument.
+
  • +

    NANPublish ( (sybbbqbbbqqqqvv) : nan_args ) --> nothing

    +

    Set the parameters of nan-publish for the interface.

    +

    Arguments

    +
    +
    (sybbbqbbbqqqqvv) : nan_args
    +
    Structure of publish parameters.
    +
    +

    Possible errors

    +
    +
    fi.w1.wpa_supplicant1.NoMemory
    +
    Needed memory was not possible to get allocated.
    +
    fi.w1.wpa_supplicant1.InvalidArgs
    +
    Invalid entries were found in the passed argument.
    +
    +
  • +
  • +

    NANCancelPublish ( i : nan_args ) --> nothing

    +

    Cancel the previous nan-publish for the interface.

    +

    Arguments

    +
    +
    i : nan_args
    +
    publish id.
    +
    +
  • +
  • +

    NANUpdatePublish ( (iqv) : nan_args ) --> nothing

    +

    Update the SSI of the previous nan-publish for the interface.

    +

    Arguments

    +
    +
    (iqv) : nan_args
    +
    publish id and SSI.
    +
    +
  • +
  • +

    NANSubscribe ( (syyqqqv) : nan_args ) --> nothing

    +

    Set the parameters of the nan-usd subscription for the interface.

    +

    Arguments

    +
    +
    (syyqqqv) : nan_args
    +
    Structure of subscribe parameters.
    +
    +

    Possible errors

    +
    +
    fi.w1.wpa_supplicant1.InvalidArgs
    +
    Invalid entries were found in the passed argument.
    +
    +
  • +
  • +

    NANCancelSubscribe ( i : nan_args ) --> nothing

    +

    Cancel the previous subscription for the interface.

    +

    Arguments

    +
    +
    i : nan_args
    +
    Subscription id.
    +
    +
  • +
  • +

    NANTransmit ( (yysqv) : nan_args ) --> nothing

    +

    Send the follow-up packet for the interface.

    +

    Arguments

    +
    +
    (yysqv) : nan_args
    +
    Parameters of the follow-up packet.
    +
    +

    Possible errors

    +
    +
    fi.w1.wpa_supplicant1.InvalidArgs
    +
    Invalid entries were found in the passed argument.
    +
    +
  • TDLSDiscover ( s : peer_address ) --> nothing

    Initiate a TDLS discovery for a peer.

    diff --git a/src/common/nan_de.h b/src/common/nan_de.h index 359c8a541..5db6d3f1b 100644 --- a/src/common/nan_de.h +++ b/src/common/nan_de.h @@ -96,7 +96,7 @@ struct nan_publish_params { unsigned int freq; /* Multi-channel frequencies (publishChannelList) */ - const int *freq_list; + int *freq_list; /* Announcement period in ms; 0 = use default */ unsigned int announcement_period; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 00b38edf5..98abf196a 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -3605,6 +3605,52 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { } }, #endif /* CONFIG_AUTOSCAN */ +#ifdef CONFIG_NAN_USD + { "NANPublish", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_publish, + { + { "nan_args", "(sybbbqbbbqqqqvv)", ARG_IN }, + { "publish_id", "i", ARG_OUT }, + END_ARGS + } + }, + { "NANCancelPublish", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_cancel_publish, + { + { "nan_args", "i", ARG_IN }, + END_ARGS + } + }, + { "NANUpdatePublish", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_update_publish, + { + { "nan_args", "(iqv)", ARG_IN }, + END_ARGS + } + }, + { "NANSubscribe", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_subscribe, + { + { "nan_args", "(syyqqqv)", ARG_IN }, + { "subscribe_id", "i", ARG_OUT }, + END_ARGS + } + }, + { "NANCancelSubscribe", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_cancel_subscribe, + { + { "nan_args", "i", ARG_IN }, + END_ARGS + } + }, + { "NANTransmit", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_nan_transmit, + { + { "nan_args", "(yysqv)", ARG_IN }, + END_ARGS + } + }, +#endif /* CONFIG_NAN_USD */ #ifdef CONFIG_TDLS { "TDLSDiscover", WPAS_DBUS_NEW_IFACE_INTERFACE, (WPADBusMethodHandler) wpas_dbus_handler_tdls_discover, @@ -3983,6 +4029,38 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, +#ifdef CONFIG_NAN_USD + { "NANDiscoveryresult", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "success", "b", ARG_OUT }, + { "discov_info", "a{sv}", ARG_OUT }, + { "ssi", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "NANReceive", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "nanrx_info", "a{sv}", ARG_OUT }, + { "ssi", "a{sv}", ARG_OUT }, + END_ARGS + } + }, + { "NanPublishterminated", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "publish_id", "i", ARG_OUT }, + { "reason", "i", ARG_OUT }, + END_ARGS + } + }, + { "NanSubscribeterminated", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "term_subscribe_id", "i", ARG_OUT }, + { "reason", "i", ARG_OUT }, + END_ARGS + } + }, + +#endif /* CONFIG_NAN_USD */ { "BSSAdded", WPAS_DBUS_NEW_IFACE_INTERFACE, { { "path", "o", ARG_OUT }, @@ -5186,3 +5264,264 @@ void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, dbus_message_unref(msg); } #endif /* CONFIG_HS20 */ + + +#ifdef CONFIG_NAN_USD + +/** + * wpas_dbus_signal_nan_discoveryresult - Send NAN discovery result signal + * @wpa_s: %wpa_supplicant network interface data + * @subscribe_id: Subscribe id of the session + * @peer_publish_id: Publish id of the sender + * @peer_addr: MAC address of the peer device + * @ssi: Service specific information payload + * @ssi_len: Length of the SSI field + * + * Notify the discovery-result + */ +void wpas_dbus_signal_nan_discovery_result(struct wpa_supplicant *wpa_s, + int subscribe_id, + int peer_publish_id, + const u8 *peer_addr, + bool fsd, bool fsd_gas, + const u8 *ssi, size_t ssi_len) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + dbus_bool_t succ; + struct wpa_dbus_discov_info disc_info; + + iface = wpa_s->global->dbus; + + /* Do nothing if the interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NanDiscoveryresult"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + succ = TRUE; + disc_info.subscribe_id = subscribe_id; + disc_info.peer_publish_id = peer_publish_id; + memcpy(disc_info.peer_addr, peer_addr, ETH_ALEN); + disc_info.fsd = fsd; + disc_info.fsd_gas = fsd_gas; + disc_info.ssi_len = ssi_len; + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &succ) || + !wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "discov_info", + (const char *) &disc_info, + sizeof(disc_info)) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "ssi", + (const char *) ssi, + ssi_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + +/** + * wpas_dbus_signal_nan_replied - Send NAN Replied signal + * @wpa_s: %wpa_supplicant network interface data + * @publish_id: Publish id of the session + * @peer_subscribe_id: Subscribe id of the sender + * @peer_addr: MAC address of the peer device + * @ssi: Service specific information payload + * @ssi_len: Length of the SSI field + * + * Notify the discovery-result + */ +void wpas_dbus_signal_nan_replied(struct wpa_supplicant *wpa_s, + int publish_id, + int peer_subscribe_id, + const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + dbus_bool_t succ; + struct wpa_dbus_reply_info reply_info; + wpa_printf(MSG_INFO, "DBUS NanReplied"); + + iface = wpa_s->global->dbus; + + /* Do nothing if the interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NanReplied"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + succ = TRUE; + reply_info.publish_id = publish_id; + reply_info.peer_subscribe_id = peer_subscribe_id; + memcpy(reply_info.peer_addr, peer_addr, ETH_ALEN); + reply_info.ssi_len = ssi_len; + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &succ) || + !wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "reply_info", + (const char *) &reply_info, + sizeof(reply_info)) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "ssi", + (const char *) ssi, + ssi_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_nan_receive - Send receive NAN USD packet signal + * @wpa_s: %wpa_supplicant network interface data + * @id: Subscribe id + * @peer_id: Id of the sender + * @peer_addr: address of the sender + * @ssi: Service specific information payload + * @ssi_len: Length of the SSID + * + * Notify while getting the follow-up packet + */ +void wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s, + int id, int peer_id, const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter, dict_iter; + struct wpa_dbus_nanrx_info nanrx_info; + + iface = wpa_s->global->dbus; + + /* Do nothing if the interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NanReceive"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + nanrx_info.id = id; + nanrx_info.peer_id = peer_id; + memcpy(nanrx_info.peer_addr, peer_addr, ETH_ALEN); + nanrx_info.ssi_len = ssi_len; + + if (!wpa_dbus_dict_open_write(&iter, &dict_iter) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "nanrx_info", + (const char *) &nanrx_info, + sizeof(nanrx_info)) || + !wpa_dbus_dict_append_byte_array(&dict_iter, "ssi", + (const char *) ssi, + ssi_len) || + !wpa_dbus_dict_close_write(&iter, &dict_iter)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_nan_publish_terminated - Send publish-terminated signal + * @wpa_s: %wpa_supplicant network interface data + * @publish_id: The publish_id of the session + * @reason: The reason of the termination + * + * Notify while the session is expired + */ +void wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s, + int publish_id, int reason) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + dbus_int32_t dpub_id = publish_id; + dbus_int32_t dreason = reason; + + iface = wpa_s->global->dbus; + + /* Do nothing if the interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NanPublishterminated"); + if (!msg) + return; + + if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, &dpub_id, + DBUS_TYPE_INVALID) || + !dbus_message_append_args(msg, DBUS_TYPE_INT32, &dreason, + DBUS_TYPE_INVALID)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else { + dbus_connection_send(iface->con, msg, NULL); + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED + "wpas_dbus_signal_nan_subscribe_terminated() dbus_connection_send (int)"); + } + dbus_message_unref(msg); +} + + +/** + * wpas_dbus_signal_nan_subscribe_terminated - Send subscribe-terminated signal + * @wpa_s: %wpa_supplicant network interface data + * @subscribe_id: The subscribe_id of the session + * @reason: The reason of the termination + * + * Notify while the session is expired. + */ +void wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, + int subscribe_id, int reason) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + dbus_int32_t dsub_id = subscribe_id; + dbus_int32_t dreason = reason; + + iface = wpa_s->global->dbus; + + /* Do nothing if the interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "NanSubscribeterminated"); + if (!msg) + return; + + if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, &dsub_id, + DBUS_TYPE_INVALID) || + !dbus_message_append_args(msg, DBUS_TYPE_INT32, &dreason, + DBUS_TYPE_INVALID)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else { + dbus_connection_send(iface->con, msg, NULL); + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED + "wpas_dbus_signal_nan_subscribe_terminated() dbus_connection_send (int)"); + } + + dbus_message_unref(msg); +} + +#endif /* CONFIG_NAN_USD */ diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index b653f10f9..7a222c01c 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -21,6 +21,7 @@ struct wpa_bss; struct wps_event_m2d; struct wps_event_fail; struct wps_credential; +struct wpa_dbus_discov_info; enum wpas_dbus_prop { WPAS_DBUS_PROP_AP_SCAN, @@ -281,6 +282,24 @@ void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s, void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s); void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url); +void wpas_dbus_signal_nan_discovery_result(struct wpa_supplicant *wpa_s, + int subscribe_id, + int peer_publish_id, + const u8 *peer_addr, + bool fsd, bool fsd_gas, + const u8 *ssi, size_t ssi_len); +void wpas_dbus_signal_nan_replied(struct wpa_supplicant *wpa_s, + int publish_id, + int peer_subscribe_id, + const u8 *peer_addr, + const u8 *ssi, size_t ssi_len); +void wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s, + int id, int peer_id, const u8 *peer_addr, + const u8 *ssi, size_t ssi_len); +void wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s, + int publish_id, int reason); +void wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, + int subscribe_id, int reason); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -658,6 +677,43 @@ void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, { } +static inline void +wpas_dbus_signal_nan_discovery_result(struct wpa_supplicant *wpa_s, + int subscribe_id, + int peer_publish_id, const u8 *peer_addr, + bool fsd, bool fsd_gas, + const u8 *ssi, size_t ssi_len) +{ +} + +static inline void +wpas_dbus_signal_nan_replied(struct wpa_supplicant *wpa_s, + int publish_id, + int peer_subscribe_id, const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ +} + + +static inline void +wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s, + int id, int peer_id, const u8 *peer_addr, + const u8 *ssi, size_t ssi_len) +{ +} + +static inline void +wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s, + int publish_id, int reason) +{ +} + +static inline void +wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, + int subscribe_id, int reason) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 6ad49a136..bc5a6d65e 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -12,6 +12,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/nan_de.h" #include "eap_peer/eap_methods.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" @@ -27,6 +28,7 @@ #include "../autoscan.h" #include "../ap.h" #include "../interworking.h" +#include "../nan_usd.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" @@ -2706,6 +2708,537 @@ DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, } +#ifdef CONFIG_NAN_USD +#define MAX_NAN_SRV_NAME_LEN 256 +#define NAN_FREQ_LIST_ALL 0xff + +int unit_len(int dbus_type) +{ + switch (dbus_type) { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + return 1; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return 2; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + return 4; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + return 8; + } + return 0; +} +static bool get_gvariant_items(DBusMessageIter *piter, int type, void* datpt, u32 dat_buf_len) +{ + int rtype = dbus_message_iter_get_arg_type(piter); + + if (rtype == DBUS_TYPE_VARIANT) { + DBusMessageIter subiter; + dbus_message_iter_recurse(piter, &subiter); + dbus_message_iter_next(piter); + return get_gvariant_items(&subiter, type, datpt, dat_buf_len); + } else if (rtype == DBUS_TYPE_ARRAY) { + DBusMessageIter array_iter; + int offset=0; + int ulen; + int arytype; + dbus_message_iter_recurse(piter, &array_iter); + dbus_message_iter_next(piter); + // Loop through the array + arytype = dbus_message_iter_get_arg_type(&array_iter); + if (arytype != type) { + wpa_printf(MSG_ERROR, "Item type: (exp, get)=(%c, %c)", type, arytype); + return false; + } + ulen = unit_len(arytype); + while ((arytype = dbus_message_iter_get_arg_type(&array_iter)) != DBUS_TYPE_INVALID) { + if (arytype != type) { + wpa_printf(MSG_ERROR, "Item type: (exp, get)=(%c, %c)", type, arytype); + return false; + } + dbus_message_iter_get_basic(&array_iter, (datpt+offset)); + dbus_message_iter_next(&array_iter); + offset+= ulen; + if ((offset+ulen) > dat_buf_len) { + wpa_printf(MSG_WARNING, "end_of_buffer(%d, %d, %u)", offset, ulen, dat_buf_len); + break; + } + } + } else { + if (rtype != type) { + wpa_printf(MSG_ERROR, "Item type: (exp, get)=(%c, %c)", type, rtype); + return false; + } + dbus_message_iter_get_basic(piter, datpt); + dbus_message_iter_next(piter); + } + return true; +} +/* + * wpas_dbus_handler_nan_publish - Send out NAN publish packets + * @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 "NANPublish" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_nan_publish(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int publish_id; + /* Parameters from DBUS */ + char service_name[MAX_NAN_SRV_NAME_LEN]; + char *psrv_name; + enum nan_service_protocol_type srv_proto_type=0; + u8 solicited; + u8 unsolicited; + u8 solicited_multicast; + u8 disable_events; + u8 fsd; + u8 fsd_gas; + u16 announcement_period; + u16 freq=0; + u16 freq_list_len; + u16 ssi_len; + u16 ttl; + DBusMessageIter iter, subiter; + + struct nan_publish_params params; + struct wpabuf *freq_list = NULL; + struct wpabuf *ssi = NULL; + + wpa_printf(MSG_INFO, "DBUS NAN_PUBLISH:"); + os_memset(¶ms, 0, sizeof(params)); + os_memset(service_name, 0, sizeof(service_name)); + + // Get the parameters from dbus + dbus_message_iter_init(message, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_INFO, "Unexpected, arg is not struct"); + goto fail; + } + // Open the structure + dbus_message_iter_recurse(&iter, &subiter); + // Extract the elements + if (get_gvariant_items(&subiter, DBUS_TYPE_STRING, (void*)&psrv_name, sizeof(&psrv_name)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching srv_name"); + goto fail; + } + strncpy(service_name, psrv_name, MAX_NAN_SRV_NAME_LEN-1); + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)&srv_proto_type, sizeof(u8)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching srv_proto_type"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&solicited, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching solicited"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&unsolicited, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching solicited"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&solicited_multicast, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching solicited_multicast"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ttl, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ttl"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&disable_events, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching disable_events"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&fsd, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching fsd"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BOOLEAN, (void*)&fsd_gas, sizeof(bool)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching fsd_gas"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&freq, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching freq"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&announcement_period, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching announcement_period"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ssi_len, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi_len"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&freq_list_len, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching freq_list_len"); + goto fail; + } + if (ssi_len > 0) { + ssi = wpabuf_alloc(ssi_len); + if (ssi == NULL) { + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)ssi->buf, ssi_len) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi"); + goto fail; + } + ssi->used= ssi_len; + } + if (freq_list_len > 0) { + if (freq_list_len == NAN_FREQ_LIST_ALL) { + params.freq_list = wpas_nan_usd_all_freqs(wpa_s); + } else if (freq_list_len > 0) { + freq_list = wpabuf_alloc(freq_list_len); + if (freq_list == NULL) { + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)freq_list->buf, (sizeof(u16)*freq_list_len)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching freq_list"); + goto fail; + } + params.freq_list = (int *)freq_list->buf; + } + } + + wpa_printf(MSG_INFO, "service_name:[%s]", service_name); + wpa_printf(MSG_INFO, "srv_proto_type:[%u]", srv_proto_type); + wpa_printf(MSG_INFO, "solicited:[%d]", solicited); + wpa_printf(MSG_INFO, "unsolicited:[%d]", unsolicited); + wpa_printf(MSG_INFO, "ttl:[%u]", ttl); + wpa_printf(MSG_INFO, "freq:[%u]", freq); + wpa_printf(MSG_INFO, "freq_list_len:[%u]", freq_list_len); + wpa_hexdump(MSG_MSGDUMP, "freq_list", params.freq_list, freq_list_len*sizeof(u16)); + wpa_printf(MSG_INFO, "ssi_len:[%u]", ssi_len); + wpa_hexdump(MSG_MSGDUMP, "publish_ssi:", ssi->buf, ssi_len); + + params.ttl = ttl; + params.solicited = solicited; + params.unsolicited = unsolicited; + params.freq = freq; + params.fsd = freq; + publish_id = wpas_nan_usd_publish(wpa_s, service_name, srv_proto_type, + ssi, ¶ms); + if (publish_id > 0) { + DBusMessage *reply; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_INT32, + &publish_id, DBUS_TYPE_INVALID); + return reply; + } +fail: + wpabuf_free(ssi); + wpabuf_free(freq_list); + return wpas_dbus_error_unknown_error( + message, "error publishing nan-usd"); +} + +/* + * wpas_dbus_handler_nan_cancel_publish - Cancel the 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 "NANCancelPublish" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_nan_cancel_publish(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int publish_id = -1; + + wpa_printf(MSG_INFO, "DBUS NAN_CANCEL_PUBLISH:"); + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_INT32, &publish_id, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_DEBUG, " DBUS NAN_CANCEL_PUBLISH, failed to get args "); + return NULL; + } + + if ((!wpa_s->nan_de) || (publish_id == -1)) + return NULL; + wpa_printf(MSG_INFO, "DBUS NAN_CANCEL_PUBLISH: %d", publish_id); + nan_de_cancel_publish(wpa_s->nan_de, publish_id); + return NULL; +} + +/* + * wpas_dbus_handler_nan_update_publish - Update the publish ssi + * @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 "NANUpdatePublish" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_nan_update_publish(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int publish_id = -1; + u16 ssi_len; + struct wpabuf *ssi = NULL; + DBusMessageIter iter, subiter; + + wpa_printf(MSG_INFO, "DBUS NAN_UPDATE_PUBLISH:"); + // Get the parameters from dbus + dbus_message_iter_init(message, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_INFO, "Unexpected, arg is not struct"); + goto fail; + } + // Open the structure + dbus_message_iter_recurse(&iter, &subiter); + // Extract the elements + if (get_gvariant_items(&subiter, DBUS_TYPE_INT32, (void*)&publish_id, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching publish_id"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ssi_len, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi_len"); + goto fail; + } + if (ssi_len > 0) { + ssi = wpabuf_alloc(ssi_len); + if (ssi == NULL) { + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)ssi->buf, ssi_len) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi"); + goto fail; + } + ssi->used= ssi_len; + } + if ((!wpa_s->nan_de) || (publish_id == -1)) + return NULL; + wpa_printf(MSG_INFO, "DBUS NAN_UPDATE_PUBLISH: %d", publish_id); + nan_de_update_publish(wpa_s->nan_de, publish_id, ssi); + + return NULL; +fail: + wpabuf_free(ssi); + return wpas_dbus_error_unknown_error( + message, "error updating nan-usd publish ssi"); +} + + +/* + * wpas_dbus_handler_nan_subscribe - Send out nan-subscribe packets + * @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 "NANSubscribe" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_nan_subscribe(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int subscribe_id; + struct nan_subscribe_params params; + + char service_name[MAX_NAN_SRV_NAME_LEN]; + char *psrv_name; + enum nan_service_protocol_type srv_proto_type=0; + u8 is_active; + u16 ttl; + u16 freq=0; + u16 ssi_len; + struct wpabuf *ssi = NULL; + DBusMessageIter iter, subiter; + + wpa_printf(MSG_INFO, "DBUS NAN_SUBSCRIBE: "); + os_memset(¶ms, 0, sizeof(params)); + + // Get the parameters from dbus + dbus_message_iter_init(message, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_INFO, "Unexpected, arg is not struct"); + goto fail; + } + // Open the structure + dbus_message_iter_recurse(&iter, &subiter); + // Extract the elements + if (get_gvariant_items(&subiter, DBUS_TYPE_STRING, (void*)&psrv_name, sizeof(&psrv_name)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching srv_name"); + goto fail; + } + strncpy(service_name, psrv_name, MAX_NAN_SRV_NAME_LEN-1); + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)&srv_proto_type, sizeof(u8)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching srv_proto_type"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)&is_active, sizeof(u8)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching is_active"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ttl, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ttl"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&freq, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching freq"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ssi_len, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi_len"); + goto fail; + } + if (ssi_len > 0) { + ssi = wpabuf_alloc(ssi_len); + if (ssi == NULL) { + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)ssi->buf, ssi_len) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi"); + goto fail; + } + ssi->used= ssi_len; + } + wpa_printf(MSG_INFO, "service_name:[%s]", service_name); + wpa_printf(MSG_INFO, "srv_proto_type:[%u]", srv_proto_type); + wpa_printf(MSG_INFO, "active:[%d]", is_active); + wpa_printf(MSG_INFO, "ttl:[%u]", ttl); + wpa_printf(MSG_INFO, "freq:[%u]", freq); + wpa_printf(MSG_INFO, "ssi_len:[%u]", ssi_len); + wpa_hexdump(MSG_MSGDUMP, "publish_ssi:", ssi->buf, ssi_len); + + params.active = is_active; + params.ttl = ttl; + params.freq = freq; + + subscribe_id = wpas_nan_usd_subscribe(wpa_s, service_name, + srv_proto_type, ssi, + ¶ms); + if (subscribe_id > 0) { + DBusMessage *reply; + reply = dbus_message_new_method_return(message); + dbus_message_append_args(reply, DBUS_TYPE_INT32, + &subscribe_id, DBUS_TYPE_INVALID); + return reply; + } +fail: + wpabuf_free(ssi); + return wpas_dbus_error_unknown_error( + message, "error subscribing nan-usd"); +} + + +/* + * wpas_dbus_handler_nan_cancel_subscribe - Cancel the 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 "NANCancelSubscribe" method call of network interface. + */ +DBusMessage * +wpas_dbus_handler_nan_cancel_subscribe(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int subscribe_id = -1; + + wpa_printf(MSG_INFO, "DBUS NAN_CANCEL_SUBSCRIBE:"); + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_INT32, &subscribe_id, + DBUS_TYPE_INVALID)) { + wpa_printf(MSG_DEBUG, " DBUS NAN_CANCEL_SUBSCRIBE, failed to get args "); + return NULL; + } + + if ((!wpa_s->nan_de)||(subscribe_id == -1)) + return NULL; + nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id); + return NULL; +} + + +/* + * wpas_dbus_handler_nan_transmit - Send out nan-followup packets + * @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 "NANTransmit" method call of network interface. + */ +DBusMessage * wpas_dbus_handler_nan_transmit(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + int handle = 0; + int req_instance_id = 0; + struct wpabuf *ssi = NULL; + u8 peer_addr[ETH_ALEN]; + char* paddr_msg; + int ret = -1; + u16 ssilen; + + DBusMessageIter iter, subiter; + + wpa_printf(MSG_INFO, "DBUS NAN_TRANSMIT:"); + + // Get the parameters from dbus + dbus_message_iter_init(message, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRUCT) { + wpa_printf(MSG_INFO, "Unexpected, arg is not struct"); + goto fail; + } + // Open the structure + dbus_message_iter_recurse(&iter, &subiter); + // Extract the elements + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)&handle, sizeof(u8)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching handle"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)&req_instance_id, sizeof(u8)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching req_instance_id"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_STRING, (void*)&paddr_msg, sizeof(&paddr_msg)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching paddr_msg"); + goto fail; + } + if (hwaddr_aton(paddr_msg, peer_addr) < 0) { + wpa_printf(MSG_ERROR, "Error while converting peer address"); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_UINT16, (void*)&ssilen, sizeof(u16)) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssilen"); + goto fail; + } + ssi = wpabuf_alloc(ssilen); + if (ssi == NULL) { + wpa_printf(MSG_ERROR, "Fail to allocate ssi_buf(%u)", ssilen); + goto fail; + } + if (get_gvariant_items(&subiter, DBUS_TYPE_BYTE, (void*)ssi->buf, ssilen) == false) { + wpa_printf(MSG_ERROR, "Error while fetching ssi"); + goto fail; + } + ssi->used= ssilen; + + 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 = wpas_nan_usd_transmit(wpa_s, handle, ssi, NULL, peer_addr, + req_instance_id); +fail: + wpa_printf(MSG_INFO, "DBUS NAN_TRANSMIT Done, %d", ret); + wpabuf_free(ssi); + return wpas_dbus_error_unknown_error( + message, "error sending follow-up packets"); +} + +#endif /* CONFIG_NAN_USD */ + + #ifdef CONFIG_TDLS static int get_peer_hwaddr_helper(DBusMessage *message, const char *func_name, diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 97fa337bd..42218495a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -285,4 +285,18 @@ DBusMessage * wpas_dbus_handler_subscribe_preq( DBusMessage * wpas_dbus_handler_unsubscribe_preq( DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_handler_nan_publish(DBusMessage *message, + struct wpa_supplicant *wpa_s); +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_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_transmit(DBusMessage *message, + struct wpa_supplicant *wpa_s); + #endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */ diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h index c8d44a00b..c45beeadc 100644 --- a/wpa_supplicant/dbus/dbus_new_helpers.h +++ b/wpa_supplicant/dbus/dbus_new_helpers.h @@ -112,6 +112,30 @@ struct wpa_dbus_property_desc { #define WPA_DBUS_PROPERTIES_SET "Set" #define WPA_DBUS_PROPERTIES_GETALL "GetAll" +struct wpa_dbus_discov_info { + u32 subscribe_id; + u32 peer_publish_id; + u8 peer_addr[ETH_ALEN]; + bool fsd; + bool fsd_gas; + u32 ssi_len; +}; + +struct wpa_dbus_reply_info { + u32 publish_id; + u32 peer_subscribe_id; + u8 peer_addr[ETH_ALEN]; + u32 ssi_len; +}; + + +struct wpa_dbus_nanrx_info { + u32 id; + u32 peer_id; + u8 peer_addr[ETH_ALEN]; + u32 ssi_len; +}; + void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc); int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, char *dbus_path, diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 7a1222f37..91630246d 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -1062,6 +1062,11 @@ void wpas_notify_nan_discovery_result(struct wpa_supplicant *wpa_s, subscribe_id, peer_publish_id, MAC2STR(peer_addr), fsd, fsd_gas, srv_proto_type, ssi_hex); os_free(ssi_hex); + + wpas_dbus_signal_nan_discovery_result(wpa_s, subscribe_id, + peer_publish_id, peer_addr, + fsd, fsd_gas, + ssi, ssi_len); } @@ -1084,6 +1089,10 @@ void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s, publish_id, MAC2STR(peer_addr), peer_subscribe_id, srv_proto_type, ssi_hex); os_free(ssi_hex); + + wpas_dbus_signal_nan_replied(wpa_s, publish_id, + peer_subscribe_id, peer_addr, + ssi, ssi_len); } @@ -1102,6 +1111,9 @@ void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id, "id=%d peer_instance_id=%d address=" MACSTR " ssi=%s", id, peer_instance_id, MAC2STR(peer_addr), ssi_hex); os_free(ssi_hex); + + wpas_dbus_signal_nan_receive(wpa_s, id, peer_instance_id, peer_addr, + ssi, ssi_len); } @@ -1127,6 +1139,8 @@ void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED "publish_id=%d reason=%s", publish_id, nan_reason_txt(reason)); + + wpas_dbus_signal_nan_publish_terminated(wpa_s, publish_id, reason); } @@ -1137,6 +1151,8 @@ void wpas_notify_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED "subscribe_id=%d reason=%s", subscribe_id, nan_reason_txt(reason)); + + wpas_dbus_signal_nan_subscribe_terminated(wpa_s, subscribe_id, reason); } #endif /* CONFIG_NAN_USD */ -- 2.21.0.windows.1 From chin-ran.lo at nxp.com Fri Aug 23 02:42:13 2024 From: chin-ran.lo at nxp.com (Chin-Ran Lo) Date: Fri, 23 Aug 2024 09:42:13 +0000 Subject: [EXT] Re: [PATCH v6] Add the similar USD APIs to dbus control interface that other apps can use the functions In-Reply-To: References: Message-ID: Hi Jouni, Thank you for the suggestions. I have pushed a new v7 patch V7 1/2: It's the 1st one you sent back V7 2/2: Please see the comment below. Thank you Chin-Ran > -----Original Message----- > From: Jouni Malinen > Sent: Thursday, August 1, 2024 1:02 AM > To: Chin-Ran Lo > Cc: hostap at lists.infradead.org; Pete Hsieh > Subject: [EXT] Re: [PATCH v6] Add the similar USD APIs to dbus control > interface that other apps can use the functions > > Caution: This is an external email. Please take care when clicking links or > opening attachments. When in doubt, report the message using the 'Report > this email' button > > > On Fri, Jul 26, 2024 at 12:38:01PM +0000, Chin-Ran Lo wrote: > > wpa_supplicant/dbus/dbus_new.c | 261 +++++++++++++++ > > wpa_supplicant/dbus/dbus_new.h | 35 ++ > > wpa_supplicant/dbus/dbus_new_handlers.c | 416 > > ++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new_handlers.h > | > > 13 +- wpa_supplicant/dbus/dbus_new_helpers.h | 14 + > > wpa_supplicant/events.c | 2 +- > > wpa_supplicant/nan_usd.c | 9 +- > > wpa_supplicant/notify.c | 27 ++ > > wpa_supplicant/notify.h | 11 + > > 9 files changed, 785 insertions(+), 3 deletions(-) > > It would be cleaner to split this into two commits: one for handling the move > of the control interface specific code from nan_usd.c into notify.c/h and > another one to add the dbus specific changes. > > As far as the proposed dbus interface is concerned, my main concern is on how > the commands are defined to take in a single string argument that is then > parsed to determine the set of actual arguments. That is not really a clean > interface for dbus. Instead, this should add the individual arguments as > separate dbus arguments with each having their own (in most cases, non-string) > type. Chin-Ran> The interface has been modified in 2/2 patch. Please review > > Why does this not add NANReplied event? Chin-Ran> It's added in 2/2 patch. Please review. > > Why does this leave out some of the arguments from events (like > FSD/FSD-GAS)? > Chin-Ran> They are added in 2/2 patch. Please review. > It would be good to update doc/dbus.doxygen to cover the new extension to > the dbus interface. Chin-Ran> It's added in 2/2 patch. Please review. > > It would be nice to get a new tests/hwsim/test_dbus.py test case for validating > the new interface. Chin-Ran> The functions are verified by using the Matter code now. I will also add the test code to here later. > > I'm attaching patches showing the two commits after a cleanup I did when > reviewing this. The first one should be ready to be applied as-is. The second > one needs those comments mentioned above addressed. > > -- > Jouni Malinen PGP id > EFC895FA From michael-cy.lee at mediatek.com Sun Aug 18 19:54:10 2024 From: michael-cy.lee at mediatek.com (Michael-CY Lee) Date: Mon, 19 Aug 2024 10:54:10 +0800 Subject: [PATCH] hostapd: do not indicate a punctured secondary channel in HT operation Message-ID: <20240819025410.20885-1-michael-cy.lee@mediatek.com> If the secondary channel is punctured, the HT operation in the beacon should not indicate a secondary channel offset. Co-developed-by: Money Wang Signed-off-by: Michael-CY Lee --- src/ap/ieee802_11_ht.c | 51 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index f90f1254e..7508587f6 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -79,6 +79,50 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) } +static void set_ht_param(struct hostapd_data *hapd, + struct ieee80211_ht_operation *oper) +{ + int secondary_channel = hapd->iconf->secondary_channel; +#ifdef CONFIG_IEEE80211BE + enum oper_chan_width chwidth = hostapd_get_oper_chwidth(hapd->iconf); + u16 bw = 0, punct_bitmap = hostapd_get_punct_bitmap(hapd); + u8 offset, chan_bit_pos; + + switch (chwidth) { + case CONF_OPER_CHWIDTH_80MHZ: + bw = 80; + offset = 6; + break; + case CONF_OPER_CHWIDTH_160MHZ: + bw = 160; + offset = 14; + break; + case CONF_OPER_CHWIDTH_320MHZ: + bw = 320; + offset = 30; + break; + default: + break; + } + + chan_bit_pos = (hapd->iconf->channel - + hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf) + + offset) / 4; + /* check if secondary channel is punctured */ + if (bw >= 80 && punct_bitmap && secondary_channel && + (punct_bitmap & BIT(chan_bit_pos + secondary_channel))) + return; +#endif /* CONFIG_IEEE80211BE */ + + if (secondary_channel == 1) + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | + HT_INFO_HT_PARAM_STA_CHNL_WIDTH; + if (secondary_channel == -1) + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | + HT_INFO_HT_PARAM_STA_CHNL_WIDTH; +} + + u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) { struct ieee80211_ht_operation *oper; @@ -96,12 +140,7 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) oper->primary_chan = hapd->iconf->channel; oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); - if (hapd->iconf->secondary_channel == 1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | - HT_INFO_HT_PARAM_STA_CHNL_WIDTH; - if (hapd->iconf->secondary_channel == -1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | - HT_INFO_HT_PARAM_STA_CHNL_WIDTH; + set_ht_param(hapd, oper); pos += sizeof(*oper); -- 2.25.1 From stratus at tuta.io Fri Aug 16 12:06:41 2024 From: stratus at tuta.io (stratus at tuta.io) Date: Fri, 16 Aug 2024 21:06:41 +0200 (CEST) Subject: Wifi not connecting at longer distances from router after upgrade to 2:2.11-2 Message-ID: Using Artix Linux, after an update that included: iproute2 (6.9.0-2 -> 6.10.0-2) wpa_supplicant (2:2.10-8 -> 2:2.11-2) the wifi at home a distance away from the router wouldn't connect. At work located next to the router it did connect but there was one time it seemed a bit slow, at home again it didn't work but finally connected after a couple of tries. Mostly it won't connect though. It requires both wpa_supplicant and iproute2 to be downgraded to fix this, not just one or the other, then it works fine with all other packages at their latest version. Installing wpa_supplicant-git and iproute2-git from the AUR gave the same result, and using dhcpcd instead of dhclient didn't help. There have been other reports of problems with this new version in the Arch Linux forums, although not identical: https://bbs.archlinux.org/viewtopic.php?id=298079 https://bbs.archlinux.org/viewtopic.php?id=298171 https://bbs.archlinux.org/viewtopic.php?id=298039 This is using a Dell E7470 with an Intel Wireless 8260 internal card, driver: iwlwifi It still seems to work but perhaps it stays in low power mode when attempting to connect or something? The same problem is also found on a Dell M4500 with both network cards, a Qualcomm Atheros AR9287 internal card, driver: ath9k and Belkin PCMCIA card, Ralink RT2760 driver: rt2800pci Wifi on script: #!/bin/bash ip link set wlan0 up wpa_supplicant -B -P /run/wpa_supplicant_wlan0.pid? -i wlan0 -D nl80211,wext \ -c /pathto/my_wpa_supplicant.conf dhclient -v -cf /pathto/dhclient.conf wlan0 #or using dhcpcd: #dhcpcd -4 -t 0 -K wlan0 $ uname -r 6.10.3-zen1-2-zen From dantas at airpost.net Sun Aug 25 20:56:56 2024 From: dantas at airpost.net (Bruno Dantas) Date: Sun, 25 Aug 2024 23:56:56 -0400 Subject: android phone often needs reboot to authenticate with 802.11ac AP Message-ID: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> Greetings, wifi gurus. I need some help and don't know where else to ask. Hopefully one of you can point me in the right direction. My home's wireless router is a homebrewed x86_64 GNU+Linux machine running linux 6.6.8 and hostapd 2.11. The AP is created using an Alfa AWUS036ACHM usb adapter. I've been happily using this router with the following hostapd configuration for many years with no problems whatsoever: ssid=homesweet_home interface=wlan1 driver=nl80211 country_code=US channel=44 ignore_broadcast_ssid=0 hw_mode=a auth_algs=1 wpa=2 wpa_passphrase=4thornberry wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP rsn_pairwise=CCMP ieee80211n=1 wmm_enabled=1 ht_capab=[HT40+][HT40-][SHORT-GI-20][SHORT-GI-40] Recently I decided to tweak the hostapd configuration so that my AP supports 802.11ac. This is my new configuration: ssid=homesweet_home interface=wlan1 driver=nl80211 country_code=US channel=36 ignore_broadcast_ssid=0 hw_mode=a auth_algs=1 wpa=2 wpa_passphrase=4thornberry wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP rsn_pairwise=CCMP ieee80211n=1 wmm_enabled=1 ht_capab=[HT40+][HT40-][SHORT-GI-20][SHORT-GI-40] # I also tried adding [GF] vht_oper_chwidth=1 vht_oper_centr_freq_seg0_idx=42 ieee80211ac=1 vht_capab=[SHORT-GI-80] # I also tried adding [MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN] per morrownr's github Everything works with this new hostapd.conf except one thing: When I return home from work, my Android phone (rooted OnePlus 5 with LineageOS 16) is sometimes unable to authenticate with my AP: The phone says "Connecting..." then "Saved" by my SSID several times, eventually says my SSID is "Disabled." Toggling wifi off and back on doesn't help. Forgetting the SSID and re-entering password doesn't help. Toggling "Airplane Mode" off and on doesn't help. To authenticate with my AP again, I have to reboot my phone. Can anyone think of an explanation why my phone has no trouble authenticating with my AP using the old (802.11n) hostapd.conf, but often needs a reboot before it can authenticate with the same AP using the new (802.11ac) hostapd.conf? Since I control the AP as well as the rooted phone, I can change settings on either end (or both ends) to make authentication reliable. I just need some guidance because I've tried everything I can think of to no avail. From dharkins at lounge.org Fri Aug 23 10:50:36 2024 From: dharkins at lounge.org (Dan Harkins) Date: Fri, 23 Aug 2024 10:50:36 -0700 Subject: Support for provisioning SAE password identifiers with DPP Message-ID: ? DPP supports provisioning of SAE password identifiers to uniquely identify a password if the enrollee indicates support for them. Support is indicated using dpp_extra_conf_req_ in the wpa_supplicant config file but if the Configurator then sends a password identifier in the Configuration Object, it would not be saved as part of the provisioned profile. This patch fixes that. ? I put everything under defines for CONFIG_DPP3 as this is a bleeding edge feature in DPP. ? This was tested against my DPP reference implementation acting as the Configurator. ------------------------------------------------------------------- diff --git a/src/common/dpp.c b/src/common/dpp.c index 3b9f35e8d..8c0fc44f8 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -2549,13 +2549,18 @@ fail: ?static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, ???? ??? ??? ??? ?struct json_token *cred) ?{ -??? struct json_token *pass, *psk_hex; +??? struct json_token *pass, *psk_hex; +#ifdef CONFIG_DPP3 +??? struct json_token *saepi; +#endif? /* CONFIG_DPP3 */ ???? wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential"); ???? pass = json_get_member(cred, "pass"); ???? psk_hex = json_get_member(cred, "psk_hex"); - +#ifdef CONFIG_DPP3 +??????? saepi = json_get_member(cred, "idpass"); +#endif? /* CONFIG_DPP3 */ ???? if (pass && pass->type == JSON_STRING) { ???? ??? size_t len = os_strlen(pass->string); @@ -2565,6 +2570,12 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf, ???? ??? ??? return -1; ???? ??? os_strlcpy(conf->passphrase, pass->string, ???? ??? ??? ?? sizeof(conf->passphrase)); +#ifdef CONFIG_DPP3 +??????????????? if (saepi && saepi->type == JSON_STRING) { +??????????????????? os_strlcpy(conf->password_id, saepi->string, +?????????????????????????????? sizeof(saepi->string)); +??????????????? } +#endif? /* CONFIG_DPP3 */ ???? } else if (psk_hex && psk_hex->type == JSON_STRING) { ???? ??? if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) { ???? ??? ??? wpa_printf(MSG_DEBUG, diff --git a/src/common/dpp.h b/src/common/dpp.h index 0f843da6a..6f6487a61 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -356,6 +356,9 @@ struct dpp_authentication { ???? ??? u8 ssid_len; ???? ??? int ssid_charset; ???? ??? char passphrase[64]; +#ifdef CONFIG_DPP3 +??????????????? char password_id[64]; +#endif? /* CONFIG_DPP3 */ ???? ??? u8 psk[PMK_LEN]; ???? ??? int psk_set; ???? ??? enum dpp_akm akm; diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f6142501e..b6ff6d73f 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -204,6 +204,9 @@ extern "C" { ?#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID " ?#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET " ?#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS " +#ifdef CONFIG_DPP3 +#define DPP_EVENT_CONFOBJ_IDPASS "DPP-CONFOBJ-IDPASS " +#endif? /* CONFIG_DPP3 */ ?#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK " ?#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR " ?#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY " diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b02b694a3..8b79eddda 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -5694,7 +5694,6 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) ???? ??? if (os_strncmp(pos, field->name, flen) != 0 || ???? ??? ??? pos[flen] != '=') ???? ??? ??? continue; - ???? ??? ret = field->parser(field, config, line, pos + flen + 1); ???? ??? if (ret < 0) { ???? ??? ??? wpa_printf(MSG_ERROR, "Line %d: failed to " diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 94d7ae990..a99f2384b 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1418,6 +1418,18 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, ???? os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len); ???? ssid->ssid_len = conf->ssid_len; +#ifdef CONFIG_DPP3 +??? if (conf->akm == DPP_AKM_SAE) { +??????????? if (conf->password_id[0]) { +??????????????? ssid->sae_password_id = os_malloc(os_strlen(conf->password_id)); +??????????????? if (!ssid->sae_password_id) { +??????????????????? goto fail; +??????????????? } +??????????????? os_memcpy(ssid->sae_password_id, conf->password_id, os_strlen(conf->password_id)); + ssid->sae_password_id[os_strlen(conf->password_id)] = '\0';???? /* ??? */ +??????????? } +??????? } +#endif? /* CONFIG_DPP3 */ ???? if (conf->connector) { ???? ??? if (dpp_akm_dpp(conf->akm)) { ???? ??? ??? ssid->key_mgmt = WPA_KEY_MGMT_DPP; @@ -1691,6 +1703,12 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, ???? ??? wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s", ???? ??? ??? hex); ???? } +#ifdef CONFIG_DPP3 +??????? if (conf->password_id[0]) { +??? ??? wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_IDPASS "%s", +??? ??? ??? conf->password_id); +??????? } +#endif? /* CONFIG_DPP3 */ ???? if (conf->c_sign_key) { ???? ??? char *hex; ???? ??? size_t hexlen; ------------------------------------------------------------------ Signed-off-by: Dan Harkins ? regards, ? Dan. -- "The object of life is not to be on the side of the majority, but to escape finding oneself in the ranks of the insane." -- Marcus Aurelius From dantas at airpost.net Mon Aug 26 04:30:48 2024 From: dantas at airpost.net (Bruno Dantas) Date: Mon, 26 Aug 2024 07:30:48 -0400 Subject: android phone often needs reboot to authenticate with 802.11ac AP In-Reply-To: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> References: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> Message-ID: <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> I edited these phones' wpa_supplicant settings (at /data/vendor/wifi/wpa/wpa_supplicant), changing `fast_reauth=1` to `fast_reauth=0`, then rebooting the phones. I have not had another failed authentication yet after limited testing (walking away from house until wifi is out of range, then walking back to see if reauthentication is successful). If this wpa_supplicant tweak turns out to be the solution, I'm puzzled as to why `fast_reath=1` never caused problems when my AP was using the 802.11n hostapd.conf. From johannes at sipsolutions.net Mon Aug 26 12:19:46 2024 From: johannes at sipsolutions.net (Johannes Berg) Date: Mon, 26 Aug 2024 21:19:46 +0200 Subject: WiFi constantly changes association In-Reply-To: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> Message-ID: <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> On Mon, 2024-08-26 at 21:14 +0200, Johannes Berg wrote: > On Mon, 2024-08-26 at 15:06 -0400, Alan Stern wrote: > > > > Is there any way to debug those INVALID_TE and PREV_AUTH_NOT_VALID errors? > > > > The kernel doesn't use those codes for its own deauth, if that were to > happen, so you'll want to look at the wpa_supplicant log, perhaps > increasing the logging verbosity for it (I think how to do that probably > depends on the distro, and I don't know off the top of my head.) > Then again, while what I said is still true, reading the log more carefully shows that wpa_s decided to roam and then got into those bad situations that caused it to deauth. So you'd want to figure out why it decides to roam there. Or perhaps roaming would be OK, if it weren't for the failures during it. johannes From lists4me at web.de Tue Aug 27 07:38:35 2024 From: lists4me at web.de (Markus) Date: Tue, 27 Aug 2024 16:38:35 +0200 Subject: Multicast stops working after second group rekey In-Reply-To: <4938094.31r3eYUQgx@markus> References: <4938094.31r3eYUQgx@markus> Message-ID: <13591774.uLZWGnKmhe@markus> Hello everyone, I asked a month ago for help but haven't received any feedback yet. Do I miss something? Is this the wrong address for my request? Thanks, Markus Am Freitag, 26. Juli 2024, 16:06:40 MESZ schrieb Markus: > Hello, > > I am running a hostapd with following setup: > > interface=wlan0 > bridge=br0 > driver=nl80211 > hw_mode=g > channel=5 > > ssid=xxx > auth_algs=1 > wnm_sleep_mode=1 > beacon_prot=1 > ieee80211w=1 > wmm_enabled=1 > #wmm_ac_* like in example > ap_isolate=1 > ieee80211n=1 > ht_capab=[HT40-][GF][SHORT-GI-20][SHORT-GI-40] > dynamic_vlan=1 > per_sta_vif=1 > wpa=2 > wpa_psk_file=/etc/hostapd/hostapd.wpa_psk > wpa_key_mgmt=WPA-PSK > rsn_pairwise=CCMP > > In general it works. But I noticed that after two days multicast > communication fails for all stations. (mdns discovery stops working.) > At the time it fails I noticed in the hostapd log the rekey entries. The > default is a rekey every 24h. So I changed it to 5 minutes to check: > wpa_group_rekey=300 > > Now multicast failed after 10 minutes. (So the first rekey after 5 minutes > worked, but the second and any further rekey succeed according to log, but > multicast does not work.) > > (I could increase rekey interval or disable it all together, but I guess > thats not recommended. ;) ) > > Deauthenticating the clients with "hostapd_cli deauthenticate" sometimes > recovers multicast for up to 10 minutes. > Not sure why it does not recover everytime. > > > Hardware is a ALFA AWUS036ACHM with mediatek mt76. > Kernel is 6.6.37, linux-firmware from July. > Recently updated hostapd to latest git version. > All stations are affected, at the moment android devices and various smart > home devices from different brands. > > Any idea what the problem could be? > Is it a misconfiguration or some bug? > > Any help is highly appreciated. > > Thank you, > Markus > > > > _______________________________________________ > Hostap mailing list > Hostap at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/hostap From stern at rowland.harvard.edu Tue Aug 27 12:09:14 2024 From: stern at rowland.harvard.edu (Alan Stern) Date: Tue, 27 Aug 2024 15:09:14 -0400 Subject: WiFi constantly changes association In-Reply-To: <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> Message-ID: <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> On Mon, Aug 26, 2024 at 09:19:46PM +0200, Johannes Berg wrote: > On Mon, 2024-08-26 at 21:14 +0200, Johannes Berg wrote: > > On Mon, 2024-08-26 at 15:06 -0400, Alan Stern wrote: > > > > > > Is there any way to debug those INVALID_TE and PREV_AUTH_NOT_VALID errors? > > > > > > > The kernel doesn't use those codes for its own deauth, if that were to > > happen, so you'll want to look at the wpa_supplicant log, perhaps > > increasing the logging verbosity for it (I think how to do that probably > > depends on the distro, and I don't know off the top of my head.) > > > > Then again, while what I said is still true, reading the log more > carefully shows that wpa_s decided to roam and then got into those bad > situations that caused it to deauth. So you'd want to figure out why it > decides to roam there. > > Or perhaps roaming would be OK, if it weren't for the failures during > it. Well, I'd prefer to avoid unnecessary roaming because of the short interruptions in service that it causes. Below is an extract from the system log for a period of about two minutes, running with wpa_supplicant's -dd option set for verbose debugging. As of the start of the extract, the system had been associated with an AP for about five minutes. The log shows a few spontaneous reassociations and some errors. I hardly understand any of it, so thanks for your efforts to make sense of what it shows. Alan Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:97:41 1 Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:ac:33 1 Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b7:d3 (SSID='Harvard Secure' freq=6535 MHz) Aug 27 14:48:56 strephon kernel: wlan0: disconnect from AP 48:b4:c3:81:b8:03 for new auth to 48:b4:c3:81:b7:d3 Aug 27 14:48:56 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b7:d3 (local address=3e:de:7e:33:e6:22) Aug 27 14:48:56 strephon kernel: wlan0: send auth to 48:b4:c3:81:b7:d3 (try 1/3) Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8123] device (wlan0): supplicant interface state: completed -> authenticating Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8124] device (p2p-dev-wlan0): supplicant management interface state: completed -> authenticating Aug 27 14:48:56 strephon kernel: wlan0: authenticated Aug 27 14:48:56 strephon kernel: wlan0: associate with 48:b4:c3:81:b7:d3 (try 1/3) Aug 27 14:48:56 strephon wpa_supplicant[5906]: nl80211: kernel reports: key not allowed Aug 27 14:48:56 strephon wpa_supplicant[5906]: FT: Failed to set PTK to the driver Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b7:d3 (SSID='Harvard Secure' freq=6535 MHz) Aug 27 14:48:56 strephon kernel: wlan0: RX ReassocResp from 48:b4:c3:81:b7:d3 (capab=0x11 status=0 aid=16) Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8326] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8326] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:48:56 strephon kernel: wlan0: associated Aug 27 14:48:56 strephon kernel: wlan0: deauthenticating from 48:b4:c3:81:b7:d3 by local choice (Reason: 13=INVALID_IE) Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame Aug 27 14:48:56 strephon wpa_supplicant[5906]: RSNE in Beacon/ProbeResp - hexdump(len=32): 30 1e 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 05 00 0f ac 03 e8 00 00 00 00 0f ac 06 Aug 27 14:48:56 strephon wpa_supplicant[5906]: RSNE in FT protocol Reassociation Response frame - hexdump(len=44): 30 2a 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 01 00 0f ac 03 e8 00 01 00 ff 84 62 84 5a a3 06 82 4f b4 2d 43 36 76 87 4b Aug 27 14:48:56 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 Aug 27 14:48:56 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 Aug 27 14:48:56 strephon wpa_supplicant[5906]: nl80211: send_event_marker failed: Source based routing not supported Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DISCONNECTED bssid=48:b4:c3:81:b7:d3 reason=13 locally_generated=1 Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: BSSID 48:b4:c3:81:b7:d3 ignore list count incremented to 3, ignoring for 60 seconds Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DSCP-POLICY clear_all Aug 27 14:48:56 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8677] device (wlan0): supplicant interface state: associating -> disconnected Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.8678] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.9676] device (wlan0): supplicant interface state: disconnected -> scanning Aug 27 14:48:56 strephon NetworkManager[978]: [1724784536.9677] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning Aug 27 14:49:00 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:e3 1 Aug 27 14:49:00 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) Aug 27 14:49:00 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b8:03 (local address=3e:de:7e:33:e6:22) Aug 27 14:49:00 strephon kernel: wlan0: send auth to 48:b4:c3:81:b8:03 (try 1/3) Aug 27 14:49:00 strephon NetworkManager[978]: [1724784540.4148] device (wlan0): supplicant interface state: scanning -> authenticating Aug 27 14:49:00 strephon NetworkManager[978]: [1724784540.4148] device (p2p-dev-wlan0): supplicant management interface state: scanning -> authenticating Aug 27 14:49:00 strephon kernel: wlan0: authenticated Aug 27 14:49:00 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) Aug 27 14:49:00 strephon NetworkManager[978]: [1724784540.4170] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:49:00 strephon NetworkManager[978]: [1724784540.4170] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:49:00 strephon kernel: wlan0: associate with 48:b4:c3:81:b8:03 (try 1/3) Aug 27 14:49:00 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 Aug 27 14:49:00 strephon kernel: wlan0: RX AssocResp from 48:b4:c3:81:b8:03 (capab=0x1 status=30 aid=0) Aug 27 14:49:00 strephon kernel: wlan0: 48:b4:c3:81:b8:03 rejected association temporarily; comeback duration 4882 TU (4999 ms) Aug 27 14:49:05 strephon kernel: wlan0: aborting association with 48:b4:c3:81:b8:03 by local choice (Reason: 3=DEAUTH_LEAVING) Aug 27 14:49:05 strephon wpa_supplicant[5906]: nl80211: send_event_marker failed: Source based routing not supported Aug 27 14:49:05 strephon wpa_supplicant[5906]: wlan0: Added BSSID 48:b4:c3:81:b8:03 into ignore list, ignoring for 10 seconds Aug 27 14:49:05 strephon wpa_supplicant[5906]: wlan0: BSSID 48:b4:c3:81:b8:03 ignore list count incremented to 2, ignoring for 10 seconds Aug 27 14:49:05 strephon NetworkManager[978]: [1724784545.4458] device (wlan0): supplicant interface state: associating -> disconnected Aug 27 14:49:05 strephon NetworkManager[978]: [1724784545.4459] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected Aug 27 14:49:05 strephon NetworkManager[978]: [1724784545.9462] device (wlan0): supplicant interface state: disconnected -> scanning Aug 27 14:49:05 strephon NetworkManager[978]: [1724784545.9463] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b1:a0 (SSID='Harvard Secure' freq=5975 MHz) Aug 27 14:49:06 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b1:a0 (local address=3e:de:7e:33:e6:22) Aug 27 14:49:06 strephon kernel: wlan0: send auth to 48:b4:c3:81:b1:a0 (try 1/3) Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5417] device (wlan0): supplicant interface state: scanning -> authenticating Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5417] device (p2p-dev-wlan0): supplicant management interface state: scanning -> authenticating Aug 27 14:49:06 strephon kernel: wlan0: authenticated Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b1:a0 (SSID='Harvard Secure' freq=5975 MHz) Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5504] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5505] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:49:06 strephon kernel: wlan0: associate with 48:b4:c3:81:b1:a0 (try 1/3) Aug 27 14:49:06 strephon kernel: wlan0: RX AssocResp from 48:b4:c3:81:b1:a0 (capab=0x111 status=0 aid=17) Aug 27 14:49:06 strephon kernel: wlan0: associated Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: Associated with 48:b4:c3:81:b1:a0 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-STARTED EAP authentication started Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5694] device (wlan0): supplicant interface state: associating -> associated Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5695] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-CERT depth=2 subject='/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority' hash=e793c9b02fd8aa13e21c31228accb08119643b749c898964b1746d46c3d4cbd2 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-CERT depth=1 subject='/C=US/O=Internet2/CN=InCommon RSA Server CA 2' hash=87e01cc4dd0c9d92a3dbd49092ff13f9cd387445cdc57e5b984e1b7721b5b029 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-CERT depth=0 subject='/C=US/ST=Massachusetts/O=President and Fellows of Harvard College/CN=getonline.noc.harvard.edu' hash=3f49c12863e8b1acf739e8ab4c55e165d9466d1ba18287d0ef1ffa1e743a3d88 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:getonline.noc.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:autoreg.fas.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:autoreg1-10wa.noc.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:autoreg1-60ox.noc.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:getonline.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:registration.noc.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:sc-cppm-pub1.net.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:sc-cppm-sub1.net.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:sc-cppm-sub10.net.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PEER-ALT depth=0 DNS:sc-cppm-sub11.net.harvard.edu Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b1:a0 1 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b1:a0 1 Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8164] device (wlan0): supplicant interface state: associated -> 4way_handshake Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8165] device (p2p-dev-wlan0): supplicant management interface state: associated -> 4way_handshake Aug 27 14:49:06 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: WPA: Key negotiation completed with 48:b4:c3:81:b1:a0 [PTK=CCMP GTK=CCMP] Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-CONNECTED - Connection to 48:b4:c3:81:b1:a0 completed [id=1 id_str=] Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8649] device (wlan0): supplicant interface state: 4way_handshake -> completed Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SIGNAL-CHANGE above=0 signal=-68 noise=9999 txrate=29200 Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] device (wlan0): ip:dhcp4: restarting Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): canceled DHCP transaction Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): state changed no lease Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8661] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8661] device (p2p-dev-wlan0): supplicant management interface state: 4way_handshake -> completed Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.9397] dhcp4 (wlan0): state changed new lease, address=10.250.66.194, acd pending Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.9401] dhcp4 (wlan0): state changed new lease, address=10.250.66.194 Aug 27 14:49:06 strephon systemd[1]: Starting NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service... Aug 27 14:49:06 strephon systemd[1]: Started NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service. Aug 27 14:49:17 strephon systemd[1]: NetworkManager-dispatcher.service: Deactivated successfully. Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:80:58:a1 1 Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c8:e2 1 Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) Aug 27 14:49:41 strephon kernel: wlan0: disconnect from AP 48:b4:c3:81:b1:a0 for new auth to 48:b4:c3:81:b8:03 Aug 27 14:49:41 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b8:03 (local address=3e:de:7e:33:e6:22) Aug 27 14:49:41 strephon kernel: wlan0: send auth to 48:b4:c3:81:b8:03 (try 1/3) Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2208] device (wlan0): supplicant interface state: completed -> authenticating Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2209] device (p2p-dev-wlan0): supplicant management interface state: completed -> authenticating Aug 27 14:49:41 strephon kernel: wlan0: authenticated Aug 27 14:49:41 strephon wpa_supplicant[5906]: nl80211: kernel reports: key not allowed Aug 27 14:49:41 strephon wpa_supplicant[5906]: FT: Failed to set PTK to the driver Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) Aug 27 14:49:41 strephon kernel: wlan0: associate with 48:b4:c3:81:b8:03 (try 1/3) Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2321] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2322] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:49:41 strephon kernel: wlan0: RX ReassocResp from 48:b4:c3:81:b8:03 (capab=0x11 status=0 aid=17) Aug 27 14:49:41 strephon kernel: wlan0: associated Aug 27 14:49:41 strephon kernel: wlan0: deauthenticating from 48:b4:c3:81:b8:03 by local choice (Reason: 13=INVALID_IE) Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame Aug 27 14:49:41 strephon wpa_supplicant[5906]: RSNE in Beacon/ProbeResp - hexdump(len=32): 30 1e 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 05 00 0f ac 03 e8 00 00 00 00 0f ac 06 Aug 27 14:49:41 strephon wpa_supplicant[5906]: RSNE in FT protocol Reassociation Response frame - hexdump(len=44): 30 2a 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 01 00 0f ac 03 e8 00 01 00 8c 34 e8 c2 21 bb 8a 04 04 fa 5b bb 29 23 ed eb Aug 27 14:49:41 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 Aug 27 14:49:41 strephon wpa_supplicant[5906]: nl80211: send_event_marker failed: Source based routing not supported Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DISCONNECTED bssid=48:b4:c3:81:b8:03 reason=13 locally_generated=1 Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: BSSID 48:b4:c3:81:b8:03 ignore list count incremented to 3, ignoring for 60 seconds Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DSCP-POLICY clear_all Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2793] device (wlan0): supplicant interface state: associating -> disconnected Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.2794] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.3794] device (wlan0): supplicant interface state: disconnected -> scanning Aug 27 14:49:41 strephon NetworkManager[978]: [1724784581.3795] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b1:a0 (SSID='Harvard Secure' freq=5975 MHz) Aug 27 14:49:44 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b1:a0 (local address=3e:de:7e:33:e6:22) Aug 27 14:49:44 strephon kernel: wlan0: send auth to 48:b4:c3:81:b1:a0 (try 1/3) Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7189] device (wlan0): supplicant interface state: scanning -> authenticating Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7189] device (p2p-dev-wlan0): supplicant management interface state: scanning -> authenticating Aug 27 14:49:44 strephon kernel: wlan0: authenticated Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b1:a0 (SSID='Harvard Secure' freq=5975 MHz) Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7253] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7254] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:49:44 strephon kernel: wlan0: associate with 48:b4:c3:81:b1:a0 (try 1/3) Aug 27 14:49:44 strephon kernel: wlan0: RX AssocResp from 48:b4:c3:81:b1:a0 (capab=0x111 status=0 aid=17) Aug 27 14:49:44 strephon kernel: wlan0: associated Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: Associated with 48:b4:c3:81:b1:a0 Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-STARTED EAP authentication started Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7446] device (wlan0): supplicant interface state: associating -> associated Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.7447] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13 Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b1:a0 1 Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b1:a0 1 Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.8524] device (wlan0): supplicant interface state: associated -> 4way_handshake Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.8525] device (p2p-dev-wlan0): supplicant management interface state: associated -> 4way_handshake Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: WPA: Key negotiation completed with 48:b4:c3:81:b1:a0 [PTK=CCMP GTK=CCMP] Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-CONNECTED - Connection to 48:b4:c3:81:b1:a0 completed [id=1 id_str=] Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9010] device (wlan0): supplicant interface state: 4way_handshake -> completed Aug 27 14:49:44 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SIGNAL-CHANGE above=0 signal=-66 noise=9999 txrate=29200 Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9021] device (wlan0): ip:dhcp4: restarting Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9022] dhcp4 (wlan0): canceled DHCP transaction Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9022] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9022] dhcp4 (wlan0): state changed no lease Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9023] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:44 strephon NetworkManager[978]: [1724784584.9024] device (p2p-dev-wlan0): supplicant management interface state: 4way_handshake -> completed Aug 27 14:49:46 strephon NetworkManager[978]: [1724784586.9194] dhcp4 (wlan0): state changed new lease, address=10.250.66.194, acd pending Aug 27 14:49:46 strephon NetworkManager[978]: [1724784586.9197] dhcp4 (wlan0): state changed new lease, address=10.250.66.194 Aug 27 14:49:46 strephon systemd[1]: Starting NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service... Aug 27 14:49:46 strephon systemd[1]: Started NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service. Aug 27 14:49:53 strephon kernel: wlan0: deauthenticating from 48:b4:c3:81:b1:a0 by local choice (Reason: 2=PREV_AUTH_NOT_VALID) Aug 27 14:49:54 strephon wpa_supplicant[5906]: nl80211: send_event_marker failed: Source based routing not supported Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DISCONNECTED bssid=48:b4:c3:81:b1:a0 reason=2 locally_generated=1 Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: Added BSSID 48:b4:c3:81:b1:a0 into ignore list, ignoring for 10 seconds Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: BSSID 48:b4:c3:81:b1:a0 ignore list count incremented to 2, ignoring for 10 seconds Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DSCP-POLICY clear_all Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.0228] device (wlan0): supplicant interface state: completed -> disconnected Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.0229] device (p2p-dev-wlan0): supplicant management interface state: completed -> disconnected Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.1210] device (wlan0): supplicant interface state: disconnected -> scanning Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.1210] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b7:b3 (SSID='Harvard Secure' freq=5220 MHz) Aug 27 14:49:54 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b7:b3 (local address=3e:de:7e:33:e6:22) Aug 27 14:49:54 strephon kernel: wlan0: send auth to 48:b4:c3:81:b7:b3 (try 1/3) Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b7:b3 (SSID='Harvard Secure' freq=5220 MHz) Aug 27 14:49:54 strephon kernel: wlan0: authenticated Aug 27 14:49:54 strephon kernel: wlan0: associate with 48:b4:c3:81:b7:b3 (try 1/3) Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.9699] device (wlan0): supplicant interface state: scanning -> associating Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.9699] device (p2p-dev-wlan0): supplicant management interface state: scanning -> associating Aug 27 14:49:54 strephon kernel: wlan0: RX AssocResp from 48:b4:c3:81:b7:b3 (capab=0x1111 status=0 aid=3) Aug 27 14:49:54 strephon kernel: wlan0: associated Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: Associated with 48:b4:c3:81:b7:b3 Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-STARTED EAP authentication started Aug 27 14:49:54 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.9854] device (wlan0): supplicant interface state: associating -> associated Aug 27 14:49:54 strephon NetworkManager[978]: [1724784594.9855] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:d3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:c3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED e8:10:98:7c:2d:42 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 54:d7:e3:d9:91:22 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b1:80 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED e8:10:98:7c:2d:52 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:f3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b1:90 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:af:c3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED dc:b7:ac:e3:18:b1 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED dc:b7:ac:e3:18:a1 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c7:93 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:cc:33 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 54:d7:e3:d9:91:32 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 54:d7:e3:d9:91:12 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:4a:e9:c1:6c:31 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:af:a3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:97:51 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c8:c2 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c8:d2 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:ac:23 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c1:b2 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c7:83 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:af:b3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:97:41 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:ac:33 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:e3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:80:58:a1 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:c8:e2 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:b3 1 Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:b3 1 Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.0976] device (wlan0): supplicant interface state: associated -> 4way_handshake Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.0976] device (p2p-dev-wlan0): supplicant management interface state: associated -> 4way_handshake Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: WPA: Key negotiation completed with 48:b4:c3:81:b7:b3 [PTK=CCMP GTK=CCMP] Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-CONNECTED - Connection to 48:b4:c3:81:b7:b3 completed [id=1 id_str=] Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1426] device (wlan0): supplicant interface state: 4way_handshake -> completed Aug 27 14:49:55 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SIGNAL-CHANGE above=1 signal=-40 noise=9999 txrate=58500 Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1431] device (wlan0): ip:dhcp4: restarting Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1498] dhcp4 (wlan0): canceled DHCP transaction Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1498] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1498] dhcp4 (wlan0): state changed no lease Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1499] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1501] device (p2p-dev-wlan0): supplicant management interface state: 4way_handshake -> completed Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1609] dhcp4 (wlan0): state changed new lease, address=10.250.66.194, acd pending Aug 27 14:49:55 strephon NetworkManager[978]: [1724784595.1610] dhcp4 (wlan0): state changed new lease, address=10.250.66.194 Aug 27 14:50:02 strephon kernel: wlan0: deauthenticating from 48:b4:c3:81:b7:b3 by local choice (Reason: 2=PREV_AUTH_NOT_VALID) Aug 27 14:50:02 strephon wpa_supplicant[5906]: nl80211: send_event_marker failed: Source based routing not supported Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DISCONNECTED bssid=48:b4:c3:81:b7:b3 reason=2 locally_generated=1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: Added BSSID 48:b4:c3:81:b7:b3 into ignore list, ignoring for 10 seconds Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: BSSID 48:b4:c3:81:b7:b3 ignore list count incremented to 2, ignoring for 10 seconds Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-DSCP-POLICY clear_all Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.2273] device (wlan0): supplicant interface state: completed -> disconnected Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.2275] device (p2p-dev-wlan0): supplicant management interface state: completed -> disconnected Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.3249] device (wlan0): supplicant interface state: disconnected -> scanning Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.3249] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:d3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:c3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:e3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:f3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 54:d7:e3:d9:91:22 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED e8:10:98:7c:2d:52 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b1:80 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED e8:10:98:7c:2d:42 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b1:90 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED dc:b7:ac:e3:18:b1 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED dc:b7:ac:e3:18:a1 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c7:93 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:af:c3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:80:58:a1 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 54:d7:e3:d9:91:32 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 54:d7:e3:d9:91:12 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:af:b3 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:4a:e9:c1:6c:31 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:ac:23 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:cc:33 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c8:d2 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:ac:33 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c8:e2 1 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b7:d3 (SSID='Harvard Secure' freq=6535 MHz) Aug 27 14:50:02 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b7:d3 (local address=3e:de:7e:33:e6:22) Aug 27 14:50:02 strephon kernel: wlan0: send auth to 48:b4:c3:81:b7:d3 (try 1/3) Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: Trying to associate with 48:b4:c3:81:b7:d3 (SSID='Harvard Secure' freq=6535 MHz) Aug 27 14:50:02 strephon kernel: wlan0: authenticated Aug 27 14:50:02 strephon kernel: wlan0: associate with 48:b4:c3:81:b7:d3 (try 1/3) Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9674] device (wlan0): supplicant interface state: scanning -> authenticating Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9674] device (p2p-dev-wlan0): supplicant management interface state: scanning -> authenticating Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9675] device (wlan0): supplicant interface state: authenticating -> associating Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9675] device (p2p-dev-wlan0): supplicant management interface state: authenticating -> associating Aug 27 14:50:02 strephon kernel: wlan0: RX AssocResp from 48:b4:c3:81:b7:d3 (capab=0x111 status=0 aid=16) Aug 27 14:50:02 strephon kernel: wlan0: associated Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: Associated with 48:b4:c3:81:b7:d3 Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-STARTED EAP authentication started Aug 27 14:50:02 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9837] device (wlan0): supplicant interface state: associating -> associated Aug 27 14:50:02 strephon NetworkManager[978]: [1724784602.9838] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13 Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-METHOD EAP vendor 0 method 13 (TLS) selected Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-REMOVED 48:b4:c3:81:b7:d3 1 Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:b7:d3 1 Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1089] device (wlan0): supplicant interface state: associated -> 4way_handshake Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1090] device (p2p-dev-wlan0): supplicant management interface state: associated -> 4way_handshake Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: WPA: Key negotiation completed with 48:b4:c3:81:b7:d3 [PTK=CCMP GTK=CCMP] Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: Removed BSSID 48:b4:c3:81:b7:d3 from ignore list Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-CONNECTED - Connection to 48:b4:c3:81:b7:d3 completed [id=1 id_str=] Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1655] device (wlan0): supplicant interface state: 4way_handshake -> completed Aug 27 14:50:03 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SIGNAL-CHANGE above=1 signal=-43 noise=9999 txrate=245000 Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1665] device (wlan0): ip:dhcp4: restarting Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1778] dhcp4 (wlan0): canceled DHCP transaction Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1778] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1778] dhcp4 (wlan0): state changed no lease Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1779] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1780] device (p2p-dev-wlan0): supplicant management interface state: 4way_handshake -> completed Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1851] dhcp4 (wlan0): state changed new lease, address=10.250.66.194, acd pending Aug 27 14:50:03 strephon NetworkManager[978]: [1724784603.1853] dhcp4 (wlan0): state changed new lease, address=10.250.66.194 Aug 27 14:50:13 strephon systemd[1]: NetworkManager-dispatcher.service: Deactivated successfully. From dfilip at colornetlabs.com Mon Aug 26 12:48:14 2024 From: dfilip at colornetlabs.com (David Filip) Date: Mon, 26 Aug 2024 15:48:14 -0400 Subject: hostap and disassociated? Message-ID: Greetings, I am having a problem related to using hostap & dnsmasq on a Raspberry Pi (RPi). It works correctly connecting from my Macs to the RPi configured as an AP, but not consistently from a ?bare metal? OS I?m working on (based on Circle), only ?every other time?. But the ?bare metal? OS does work every time with my hardware AP, just not hostap. Also, the problem appears to be related to hostap disassociating from the MAC address. So your first reaction might be ?Who cares if it doesn?t work on your 'bare metal' OS, if it works from your Mac, then hostap is working, fix your ?bare metal? OS. While I don?t entirely disagree with that, I?m trying to figure out what the problem / incompatibility is, and how to further debug and/or fix it. Which is why I am writing this list to try to better understand how hostap is working. By ?every other time?, it is entirely consistent in that if I have hostap running and I try to connect from my ?bare metal? OS, it will initially work correctly, then if I reboot the "bare metal" OS (and NOT the hostap computer), it will not work, then if I reboot the "bare metal" OS again, it will work, then if I reboot again, it won?t work, then if I reboot again it will work, etc. I?ve also left it running overnight, and when it works, it stays connected, so it is not just an ?intermittent? thing. Also, the computers are < 10 feet apart. Also, if I reboot the hostap computer before I reboot the ?bare metal? computer, then it will always work. Also, if I restart hostap (systemctl restart hosted) before I reboot the ?bare metal? computer, then it will always work. When it doesn?t work, I get a ton (over 300) ?disassociated? messages on the hostap computer, e.g. from /var/log/syslog: May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ... Or sometimes without the second ?associated?, and just: Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ? When it does work correctly (every odd time, or after rebooting the hostap computer, or after restarting hostap): May 27 03:41:43 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 RADIUS: starting accounting session 09EB81D0E910BBA8 May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 WPA: pairwise key handshake completed (RSN) So my question is how / why does hostap flag a MAC address as ?disassociated?, and is there any way through configuration to prevent that (e.g., whitelist a MAC address to never get ?disassociated?)? If I have a better idea of what would cause the ?disassociated? behavior, I might be able to figure out how to prevent it (or at least go back to the maintainer for the drivers I?m using in my ?bare metal? OS and telling them what hostap needs and is not getting). Also, to confirm, the ?bare metal? OS can always connect every time to my hardware AP (NETGEAR Orbi AP), this problem only occurs when connecting to a RPi running hostap. I also have several RPis running hostap, and it behaves exactly the same using these versions: ======================================================== Raspberry Pi OS / Debian 10 / Buster $ hostapd -v hostapd v2.8-devel User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== Raspberry Pi OS / Debian 11 / Bullseye $ hostapd v2.9 User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== I think the key is to try to figure out why hostap keeps disassociating from the ?bare metal? OS MAC address. Any help or advice to help debug this would be appraised, Thanks, Dave. From j at w1.fi Tue Aug 27 14:18:40 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 00:18:40 +0300 Subject: [PATCH v3 00/25] Add support for P2P2 In-Reply-To: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> References: <1722850403-8852-1-git-send-email-quic_shivbara@quicinc.com> Message-ID: On Mon, Aug 05, 2024 at 03:02:58PM +0530, Shivani Baranwal wrote: > Implementation to support the P2P2 discovery and PASN pairing, > join and verification. > > Shivani Baranwal (25): > NAN: Option to offload NAN DE for USD into the driver > P2P: Allow P2P IE to be added into NAN SDFs > P2P: Add PCEA and PBMA attributes to P2P2 IE of NAN SDFs > P2P: Add DIRA attributes to P2P2 IE of NAN SDFs > P2P: Add config support to fetch Device Identity key > P2P: Add freq list to subscriber to search for publisher on mutli > channels > P2P: Allow to process Element container attr from NAN SDFs > P2P: Cleanup of provision discovery req and resp processing > P2P: Add bootstrapping support with pd frames > P2P: Notify bootstrapping request and completed events > WPA: Add support for KEK derivation in PTK > Define PMKSA helper functions for PASN initiator and responder > P2P: Cleanup of go-negotiation and invitation processing > P2P: Add support for go negotiation action wrapper format for p2p2 > P2P: Encapsulate P2P2 vendor IE with size more than 255 bytes > P2P: Add support for GO negotiation wrapped in PASN auth frame > p2p: Add support for p2p2 set apis > Add p2p2 support for group formation on successful negotiation > p2p: Add support for Invitation using pairing verification > P2P: Add P2P2 support for autogo and client join > P2P: Add device identity block to p2p_supplicant.conf > P2P: Add support to validate DIRA and configure PMK > P2P: Add support to store indentity key in conf file > P2P: Add support to get PASN PTK > P2P: Add support for Assited DFS for P2P2 GO in 5GHz Thanks, applied patches 1..9 with fixes and cleanup. In particular, please note that I changed the format for wpa_supplicant configuration parameters for DevIK to be more consistent with existing design to use a single hex-encoded binary value instead of a string and length. There were number of likely security issues with received message parsing since the received buffer size was not validated before reading the value (at least two instances for the cookie and I think I fixed something else with a similar issue). Patch 10 introduces new D-Bus signals. Those need to be documented in doc/dbus.doxygen. Some of the later patches in the series included FIXME comments that need to be addressed. -- Jouni Malinen PGP id EFC895FA From johannes at sipsolutions.net Wed Aug 28 00:19:05 2024 From: johannes at sipsolutions.net (Johannes Berg) Date: Wed, 28 Aug 2024 09:19:05 +0200 Subject: WiFi constantly changes association In-Reply-To: <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> Message-ID: <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> On Tue, 2024-08-27 at 15:09 -0400, Alan Stern wrote: > > Well, I'd prefer to avoid unnecessary roaming because of the short > interruptions in service that it causes. Right, but the interruptions for you are much longer because it _fails_. Perhaps wpa_supplicant should remember that, and not attempt to use FT when it keeps failing. > Below is an extract from the system log for a period of about two > minutes, running with wpa_supplicant's -dd option set for verbose > debugging. As of the start of the extract, the system had been > associated with an AP for about five minutes. The log shows a few > spontaneous reassociations and some errors. I hardly understand any of > it, so thanks for your efforts to make sense of what it shows. I'm not sure I understand it either ... I don't see anything that _caused_ the roaming. > [snip] I'll skip that since I don't know if it's complete, or what came before. There are some failed transitions there, but eventually it's connected again: > Aug 27 14:49:06 strephon kernel: wlan0: associated > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: Associated with 48:b4:c3:81:b1:a0 > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-STARTED EAP authentication started > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5694] device (wlan0): supplicant interface state: associating -> associated > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.5695] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13 > ... > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8164] device (wlan0): supplicant interface state: associated -> 4way_handshake > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8165] device (p2p-dev-wlan0): supplicant management interface state: associated -> 4way_handshake > Aug 27 14:49:06 strephon kernel: iwlwifi 0000:72:00.0: Unhandled alg: 0x707 > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: WPA: Key negotiation completed with 48:b4:c3:81:b1:a0 [PTK=CCMP GTK=CCMP] > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-CONNECTED - Connection to 48:b4:c3:81:b1:a0 completed [id=1 id_str=] > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8649] device (wlan0): supplicant interface state: 4way_handshake -> completed Now it's fully connected. > Aug 27 14:49:06 strephon wpa_supplicant[5906]: wlan0: CTRL-EVENT-SIGNAL-CHANGE above=0 signal=-68 noise=9999 txrate=29200 > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] device (wlan0): ip:dhcp4: restarting > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): canceled DHCP transaction > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8660] dhcp4 (wlan0): state changed no lease > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8661] dhcp4 (wlan0): activation: beginning transaction (timeout in 45 seconds) > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.8661] device (p2p-dev-wlan0): supplicant management interface state: 4way_handshake -> completed > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.9397] dhcp4 (wlan0): state changed new lease, address=10.250.66.194, acd pending > Aug 27 14:49:06 strephon NetworkManager[978]: [1724784546.9401] dhcp4 (wlan0): state changed new lease, address=10.250.66.194 and also with DHCP from NetworkManager now. > Aug 27 14:49:06 strephon systemd[1]: Starting NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service... > Aug 27 14:49:06 strephon systemd[1]: Started NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service. > Aug 27 14:49:17 strephon systemd[1]: NetworkManager-dispatcher.service: Deactivated successfully. > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:80:58:a1 1 > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c8:e2 1 > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) > Aug 27 14:49:41 strephon kernel: wlan0: disconnect from AP 48:b4:c3:81:b1:a0 for new auth to 48:b4:c3:81:b8:03 > Aug 27 14:49:41 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b8:03 (local address=3e:de:7e:33:e6:22) > Aug 27 14:49:41 strephon kernel: wlan0: send auth to 48:b4:c3:81:b8:03 (try 1/3) But I don't know what causes this? Maybe a higher debug level would show something here? But also I don't know too much about wpa_supplicant behaviour, so perhaps someone on the list can chime in what might've caused it to decide to roam here. johannes From j at w1.fi Wed Aug 28 00:49:14 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 10:49:14 +0300 Subject: WiFi constantly changes association In-Reply-To: <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 09:19:05AM +0200, Johannes Berg wrote: > On Tue, 2024-08-27 at 15:09 -0400, Alan Stern wrote: > > Well, I'd prefer to avoid unnecessary roaming because of the short > > interruptions in service that it causes. > > Right, but the interruptions for you are much longer because it _fails_. > Perhaps wpa_supplicant should remember that, and not attempt to use FT > when it keeps failing. That depends on what exactly is failing.. I did not bother going through all the details of the debug log since it seemed to be missing something. I did notice one of the APs using comeback mechanism which is a sign of the STA having an older entry on it and PMF being used. That is actually not a failure but part of the expected behavior for protecting against disconnection attacks. One would need to have a full log from the first initial connection to the point of a failed reassociation. Ideally, I'd like to see that from wpa_supplicant stdout with -ddt on the command line instead of syslog. > > Below is an extract from the system log for a period of about two > > minutes, running with wpa_supplicant's -dd option set for verbose > > debugging. As of the start of the extract, the system had been > > associated with an AP for about five minutes. The log shows a few > > spontaneous reassociations and some errors. I hardly understand any of > > it, so thanks for your efforts to make sense of what it shows. > > I'm not sure I understand it either ... I don't see anything that > _caused_ the roaming. Indeed. That log is not sufficient to debug this. > > Aug 27 14:49:06 strephon systemd[1]: Starting NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service... > > Aug 27 14:49:06 strephon systemd[1]: Started NetworkManager-dispatcher.service - Network Manager Script Dispatcher Service. > > Aug 27 14:49:17 strephon systemd[1]: NetworkManager-dispatcher.service: Deactivated successfully. > > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:80:58:a1 1 > > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: PMKSA-CACHE-ADDED 48:b4:c3:81:c8:e2 1 > > Aug 27 14:49:41 strephon wpa_supplicant[5906]: wlan0: SME: Trying to authenticate with 48:b4:c3:81:b8:03 (SSID='Harvard Secure' freq=6215 MHz) > > Aug 27 14:49:41 strephon kernel: wlan0: disconnect from AP 48:b4:c3:81:b1:a0 for new auth to 48:b4:c3:81:b8:03 > > Aug 27 14:49:41 strephon kernel: wlan0: authenticate with 48:b4:c3:81:b8:03 (local address=3e:de:7e:33:e6:22) > > Aug 27 14:49:41 strephon kernel: wlan0: send auth to 48:b4:c3:81:b8:03 (try 1/3) > > But I don't know what causes this? Maybe a higher debug level would show > something here? But also I don't know too much about wpa_supplicant > behaviour, so perhaps someone on the list can chime in what might've > caused it to decide to roam here. This is clearly missing entries. Maybe something in syslog is filtering things out? Like I noted above, debug log directly from wpa_supplicant stdout would be better way of getting a complete log in a form that could be analyzed without having to guess what exactly happened in this type of a case. Something external(?) seemed to do some management of the PMKSA cache here. It is not what that is. If it is NetworkManager through the wpa_supplicant D-Bus interface, it is possible that wpa_supplicant does not log all the details in its debug log. If that is indeed the case, I would recommend testing this with NM disabled or with a closer look at NM debug log to see what it is trying to do here. Adding PMKSA cache entries should not result in roaming, but removing them could if something is removing the currently used PMKSA entry. I'd expect wpa_supplicant debug log to include more detaild about that, though. -- Jouni Malinen PGP id EFC895FA From johannes at sipsolutions.net Wed Aug 28 00:55:09 2024 From: johannes at sipsolutions.net (Johannes Berg) Date: Wed, 28 Aug 2024 09:55:09 +0200 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, 2024-08-28 at 10:49 +0300, Jouni Malinen wrote: > On Wed, Aug 28, 2024 at 09:19:05AM +0200, Johannes Berg wrote: > > On Tue, 2024-08-27 at 15:09 -0400, Alan Stern wrote: > > > Well, I'd prefer to avoid unnecessary roaming because of the short > > > interruptions in service that it causes. > > > > Right, but the interruptions for you are much longer because it _fails_. > > Perhaps wpa_supplicant should remember that, and not attempt to use FT > > when it keeps failing. > > That depends on what exactly is failing.. Agree. > I did not bother going through > all the details of the debug log since it seemed to be missing > something. Also seems that way, yes, though not sure why. But for example: > wpa_supplicant[5906]: wlan0: FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame is something that perhaps could result in an FT-blocklist or something for the BSSID in question, or perhaps even the whole network since it's likely to be a single controller/unified installation or so. > I did notice one of the APs using comeback mechanism which is > a sign of the STA having an older entry on it and PMF being used. That > is actually not a failure but part of the expected behavior for > protecting against disconnection attacks. One would need to have a full > log from the first initial connection to the point of a failed > reassociation.? True. > Ideally, I'd like to see that from wpa_supplicant stdout > with -ddt on the command line instead of syslog. Right ... That needs more arguments to integrate with NetworkManager (or configuration to have at least dbus), but I'm not sure how exactly that'd work and how you'd stop the system one. Actually if it's with systemd then that/journal will log everything from the stdout/stderr, just not necessarily in the syslog - so perhaps adding -t in addition to -dd and then using journalctl -u wpa_supplicant would work. johannes From j at w1.fi Wed Aug 28 01:21:38 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 11:21:38 +0300 Subject: android phone often needs reboot to authenticate with 802.11ac AP In-Reply-To: <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> References: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> Message-ID: On Mon, Aug 26, 2024 at 07:30:48AM -0400, Bruno Dantas wrote: > I edited these phones' wpa_supplicant settings (at /data/vendor/wifi/wpa/wpa_supplicant), changing `fast_reauth=1` to `fast_reauth=0`, then rebooting the phones. I have not had another failed authentication yet after limited testing (walking away from house until wifi is out of range, then walking back to see if reauthentication is successful). > > If this wpa_supplicant tweak turns out to be the solution, I'm puzzled as to why `fast_reath=1` never caused problems when my AP was using the 802.11n hostapd.conf. fast_reauth configures EAP behavior and your AP configuration indicated that EAP is not used at all. In other words, that change in wpa_supplicant configuration should have no impact whatsoever to the observed behavior and whatever change you may have seen is likely a coincidence.. Figuring out the real issue for this would likely require debugging the WLAN driver on the Android phone if restarting wpa_supplicant alone is not sufficient to work around issues and the phone needs to be fully rebooted. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Wed Aug 28 01:50:13 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 11:50:13 +0300 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 09:55:09AM +0200, Johannes Berg wrote: > But for example: > > > wpa_supplicant[5906]: wlan0: FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame > > is something that perhaps could result in an FT-blocklist or something > for the BSSID in question, or perhaps even the whole network since it's > likely to be a single controller/unified installation or so. Somehow I managed to miss then entry.. This is something that I'd be quite interested in getting more details for since this seems to show a clear interoperability issue with the FT reassociation implementation between the AP and the STA.. I'd like to see the full wpa_supplicant debug sequence that started from selecting the AP and how it resulted in this mismatch. Is there any idea which AP devices are used in the network? It is clearly misbehaving if the wpa_supplicant debug log entries are accurate on what RSNE values it uses: RSNE in Beacon/ProbeResp - hexdump(len=32): 30 1e 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 05 00 0f ac 03 e8 00 00 00 00 0f ac 06 RSNE in FT protocol Reassociation Response frame - hexdump(len=44): 30 2a 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f ac 01 00 0f ac 03 e8 00 01 00 ff 84 62 84 5a a3 06 82 4f b4 2d 43 36 76 87 4b It is expected to add the PMKID entry for FT, but the AP changed its list of AKM suites (!?) and removed the group management cipher suite. Such changes are not allowed and the STA has to stop since those would be a clear indication of an active downgrade attack. While wpa_supplicant could in theory prevent FT attempts with this AP for some time from the view point of interoperability workarounds, I'm not exactly happy about such a change since it could make it easier to perform various attacks. As far as the AKM suite lists are concerned, the RSNE from scan results indicated 00-0F-AC:5 (802.1X with SHA-256) and 00-0F-AC:3 (FT with 802.1X) while the RSNE from Reassocation Response frame indicated 00-0F-AC:1 (802.1X with SHA-1) and 00-0F-AC:3 (FT with 802.1X). This feels really strange. Either the AP has a really broken FT implementation or something has messed up with scan results.. Since this attempt is on the 6 GHz band, I'm assuming the AP has other BSSs on the 2.4 and 5 GHz bands and it might be possible that there are differences in which AKMs are enabled on different bands. That would be a bit strange configuration of the AP, but still, possible. It would be nice to get full scan results that show the RSNE values from all bands. -- Jouni Malinen PGP id EFC895FA From dantas at airpost.net Wed Aug 28 05:07:19 2024 From: dantas at airpost.net (Bruno Dantas) Date: Wed, 28 Aug 2024 08:07:19 -0400 Subject: android phone often needs reboot to authenticate with 802.11ac AP In-Reply-To: References: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> Message-ID: <23d94afc-3659-2961-78f5-ab65ecb5224f@airpost.net> > that change in > wpa_supplicant configuration should have no impact whatsoever to the > observed behavior and whatever change you may have seen is likely a > coincidence.. > Hi Jouni. I feared as much. I will save the phone's wpa_supplicant log of a successful authentication and, when it happens again, a log of a failed authentication attempt. My router is dual-band: It creates a 5 GHz 802.11ac AP and a 2.4 GHz 802.11n AP. If comparing the wpa_supplicant logs does not reveal an easy way to make authentication with the 5 GHz 802.11ac AP more reliable, then I'll stick to using the 2.4 GHz 802.11n AP for the phones. Thank you for your help! -Bruno From stern at rowland.harvard.edu Wed Aug 28 11:02:32 2024 From: stern at rowland.harvard.edu (Alan Stern) Date: Wed, 28 Aug 2024 14:02:32 -0400 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 09:55:09AM +0200, Johannes Berg wrote: > On Wed, 2024-08-28 at 10:49 +0300, Jouni Malinen wrote: > > Ideally, I'd like to see that from wpa_supplicant stdout > > with -ddt on the command line instead of syslog. > > Right ... That needs more arguments to integrate with NetworkManager (or > configuration to have at least dbus), but I'm not sure how exactly > that'd work and how you'd stop the system one. > > Actually if it's with systemd then that/journal will log everything from > the stdout/stderr, just not necessarily in the syslog - so perhaps > adding -t in addition to -dd and then using > > journalctl -u wpa_supplicant > > would work. Attached is a compressed file containing a 10-minute section of the journalctl output. wpa_supplicant was running with -ddt and without -s, so this should contain all of its output. Initially both wpa_supplicant and NetworkManager were turned off. The log starts at the time when I turned on wpa_supplicant, and a few seconds later, turned on NetworkManager. An INVALID_IE event occurred at timestamp 12:03:59. The output is so voluminous it's hard to see what's really happening, however. Alan Stern -------------- next part -------------- A non-text attachment was scrubbed... Name: wpa-log2.txt.gz Type: application/gzip Size: 97985 bytes Desc: not available URL: From dfilip at colornetlabs.com Wed Aug 28 09:55:23 2024 From: dfilip at colornetlabs.com (David Filip) Date: Wed, 28 Aug 2024 12:55:23 -0400 Subject: hostap and disassociated? In-Reply-To: References: Message-ID: <6A6332B5-24E2-4A2D-80D0-A515A65B4A72@colornetlabs.com> No, but I do have: denyinterfaces wlan0 But I will try that to see if it makes a difference. > On Aug 28, 2024, at 10:46 AM, Jamie Fargen wrote: > > In the /etc/dhcpcd.conf do you have a stanza that resembles the one below: > > interface wlan0 > nohook wpa_supplicant > > > > Regards, > > -Jamie > > > On Tue, Aug 27, 2024 at 5:16?PM David Filip wrote: > Greetings, > > I am having a problem related to using hostap & dnsmasq on a Raspberry Pi (RPi). It works correctly connecting from my Macs to the RPi configured as an AP, but not consistently from a ?bare metal? OS I?m working on (based on Circle), only ?every other time?. But the ?bare metal? OS does work every time with my hardware AP, just not hostap. > > Also, the problem appears to be related to hostap disassociating from the MAC address. > > So your first reaction might be ?Who cares if it doesn?t work on your 'bare metal' OS, if it works from your Mac, then hostap is working, fix your ?bare metal? OS. > > While I don?t entirely disagree with that, I?m trying to figure out what the problem / incompatibility is, and how to further debug and/or fix it. Which is why I am writing this list to try to better understand how hostap is working. > > By ?every other time?, it is entirely consistent in that if I have hostap running and I try to connect from my ?bare metal? OS, it will initially work correctly, then if I reboot the "bare metal" OS (and NOT the hostap computer), it will not work, then if I reboot the "bare metal" OS again, it will work, then if I reboot again, it won?t work, then if I reboot again it will work, etc. I?ve also left it running overnight, and when it works, it stays connected, so it is not just an ?intermittent? thing. Also, the computers are < 10 feet apart. > > Also, if I reboot the hostap computer before I reboot the ?bare metal? computer, then it will always work. > > Also, if I restart hostap (systemctl restart hosted) before I reboot the ?bare metal? computer, then it will always work. > > When it doesn?t work, I get a ton (over 300) ?disassociated? messages on the hostap computer, e.g. from /var/log/syslog: > > May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated > May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > ... etc > 300 times ... > > Or sometimes without the second ?associated?, and just: > > Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated > ... etc > 300 times ? > > When it does work correctly (every odd time, or after rebooting the hostap computer, or after restarting hostap): > > May 27 03:41:43 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated > May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 RADIUS: starting accounting session 09EB81D0E910BBA8 > May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 WPA: pairwise key handshake completed (RSN) > > So my question is how / why does hostap flag a MAC address as ?disassociated?, and is there any way through configuration to prevent that (e.g., whitelist a MAC address to never get ?disassociated?)? > > If I have a better idea of what would cause the ?disassociated? behavior, I might be able to figure out how to prevent it (or at least go back to the maintainer for the drivers I?m using in my ?bare metal? OS and telling them what hostap needs and is not getting). > > Also, to confirm, the ?bare metal? OS can always connect every time to my hardware AP (NETGEAR Orbi AP), this problem only occurs when connecting to a RPi running hostap. > > I also have several RPis running hostap, and it behaves exactly the same using these versions: > > ======================================================== > Raspberry Pi OS / Debian 10 / Buster > > $ hostapd -v > hostapd v2.8-devel > User space daemon for IEEE 802.11 AP management, > IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator > Copyright (c) 2002-2019, Jouni Malinen and contributors > ======================================================== > Raspberry Pi OS / Debian 11 / Bullseye > > $ hostapd v2.9 > User space daemon for IEEE 802.11 AP management, > IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator > Copyright (c) 2002-2019, Jouni Malinen and contributors > ======================================================== > > I think the key is to try to figure out why hostap keeps disassociating from the ?bare metal? OS MAC address. Any help or advice to help debug this would be appraised, > > Thanks, > > Dave. > > > _______________________________________________ > Hostap mailing list > Hostap at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/hostap From dfilip at colornetlabs.com Wed Aug 28 10:17:02 2024 From: dfilip at colornetlabs.com (David Filip) Date: Wed, 28 Aug 2024 13:17:02 -0400 Subject: hostap and disassociated? In-Reply-To: <6BC03DA8-85B5-499E-B018-17269C737240@colornetlabs.com> References: <6BC03DA8-85B5-499E-B018-17269C737240@colornetlabs.com> Message-ID: <23D2A799-F094-4B9D-AC30-B1373A8E69EE@colornetlabs.com> I have tried adding: interface wlan0 nohook wpa_supplicant To my /etc/dhcpcd.conf and rebooted, but it has not solved the problem; it still works every ?odd? time I connect, and failed every ?even? time I connect (IOW, every other time). Any thoughts as to what might be missing to make hostapd disassociate? Every time if fails, the first message in the log is a disassociate from the MAC of my ?bare metal? computer. I?m thinking that maybe hostapd sends some sort of periodic check to make sure the connection is still good? And maybe the open source drivers I?m using are not responding? Again, it works every time connecting from my ?bare metal? computer to a real (NETGEAR Orbi) WAP. But it only works every other time connecting from my ?bare metal? computer to hostapd. So it appears as though hostapd is flagging my connection as bad after I disconnect (reboot) my ?bare metal? computer. When it does connect (every other time), the connecting is very stable, and I have even left it running overnight without any disconnects. Any other thoughts? On another subject ? I?ve tried subscribing to this mailing list by sending a plan text message to: hostap-join at lists.infradead.org With the single line ?subscribe?, but it does not appear to work. Any ideas? Is this now a closed list? Otherwise, it looks like the moderator has to manually approve each of my messages (unless that is intentional)? On Aug 28, 2024, at 12:53 PM, David Filip wrote: No, but I do have: denyinterfaces wlan0 But I will try that to see if it makes a difference. On Aug 28, 2024, at 10:46 AM, Jamie Fargen wrote: In the /etc/dhcpcd.conf do you have a stanza that resembles the one below: interface wlan0 nohook wpa_supplicant Regards, -Jamie On Tue, Aug 27, 2024 at 5:16?PM David Filip wrote: Greetings, I am having a problem related to using hostap & dnsmasq on a Raspberry Pi (RPi). It works correctly connecting from my Macs to the RPi configured as an AP, but not consistently from a ?bare metal? OS I?m working on (based on Circle), only ?every other time?. But the ?bare metal? OS does work every time with my hardware AP, just not hostap. Also, the problem appears to be related to hostap disassociating from the MAC address. So your first reaction might be ?Who cares if it doesn?t work on your 'bare metal' OS, if it works from your Mac, then hostap is working, fix your ?bare metal? OS. While I don?t entirely disagree with that, I?m trying to figure out what the problem / incompatibility is, and how to further debug and/or fix it. Which is why I am writing this list to try to better understand how hostap is working. By ?every other time?, it is entirely consistent in that if I have hostap running and I try to connect from my ?bare metal? OS, it will initially work correctly, then if I reboot the "bare metal" OS (and NOT the hostap computer), it will not work, then if I reboot the "bare metal" OS again, it will work, then if I reboot again, it won?t work, then if I reboot again it will work, etc. I?ve also left it running overnight, and when it works, it stays connected, so it is not just an ?intermittent? thing. Also, the computers are < 10 feet apart. Also, if I reboot the hostap computer before I reboot the ?bare metal? computer, then it will always work. Also, if I restart hostap (systemctl restart hosted) before I reboot the ?bare metal? computer, then it will always work. When it doesn?t work, I get a ton (over 300) ?disassociated? messages on the hostap computer, e.g. from /var/log/syslog: May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ... Or sometimes without the second ?associated?, and just: Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ? When it does work correctly (every odd time, or after rebooting the hostap computer, or after restarting hostap): May 27 03:41:43 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 RADIUS: starting accounting session 09EB81D0E910BBA8 May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 WPA: pairwise key handshake completed (RSN) So my question is how / why does hostap flag a MAC address as ?disassociated?, and is there any way through configuration to prevent that (e.g., whitelist a MAC address to never get ?disassociated?)? If I have a better idea of what would cause the ?disassociated? behavior, I might be able to figure out how to prevent it (or at least go back to the maintainer for the drivers I?m using in my ?bare metal? OS and telling them what hostap needs and is not getting). Also, to confirm, the ?bare metal? OS can always connect every time to my hardware AP (NETGEAR Orbi AP), this problem only occurs when connecting to a RPi running hostap. I also have several RPis running hostap, and it behaves exactly the same using these versions: ======================================================== Raspberry Pi OS / Debian 10 / Buster $ hostapd -v hostapd v2.8-devel User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== Raspberry Pi OS / Debian 11 / Bullseye $ hostapd v2.9 User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== I think the key is to try to figure out why hostap keeps disassociating from the ?bare metal? OS MAC address. Any help or advice to help debug this would be appraised, Thanks, Dave. _______________________________________________ Hostap mailing list Hostap at lists.infradead.org http://lists.infradead.org/mailman/listinfo/hostap From j at w1.fi Wed Aug 28 12:00:22 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 22:00:22 +0300 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 02:02:32PM -0400, Alan Stern wrote: > Attached is a compressed file containing a 10-minute section of the > journalctl output. wpa_supplicant was running with -ddt and without -s, > so this should contain all of its output. > > Initially both wpa_supplicant and NetworkManager were turned off. The > log starts at the time when I turned on wpa_supplicant, and a few > seconds later, turned on NetworkManager. An INVALID_IE event occurred > at timestamp 12:03:59. The output is so voluminous it's hard to see > what's really happening, however. Thanks. This seems to make it clear that the AP has an issue in its FT implementation at least in the BSS that operates on the 6 GHz band. Based on the OUI, that AP is from HPE (Aruba?), so I guess I'll check with them whether this is a known issue. The log did not include any other attempt to use the FT protocol, so I could not check whether it could have worked on other bands. However, I do note that the RSNE from the 5 GHz band is indeed different and matches the value that the AP included on the 6 GHz band in the Reassociation Response frame, so this seems to point towards some implementation or configuration issues on the AP side and that could result in an issue that is specific to the 6 GHz band. PS. The reason for this particular sequence is in the STA first connecting on the 5 GHz band and wpa_supplicant being configured to use bgscan to find a better candidate. Background scan from that ends up finding a 6 GHz AP and that has better estimated throughput and wpa_supplicant decides to roam based on that. Since FT is enabled here, that roam tries to use FT from the 5 GHz AP to the 6 GHz one and that fails. This results in the 6 GHz AP getting temporarily disabled and a 5 GHz AP being selected as the next option. That succeeds with initial FT mobility domain association (i.e., not using FT protocol). However, now we get back to that same state where bgscan will find a better AP on 6 GHz and that will result in the same failure.. As far as I can tell, the main issue here is in AP misbehavior. This could be worked around by disabling FT or bgscan. A potential wpa_supplicant change could be considered to disable FT protocol for that specific AP when this type of behavior is detected. I'll talk to Aruba first to see if I can get a better understanding on what is behind this AP behavior. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Wed Aug 28 12:17:18 2024 From: j at w1.fi (Jouni Malinen) Date: Wed, 28 Aug 2024 22:17:18 +0300 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 03:07:14PM -0400, Alan Stern wrote: > Is there a way to tell wpa_supplicant to ignore APs on the 6-GHz band? You can configure a list of allowed frequencies with the freq_list parameter (space separated list of channel frequencies), so that could be used to list all the 2.4 and 5 GHz channels. With some drivers, there might be some other options like the control interface command "SET setband 2G,5G". -- Jouni Malinen PGP id EFC895FA From dantas at airpost.net Wed Aug 28 18:47:34 2024 From: dantas at airpost.net (Bruno Dantas) Date: Wed, 28 Aug 2024 21:47:34 -0400 Subject: android phone often needs reboot to authenticate with 802.11ac AP In-Reply-To: References: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> Message-ID: <947f80cb-920f-0f68-a7bb-a05dc1e22eba@airpost.net> Hi, Jouni. The problem happened again today. It seems random and unprovoked. There seems to be nothing I can do to trigger it. To have a log of a successful authentication to look at as a baseline, I saved this one from yesterday. I started logging, then at exactly 21:32 I toggled wifi off and back on on the phone: Excerpt from wpa_supplicant log successful authentication at 21:32: 08-27 21:32:04.838 31387 31387 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' 08-27 21:32:04.879 31387 31387 I wpa_supplicant: wlan0: Associated with 00:c0:ca:b1:09:0c 08-27 21:32:04.879 31387 31387 I wpa_supplicant: wlan0: CTRL-EVENT-SUBNET-STATUS-UPDATE status=0 08-27 21:32:05.185 31387 31387 I wpa_supplicant: wlan0: WPA: RX message 1 of 4-Way Handshake from 00:c0:ca:b1:09:0c (ver=2) 08-27 21:32:05.188 31387 31387 I wpa_supplicant: wlan0: WPA: Sending EAPOL-Key 2/4 08-27 21:32:05.191 31387 31387 I wpa_supplicant: wlan0: WPA: RX message 3 of 4-Way Handshake from 00:c0:ca:b1:09:0c (ver=2) 08-27 21:32:05.191 31387 31387 I wpa_supplicant: wlan0: WPA: Sending EAPOL-Key 4/4 08-27 21:32:05.207 31387 31387 I wpa_supplicant: wlan0: WPA: Key negotiation completed with 00:c0:ca:b1:09:0c [PTK=CCMP GTK=CCMP] 08-27 21:32:05.207 31387 31387 I wpa_supplicant: wlan0: CTRL-EVENT-CONNECTED - Connection to 00:c0:ca:b1:09:0c completed [id=0 id_str=%7B%22configKey%22%3A%22%5C%22bibliotheca_alexandrina%5C%22WPA_PSK%22%2C%22creatorUid%22%3A%221000%22%7D] 08-27 21:32:05.652 31387 31387 I wpa_supplicant: p2p0: CTRL-EVENT-AVOID-FREQ ranges=5180-5320,5540-5660 (Full log of successful authentication at 21:32 is here: https://pastebin.com/ZvvLFwy3) Sometimes the problem strikes my phone, sometimes my wife's. The phones are not usually affected at the same time. Both phones are OnePlus5 running LineageOS 16 (based on AOSP 9). Here is an excerpt from wpa_supplicant log for a failed authentication attempt at exactly 21:18 (note: the phone that failed authentication was successfully authenticated earlier in the day). Only way to get this phone to successfully authenticate with my 5 GHz 802.11ac AP again will be to reboot the phone. Note that we never had any problems using all same hardware and software when hostapd was running at 5 GHz 802.11n. 08-28 21:18:04.969 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' 08-28 21:18:08.074 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 08-28 21:18:11.282 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' 08-28 21:18:14.383 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 08-28 21:18:17.989 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' 08-28 21:18:21.089 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 (Full log of failed authentication at 21:18: https://pastebin.com/nT1Mmsg7) Any idea what I can do to prevent this kind of authentication failure? From Dominik.Cermak at joynext.com Thu Aug 29 00:28:20 2024 From: Dominik.Cermak at joynext.com (Cermak Dominik) Date: Thu, 29 Aug 2024 07:28:20 +0000 Subject: [PATCH] nl80211: Pass "global" events to all interfaces Message-ID: Extending commit f136837202393a7e1f3182e9efdbf1aaa0c1a5c2. We got connection failures because of outdated channel information. That's because the NL80211_CMD_REG_CHANGE event is important for all interfaces, but the early termination still kicks in because it is not directed to a specific wiphy. Therefore from three interfaces, only one got the updated channel list. Fix this by changing the early termination logic to only apply to events directed either to a specific interface index for wdev. Signed-off-by: Dominik Cermak --- src/drivers/driver_nl80211_event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 903207067..8e79b5848 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -4257,7 +4257,13 @@ int process_global_event(struct nl_msg *msg, void *arg) wdev_id == bss->wdev_id)) { processed = true; do_process_drv_event(bss, gnlh->cmd, tb); - if (!wiphy_idx_set) + /* There are two types of events that may need to be + * delivered to multiple interfaces: + * 1. Events for a wiphy, as it can have multiple interfaces. + * 2. "Global" events, like NL80211_CMD_REG_CHANGE. + * Or in other words, terminate early only if it is + * directed to a specific interface or wdev. */ + if (ifidx != 1 || wdev_id_set) return NL_SKIP; /* The driver instance could have been removed, * e.g., due to NL80211_CMD_RADAR_DETECT event, -- 2.44.1 From stern at rowland.harvard.edu Wed Aug 28 12:07:14 2024 From: stern at rowland.harvard.edu (Alan Stern) Date: Wed, 28 Aug 2024 15:07:14 -0400 Subject: WiFi constantly changes association In-Reply-To: References: <9f32e4ff8b59f137208d99c40fd166f81e8de4bc.camel@sipsolutions.net> <52752800050fdd10e3d883cb4870624455d1b34e.camel@sipsolutions.net> <9cd7bc93-090a-4fcd-9af1-af6ff108064b@rowland.harvard.edu> <25391c67947d47c4cb75e89664a882905e125863.camel@sipsolutions.net> Message-ID: On Wed, Aug 28, 2024 at 10:00:22PM +0300, Jouni Malinen wrote: > On Wed, Aug 28, 2024 at 02:02:32PM -0400, Alan Stern wrote: > > Attached is a compressed file containing a 10-minute section of the > > journalctl output. wpa_supplicant was running with -ddt and without -s, > > so this should contain all of its output. > > > > Initially both wpa_supplicant and NetworkManager were turned off. The > > log starts at the time when I turned on wpa_supplicant, and a few > > seconds later, turned on NetworkManager. An INVALID_IE event occurred > > at timestamp 12:03:59. The output is so voluminous it's hard to see > > what's really happening, however. > > Thanks. This seems to make it clear that the AP has an issue in its FT > implementation at least in the BSS that operates on the 6 GHz band. > Based on the OUI, that AP is from HPE (Aruba?), so I guess I'll check > with them whether this is a known issue. Yes, I believe Harvard uses Aruba hardware for their access points. > The log did not include any other attempt to use the FT protocol, so I > could not check whether it could have worked on other bands. However, I > do note that the RSNE from the 5 GHz band is indeed different and > matches the value that the AP included on the 6 GHz band in the > Reassociation Response frame, so this seems to point towards some > implementation or configuration issues on the AP side and that could > result in an issue that is specific to the 6 GHz band. > > PS. > > The reason for this particular sequence is in the STA first connecting > on the 5 GHz band and wpa_supplicant being configured to use bgscan > to find a better candidate. Background scan from that ends up finding a > 6 GHz AP and that has better estimated throughput and wpa_supplicant > decides to roam based on that. Since FT is enabled here, that roam tries > to use FT from the 5 GHz AP to the 6 GHz one and that fails. This > results in the 6 GHz AP getting temporarily disabled and a 5 GHz AP > being selected as the next option. That succeeds with initial FT > mobility domain association (i.e., not using FT protocol). However, now > we get back to that same state where bgscan will find a better AP on 6 > GHz and that will result in the same failure.. Is there a way to tell wpa_supplicant to ignore APs on the 6-GHz band? > As far as I can tell, the main issue here is in AP misbehavior. This > could be worked around by disabling FT or bgscan. A potential > wpa_supplicant change could be considered to disable FT protocol for > that specific AP when this type of behavior is detected. I'll talk to > Aruba first to see if I can get a better understanding on what is behind > this AP behavior. Thanks. If you need more information, let me know. Alan Stern From dfilip at colornetlabs.com Wed Aug 28 16:56:26 2024 From: dfilip at colornetlabs.com (David Filip) Date: Wed, 28 Aug 2024 19:56:26 -0400 Subject: hostap and disassociated? In-Reply-To: References: <6BC03DA8-85B5-499E-B018-17269C737240@colornetlabs.com> <23D2A799-F094-4B9D-AC30-B1373A8E69EE@colornetlabs.com> <010001919a9093af-3dc6d963-380d-4740-ac55-7c6af20936cd-000000@email.amazonses.com> Message-ID: Jamie, Just testing one or two connections at a time right now: One from my Mac (running Ventura 13.x) and One from my ?Bare Metal? OS (built using Circle running on a Raspberry Pi). The ?Bare Metal? OS I?ve tested on a RPi 3 and a RPi Zero 2W, and both exhibit the exact same behavior. I just now compiled for a RPi 4, and see the exact same behavior there as well. For running hostapd: I have three (3) Raspberry Pis running hostapd, two are RPi 4?s and one is a RPi 3. I?ve been using them for other projects, without problems until now (since I just started the ?bare metal? OS a couple of months ago). Pretty much the same configuration on all of the RPis running hostapd. One is running Buster (Debian 10 with hostapd 2.8) and two are running Bullseye (Debian 11 with hostapd 2.9). My end goal is use my ?Bare Metal? OS do real time monitoring, and send the results to a Raspberry Pi running hostapd with full Raspberry Pi OS, security, Apache web server, Python, etc., for aggregation. I did try adding: interface wlan0 nohook wpa_supplicant And removing: wpa_pairwise=TKIP But neither seems to have changed anything. So do we know how hostapd determines when to disassociate a particular MAC address? And is there any way to stop / alter it doing that? Or to whitelist a MAC address from ever being disassociated? Just grasping a straws here, looking for another way to solve this. It may turn out that my ?bare metal? WiFi client is not doing something it should, but I?m sure how to determine what that is? Regards, Dave. On Aug 28, 2024, at 4:07 PM, Jamie Fargen wrote: David- Let me look at it the config. Do you know how many devices are connecting to the RPI? What RPI model you are using? And what firmware version is installed? Regards, -Jamei On Wed, Aug 28, 2024 at 3:57?PM David Filip wrote: Jamie, Here is my /etc/hostapd/hostapd.conf file: country_code=US bridge=br0 interface=wlan0 hw_mode=g channel=7 wmm_enabled=0 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP ssid=ClearWaterways wpa_passphrase=************ Let me know if you have any suggestions. To confirm, I can connect without any problem ? every time ? from my Mac to hostapd. Connecting from my ?bare metal? OS works only every other time ? unless hostapd is restarted ? and when it fails, I get many disassociated errors from hostapd in syslog. So to a novice like me, it appears as though hostapd is ?remembering? something from the last ?bare metal? OS connection that is preventing it from connecting again. Thanks, Dave. On Aug 28, 2024, at 2:31?PM, Jamie Fargen wrote: David- Please provide your hostapd.conf file and redact any confidential information. Regards, -Jamie On Wed, Aug 28, 2024 at 1:17?PM David Filip wrote: I have tried adding: interface wlan0 nohook wpa_supplicant To my /etc/dhcpcd.conf and rebooted, but it has not solved the problem; it still works every ?odd? time I connect, and failed every ?even? time I connect (IOW, every other time). Any thoughts as to what might be missing to make hostapd disassociate? Every time if fails, the first message in the log is a disassociate from the MAC of my ?bare metal? computer. I?m thinking that maybe hostapd sends some sort of periodic check to make sure the connection is still good? And maybe the open source drivers I?m using are not responding? Again, it works every time connecting from my ?bare metal? computer to a real (NETGEAR Orbi) WAP. But it only works every other time connecting from my ?bare metal? computer to hostapd. So it appears as though hostapd is flagging my connection as bad after I disconnect (reboot) my ?bare metal? computer. When it does connect (every other time), the connecting is very stable, and I have even left it running overnight without any disconnects. Any other thoughts? On another subject ? I?ve tried subscribing to this mailing list by sending a plan text message to: hostap-join at lists.infradead.org With the single line ?subscribe?, but it does not appear to work. Any ideas? Is this now a closed list? Otherwise, it looks like the moderator has to manually approve each of my messages (unless that is intentional)? On Aug 28, 2024, at 12:53 PM, David Filip wrote: No, but I do have: denyinterfaces wlan0 But I will try that to see if it makes a difference. On Aug 28, 2024, at 10:46 AM, Jamie Fargen wrote: In the /etc/dhcpcd.conf do you have a stanza that resembles the one below: interface wlan0 nohook wpa_supplicant Regards, -Jamie On Tue, Aug 27, 2024 at 5:16?PM David Filip wrote: Greetings, I am having a problem related to using hostap & dnsmasq on a Raspberry Pi (RPi). It works correctly connecting from my Macs to the RPi configured as an AP, but not consistently from a ?bare metal? OS I?m working on (based on Circle), only ?every other time?. But the ?bare metal? OS does work every time with my hardware AP, just not hostap. Also, the problem appears to be related to hostap disassociating from the MAC address. So your first reaction might be ?Who cares if it doesn?t work on your 'bare metal' OS, if it works from your Mac, then hostap is working, fix your ?bare metal? OS. While I don?t entirely disagree with that, I?m trying to figure out what the problem / incompatibility is, and how to further debug and/or fix it. Which is why I am writing this list to try to better understand how hostap is working. By ?every other time?, it is entirely consistent in that if I have hostap running and I try to connect from my ?bare metal? OS, it will initially work correctly, then if I reboot the "bare metal" OS (and NOT the hostap computer), it will not work, then if I reboot the "bare metal" OS again, it will work, then if I reboot again, it won?t work, then if I reboot again it will work, etc. I?ve also left it running overnight, and when it works, it stays connected, so it is not just an ?intermittent? thing. Also, the computers are < 10 feet apart. Also, if I reboot the hostap computer before I reboot the ?bare metal? computer, then it will always work. Also, if I restart hostap (systemctl restart hosted) before I reboot the ?bare metal? computer, then it will always work. When it doesn?t work, I get a ton (over 300) ?disassociated? messages on the hostap computer, e.g. from /var/log/syslog: May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ... Or sometimes without the second ?associated?, and just: Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ? When it does work correctly (every odd time, or after rebooting the hostap computer, or after restarting hostap): May 27 03:41:43 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 RADIUS: starting accounting session 09EB81D0E910BBA8 May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 WPA: pairwise key handshake completed (RSN) So my question is how / why does hostap flag a MAC address as ?disassociated?, and is there any way through configuration to prevent that (e.g., whitelist a MAC address to never get ?disassociated?)? If I have a better idea of what would cause the ?disassociated? behavior, I might be able to figure out how to prevent it (or at least go back to the maintainer for the drivers I?m using in my ?bare metal? OS and telling them what hostap needs and is not getting). Also, to confirm, the ?bare metal? OS can always connect every time to my hardware AP (NETGEAR Orbi AP), this problem only occurs when connecting to a RPi running hostap. I also have several RPis running hostap, and it behaves exactly the same using these versions: ======================================================== Raspberry Pi OS / Debian 10 / Buster $ hostapd -v hostapd v2.8-devel User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== Raspberry Pi OS / Debian 11 / Bullseye $ hostapd v2.9 User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== I think the key is to try to figure out why hostap keeps disassociating from the ?bare metal? OS MAC address. Any help or advice to help debug this would be appraised, Thanks, Dave. _______________________________________________ Hostap mailing list Hostap at lists.infradead.org http://lists.infradead.org/mailman/listinfo/hostap From dfilip at colornetlabs.com Wed Aug 28 12:57:31 2024 From: dfilip at colornetlabs.com (David Filip) Date: Wed, 28 Aug 2024 19:57:31 +0000 Subject: hostap and disassociated? In-Reply-To: References: <6BC03DA8-85B5-499E-B018-17269C737240@colornetlabs.com> <23D2A799-F094-4B9D-AC30-B1373A8E69EE@colornetlabs.com> Message-ID: <010001919a9093af-3dc6d963-380d-4740-ac55-7c6af20936cd-000000@email.amazonses.com> Jamie, Here is my /etc/hostapd/hostapd.conf file: country_code=US bridge=br0 interface=wlan0 hw_mode=g channel=7 wmm_enabled=0 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP ssid=ClearWaterways wpa_passphrase=************ Let me know if you have any suggestions. To confirm, I can connect without any problem ? every time ? from my Mac to hostapd. Connecting from my ?bare metal? OS works only every other time ? unless hostapd is restarted ? and when it fails, I get many disassociated errors from hostapd in syslog. So to a novice like me, it appears as though hostapd is ?remembering? something from the last ?bare metal? OS connection that is preventing it from connecting again. Thanks, Dave. On Aug 28, 2024, at 2:31?PM, Jamie Fargen wrote: David- Please provide your hostapd.conf file and redact any confidential information. Regards, -Jamie On Wed, Aug 28, 2024 at 1:17?PM David Filip wrote: I have tried adding: interface wlan0 nohook wpa_supplicant To my /etc/dhcpcd.conf and rebooted, but it has not solved the problem; it still works every ?odd? time I connect, and failed every ?even? time I connect (IOW, every other time). Any thoughts as to what might be missing to make hostapd disassociate? Every time if fails, the first message in the log is a disassociate from the MAC of my ?bare metal? computer. I?m thinking that maybe hostapd sends some sort of periodic check to make sure the connection is still good? And maybe the open source drivers I?m using are not responding? Again, it works every time connecting from my ?bare metal? computer to a real (NETGEAR Orbi) WAP. But it only works every other time connecting from my ?bare metal? computer to hostapd. So it appears as though hostapd is flagging my connection as bad after I disconnect (reboot) my ?bare metal? computer. When it does connect (every other time), the connecting is very stable, and I have even left it running overnight without any disconnects. Any other thoughts? On another subject ? I?ve tried subscribing to this mailing list by sending a plan text message to: hostap-join at lists.infradead.org With the single line ?subscribe?, but it does not appear to work. Any ideas? Is this now a closed list? Otherwise, it looks like the moderator has to manually approve each of my messages (unless that is intentional)? On Aug 28, 2024, at 12:53 PM, David Filip wrote: No, but I do have: denyinterfaces wlan0 But I will try that to see if it makes a difference. On Aug 28, 2024, at 10:46 AM, Jamie Fargen wrote: In the /etc/dhcpcd.conf do you have a stanza that resembles the one below: interface wlan0 nohook wpa_supplicant Regards, -Jamie On Tue, Aug 27, 2024 at 5:16?PM David Filip wrote: Greetings, I am having a problem related to using hostap & dnsmasq on a Raspberry Pi (RPi). It works correctly connecting from my Macs to the RPi configured as an AP, but not consistently from a ?bare metal? OS I?m working on (based on Circle), only ?every other time?. But the ?bare metal? OS does work every time with my hardware AP, just not hostap. Also, the problem appears to be related to hostap disassociating from the MAC address. So your first reaction might be ?Who cares if it doesn?t work on your 'bare metal' OS, if it works from your Mac, then hostap is working, fix your ?bare metal? OS. While I don?t entirely disagree with that, I?m trying to figure out what the problem / incompatibility is, and how to further debug and/or fix it. Which is why I am writing this list to try to better understand how hostap is working. By ?every other time?, it is entirely consistent in that if I have hostap running and I try to connect from my ?bare metal? OS, it will initially work correctly, then if I reboot the "bare metal" OS (and NOT the hostap computer), it will not work, then if I reboot the "bare metal" OS again, it will work, then if I reboot again, it won?t work, then if I reboot again it will work, etc. I?ve also left it running overnight, and when it works, it stays connected, so it is not just an ?intermittent? thing. Also, the computers are < 10 feet apart. Also, if I reboot the hostap computer before I reboot the ?bare metal? computer, then it will always work. Also, if I restart hostap (systemctl restart hosted) before I reboot the ?bare metal? computer, then it will always work. When it doesn?t work, I get a ton (over 300) ?disassociated? messages on the hostap computer, e.g. from /var/log/syslog: May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated May 27 03:44:40 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ... Or sometimes without the second ?associated?, and just: Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated Aug 26 08:58:13 demo hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: disassociated ... etc > 300 times ? When it does work correctly (every odd time, or after rebooting the hostap computer, or after restarting hostap): May 27 03:41:43 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 IEEE 802.11: associated May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 RADIUS: starting accounting session 09EB81D0E910BBA8 May 27 03:41:44 barge-bow hostapd: wlan0: STA b8:27:eb:fe:11:c3 WPA: pairwise key handshake completed (RSN) So my question is how / why does hostap flag a MAC address as ?disassociated?, and is there any way through configuration to prevent that (e.g., whitelist a MAC address to never get ?disassociated?)? If I have a better idea of what would cause the ?disassociated? behavior, I might be able to figure out how to prevent it (or at least go back to the maintainer for the drivers I?m using in my ?bare metal? OS and telling them what hostap needs and is not getting). Also, to confirm, the ?bare metal? OS can always connect every time to my hardware AP (NETGEAR Orbi AP), this problem only occurs when connecting to a RPi running hostap. I also have several RPis running hostap, and it behaves exactly the same using these versions: ======================================================== Raspberry Pi OS / Debian 10 / Buster $ hostapd -v hostapd v2.8-devel User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== Raspberry Pi OS / Debian 11 / Bullseye $ hostapd v2.9 User space daemon for IEEE 802.11 AP management, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator Copyright (c) 2002-2019, Jouni Malinen and contributors ======================================================== I think the key is to try to figure out why hostap keeps disassociating from the ?bare metal? OS MAC address. Any help or advice to help debug this would be appraised, Thanks, Dave. _______________________________________________ Hostap mailing list Hostap at lists.infradead.org http://lists.infradead.org/mailman/listinfo/hostap From Dominik.Cermak at joynext.com Thu Aug 29 00:50:38 2024 From: Dominik.Cermak at joynext.com (Cermak Dominik) Date: Thu, 29 Aug 2024 07:50:38 +0000 Subject: AW: [PATCH] nl80211: Pass "global" events to all interfaces In-Reply-To: References: Message-ID: Wrong patch obviously. Should have been "ifidx != -1", sorry about that. Sent a v2 with the correct patch. Best regards Dominik Cermak | Software Engineer ______________________________________________ JOYNEXT GmbH Gewerbepark Merbitz 5, 01156 Dresden / Germany Tel +49 351 45355-6385, Fax +49 351 45355 40 Dominik.Cermak at joynext.com, www.joynext.com For legal and security reasons the information provided in this e-mail is not legally binding. Upon request we would be pleased to provide you with a legally binding confirmation in written form. Any form of unauthorised use, publication, reproduction, copying or disclosure of the content of this e-mail is not permitted. This message is exclusively for the person addressed or their representative. If you are not the intended recipient of this message and its contents, please notify the sender immediately. JOYNEXT GmbH; Gesch?ftsf?hrung: Stavros Mitrakis (Vors.), Dr. Holger Buchner; Gesellschaft mit beschr?nkter Haftung mit Sitz in Dresden; Amtsgericht Dresden HRB 657; USt.-IdNr.: DE 140 212 281 From Dominik.Cermak at joynext.com Thu Aug 29 01:01:21 2024 From: Dominik.Cermak at joynext.com (Cermak Dominik) Date: Thu, 29 Aug 2024 08:01:21 +0000 Subject: [PATCH v2] nl80211: Pass "global" events to all interfaces Message-ID: Extending commit f136837202393a7e1f3182e9efdbf1aaa0c1a5c2. We got connection failures because of outdated channel information. That's because the NL80211_CMD_REG_CHANGE event is important for all interfaces, but the early termination still kicks in because it is not directed to a specific wiphy. Therefore from three interfaces, only one got the updated channel list. Fix this by changing the early termination logic to only apply to events directed either to a specific interface index for wdev. Signed-off-by: Dominik Cermak --- src/drivers/driver_nl80211_event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 903207067..8e79b5848 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -4257,7 +4257,13 @@ int process_global_event(struct nl_msg *msg, void *arg) wdev_id == bss->wdev_id)) { processed = true; do_process_drv_event(bss, gnlh->cmd, tb); - if (!wiphy_idx_set) + /* There are two types of events that may need to be + * delivered to multiple interfaces: + * 1. Events for a wiphy, as it can have multiple interfaces. + * 2. "Global" events, like NL80211_CMD_REG_CHANGE. + * Or in other words, terminate early only if it is + * directed to a specific interface or wdev. */ + if (ifidx != -1 || wdev_id_set) return NL_SKIP; /* The driver instance could have been removed, * e.g., due to NL80211_CMD_RADAR_DETECT event, -- 2.44.1 From j at w1.fi Thu Aug 29 01:33:45 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 29 Aug 2024 11:33:45 +0300 Subject: [PATCH v7 2/2] Add the similar USD APIs to dbus control interface that other apps can use the functions In-Reply-To: References: Message-ID: On Fri, Aug 23, 2024 at 09:41:19AM +0000, Chin-Ran Lo wrote: > diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen > +

    NANPublish ( (sybbbqbbbqqqqvv) : nan_args ) --> nothing

    > +

    Set the parameters of nan-publish for the interface.

    This looks very different style from existing methods. Could you please clarify the reasoning behind this vs. the "a{sv} : args" style used in many existing methods? For example, see how the Scan() method is used with a large number of optional named arguments in a dictionary. That "--> nothing" part looks incorrect. Isn't this returning "publish_id : i"? > +

    NANCancelPublish ( i : nan_args ) --> nothing

    Calling that nan_args feels unnecessarily confusing when this is publish_id from NANPublish. What about the new signals? It would be good to document them in dbus.doxygen. > diff --git a/src/common/nan_de.h b/src/common/nan_de.h > @@ -96,7 +96,7 @@ struct nan_publish_params { > unsigned int freq; > > /* Multi-channel frequencies (publishChannelList) */ > - const int *freq_list; > + int *freq_list; Why? > diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c > @@ -3605,6 +3605,52 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { > +#ifdef CONFIG_NAN_USD > + { "NANPublish", WPAS_DBUS_NEW_IFACE_INTERFACE, > + (WPADBusMethodHandler) wpas_dbus_handler_nan_publish, > + { > + { "nan_args", "(sybbbqbbbqqqqvv)", ARG_IN }, > + { "publish_id", "i", ARG_OUT }, > + END_ARGS > + } > + }, > + { "NANCancelPublish", WPAS_DBUS_NEW_IFACE_INTERFACE, > + (WPADBusMethodHandler) wpas_dbus_handler_nan_cancel_publish, > + { > + { "nan_args", "i", ARG_IN }, > + END_ARGS > + } > + }, The comments above on dbus.doxygen applies here as well.. > @@ -3983,6 +4029,38 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { > +#ifdef CONFIG_NAN_USD > + { "NANDiscoveryresult", WPAS_DBUS_NEW_IFACE_INTERFACE, And these are the undocumented signals.. I would use upper case 'r' in Result here, i.e., NANDiscoveryResult. > + { "NanPublishterminated", WPAS_DBUS_NEW_IFACE_INTERFACE, Why would this use inconsistent spelling of NAN? I would uses "NANPublishTerminated" > + { "NanSubscribeterminated", WPAS_DBUS_NEW_IFACE_INTERFACE, and "NANSubscribeTerminated". And this list of signals seems to be missing "NANReplied". > +void wpas_dbus_signal_nan_discovery_result(struct wpa_supplicant *wpa_s, > + msg = dbus_message_new_signal(wpa_s->dbus_new_path, > + WPAS_DBUS_NEW_IFACE_INTERFACE, > + "NanDiscoveryresult"); That name is not consistent with the list of signals, i.e., this should be "NANDiscoveryResult". > +void wpas_dbus_signal_nan_replied(struct wpa_supplicant *wpa_s, > + wpa_printf(MSG_INFO, "DBUS NanReplied"); I would not add that print at INFO level here. > + msg = dbus_message_new_signal(wpa_s->dbus_new_path, > + WPAS_DBUS_NEW_IFACE_INTERFACE, > + "NanReplied"); The name should be "NANReplied" to be consistent with other methods and signals. > + memcpy(reply_info.peer_addr, peer_addr, ETH_ALEN); Please use os_memcpy() instead of memcpy(). > +void wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s, > + msg = dbus_message_new_signal(wpa_s->dbus_new_path, > + WPAS_DBUS_NEW_IFACE_INTERFACE, > + "NanReceive"); "NANReceive" > +void wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s, > + int publish_id, int reason) > + msg = dbus_message_new_signal(wpa_s->dbus_new_path, > + WPAS_DBUS_NEW_IFACE_INTERFACE, > + "NanPublishterminated"); "NANPublishTerminated" > + if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, &dpub_id, > + DBUS_TYPE_INVALID) || > + !dbus_message_append_args(msg, DBUS_TYPE_INT32, &dreason, > + DBUS_TYPE_INVALID)) > + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); > + else { > + dbus_connection_send(iface->con, msg, NULL); > + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED > + "wpas_dbus_signal_nan_subscribe_terminated() dbus_connection_send (int)"); > + } Why would the D-Bus interface implementation send out that control interface NAN_SUBSCRIBE_TERMINATED event with wpa_msg()? Please remove it. wpa_printf() could be used for debug prints, but I don't see need for this entry on success. > +void wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s, > + msg = dbus_message_new_signal(wpa_s->dbus_new_path, > + WPAS_DBUS_NEW_IFACE_INTERFACE, > + "NanSubscribeterminated"); "NANSubscribeTerminated" > + if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, &dsub_id, > + DBUS_TYPE_INVALID) || > + !dbus_message_append_args(msg, DBUS_TYPE_INT32, &dreason, > + DBUS_TYPE_INVALID)) > + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); > + else { > + dbus_connection_send(iface->con, msg, NULL); > + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED > + "wpas_dbus_signal_nan_subscribe_terminated() dbus_connection_send (int)"); > + } Same here about wpa_msg(). > diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h > +++ b/wpa_supplicant/dbus/dbus_new.h > @@ -21,6 +21,7 @@ struct wpa_bss; > struct wps_event_m2d; > struct wps_event_fail; > struct wps_credential; > +struct wpa_dbus_discov_info; Why? > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c > +#define MAX_NAN_SRV_NAME_LEN 256 > +#define NAN_FREQ_LIST_ALL 0xff That second name and use of hex looks strange here since NAN_FREQ_LIST_ALL is used as the maximum number of frequencies. Why not "MAX_NAN_FREQS 255" to be consistent with the other limit? Is there particular need for these explicit limits? > +int unit_len(int dbus_type) That should be a static function since it is not used outside this file. > +{ > + switch (dbus_type) { > + case DBUS_TYPE_BYTE: > + case DBUS_TYPE_BOOLEAN: > + return 1; > + case DBUS_TYPE_INT16: > + case DBUS_TYPE_UINT16: > + return 2; > + case DBUS_TYPE_INT32: > + case DBUS_TYPE_UINT32: > + return 4; > + case DBUS_TYPE_INT64: > + case DBUS_TYPE_UINT64: > + case DBUS_TYPE_DOUBLE: > + return 8; > + } > + return 0; > +} I don't really like this at all.. Isn't there any shared function from the library to get this information? Then again, I don't think this should be needed at all since the overall design with fixed sequence of arguments looks really inconvenient. > +static bool get_gvariant_items(DBusMessageIter *piter, int type, void* datpt, u32 dat_buf_len) Why would this be needed? Wouldn't it be much more flexible and future proof to use an array with a dictionary of named arguments like more or less all other methods taking in multiple optional values use? > +DBusMessage * wpas_dbus_handler_nan_publish(DBusMessage *message, > + struct wpa_supplicant *wpa_s) > + // Extract the elements > + if (get_gvariant_items(&subiter, DBUS_TYPE_STRING, (void*)&psrv_name, sizeof(&psrv_name)) == false) { > + wpa_printf(MSG_ERROR, "Error while fetching srv_name"); > + goto fail; > + } Isn't this style of get_gvariant_items() calls forcing all the arguments to be present and in the exact this order? That seems to make this way too strict and inconvenient to use. Dictionary of named arguments seems to be much cleaner approach. > + strncpy(service_name, psrv_name, MAX_NAN_SRV_NAME_LEN-1); That could result in a truncated string. wpa_dbus_dict_*() helpers would provide all the needed code to take care of this type of details and would also get rid of the explicit MAX_NAN_SRV_NAME_LEN length limit. -- Jouni Malinen PGP id EFC895FA From j at w1.fi Thu Aug 29 01:44:32 2024 From: j at w1.fi (Jouni Malinen) Date: Thu, 29 Aug 2024 11:44:32 +0300 Subject: [PATCH v7 1/2] Add the similar USD APIs to dbus control interface that other apps can use the functions In-Reply-To: References: Message-ID: On Fri, Aug 23, 2024 at 09:41:16AM +0000, Chin-Ran Lo wrote: > This separates the control interface specific generation of a text event > message away from the main implementation of USD and makes it more > convenient to add support for other control interface mechanisms like > dbus. > Changelog since v6: > * Separate dbus parameters as its individual type > * Add the missing method, nan-update-publish > * Add the missing signal parameters: FSD, FSD-GAS > * Add the NANReplied event. > * Add the information to doc/dbus.doxygen Thanks, I applied this patch 1/2 even when there are open items on patch 2/2 since there has been and continues to be changes in this area and it is better to try to minimize the number of merge conflicts with the other changes. -- Jouni Malinen PGP id EFC895FA From benjamin at sipsolutions.net Thu Aug 29 01:54:58 2024 From: benjamin at sipsolutions.net (Benjamin Berg) Date: Thu, 29 Aug 2024 10:54:58 +0200 Subject: [PATCH v2] nl80211: Pass "global" events to all interfaces In-Reply-To: References: Message-ID: <614d3371d889a0f3e95d37465f9d1fab62586163.camel@sipsolutions.net> Hi, On Thu, 2024-08-29 at 08:01 +0000, Cermak Dominik wrote: > Extending commit f136837202393a7e1f3182e9efdbf1aaa0c1a5c2. Usually the format used is commit <12 sha1 characters> ("message") which would at least give the first line/subject of the commit message. In this case, a little bit more context is probably a good idea, especially if you reference it later using "still". > We got connection failures because of outdated channel information. > That's because the NL80211_CMD_REG_CHANGE event is important for all > interfaces, but the early termination still kicks in because it is not > directed to a specific wiphy. > Therefore from three interfaces, only one got the updated channel list. > > Fix this by changing the early termination logic to only apply to events > directed either to a specific interface index for wdev. The logic looks good to me. Benjamin > Signed-off-by: Dominik Cermak > --- > ?src/drivers/driver_nl80211_event.c | 8 +++++++- > ?1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/src/drivers/driver_nl80211_event.c > b/src/drivers/driver_nl80211_event.c > index 903207067..8e79b5848 100644 > --- a/src/drivers/driver_nl80211_event.c > +++ b/src/drivers/driver_nl80211_event.c > @@ -4257,7 +4257,13 @@ int process_global_event(struct nl_msg *msg, > void *arg) > ? ???? wdev_id == bss->wdev_id)) { > ? processed = true; > ? do_process_drv_event(bss, gnlh->cmd, > tb); > - if (!wiphy_idx_set) > + /* There are two types of events > that may need to be > + * delivered to multiple interfaces: > + * 1. Events for a wiphy, as it can > have multiple interfaces. > + * 2. "Global" events, like > NL80211_CMD_REG_CHANGE. > + * Or in other words, terminate > early only if it is > + * directed to a specific interface > or wdev. */ > + if (ifidx != -1 || wdev_id_set) > ? return NL_SKIP; > ? /* The driver instance could have > been removed, > ? * e.g., due to > NL80211_CMD_RADAR_DETECT event, From Dominik.Cermak at joynext.com Thu Aug 29 04:54:58 2024 From: Dominik.Cermak at joynext.com (Cermak Dominik) Date: Thu, 29 Aug 2024 11:54:58 +0000 Subject: AW: [PATCH v2] nl80211: Pass "global" events to all interfaces In-Reply-To: <614d3371d889a0f3e95d37465f9d1fab62586163.camel@sipsolutions.net> References: <614d3371d889a0f3e95d37465f9d1fab62586163.camel@sipsolutions.net> Message-ID: Hi Benjamin, thanks for the feedback! >On Thu, 2024-08-29 at 08:01 +0000, Cermak Dominik wrote: >> Extending commit f136837202393a7e1f3182e9efdbf1aaa0c1a5c2. > >Usually the format used is > commit <12 sha1 characters> ("message") >which would at least give the first line/subject of the commit message. > >In this case, a little bit more context is probably a good idea, >especially if you reference it later using "still". Here is my try at improving the commit message: " We got connection failures because of outdated channel information. That's because the NL80211_CMD_REG_CHANGE event is important for all interfaces. Commit f13683720239 ("nl80211: Pass wiphy events to all affected interfaces") skips the early termination for events directed to a wiphy, but that doesn't cover the regulatory change event because it doesn't have a wiphy set either. Therefore the early termination still kicks in and from three interfaces, only one got the updated channel list. Fix this by changing the early termination logic to only apply to events directed either to a specific interface index for wdev. " What do you think? Does it cover your concerns about context? Best regards Dominik Cermak | Software Engineer ______________________________________________ JOYNEXT GmbH Gewerbepark Merbitz 5, 01156 Dresden / Germany Tel +49 351 45355-6385, Fax +49 351 45355 40 Dominik.Cermak at joynext.com, www.joynext.com For legal and security reasons the information provided in this e-mail is not legally binding. Upon request we would be pleased to provide you with a legally binding confirmation in written form. Any form of unauthorised use, publication, reproduction, copying or disclosure of the content of this e-mail is not permitted. This message is exclusively for the person addressed or their representative. If you are not the intended recipient of this message and its contents, please notify the sender immediately. JOYNEXT GmbH; Gesch?ftsf?hrung: Stavros Mitrakis (Vors.), Dr. Holger Buchner; Gesellschaft mit beschr?nkter Haftung mit Sitz in Dresden; Amtsgericht Dresden HRB 657; USt.-IdNr.: DE 140 212 281 From j at w1.fi Sat Aug 31 00:37:41 2024 From: j at w1.fi (Jouni Malinen) Date: Sat, 31 Aug 2024 10:37:41 +0300 Subject: android phone often needs reboot to authenticate with 802.11ac AP In-Reply-To: <947f80cb-920f-0f68-a7bb-a05dc1e22eba@airpost.net> References: <35e2c4e8-9f49-e8d0-8692-5922fddd82e7@airpost.net> <4f33bdf8-1389-ccfd-ff26-51a1dbc0629e@airpost.net> <947f80cb-920f-0f68-a7bb-a05dc1e22eba@airpost.net> Message-ID: On Wed, Aug 28, 2024 at 09:47:34PM -0400, Bruno Dantas wrote: > The problem happened again today. It seems random and unprovoked. There seems to be nothing I can do to trigger it. > Here is an excerpt from wpa_supplicant log for a failed authentication attempt at exactly 21:18 (note: the phone that failed authentication was successfully authenticated earlier in the day). Only way to get this phone to successfully authenticate with my 5 GHz 802.11ac AP again will be to reboot the phone. Note that we never had any problems using all same hardware and software when hostapd was running at 5 GHz 802.11n. > > 08-28 21:18:04.969 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' > 08-28 21:18:08.074 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 > 08-28 21:18:11.282 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' > 08-28 21:18:14.383 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 > 08-28 21:18:17.989 3153 3153 I wpa_supplicant: wlan0: Trying to associate with SSID 'bibliotheca_alexandrina' > 08-28 21:18:21.089 3153 3153 I wpa_supplicant: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:c0:ca:b1:09:0c status_code=1 > > (Full log of failed authentication at 21:18: https://pastebin.com/nT1Mmsg7) > > Any idea what I can do to prevent this kind of authentication failure? That debug log seems to start with more verbosity (debug level entries until 21:18:00), but that drops to just information level entries when the actual connection attempt happens. As such, there is not really much to say about that since none of the details are included. -- Jouni Malinen PGP id EFC895FA