From akomisar at maxlinear.com  Mon Mar  1 04:38:52 2021
From: akomisar at maxlinear.com (Aaron Komisar)
Date: Mon, 1 Mar 2021 09:38:52 +0000
Subject: [PATCH] Add an option to set secondary channel in hostapd conf
Message-ID: <BY5PR19MB3271EC2CCB6F640C5A98D016DD9A9@BY5PR19MB3271.namprd19.prod.outlook.com>

On Fri, 26 Feb 2021 23:16:20 +0200, Jouni Malinen wrote:
> > Usefull in case we want to specify the secondary channel
> > or in case we want to be on 20mghz with 40mghz capabilities.
> > 
> > It is possible in chan_switch to set secondary channel,
> > however it was not possible to do so when hostapd start.
> > This commit adds this option.
> 
> Can you please clarify how this proposed new parameter differs from the
> existing ht_capab=[HT40+], ht_capab=[HT40-], and ht_capab=[HT40+][HT40-]
> options?
> 

The existing parameter enables setting capabilities but not the actual current
operating channel configuration.

> Please also note that the IEEE 802.11 standard has mandatory
> requirements for 40 MHz co-existence on when the primary and secondary
> channels have to be switched and I'm unlikely to accept changes
> that would allow the user to bypass those requirements.
> 

The purpose of the patch is to provide capabilities similar to chan_swich
command, which already supports setting secondary channel dynamically.

A similar commit has already been integrated to prplMESH project in order to
support cancel CAC command by disabling interfaces, setting a specific channel
and enabling the interfaces.
(https://gitlab.com/prpl-foundation/intel/iwlwav-hostap/-/merge_requests/5) 
Currently a 20Mhz channel cannot be set.

-- 
Aaron Komisar



From j at w1.fi  Mon Mar  1 11:11:19 2021
From: j at w1.fi (Jouni Malinen)
Date: Mon, 1 Mar 2021 18:11:19 +0200
Subject: [PATCH] Update old link to ACS wiki documentation
In-Reply-To: <20210301041926.539327-1-nikolas@gnu.org>
References: <20210301041926.539327-1-nikolas@gnu.org>
Message-ID: <20210301161119.GA846808@w1.fi>

On Sun, Feb 28, 2021 at 11:19:26PM -0500, Nikolas Nyby wrote:
> The old links here were broken.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From michael-dev at fami-braun.de  Mon Mar  1 16:56:14 2021
From: michael-dev at fami-braun.de (michael-dev)
Date: Mon, 01 Mar 2021 22:56:14 +0100
Subject: Crash in hostapd_eid_time_adv with DFS CAC
Message-ID: <f842dc7280e61e0335d9a12abee59375@fami-braun.de>

Hi,

I'm seeing the following and very similar backtrace in different hostapd 
versions (based on 59e9794c or c7a9a574). I'll still need to reproduce 
this with upstream (vanilla) hostapd, but was wondering, if there is any 
hint on it yet? (as the locally applied patches do not alter beacon 
setup or timeadv).

wpabuf.h:60 ist wpabuf_len, which is called from hostapd_eid_time_adv on 
hapd->time_adv

#0  0x0fb5c4a8 in _wordcopy_fwd_dest_aligned () from /lib/libc.so.6
#1  0x0fb5c2e4 in memcpy () from /lib/libc.so.6
#2  0x10028d7c in     (hapd=hapd at entry=0x106b07f0, eid=0x106cc6d9 <error 
reading variable>) at ../src/utils/wpabuf.h:60
#3  0x1002ab58 in ieee802_11_build_ap_params 
(hapd=hapd at entry=0x106b07f0, params=0xbffd0d30, params at entry=0xbffd0d40) 
at ../src/ap/beacon.c:1532
#4  0x1002afe8 in ieee802_11_set_beacon (hapd=hapd at entry=0x106b07f0) at 
../src/ap/beacon.c:1763
#5  0x100093b4 in hostapd_setup_bss (hapd=hapd at entry=0x106b07f0, 
first=first at entry=0) at ../src/ap/hostapd.c:1377
#6  0x1000b500 in hostapd_setup_interface_complete_sync 
(iface=0x106acf70, err=<optimized out>) at ../src/ap/hostapd.c:2089
#7  0x1000b5fc in hostapd_setup_interface_complete 
(iface=iface at entry=0x106acf70, err=err at entry=0) at 
../src/ap/hostapd.c:2260
#8  0x10082c48 in hostapd_dfs_complete_cac (iface=0x106acf70, success=1, 
freq=5620, ht_enabled=<optimized out>, chan_offset=<optimized out>, 
chan_width=2, cf1=5630, cf2=0) at ../src/ap/dfs.c:908
#9  0x10012388 in hostapd_event_dfs_cac_aborted (hapd=<optimized out>, 
radar=<optimized out>) at ../src/ap/drv_callbacks.c:1713
#10 wpa_supplicant_event (ctx=0x106ad980, event=EVENT_DFS_CAC_FINISHED, 
data=0xbffd1550) at ../src/ap/drv_callbacks.c:2004
#11 0x1006ce14 in mlme_event_dh_event (drv=<optimized out>, 
bss=<optimized out>, tb=<optimized out>) at ../src/drivers/driver.h:6049
#12 do_process_drv_event (tb=0xbffd10c8, cmd=<optimized out>, 
bss=<optimized out>) at ../src/drivers/driver_nl80211_event.c:2971
#13 process_global_event (msg=<optimized out>, arg=<optimized out>) at 
../src/drivers/driver_nl80211_event.c:3030
#14 0x0fe3f988 in nl_cb_call (msg=<optimized out>, type=<optimized out>, 
cb=<optimized out>) at ./include/netlink-private/netlink.h:144
#15 recvmsgs (cb=0x106b3390, sk=0x106b34b0) at lib/nl.c:1007
#16 nl_recvmsgs_report (sk=sk at entry=0x106b34b0, cb=cb at entry=0x106b3390) 
at lib/nl.c:1058
#17 0x0fe3fc00 in nl_recvmsgs (sk=sk at entry=0x106b34b0, 
cb=cb at entry=0x106b3390) at lib/nl.c:1082
#18 0x100545d8 in wpa_driver_nl80211_event_receive (sock=<optimized 
out>, eloop_ctx=0x106b3390, handle=0x106b34b0) at 
../src/drivers/driver_nl80211.c:1758
#19 0x1002d220 in eloop_sock_table_dispatch 
(table=table at entry=0x100e1410 <eloop+8>, fds=fds at entry=0x106b8c70) at 
../src/utils/eloop.c:603
#20 0x1002df9c in eloop_sock_table_dispatch (fds=<optimized out>, 
table=0x100e1410 <eloop+8>) at ../src/utils/eloop.c:597
#21 eloop_run () at ../src/utils/eloop.c:1228

Regards,
M. Braun


From michael-dev at fami-braun.de  Mon Mar  1 17:35:01 2021
From: michael-dev at fami-braun.de (michael-dev)
Date: Mon, 01 Mar 2021 23:35:01 +0100
Subject: Crash in hostapd_eid_time_adv with DFS CAC
In-Reply-To: <f842dc7280e61e0335d9a12abee59375@fami-braun.de>
References: <f842dc7280e61e0335d9a12abee59375@fami-braun.de>
Message-ID: <ffadc0e0f91e12022dd15f1ed4e55586@fami-braun.de>

Hi,

this is the logs resulting in the crash.

It can be seen that we have DFS-RADAR-DETECTED on wlan1, wlan1: 
interface state ENABLED->DISABLED, and later wlan1 is reenabled.
Thus hostapd_disable_iface -> hostapd_free_hapd_data -> 
wpabuf_free(hapd->time_adv) when wlan1 becomes disabled.
Later when wlan1 is re-enabled, hapd->time_adv points to a freed 
pointer, as - different to e.g. hapd->radius - it is not cleared after 
freeing.

Please find attached a patch that addresses this.

Regards,
M. Braun

1614623852.209013: wl1_2: STA xx:xx:xx:xx:xx:xx WPA: sending 1/4 msg of 
4-Way Handshake
VLAN: Interface wl1_2.4096 configured to vlan 527 in br_vlan_add
VLAN (netlink): Interface wl1_2.4096 add to vlan 527 in _linux_br_vlan
VLAN: Interface wl1_2.4096 configured to vlan 527 in vlan_newlink_real
1614623852.219940: wl1_2: STA xx:xx:xx:xx:xx:xx WPA: received EAPOL-Key 
frame (2/4 Pairwise)
1614623852.220845: wl1_2: STA xx:xx:xx:xx:xx:xx WPA: sending 3/4 msg of 
4-Way Handshake
1614623852.236195: wl1_2: STA xx:xx:xx:xx:xx:xx WPA: received EAPOL-Key 
frame (4/4 Pairwise)
wl1_2: AP-STA-CONNECTED xx:xx:xx:xx:xx:xx
1614623852.238279: wl1_2: STA xx:xx:xx:xx:xx:xx IEEE 802.1X: authorizing 
port
1614623852.239046: wl1_2: STA xx:xx:xx:xx:xx:xx RADIUS: starting 
accounting session E517AD69514481A6
1614623852.239385: wl1_2: RADIUS Sending RADIUS message to accounting 
server
1614623852.240467: wl1_2: RADIUS Next RADIUS client retransmit in 3 
seconds
1614623852.240820: wl1_2: STA xx:xx:xx:xx:xx:xx WPA: pairwise key 
handshake completed (RSN)
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan1: DFS-NEW-CHANNEL freq=5620 chan=124 sec_chan=1
DFS failed to schedule CSA (-22) - trying fallback
wlan1: AP-DISABLED
1614623852.294656: wlan1: RADIUS Sending RADIUS message to accounting 
server
1614623852.295534: wlan1: RADIUS Next RADIUS client retransmit in 3 
seconds
1614623852.296736: wl1_1: RADIUS Sending RADIUS message to accounting 
server
1614623852.297268: wl1_1: RADIUS Next RADIUS client retransmit in 3 
seconds
Failed to remove bssid to ft_bridge br-mgnt
1614623852.634842: wl1_2: STA xx:xx:xx:xx:xx:xx MLME: 
MLME-DEAUTHENTICATE.indication(xx:xx:xx:xx:xx:xx, 1)
1614623852.635865: wl1_2: STA xx:xx:xx:xx:xx:xx RADIUS: updated TX/RX 
stats: rx_bytes=1411 [0:0] tx_bytes=557 [0:0] bytes_64bit=1
1614623852.636632: wl1_2: RADIUS Sending RADIUS message to accounting 
server
1614623852.637981: wl1_2: RADIUS Next RADIUS client retransmit in 3 
seconds
1614623852.638568: wl1_2: STA xx:xx:xx:xx:xx:xx RADIUS: stopped 
accounting session E517AD69514481A6
wl1_2: AP-STA-DISCONNECTED xx:xx:xx:xx:xx:xx
1614623853.044158: wl1_2: RADIUS Sending RADIUS message to accounting 
server
1614623853.044909: wl1_2: RADIUS Next RADIUS client retransmit in 2 
seconds
1614623853.247363: wl1_6: RADIUS Sending RADIUS message to accounting 
server
1614623853.250053: wl1_6: RADIUS Next RADIUS client retransmit in 3 
seconds
nl80211: Failed to remove interface wl1_6 from bridge br-wlan: Invalid 
argument
nl80211: deinit ifname=wlan1 disabled_11b_rates=0
wlan1: interface state ENABLED->DISABLED
rfkill: Cannot open RFKILL control device
wlan1: interface state DISABLED->COUNTRY_UPDATE
wlan1: interface state COUNTRY_UPDATE->HT_SCAN
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
wlan0: DFS-RADAR-DETECTED freq=5260 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5270 cf2=0
current_mode != IEEE80211A
wlan1: interface state HT_SCAN->DFS
wlan1: DFS-CAC-START freq=5620 chan=124 sec_chan=1, width=0, seg0=0, 
seg1=0, cac_time=60s
1614623880.597302: wl0_2: STA xx:xx:xx:xx:xx:xx RADIUS: updated TX/RX 
stats: rx_bytes=259709 [0:0] tx_bytes=4886318 [0:0] bytes_64bit=1
1614623880.597809: wl0_2: RADIUS Sending RADIUS message to accounting 
server
1614623880.598291: wl0_2: RADIUS Next RADIUS client retransmit in 3 
seconds
1614623880.653695: wl0_2: RADIUS Received 20 bytes from RADIUS server
1614623880.654185: wl0_2: RADIUS Received RADIUS message
1614623880.654969: wl0_2: STA xx:xx:xx:xx:xx:xx RADIUS: Received RADIUS 
packet matched with a pending request, round trip time 0.05 sec
wlan0: DFS-CAC-COMPLETED success=1 freq=5620 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5630 cf2=0
current_mode != IEEE80211A
wlan1: DFS-CAC-COMPLETED success=1 freq=5620 ht_enabled=1 chan_offset=1 
chan_width=2 cf1=5630 cf2=0
1614623915.642704: wlan1: RADIUS Accounting server 10.30.254.16:1813
1614623915.643888: wlan1: RADIUS Sending RADIUS message to accounting 
server
1614623915.644632: wlan1: RADIUS Next RADIUS client retransmit in 3 
seconds
10.30.1.94 2021-03-01T18:38:35+01:00 femap015e hostapd-capture:
10.30.1.94 2021-03-01T18:38:35+01:00 femap015e hostapd-capture: Program 
received signal SIGSEGV, Segmentation fault.


Am 01.03.2021 22:56, schrieb michael-dev:
> Hi,
> 
> I'm seeing the following and very similar backtrace in different
> hostapd versions (based on 59e9794c or c7a9a574). I'll still need to
> reproduce this with upstream (vanilla) hostapd, but was wondering, if
> there is any hint on it yet? (as the locally applied patches do not
> alter beacon setup or timeadv).
> 
> wpabuf.h:60 ist wpabuf_len, which is called from hostapd_eid_time_adv
> on hapd->time_adv
> 
> #0  0x0fb5c4a8 in _wordcopy_fwd_dest_aligned () from /lib/libc.so.6
> #1  0x0fb5c2e4 in memcpy () from /lib/libc.so.6
> #2  0x10028d7c in     (hapd=hapd at entry=0x106b07f0, eid=0x106cc6d9
> <error reading variable>) at ../src/utils/wpabuf.h:60
> #3  0x1002ab58 in ieee802_11_build_ap_params
> (hapd=hapd at entry=0x106b07f0, params=0xbffd0d30,
> params at entry=0xbffd0d40) at ../src/ap/beacon.c:1532
> #4  0x1002afe8 in ieee802_11_set_beacon (hapd=hapd at entry=0x106b07f0)
> at ../src/ap/beacon.c:1763
> #5  0x100093b4 in hostapd_setup_bss (hapd=hapd at entry=0x106b07f0,
> first=first at entry=0) at ../src/ap/hostapd.c:1377
> #6  0x1000b500 in hostapd_setup_interface_complete_sync
> (iface=0x106acf70, err=<optimized out>) at ../src/ap/hostapd.c:2089
> #7  0x1000b5fc in hostapd_setup_interface_complete
> (iface=iface at entry=0x106acf70, err=err at entry=0) at
> ../src/ap/hostapd.c:2260
> #8  0x10082c48 in hostapd_dfs_complete_cac (iface=0x106acf70,
> success=1, freq=5620, ht_enabled=<optimized out>,
> chan_offset=<optimized out>, chan_width=2, cf1=5630, cf2=0) at
> ../src/ap/dfs.c:908
> #9  0x10012388 in hostapd_event_dfs_cac_aborted (hapd=<optimized out>,
> radar=<optimized out>) at ../src/ap/drv_callbacks.c:1713
> #10 wpa_supplicant_event (ctx=0x106ad980,
> event=EVENT_DFS_CAC_FINISHED, data=0xbffd1550) at
> ../src/ap/drv_callbacks.c:2004
> #11 0x1006ce14 in mlme_event_dh_event (drv=<optimized out>,
> bss=<optimized out>, tb=<optimized out>) at
> ../src/drivers/driver.h:6049
> #12 do_process_drv_event (tb=0xbffd10c8, cmd=<optimized out>,
> bss=<optimized out>) at ../src/drivers/driver_nl80211_event.c:2971
> #13 process_global_event (msg=<optimized out>, arg=<optimized out>) at
> ../src/drivers/driver_nl80211_event.c:3030
> #14 0x0fe3f988 in nl_cb_call (msg=<optimized out>, type=<optimized
> out>, cb=<optimized out>) at ./include/netlink-private/netlink.h:144
> #15 recvmsgs (cb=0x106b3390, sk=0x106b34b0) at lib/nl.c:1007
> #16 nl_recvmsgs_report (sk=sk at entry=0x106b34b0,
> cb=cb at entry=0x106b3390) at lib/nl.c:1058
> #17 0x0fe3fc00 in nl_recvmsgs (sk=sk at entry=0x106b34b0,
> cb=cb at entry=0x106b3390) at lib/nl.c:1082
> #18 0x100545d8 in wpa_driver_nl80211_event_receive (sock=<optimized
> out>, eloop_ctx=0x106b3390, handle=0x106b34b0) at
> ../src/drivers/driver_nl80211.c:1758
> #19 0x1002d220 in eloop_sock_table_dispatch
> (table=table at entry=0x100e1410 <eloop+8>, fds=fds at entry=0x106b8c70) at
> ../src/utils/eloop.c:603
> #20 0x1002df9c in eloop_sock_table_dispatch (fds=<optimized out>,
> table=0x100e1410 <eloop+8>) at ../src/utils/eloop.c:597
> #21 eloop_run () at ../src/utils/eloop.c:1228
> 
> Regards,
> M. Braun
> 
> _______________________________________________
> Hostap mailing list
> Hostap at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap
-------------- next part --------------
A non-text attachment was scrubbed...
Name: timeadv-fix.patch
Type: text/x-diff
Size: 844 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210301/70820c14/attachment.bin>

From matthewmwang at chromium.org  Mon Mar  1 18:34:06 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Mon,  1 Mar 2021 15:34:06 -0800
Subject: [PATCH v2] Reject auths during explicit roam requests
Message-ID: <20210301233406.3964281-1-matthewmwang@chromium.org>

The roam D-Bus and wpa_cli commands flip the reassociate bit before
calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
ongoing scans, which causes scan results to be reported. Since the
reassociate bit is set, this will trigger a connection attempt based on
the aborted scan's scan results and cancel the initial connetion
request. This often causes wpa_supplicant to reassociate to the same AP
it is currently associated to.

Add a roam_in_progress flag to indicate that we're currently attempting
to roam via D-Bus so that we don't initate another connection attempt.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
Series-to: hostap at lists.infradead.org
Series-cc: j at w1.fi, matthewmwang at chromium.org
Change-Id: Ibeb6cceddabd10cab6938411f54ed63f4d4428c1
---
 wpa_supplicant/ctrl_iface.c             | 9 +++++++++
 wpa_supplicant/dbus/dbus_new_handlers.c | 9 +++++++++
 wpa_supplicant/sme.c                    | 7 +++++++
 wpa_supplicant/wpa_supplicant_i.h       | 1 +
 4 files changed, 26 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0d4c2bc8f0b..048fe72d472 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return 0;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 7d20f2123a8..6803558accd 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2005,6 +2005,15 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return NULL;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 522c8297f7e..dde80863a98 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	struct wpa_connect_work *cwork = work->ctx;
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 
+	wpa_s->roam_in_progress = false;
+
 	if (deinit) {
 		if (work->started)
 			wpa_s->connect_work = NULL;
@@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 		return;
 	}
 
+	if (wpa_s->roam_in_progress) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"SME: Reject sme_authenticate() in favor of explicit roam request");
+		return;
+	}
 	if (radio_work_pending(wpa_s, "sme-connect")) {
 		/*
 		 * The previous sme-connect work might no longer be valid due to
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7d14b627d89..b6c339ab711 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -621,6 +621,7 @@ struct wpa_supplicant {
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
+	bool roam_in_progress; /* roam in progress */
 	unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
 	unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
-- 
2.29.2



From matthewmwang at chromium.org  Mon Mar  1 18:34:17 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Mon, 1 Mar 2021 15:34:17 -0800
Subject: [PATCH] Reject auths during explicit roam requests
In-Reply-To: <20210226212530.GC508088@w1.fi>
References: <20210223004925.342911-1-matthewmwang@chromium.org>
 <20210226212530.GC508088@w1.fi>
Message-ID: <CABRiz0p7deb2QLw-ffWU_JhNyBLzVNVK7saNUUBYhmzNL4ONdQ@mail.gmail.com>

Thanks for the replies Jouni.

> Is this limited to "sme-connect" on purpose or should "connect" be included as well?

This is limited to sme-connect. Where the two differ is that
sme-connect always prefers the newest request while connect defaults
to keeping the pending one.

> This is now the only place where this new variable is reset to 0. Is
that sufficient? What if the roam attempt fails for some reason before
being able to reach the authentication step? Could this flag be
forgotten in place and could that cause issues for the future completely
unrelated connection attempt?

As far as I can tell, the callback will always be called. The flag
will only be set when we see that there is an 'sme-connect' radio work
pending, and when the radio work is pending, it should always call the
callback (and the flag is reset at the very top of the callback). Even
cancelling the radio work should call the callback, just with deinit
== 1 (this won't prevent the flag from being reset since it's done
before we check for deinit). Unless there is a way to cancel the radio
work without triggering the callback (I'm not aware of any), then the
flag should always be reset.

I'll resend the patch with bool instead of int.

On Fri, Feb 26, 2021 at 1:25 PM Jouni Malinen <j at w1.fi> wrote:
>
> On Mon, Feb 22, 2021 at 04:49:25PM -0800, Matthew Wang wrote:
> > The roam D-Bus and wpa_cli commands flip the reassociate bit before
> > calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
> > ongoing scans, which causes scan results to be reported. Since the
> > reassociate bit is set, this will trigger a connection attempt based on
> > the aborted scan's scan results and cancel the initial connetion
> > request. This often causes wpa_supplicant to reassociate to the same AP
> > it is currently associated to.
> >
> > Add a roam_in_progress flag to indicate that we're currently attempting
> > to roam via D-Bus so that we don't initate another connection attempt.
>
> > diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> > @@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
> > +     /*
> > +      * Indicate that an explicitly requested roam is in progress so scan
> > +      * results that come in before the 'sme-connect' radio work gets
> > +      * executed do not override the original connection attempt.
> > +      */
> > +     if (radio_work_pending(wpa_s, "sme-connect")) {
> > +             wpa_s->roam_in_progress = 1;
> > +     }
>
> Is this limited to "sme-connect" on purpose or should "connect" be
> included as well? I understand the only user of wpa_s->roam_in_progress
> in this patch is in sme.c, but is that really the only issue that this
> tries to address or could the same issue with ignoring an explicit roam
> request apply to drivers that use internal SME instead of the
> wpa_supplicant/sme.c implementation with split authentication and
> association steps?
>
> > diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
> > index c6cef5b1447..4fd0c5e104f 100644
> > --- a/wpa_supplicant/sme.c
> > +++ b/wpa_supplicant/sme.c
> > @@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
> >       struct wpa_connect_work *cwork = work->ctx;
> >       struct wpa_supplicant *wpa_s = work->wpa_s;
> >
> > +     wpa_s->roam_in_progress = 0;
>
> This is now the only place where this new variable is reset to 0. Is
> that sufficient? What if the roam attempt fails for some reason before
> being able to reach the authentication step? Could this flag be
> forgotten in place and could that cause issues for the future completely
> unrelated connection attempt?
>
> > @@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
> >               return;
> >       }
> >
> > +     if (wpa_s->roam_in_progress) {
> > +             wpa_dbg(wpa_s, MSG_DEBUG,
> > +                     "SME: Reject sme_authenticate() in favor of explicit roam request");
> > +             return;
> > +     }
>
> I.e., how would this recover from sme_auth_start_cb() not getting called
> after the last roam request?
>
> > diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
> > +     int roam_in_progress; /* roam in progress */
>
> The preferred type for new boolean variables is to use the C99 boolean
> type through bool val = true/false.
>
> --
> Jouni Malinen                                            PGP id EFC895FA


From matthewmwang at chromium.org  Mon Mar  1 18:56:50 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Mon,  1 Mar 2021 15:56:50 -0800
Subject: [PATCH v2] Reject auths during explicit roam requests
Message-ID: <20210301235650.3965595-1-matthewmwang@chromium.org>

The roam D-Bus and wpa_cli commands flip the reassociate bit before
calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
ongoing scans, which causes scan results to be reported. Since the
reassociate bit is set, this will trigger a connection attempt based on
the aborted scan's scan results and cancel the initial connetion
request. This often causes wpa_supplicant to reassociate to the same AP
it is currently associated to.

Add a roam_in_progress flag to indicate that we're currently attempting
to roam via D-Bus so that we don't initate another connection attempt.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
Series-to: hostap at lists.infradead.org
Series-cc: j at w1.fi, matthewmwang at chromium.org
Change-Id: Ibeb6cceddabd10cab6938411f54ed63f4d4428c1
---
 wpa_supplicant/ctrl_iface.c             | 9 +++++++++
 wpa_supplicant/dbus/dbus_new_handlers.c | 9 +++++++++
 wpa_supplicant/sme.c                    | 7 +++++++
 wpa_supplicant/wpa_supplicant_i.h       | 1 +
 4 files changed, 26 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0d4c2bc8f0b..048fe72d472 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return 0;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 7d20f2123a8..6803558accd 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2005,6 +2005,15 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return NULL;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 522c8297f7e..dde80863a98 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	struct wpa_connect_work *cwork = work->ctx;
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 
+	wpa_s->roam_in_progress = false;
+
 	if (deinit) {
 		if (work->started)
 			wpa_s->connect_work = NULL;
@@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 		return;
 	}
 
+	if (wpa_s->roam_in_progress) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"SME: Reject sme_authenticate() in favor of explicit roam request");
+		return;
+	}
 	if (radio_work_pending(wpa_s, "sme-connect")) {
 		/*
 		 * The previous sme-connect work might no longer be valid due to
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7d14b627d89..b6c339ab711 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -621,6 +621,7 @@ struct wpa_supplicant {
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
+	bool roam_in_progress; /* roam in progress */
 	unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
 	unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
-- 
2.29.2



From greearb at candelatech.com  Mon Mar  1 18:58:03 2021
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 1 Mar 2021 15:58:03 -0800
Subject: [PATCH v2] Reject auths during explicit roam requests
In-Reply-To: <20210301233406.3964281-1-matthewmwang@chromium.org>
References: <20210301233406.3964281-1-matthewmwang@chromium.org>
Message-ID: <77e2dc14-64fa-bcd4-b17c-4d2584e57847@candelatech.com>

On 3/1/21 3:34 PM, Matthew Wang wrote:
> The roam D-Bus and wpa_cli commands flip the reassociate bit before
> calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
> ongoing scans, which causes scan results to be reported. Since the
> reassociate bit is set, this will trigger a connection attempt based on
> the aborted scan's scan results and cancel the initial connetion
> request. This often causes wpa_supplicant to reassociate to the same AP
> it is currently associated to.
> 
> Add a roam_in_progress flag to indicate that we're currently attempting
> to roam via D-Bus so that we don't initate another connection attempt.

I had similar issues, in case it helps, here is my patch:

https://github.com/greearb/hostap-ct/commit/50b1c17d0a782dc4d354ac7366500763611ea5af

I first relaxed thresholds by default, and then allowed configuring them.  When something
beyond hostapd is controlling roaming, I set the thresholds so that it would never automatically
roam based on scan results.

Lord git only knows how much of this was built on previous patches in my tree...

Thanks,
Ben


> 
> Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
> Series-to: hostap at lists.infradead.org
> Series-cc: j at w1.fi, matthewmwang at chromium.org
> Change-Id: Ibeb6cceddabd10cab6938411f54ed63f4d4428c1
> ---
>   wpa_supplicant/ctrl_iface.c             | 9 +++++++++
>   wpa_supplicant/dbus/dbus_new_handlers.c | 9 +++++++++
>   wpa_supplicant/sme.c                    | 7 +++++++
>   wpa_supplicant/wpa_supplicant_i.h       | 1 +
>   4 files changed, 26 insertions(+)
> 
> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> index 0d4c2bc8f0b..048fe72d472 100644
> --- a/wpa_supplicant/ctrl_iface.c
> +++ b/wpa_supplicant/ctrl_iface.c
> @@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
>   	wpa_s->reassociate = 1;
>   	wpa_supplicant_connect(wpa_s, bss, ssid);
>   
> +	/*
> +	 * Indicate that an explicitly requested roam is in progress so scan
> +	 * results that come in before the 'sme-connect' radio work gets
> +	 * executed do not override the original connection attempt.
> +	 */
> +	if (radio_work_pending(wpa_s, "sme-connect")) {
> +		wpa_s->roam_in_progress = true;
> +	}
> +
>   	return 0;
>   #endif /* CONFIG_NO_SCAN_PROCESSING */
>   }
> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
> index 7d20f2123a8..6803558accd 100644
> --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> @@ -2005,6 +2005,15 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
>   	wpa_s->reassociate = 1;
>   	wpa_supplicant_connect(wpa_s, bss, ssid);
>   
> +	/*
> +	 * Indicate that an explicitly requested roam is in progress so scan
> +	 * results that come in before the 'sme-connect' radio work gets
> +	 * executed do not override the original connection attempt.
> +	 */
> +	if (radio_work_pending(wpa_s, "sme-connect")) {
> +		wpa_s->roam_in_progress = true;
> +	}
> +
>   	return NULL;
>   #endif /* CONFIG_NO_SCAN_PROCESSING */
>   }
> diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
> index 522c8297f7e..dde80863a98 100644
> --- a/wpa_supplicant/sme.c
> +++ b/wpa_supplicant/sme.c
> @@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
>   	struct wpa_connect_work *cwork = work->ctx;
>   	struct wpa_supplicant *wpa_s = work->wpa_s;
>   
> +	wpa_s->roam_in_progress = false;
> +
>   	if (deinit) {
>   		if (work->started)
>   			wpa_s->connect_work = NULL;
> @@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
>   		return;
>   	}
>   
> +	if (wpa_s->roam_in_progress) {
> +		wpa_dbg(wpa_s, MSG_DEBUG,
> +			"SME: Reject sme_authenticate() in favor of explicit roam request");
> +		return;
> +	}
>   	if (radio_work_pending(wpa_s, "sme-connect")) {
>   		/*
>   		 * The previous sme-connect work might no longer be valid due to
> diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
> index 7d14b627d89..b6c339ab711 100644
> --- a/wpa_supplicant/wpa_supplicant_i.h
> +++ b/wpa_supplicant/wpa_supplicant_i.h
> @@ -621,6 +621,7 @@ struct wpa_supplicant {
>   	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
>   				     * field contains the target BSSID. */
>   	int reassociate; /* reassociation requested */
> +	bool roam_in_progress; /* roam in progress */
>   	unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
>   	unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
>   	int disconnected; /* all connections disabled; i.e., do no reassociate
> 


-- 
Ben Greear <greearb at candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


From matthewmwang at chromium.org  Mon Mar  1 20:22:26 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Mon, 1 Mar 2021 17:22:26 -0800
Subject: [PATCH 2/6] Rewrite roaming logic
In-Reply-To: <20210228092231.GA10281@w1.fi>
References: <20200602001018.83640-1-matthewmwang@chromium.org>
 <20200602001018.83640-2-matthewmwang@chromium.org>
 <20200619152927.GA26140@w1.fi>
 <CABRiz0rOiQMDmBpci5HrC=Nz-3zAs_Hhc6WbFXtknp=BiTUmpw@mail.gmail.com>
 <CABRiz0rF-LF6rkQGOpxz4h84MhEvffbKujC_YGjm9EQ+1J7__g@mail.gmail.com>
 <20210228092231.GA10281@w1.fi>
Message-ID: <CABRiz0rDBCesbRdGUpo5+qKpgSKBN6-4uHX--ema1n4bR5BWww@mail.gmail.com>

> the main issue I see
here is in that behavior that seems to completely prevent roaming unless
signal level increases significantly regardless of other factors.

This is only the case for the lowest bucket (< -85dBm), as you've
pointed out, and in this case, I would argue that roaming for
estimated throughput gains doesn't actually provide much (if any)
benefit. -86dBm is hardly usable WiFi, and the roam will only add to
the disruption in connectivity, resulting in a decrease in the actual
throughput. Putting the non-HT vs HT question aside for a moment, if
we take two APs that are both at approximately -86 dBm from the
device, according to the original algorithm, any fluctuation in signal
level where the current signal is any worse than the signal of the
other AP will cause a roam, and as I'm sure you're aware, fluctuation
in signal level happens constantly. What we end up seeing is the
device aggressively roaming back and forth for no real signal or
throughput gains. The poor signal level (combined with constant
roaming) far outweighs any gains in estimated throughput.

Even taking into consideration the 2 Mbps non-HT AP vs the 8.666 Mbps
HT AP situation, I think it makes sense to encode some slight bias
towards the HT AP for the reasons you mentioned (A-MPDU and A-MSDU),
but there's no point in roaming to the HT AP if we're just going to
roam away from it because the signal fluctuated a couple dBm.

The point I'm trying to make is that RSSI measurements are moving
targets and can see quite a bit of variance, and the algorithm should
be able to absorb some of this. If we encoded a preference for HT, we
could see something like: at -86 dBm, roam to HT AP when signal is 2
dBm greater, roam to non-HT AP when signal is 6 dBm greater. In this
case, even if two APs have the same "real" RSSI relative to the
device, it's extremely likely, and, in fact, almost inevitable, that
the HT AP will be > 2 dBm greater at some point, and it's much less
likely that the non-HT AP will be > 6 dBm greater at some point. Using
the mac80211_hwsim module to test roaming has this shortcoming - that
the RSSI measurements are too precise and don't actually simulate
real-world environments accurately in this regard.

My arguments up to now have been pretty much entirely conjecture, but
I'd like to offer some (maybe slightly hand-wavy) data. ChromeOS is
one of the largest (if not the largest) consumers of the roaming
functionality in wpa_supplicant since Android offloads roaming to the
chipset. We've gotten many complaints about roaming from enterprise
customers in the past, but ever since we've adopted these roaming
changes nine or so months ago (along with a few more since I first
submitted this patch) in our tree, we've had customers tell us that
their issues were resolved and roaming complaints as a whole have
become more or less non-existent. Additionally, we've since added
integration tests to simulate movement between APs using programmable
attenuators, and we've seen measurable improvements in stability
(device is able to withstand minor fluctuations in signal level
without roaming) and no decreases in mobility (device is still able to
roam before getting deauth-ed for leaving the original AP).

I hope this makes sense, and I'm more than happy to continue
discussing anything you still think needs to be improved or is
unsatisfactory. I think encoding the HT preference is reasonable and
I'll go ahead and do that when I get a chance, but beyond that, I
still believe this is a step in the right direction. Sorry for the
long response, and if you've made it this far, thanks for reading :)

On Sun, Feb 28, 2021 at 1:22 AM Jouni Malinen <j at w1.fi> wrote:
>
> On Tue, Jun 23, 2020 at 02:41:19PM -0700, Matthew Wang wrote:
> > Thanks for the response. I ran the prefer_ht20_during_roam test and it
> > looks like it expects a roam from a non-HT AP at -30 dBm with 54 Mbps
> > est_tpt to an HT AP at -30 dBm with 65 Mbps est_tpt. I'm not too clear
> > on all the phy layer details of HT, but in my opinion, roaming from an
> > AP at such a strong signal level (-30 dBm) needs a fairly strong
> > justification, and a 20% increase (54 -> 65) in estimated throughput
> > is not that strong. That being said, if there are benefits to moving
> > from non-HT to HT that aren't captured in the {signal, est_tpt} pair,
> > then I'd advocate for using a flag that behaves similarly to the
> > to_{2,5}ghz flags, which adjusts the roaming difficulty up/down 2 dBm
> > depending on the direction of the roam. We can assign some value for
> > {to,from}_ht flags that subtracts from or adds to the roaming
> > difficulty depending on how valuable HT vs non-HT is. Does this make
> > sense?
>
> That behavior is not limited to so high signal strength value. Same
> happens with all other values and the impact is much more severe in some
> cases. For example, with both APs at -86 dBm non-HT AP gets 2 Mbps
> est_tpt and HT AP gets 8.666 Mbps. Still, roaming is prevented ("Skip
> roam - too small difference in signal level (0 < 4)"). In other words,
> even that min_diff -= 2 style adjustment that is given for to_5ghz would
> not help here. In fact, it looks like this patch would make it
> impossible to roam to an AP that shows better throughput estimate
> (regardless of how large a difference) on the same band unless there is
> also at least 4 dB increase in the signal level when cur_level < -85.
> That does not look reasonable.
>
> And yes, HT does come with possibility of using A-MPDU and A-MSDU
> aggregation which can result in significant improvement in throughput
> and airtime efficiency and that is in addition to the estimated
> throughput values from TX rates. So it might indeed make sense to
> add/subtract difficulty for roaming, but still, the main issue I see
> here is in that behavior that seems to completely prevent roaming unless
> signal level increases significantly regardless of other factors.
>
> --
> Jouni Malinen                                            PGP id EFC895FA


From matthewmwang at chromium.org  Mon Mar  1 20:25:36 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Mon, 1 Mar 2021 17:25:36 -0800
Subject: [PATCH v2] Reject auths during explicit roam requests
In-Reply-To: <77e2dc14-64fa-bcd4-b17c-4d2584e57847@candelatech.com>
References: <20210301233406.3964281-1-matthewmwang@chromium.org>
 <77e2dc14-64fa-bcd4-b17c-4d2584e57847@candelatech.com>
Message-ID: <CABRiz0ohRN3FAhXy6abYufsKFAckqfhqo1CREvQ5r4V9Hx8OOg@mail.gmail.com>

Thanks Ben, the patch is a good idea, but doesn't exactly address my
issue. The D-Bus/wpa_cli roam command sets the reassociate bit, and
this short circuits the roam logic in wpa_supplicant_need_to_roam (it
just returns true at the top of the function instead of going into
need_to_roam_within_ess).

On Mon, Mar 1, 2021 at 3:58 PM Ben Greear <greearb at candelatech.com> wrote:
>
> On 3/1/21 3:34 PM, Matthew Wang wrote:
> > The roam D-Bus and wpa_cli commands flip the reassociate bit before
> > calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
> > ongoing scans, which causes scan results to be reported. Since the
> > reassociate bit is set, this will trigger a connection attempt based on
> > the aborted scan's scan results and cancel the initial connetion
> > request. This often causes wpa_supplicant to reassociate to the same AP
> > it is currently associated to.
> >
> > Add a roam_in_progress flag to indicate that we're currently attempting
> > to roam via D-Bus so that we don't initate another connection attempt.
>
> I had similar issues, in case it helps, here is my patch:
>
> https://github.com/greearb/hostap-ct/commit/50b1c17d0a782dc4d354ac7366500763611ea5af
>
> I first relaxed thresholds by default, and then allowed configuring them.  When something
> beyond hostapd is controlling roaming, I set the thresholds so that it would never automatically
> roam based on scan results.
>
> Lord git only knows how much of this was built on previous patches in my tree...
>
> Thanks,
> Ben
>
>
> >
> > Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
> > Series-to: hostap at lists.infradead.org
> > Series-cc: j at w1.fi, matthewmwang at chromium.org
> > Change-Id: Ibeb6cceddabd10cab6938411f54ed63f4d4428c1
> > ---
> >   wpa_supplicant/ctrl_iface.c             | 9 +++++++++
> >   wpa_supplicant/dbus/dbus_new_handlers.c | 9 +++++++++
> >   wpa_supplicant/sme.c                    | 7 +++++++
> >   wpa_supplicant/wpa_supplicant_i.h       | 1 +
> >   4 files changed, 26 insertions(+)
> >
> > diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
> > index 0d4c2bc8f0b..048fe72d472 100644
> > --- a/wpa_supplicant/ctrl_iface.c
> > +++ b/wpa_supplicant/ctrl_iface.c
> > @@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
> >       wpa_s->reassociate = 1;
> >       wpa_supplicant_connect(wpa_s, bss, ssid);
> >
> > +     /*
> > +      * Indicate that an explicitly requested roam is in progress so scan
> > +      * results that come in before the 'sme-connect' radio work gets
> > +      * executed do not override the original connection attempt.
> > +      */
> > +     if (radio_work_pending(wpa_s, "sme-connect")) {
> > +             wpa_s->roam_in_progress = true;
> > +     }
> > +
> >       return 0;
> >   #endif /* CONFIG_NO_SCAN_PROCESSING */
> >   }
> > diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
> > index 7d20f2123a8..6803558accd 100644
> > --- a/wpa_supplicant/dbus/dbus_new_handlers.c
> > +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
> > @@ -2005,6 +2005,15 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
> >       wpa_s->reassociate = 1;
> >       wpa_supplicant_connect(wpa_s, bss, ssid);
> >
> > +     /*
> > +      * Indicate that an explicitly requested roam is in progress so scan
> > +      * results that come in before the 'sme-connect' radio work gets
> > +      * executed do not override the original connection attempt.
> > +      */
> > +     if (radio_work_pending(wpa_s, "sme-connect")) {
> > +             wpa_s->roam_in_progress = true;
> > +     }
> > +
> >       return NULL;
> >   #endif /* CONFIG_NO_SCAN_PROCESSING */
> >   }
> > diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
> > index 522c8297f7e..dde80863a98 100644
> > --- a/wpa_supplicant/sme.c
> > +++ b/wpa_supplicant/sme.c
> > @@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
> >       struct wpa_connect_work *cwork = work->ctx;
> >       struct wpa_supplicant *wpa_s = work->wpa_s;
> >
> > +     wpa_s->roam_in_progress = false;
> > +
> >       if (deinit) {
> >               if (work->started)
> >                       wpa_s->connect_work = NULL;
> > @@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
> >               return;
> >       }
> >
> > +     if (wpa_s->roam_in_progress) {
> > +             wpa_dbg(wpa_s, MSG_DEBUG,
> > +                     "SME: Reject sme_authenticate() in favor of explicit roam request");
> > +             return;
> > +     }
> >       if (radio_work_pending(wpa_s, "sme-connect")) {
> >               /*
> >                * The previous sme-connect work might no longer be valid due to
> > diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
> > index 7d14b627d89..b6c339ab711 100644
> > --- a/wpa_supplicant/wpa_supplicant_i.h
> > +++ b/wpa_supplicant/wpa_supplicant_i.h
> > @@ -621,6 +621,7 @@ struct wpa_supplicant {
> >       u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
> >                                    * field contains the target BSSID. */
> >       int reassociate; /* reassociation requested */
> > +     bool roam_in_progress; /* roam in progress */
> >       unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
> >       unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
> >       int disconnected; /* all connections disabled; i.e., do no reassociate
> >
>
>
> --
> Ben Greear <greearb at candelatech.com>
> Candela Technologies Inc  http://www.candelatech.com


From greearb at candelatech.com  Mon Mar  1 20:36:42 2021
From: greearb at candelatech.com (Ben Greear)
Date: Mon, 1 Mar 2021 17:36:42 -0800
Subject: [PATCH v2] Reject auths during explicit roam requests
In-Reply-To: <CABRiz0ohRN3FAhXy6abYufsKFAckqfhqo1CREvQ5r4V9Hx8OOg@mail.gmail.com>
References: <20210301233406.3964281-1-matthewmwang@chromium.org>
 <77e2dc14-64fa-bcd4-b17c-4d2584e57847@candelatech.com>
 <CABRiz0ohRN3FAhXy6abYufsKFAckqfhqo1CREvQ5r4V9Hx8OOg@mail.gmail.com>
Message-ID: <538268a7-1df3-e4b5-cc3e-8cf05155c11a@candelatech.com>

On 3/1/21 5:25 PM, Matthew Wang wrote:
> Thanks Ben, the patch is a good idea, but doesn't exactly address my
> issue. The D-Bus/wpa_cli roam command sets the reassociate bit, and
> this short circuits the roam logic in wpa_supplicant_need_to_roam (it
> just returns true at the top of the function instead of going into
> need_to_roam_within_ess).

Yeah, I believe your application would only want to temporarily fully restrict
the auto-roaming, where I wanted a way to do it for the duration of my
scenario (and then would re-load a new supplicant config afterwards).

Seems to me that you would want to disable roam-based-on-scan results for a bit longer
though if you are explicitly trying a roam based on logic that should know better
than supplicant (otherwise, why bother, just let supplicant do the job).

Thanks,
Ben

> 
> On Mon, Mar 1, 2021 at 3:58 PM Ben Greear <greearb at candelatech.com> wrote:
>>
>> On 3/1/21 3:34 PM, Matthew Wang wrote:
>>> The roam D-Bus and wpa_cli commands flip the reassociate bit before
>>> calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
>>> ongoing scans, which causes scan results to be reported. Since the
>>> reassociate bit is set, this will trigger a connection attempt based on
>>> the aborted scan's scan results and cancel the initial connetion
>>> request. This often causes wpa_supplicant to reassociate to the same AP
>>> it is currently associated to.
>>>
>>> Add a roam_in_progress flag to indicate that we're currently attempting
>>> to roam via D-Bus so that we don't initate another connection attempt.
>>
>> I had similar issues, in case it helps, here is my patch:
>>
>> https://github.com/greearb/hostap-ct/commit/50b1c17d0a782dc4d354ac7366500763611ea5af
>>
>> I first relaxed thresholds by default, and then allowed configuring them.  When something
>> beyond hostapd is controlling roaming, I set the thresholds so that it would never automatically
>> roam based on scan results.
>>
>> Lord git only knows how much of this was built on previous patches in my tree...
>>
>> Thanks,
>> Ben
>>
>>
>>>
>>> Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
>>> Series-to: hostap at lists.infradead.org
>>> Series-cc: j at w1.fi, matthewmwang at chromium.org
>>> Change-Id: Ibeb6cceddabd10cab6938411f54ed63f4d4428c1
>>> ---
>>>    wpa_supplicant/ctrl_iface.c             | 9 +++++++++
>>>    wpa_supplicant/dbus/dbus_new_handlers.c | 9 +++++++++
>>>    wpa_supplicant/sme.c                    | 7 +++++++
>>>    wpa_supplicant/wpa_supplicant_i.h       | 1 +
>>>    4 files changed, 26 insertions(+)
>>>
>>> diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
>>> index 0d4c2bc8f0b..048fe72d472 100644
>>> --- a/wpa_supplicant/ctrl_iface.c
>>> +++ b/wpa_supplicant/ctrl_iface.c
>>> @@ -5686,6 +5686,15 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
>>>        wpa_s->reassociate = 1;
>>>        wpa_supplicant_connect(wpa_s, bss, ssid);
>>>
>>> +     /*
>>> +      * Indicate that an explicitly requested roam is in progress so scan
>>> +      * results that come in before the 'sme-connect' radio work gets
>>> +      * executed do not override the original connection attempt.
>>> +      */
>>> +     if (radio_work_pending(wpa_s, "sme-connect")) {
>>> +             wpa_s->roam_in_progress = true;
>>> +     }
>>> +
>>>        return 0;
>>>    #endif /* CONFIG_NO_SCAN_PROCESSING */
>>>    }
>>> diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
>>> index 7d20f2123a8..6803558accd 100644
>>> --- a/wpa_supplicant/dbus/dbus_new_handlers.c
>>> +++ b/wpa_supplicant/dbus/dbus_new_handlers.c
>>> @@ -2005,6 +2005,15 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
>>>        wpa_s->reassociate = 1;
>>>        wpa_supplicant_connect(wpa_s, bss, ssid);
>>>
>>> +     /*
>>> +      * Indicate that an explicitly requested roam is in progress so scan
>>> +      * results that come in before the 'sme-connect' radio work gets
>>> +      * executed do not override the original connection attempt.
>>> +      */
>>> +     if (radio_work_pending(wpa_s, "sme-connect")) {
>>> +             wpa_s->roam_in_progress = true;
>>> +     }
>>> +
>>>        return NULL;
>>>    #endif /* CONFIG_NO_SCAN_PROCESSING */
>>>    }
>>> diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
>>> index 522c8297f7e..dde80863a98 100644
>>> --- a/wpa_supplicant/sme.c
>>> +++ b/wpa_supplicant/sme.c
>>> @@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
>>>        struct wpa_connect_work *cwork = work->ctx;
>>>        struct wpa_supplicant *wpa_s = work->wpa_s;
>>>
>>> +     wpa_s->roam_in_progress = false;
>>> +
>>>        if (deinit) {
>>>                if (work->started)
>>>                        wpa_s->connect_work = NULL;
>>> @@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
>>>                return;
>>>        }
>>>
>>> +     if (wpa_s->roam_in_progress) {
>>> +             wpa_dbg(wpa_s, MSG_DEBUG,
>>> +                     "SME: Reject sme_authenticate() in favor of explicit roam request");
>>> +             return;
>>> +     }
>>>        if (radio_work_pending(wpa_s, "sme-connect")) {
>>>                /*
>>>                 * The previous sme-connect work might no longer be valid due to
>>> diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
>>> index 7d14b627d89..b6c339ab711 100644
>>> --- a/wpa_supplicant/wpa_supplicant_i.h
>>> +++ b/wpa_supplicant/wpa_supplicant_i.h
>>> @@ -621,6 +621,7 @@ struct wpa_supplicant {
>>>        u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
>>>                                     * field contains the target BSSID. */
>>>        int reassociate; /* reassociation requested */
>>> +     bool roam_in_progress; /* roam in progress */
>>>        unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
>>>        unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
>>>        int disconnected; /* all connections disabled; i.e., do no reassociate
>>>
>>
>>
>> --
>> Ben Greear <greearb at candelatech.com>
>> Candela Technologies Inc  http://www.candelatech.com
> 


-- 
Ben Greear <greearb at candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


From kazikcz at gmail.com  Wed Mar  3 10:26:05 2021
From: kazikcz at gmail.com (Michal Kazior)
Date: Wed,  3 Mar 2021 10:26:05 +0000
Subject: [PATCHv2] DPP: prevent processing dpp action frames when stopped
Message-ID: <20210303102605.9891-1-kazikcz@gmail.com>

From: Michal Kazior <michal at plume.com>

DPP configurator params can be configured per
interface. DPP listening can also be started and
stopped per interface.

However DPP rx processing was always doomed to
process incomming frames even on interfaces which
were not explicitly started to do DPP listen. This
happened because not only the initial value but
also because the dpp_allowed_roles could never be
reset to 0.

This would result in random failures in
configuring Enrollees when running multiple AP
interfaces if some of these APs happened to not
have DPP configurator params set.

Signed-off-by: Michal Kazior <michal at plume.com>
---
v2:
 * dropped the change from hostapd_dpp_init()

 src/ap/dpp_hostapd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index e1e5a3ac4..da2dfe860 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -706,6 +706,7 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
 
 void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
 {
+	hapd->dpp_allowed_roles = 0;
 	hostapd_drv_dpp_listen(hapd, false);
 	/* TODO: Stop listen operation on non-operating channel */
 }
-- 
2.27.0



From kazikcz at gmail.com  Wed Mar  3 09:53:33 2021
From: kazikcz at gmail.com (Michal Kazior)
Date: Wed,  3 Mar 2021 09:53:33 +0000
Subject: [PATCH] DPP: respond to GAS on the same channel it was received on
Message-ID: <20210303095333.8420-1-kazikcz@gmail.com>

From: Michal Kazior <michal at plume.com>

When I was testing dpp_auth_init on an AP with
Enrollee on a different channel from the AP I was
getting failures. This happened on hwsim in UML
with time-travel for me. I don't recall seeing
this with real devices, presumably because of lax
offchan implementation.

The DPP authentication would succeed. However the
station would then try to get configuration
through a GAS request and fail.

The AP reported the following logs (grepped):

> 1614762426.860212: RX_ACTION category 4 action 10 sa 02:00:00:00:01:00 da 02:00:00:00:00:00 len 227 freq 2412
> 1614762426.860212: wlan0: GAS: GAS Initial Request from 02:00:00:00:01:00 (dialog token 239)
> 1614762426.860233: DPP: Wait for Configuration Result
> 1614762426.860234: nl80211: Send Action frame (ifindex=5, freq=2462 MHz wait=0 ms no_cck=0 offchanok=0)
> 1614762428.861186: DPP: Timeout while waiting for Configuration Result
> 1614762428.861186: wlan0: DPP-CONF-FAILED

While the STA reported the following logs (grepped):

> 1614762426.860193: wlan1: DPP-AUTH-SUCCESS init=0
> 1614762426.860195: DPP: Stop listen on 2412 MHz
> 1614762426.860202: wlan1: GAS-QUERY-START addr=02:00:00:00:00:00 dialog_token=239 freq=2412
> 1614762428.861185: GAS: No response received for query to 02:00:00:00:00:00 dialog token 239
> 1614762428.861189: DPP: GAS query did not succeed
> 1614762428.861189: wlan1: DPP-CONF-FAILED

AP would still receive the GAS request on ch1 but
would then try to respond on ch11 while STA was
waiting on ch1.

Signed-off-by: Michal Kazior <michal at plume.com>
---

I'm not sure if this is the right thing to do. And
there seems to be more cases where APs freq is
used instead of the GAS req freq that could
potentially be updated. There's at least the GAS
comeback case I don't handle here. This as-is does
help with my hwsim test though.

On one hand it seems perhaps the Enrollee should
try to do GAS on the APs channel. But is it well
equiped/informed to do so? I'm not familiar with
the spec that much.

On another hand backward compat could be a problem
without this fix.

Happy to dig more into this if needed.


 src/ap/dpp_hostapd.c |  2 +-
 src/ap/gas_serv.c    | 11 ++++++-----
 src/ap/gas_serv.h    |  3 ++-
 src/ap/ieee802_11.c  |  2 +-
 4 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index e1e5a3ac4..c417b9172 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -2198,7 +2198,7 @@ static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr,
 {
 	struct hostapd_data *hapd = ctx;
 
-	gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf);
+	gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf, 0);
 }
 
 #endif /* CONFIG_DPP2 */
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 90f15778b..24183685b 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1524,7 +1524,8 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
 #ifdef CONFIG_DPP
 void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
 				 const u8 *sa, u8 dialog_token,
-				 int prot, struct wpabuf *buf)
+				 int prot, struct wpabuf *buf,
+				 int freq)
 {
 	struct wpabuf *tx_buf;
 
@@ -1582,7 +1583,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
 		return;
 	if (prot)
 		convert_to_protected_dual(tx_buf);
-	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+	hostapd_drv_send_action(hapd, freq ?: hapd->iface->freq, 0, sa,
 				wpabuf_head(tx_buf),
 				wpabuf_len(tx_buf));
 	wpabuf_free(tx_buf);
@@ -1593,7 +1594,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
 					const u8 *sa,
 					const u8 *data, size_t len, int prot,
-					int std_addr3)
+					int std_addr3, int freq)
 {
 	const u8 *pos = data;
 	const u8 *end = data + len;
@@ -1688,7 +1689,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
 						  data, len);
 		if (!msg)
 			return;
-		gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
+		gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg, freq);
 		return;
 	}
 #endif /* CONFIG_DPP */
@@ -1871,7 +1872,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
 	switch (data[0]) {
 	case WLAN_PA_GAS_INITIAL_REQ:
 		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
-					    std_addr3);
+					    std_addr3, freq);
 		break;
 	case WLAN_PA_GAS_COMEBACK_REQ:
 		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 1528af4af..523fe8e94 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -90,6 +90,7 @@ void gas_serv_deinit(struct hostapd_data *hapd);
 
 void gas_serv_req_dpp_processing(struct hostapd_data *hapd,
 				 const u8 *sa, u8 dialog_token,
-				 int prot, struct wpabuf *buf);
+				 int prot, struct wpabuf *buf,
+				 int freq);
 
 #endif /* GAS_SERV_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1c01241bc..71245aad7 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -5973,7 +5973,7 @@ static int handle_action(struct hostapd_data *hapd,
 		if (hapd->public_action_cb2) {
 			hapd->public_action_cb2(hapd->public_action_cb2_ctx,
 						(u8 *) mgmt, len,
-						hapd->iface->freq);
+						freq);
 		}
 		if (hapd->public_action_cb || hapd->public_action_cb2)
 			return 1;
-- 
2.27.0



From raghavendra.akkasali at gmail.com  Thu Mar  4 02:46:54 2021
From: raghavendra.akkasali at gmail.com (Raghavendra. S)
Date: Wed, 3 Mar 2021 18:46:54 -0800
Subject: Unable to connect to SAE-H2E
Message-ID: <CA+VoN8idXdyGrfxZx=-E6snHKbOLiPKo5=aCDr4wc8WtL=G_cQ@mail.gmail.com>

Hi,
   I downloaded latest wpa_supplicant from https://w1.fi/cgit/hostap/

  Following is my config file.

ctrl_interface=DIR=/run/wpa_supplicant
update_config=1
pmf=1

network={
        ssid="raghu-test-h2e"
#       psk="12345678"
        proto=RSN
        key_mgmt=SAE
        group=CCMP
        ieee80211w=2
#       sae_pwe=2
        sae_password=12345678
}

I am seeing:
1614825503.405438: wlp5s0: 0: f8:a2:d6:bc:d0:51 ssid='raghu-test-h2e'
wpa_ie_len=0 rsn_ie_len=20 caps=0x411 level=-45 freq=2412
1614825503.405449: wlp5s0:    selected based on RSN IE
1614825503.405457: wlp5s0:    SAE H2E disabled
1614825503.405464: wlp5s0:    skip - rate sets do not match


Unable to connect another laptop acting as SAE-H2E AP having the
latest hostapd. I am seeing rsnxe IE in beacon. hostapd.conf has.
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
interface=wlp5s0
ssid=raghu-test-h2e
country_code=US
hw_mode=g
channel=1
beacon_int=100
dtim_period=2
max_num_sta=255
rts_threshold=-1
fragm_threshold=-1
macaddr_acl=0
auth_algs=3
ignore_broadcast_ssid=0
wmm_enabled=1
eapol_key_index_workaround=0
eap_server=0
own_ip_addr=127.0.0.1
wpa=2
wpa_key_mgmt=SAE
wpa_pairwise=TKIP CCMP
rsn_pairwise=CCMP
group_cipher=CCMP
wpa_group_rekey=86400
ieee80211w=2
sae_password=12345678
sae_groups=19
sae_pwe=1
transition_disable=0x01


May I know what is the issue in my config?

-Raghu


From astrand at lysator.liu.se  Fri Mar  5 14:39:04 2021
From: astrand at lysator.liu.se (=?UTF-8?Q?Peter_=C3=85strand?=)
Date: Fri, 5 Mar 2021 15:39:04 +0100 (CET)
Subject: mac80211_hwsim: AP and Mesh on same phy?
Message-ID: <5b5aeb1b-a350-9d79-f71c-154134c3bcea@lysator.liu.se>


With wl18xx driver, we can run AP and Mesh on the same phy:

# iw dev wlan0 interface add wlan0_ap type __ap
# iw dev wlan0 interface add wlan0_mesh type mesh
# hostapd &
# wpa_supplicant -Dnl80211 -i wlan0_mesh

However, with mac80211_hwsim:

ccessfully initialized wpa_supplicant
nl80211: Could not set interface 'p2p-dev-wlan0_m' UP
nl80211: deinit ifname=p2p-dev-wlan0_m disabled_11b_rates=0
p2p-dev-wlan0_m: Failed to initialize driver interface
P2P: Failed to enable P2P Device interface
wlan0_mesh: leaving mesh
wlan0_mesh: mesh leave error=-95
wlan0_mesh: interface state UNINITIALIZED->ENABLED
wlan0_mesh: AP-ENABLED 
wlan0_mesh: joining mesh cs2_ssid
wlan0_mesh: mesh join error=-16

This is with kernel 5.4. mac80211_hwsim loaded with channels=3. Is this a 
known limitation with mac80211_hwsim?


Br,
Peter Astrand



From fionn.cleary at streamunlimited.com  Thu Mar  4 16:18:38 2021
From: fionn.cleary at streamunlimited.com (Fionn Cleary)
Date: Thu, 04 Mar 2021 16:18:38 +0000
Subject: [PATCH] dbus: Add SsidTempDisabled signal
In-Reply-To: <20210226210815.GA508088@w1.fi>
Message-ID: <87ft1ahoyp.fsf@tcd.ie>

Hi,

Peter is pretty busy elsewhere, but I have some time to get this feature
merged.

> This looks a bit strange.. Why would a D-Bus signal include the SSID?
> Shouldn't this instead be identifying the network object that is being
> temporarily disabled?

This should be straightforward enough to change.  For our initial test
code it was just more straightforward to match the SSIDs, but changing
our side to use the network object instead is fine.

> If there is a signal notifying that a network got temporarily disabled,
> shouldn't there be a signal to notify that such temporarily disablement
> was removed?

Also straightforward, and also makes sense for us too (in the near-term
future this will be useful).

I was examining how the Network object "Enabled" property behaves, so
perhaps it might actually just make more sense to make this another
related property?  I?m not quite sure what it would be called though,
"TemporarilyDisabled" (defaulting to false) seems a bit unwieldy, even
if it is descriptive.

Regards
Fionn


From matthewmwang at chromium.org  Sat Mar  6 01:43:44 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Fri,  5 Mar 2021 17:43:44 -0800
Subject: [PATCH v3] Reject auths during explicit roam requests
Message-ID: <20210306014344.431232-1-matthewmwang@chromium.org>

The roam D-Bus and wpa_cli commands flip the reassociate bit before
calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
ongoing scans, which causes scan results to be reported. Since the
reassociate bit is set, this will trigger a connection attempt based on
the aborted scan's scan results and cancel the initial connetion
request. This often causes wpa_supplicant to reassociate to the same AP
it is currently associated to.

Add a roam_in_progress flag to indicate that we're currently attempting
to roam via D-Bus so that we don't initate another connection attempt.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
Series-to: hostap at lists.infradead.org
Series-cc: j at w1.fi, matthewmwang at chromium.org
---
 wpa_supplicant/ctrl_iface.c             | 11 +++++++++++
 wpa_supplicant/dbus/dbus_new_handlers.c | 11 +++++++++++
 wpa_supplicant/sme.c                    |  7 +++++++
 wpa_supplicant/wpa_supplicant_i.h       |  1 +
 4 files changed, 30 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0d4c2bc8f0b..93cfa9dd18f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5656,6 +5656,7 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 	u8 bssid[ETH_ALEN];
 	struct wpa_bss *bss;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct wpa_radio_work *already_connecting;
 
 	if (hwaddr_aton(addr, bssid)) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
@@ -5683,9 +5684,19 @@ static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 	 * allow roaming to other networks
 	 */
 
+	already_connecting = radio_work_pending(wpa_s, "sme-connect");
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return 0;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 7d20f2123a8..6c3646979c1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1979,6 +1979,7 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
 	struct wpa_bss *bss;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	char *addr;
+	struct wpa_radio_work *already_connecting;
 
 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &addr,
 				   DBUS_TYPE_INVALID))
@@ -2002,9 +2003,19 @@ DBusMessage * wpas_dbus_handler_roam(DBusMessage *message,
 			message, "Target BSS not found");
 	}
 
+	already_connecting = radio_work_pending(wpa_s, "sme-connect");
 	wpa_s->reassociate = 1;
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
+	/*
+	 * Indicate that an explicitly requested roam is in progress so scan
+	 * results that come in before the 'sme-connect' radio work gets
+	 * executed do not override the original connection attempt.
+	 */
+	if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) {
+		wpa_s->roam_in_progress = true;
+	}
+
 	return NULL;
 #endif /* CONFIG_NO_SCAN_PROCESSING */
 }
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 522c8297f7e..dde80863a98 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -941,6 +941,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	struct wpa_connect_work *cwork = work->ctx;
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 
+	wpa_s->roam_in_progress = false;
+
 	if (deinit) {
 		if (work->started)
 			wpa_s->connect_work = NULL;
@@ -981,6 +983,11 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
 		return;
 	}
 
+	if (wpa_s->roam_in_progress) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"SME: Reject sme_authenticate() in favor of explicit roam request");
+		return;
+	}
 	if (radio_work_pending(wpa_s, "sme-connect")) {
 		/*
 		 * The previous sme-connect work might no longer be valid due to
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7d14b627d89..b6c339ab711 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -621,6 +621,7 @@ struct wpa_supplicant {
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
+	bool roam_in_progress; /* roam in progress */
 	unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
 	unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
-- 
2.29.2



From j at w1.fi  Sat Mar  6 10:03:45 2021
From: j at w1.fi (Jouni Malinen)
Date: Sat, 6 Mar 2021 12:03:45 +0200
Subject: [PATCH] DPP: respond to GAS on the same channel it was received on
In-Reply-To: <20210303095333.8420-1-kazikcz@gmail.com>
References: <20210303095333.8420-1-kazikcz@gmail.com>
Message-ID: <20210306100345.GA25876@w1.fi>

On Wed, Mar 03, 2021 at 09:53:33AM +0000, Michal Kazior wrote:
> When I was testing dpp_auth_init on an AP with
> Enrollee on a different channel from the AP I was
> getting failures. This happened on hwsim in UML
> with time-travel for me. I don't recall seeing
> this with real devices, presumably because of lax
> offchan implementation.

Is this with a hwsim test case that already exists in hostap.git? Does
it fail every time in your test setup?

> The AP reported the following logs (grepped):
> 
> > 1614762426.860212: RX_ACTION category 4 action 10 sa 02:00:00:00:01:00 da 02:00:00:00:00:00 len 227 freq 2412
> > 1614762426.860212: wlan0: GAS: GAS Initial Request from 02:00:00:00:01:00 (dialog token 239)
> > 1614762426.860233: DPP: Wait for Configuration Result
> > 1614762426.860234: nl80211: Send Action frame (ifindex=5, freq=2462 MHz wait=0 ms no_cck=0 offchanok=0)
> > 1614762428.861186: DPP: Timeout while waiting for Configuration Result
> > 1614762428.861186: wlan0: DPP-CONF-FAILED

Can you please share the full debug log for this? I'd like to understand
what exactly happened with the channel negotiation here.

> I'm not sure if this is the right thing to do. And
> there seems to be more cases where APs freq is
> used instead of the GAS req freq that could
> potentially be updated. There's at least the GAS
> comeback case I don't handle here. This as-is does
> help with my hwsim test though.
> 
> On one hand it seems perhaps the Enrollee should
> try to do GAS on the APs channel. But is it well
> equiped/informed to do so? I'm not familiar with
> the spec that much.

DPP configuration exchange (GAS) is supposed to happen on the same
channel on which the last frame of DPP authentication exchange happened.

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Sat Mar  6 11:17:16 2021
From: j at w1.fi (Jouni Malinen)
Date: Sat, 6 Mar 2021 13:17:16 +0200
Subject: [PATCHv2] DPP: prevent processing dpp action frames when stopped
In-Reply-To: <20210303102605.9891-1-kazikcz@gmail.com>
References: <20210303102605.9891-1-kazikcz@gmail.com>
Message-ID: <20210306111716.GA454422@w1.fi>

On Wed, Mar 03, 2021 at 10:26:05AM +0000, Michal Kazior wrote:
> diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
> @@ -706,6 +706,7 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
>  
>  void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
>  {
> +	hapd->dpp_allowed_roles = 0;
>  	hostapd_drv_dpp_listen(hapd, false);
>  	/* TODO: Stop listen operation on non-operating channel */
>  }

This breaks chirping mode since hostapd_dpp_chirp_next() calls
hostapd_dpp_listen_stop() in the middle of the iteration. I don't think
this approach in hostapd_dpp_listen_stop() changing dpp_allowed_roles is
going to be acceptable.

I'm not sure I fully understood your use case, but please note that the
DPP_STOP_LISTEN command is also calling hostapd_dpp_stop(). Would that
function be more appropriate place for clearing dpp_allowed_roles? Or
well, I'm not sure clearing dpp_allowed_roles is really the correct
thing to do to address this issue, i.e., it might be safer to provide a
different variable for tracking whether there should be any action
taken based on received DPP Action frames.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Sat Mar  6 13:50:36 2021
From: j at w1.fi (Jouni Malinen)
Date: Sat, 6 Mar 2021 15:50:36 +0200
Subject: [PATCH v2 2/2] nl80211: use the process_bss_event for the
 nl_connect handler
In-Reply-To: <SJ0PR11MB4941AE9A504A7F39486D697CF5809@SJ0PR11MB4941.namprd11.prod.outlook.com>
References: <SJ0PR11MB4941B7B5141CB028291278B1F58D9@SJ0PR11MB4941.namprd11.prod.outlook.com>
 <20210217101433.14673-2-andrei.otcheretianski@intel.com>
 <20210219224210.GB97575@w1.fi>
 <SJ0PR11MB4941AE9A504A7F39486D697CF5809@SJ0PR11MB4941.namprd11.prod.outlook.com>
Message-ID: <20210306135036.GA868941@w1.fi>

On Tue, Feb 23, 2021 at 10:47:57AM +0000, Otcheretianski, Andrei wrote:
> > > -	ret = send_and_recv_msgs_owner(drv, msg,
> > get_connect_handle(bss), 0,
> > > -				       NULL, NULL, NULL, NULL);
> > > +	ret = send_and_recv_msgs_connect_handle(drv, msg, bss);
> > 
> > This one here uses set_owner == 0.. Is it really correct to replace that with 1?
> 
> After looking at nl80211 code, looks that these attributes are ignored for leave_mesh().. So I guess this should be ok.

That does not sound exactly like the level of confidence I'd like to
hear.. I applied this with the set_owner argument passed through
send_and_recv_msgs_connect_handle() to maintain existing behavior.

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Sat Mar  6 13:51:08 2021
From: j at w1.fi (Jouni Malinen)
Date: Sat, 6 Mar 2021 15:51:08 +0200
Subject: Crash in hostapd_eid_time_adv with DFS CAC
In-Reply-To: <ffadc0e0f91e12022dd15f1ed4e55586@fami-braun.de>
References: <f842dc7280e61e0335d9a12abee59375@fami-braun.de>
 <ffadc0e0f91e12022dd15f1ed4e55586@fami-braun.de>
Message-ID: <20210306135108.GB868941@w1.fi>

On Mon, Mar 01, 2021 at 11:35:01PM +0100, michael-dev wrote:
> this is the logs resulting in the crash.
> 
> It can be seen that we have DFS-RADAR-DETECTED on wlan1, wlan1: interface
> state ENABLED->DISABLED, and later wlan1 is reenabled.
> Thus hostapd_disable_iface -> hostapd_free_hapd_data ->
> wpabuf_free(hapd->time_adv) when wlan1 becomes disabled.
> Later when wlan1 is re-enabled, hapd->time_adv points to a freed pointer, as
> - different to e.g. hapd->radius - it is not cleared after freeing.
> 
> Please find attached a patch that addresses this.

Thanks, applied.

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Sat Mar  6 13:51:36 2021
From: j at w1.fi (Jouni Malinen)
Date: Sat, 6 Mar 2021 15:51:36 +0200
Subject: [PATCH v3] Reject auths during explicit roam requests
In-Reply-To: <20210306014344.431232-1-matthewmwang@chromium.org>
References: <20210306014344.431232-1-matthewmwang@chromium.org>
Message-ID: <20210306135136.GC868941@w1.fi>

On Fri, Mar 05, 2021 at 05:43:44PM -0800, Matthew Wang wrote:
> The roam D-Bus and wpa_cli commands flip the reassociate bit before
> calling wpa_supplicant_connect. wpa_supplicant connect eventually aborts
> ongoing scans, which causes scan results to be reported. Since the
> reassociate bit is set, this will trigger a connection attempt based on
> the aborted scan's scan results and cancel the initial connetion
> request. This often causes wpa_supplicant to reassociate to the same AP
> it is currently associated to.
> 
> Add a roam_in_progress flag to indicate that we're currently attempting
> to roam via D-Bus so that we don't initate another connection attempt.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From greearb at candelatech.com  Sat Mar  6 16:18:37 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Sat,  6 Mar 2021 08:18:37 -0800
Subject: [PATCH 1/5] supplicant:  Support disabling HE for stations.
Message-ID: <20210306161840.16652-1-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

Send a flag to the kernel with user has specified disable_he
in supplicant config file.  Requires kernel patch to function
as expected.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 src/drivers/driver_nl80211.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a9d5fe3d8..f32890d1d 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5913,6 +5913,14 @@ static int nl80211_ht_vht_overrides(struct nl_msg *msg,
 	}
 #endif /* CONFIG_VHT_OVERRIDES */
 
+#ifdef CONFIG_VHT_OVERRIDES
+	if (params->disable_he) {
+		wpa_printf(MSG_DEBUG, "  * HE disabled");
+		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
+			return -1;
+	}
+#endif
+
 	return 0;
 }
 
-- 
2.20.1



From greearb at candelatech.com  Sat Mar  6 16:18:38 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Sat,  6 Mar 2021 08:18:38 -0800
Subject: [PATCH 3/5] supplicant:  Support sending twt-request action frames.
In-Reply-To: <20210306161840.16652-1-greearb@candelatech.com>
References: <20210306161840.16652-1-greearb@candelatech.com>
Message-ID: <20210306161840.16652-2-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

With ability to specify some options.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 src/common/ieee802_11_defs.h      | 15 ++++++
 wpa_supplicant/Makefile           |  1 +
 wpa_supplicant/ctrl_iface.c       | 29 ++++++++++
 wpa_supplicant/twt.c              | 90 +++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_cli.c          | 10 ++++
 wpa_supplicant/wpa_supplicant_i.h |  4 ++
 6 files changed, 149 insertions(+)
 create mode 100644 wpa_supplicant/twt.c

diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b8dee8dbf..c67c6f46c 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -446,6 +446,7 @@
 #define WLAN_EID_WHITE_SPACE_MAP 205
 #define WLAN_EID_FTM_PARAMETERS 206
 #define WLAN_EID_S1G_BCN_COMPAT 213
+#define WLAN_EID_TWT              216
 #define WLAN_EID_S1G_CAPABILITIES 217
 #define WLAN_EID_VENDOR_SPECIFIC 221
 #define WLAN_EID_S1G_OPERATION 232
@@ -603,6 +604,7 @@
 #define WLAN_ACTION_ROBUST_AV_STREAMING 19
 #define WLAN_ACTION_UNPROTECTED_DMG 20
 #define WLAN_ACTION_VHT 21
+#define WLAN_ACTION_S1G 22
 #define WLAN_ACTION_FILS 26
 #define WLAN_ACTION_PROTECTED_FTM 34
 #define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
@@ -820,6 +822,19 @@ enum nai_realm_eap_cred_type {
 	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
 };
 
+#define S1G_ACT_AID_SWITCH_REQUEST   0
+#define S1G_ACT_AID_SWITCH_RESPONSE  1
+#define S1G_ACT_SYNC_CONTROL         2
+#define S1G_ACT_STA_INFO_ANNOUNCE    3
+#define S1G_ACT_EDCA_PARAM_SET       4
+#define S1G_ACT_EL_OPERATION         5
+#define S1G_ACT_TWT_SETUP            6
+#define S1G_ACT_TWT_TEARDOWN         7
+#define S1G_ACT_SECT_GROUP_ID_LIST   8
+#define S1G_ACT_SECT_ID_FEEDBACK     9
+#define S1G_ACT_RESERVED             10
+#define S1G_ACT_TWT_INFORMATION      11
+
 /*
  * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
  * measurement requests
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index fb665b160..77baa1bb5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -95,6 +95,7 @@ OBJS += ../src/utils/ip_addr.o
 OBJS += ../src/utils/crc32.o
 OBJS += op_classes.o
 OBJS += rrm.o
+OBJS += twt.o
 OBJS += robust_av.o
 OBJS_p = wpa_passphrase.o
 OBJS_p += ../src/utils/common.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d679b56af..1a1c2ca82 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10108,6 +10108,32 @@ static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
 	return ret;
 }
 
+static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
+					  char *cmd)
+{
+	int ret;
+	int dtok = 1;
+	int exponent = 10;
+	int mantissa = 8192;
+	int min_twt = 255;
+
+	char* tok_s = os_strstr(cmd, "dialog=");
+	if (tok_s)
+		dtok = atoi(tok_s + strlen("dialog="));
+
+	tok_s = os_strstr(cmd, "exponent=");
+	if (tok_s)
+		exponent = atoi(tok_s + strlen("exponent="));
+
+	tok_s = os_strstr(cmd, "mantissa=");
+	if (tok_s)
+		exponent = atoi(tok_s + strlen("mantissa="));
+
+	ret = wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt);
+
+	return ret;
+}
+
 
 static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
 {
@@ -11330,6 +11356,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
 		if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TWT_SETUP", 20) == 0) {
+		if (wpas_ctrl_iface_send_twt_setup(wpa_s, buf + 9))
+			reply_len = -1;
 	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
 		wpas_ctrl_iface_erp_flush(wpa_s);
 	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
new file mode 100644
index 000000000..6b62631b7
--- /dev/null
+++ b/wpa_supplicant/twt.c
@@ -0,0 +1,90 @@
+/*
+ * wpa_supplicant - TWT
+ * Copyright (c) 2003-2016, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+
+
+/**
+ * wpas_twt_send_setup - Send TWT setup request to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @dtok: Dialog token.
+ * @exponent: TWT wake-interval exponent
+ * @mantissa:  TWT wake-interval Mantissa
+ * @min_twt:  TWT Minimum TWT Wake Duration.
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
+			int dtok, int exponent, int mantissa, int min_twt)
+{
+	struct wpabuf *buf;
+	u16 req_type = 0;
+	unsigned char targ_wait_time[8] = {0};
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "TWT: No connection, no TWT.");
+		return -ENOTCONN;
+	}
+
+	/* 3 = action category + action code + dialog token */
+	/* 17 = target wait time IE */
+	buf = wpabuf_alloc(3 + 17);
+	
+	if (buf == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to allocate TWT Setup Request");
+		return -ENOMEM;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"TWT: Setup request, dtok: %d  exponent: %d  mantissa: %d  min-twt: %d",
+		dtok, exponent, mantissa, min_twt);
+
+	wpabuf_put_u8(buf, WLAN_ACTION_S1G);
+	wpabuf_put_u8(buf, S1G_ACT_TWT_SETUP);
+	wpabuf_put_u8(buf, dtok);
+
+	wpabuf_put_u8(buf, WLAN_EID_TWT);
+	wpabuf_put_u8(buf, 15); /* len */
+
+	wpabuf_put_u8(buf, 0x10); /* control field */
+
+	req_type |= (0x1); /* This STA is a TWT Requesting STA */
+	req_type |= (0x70); /* TWT SP includes trigger frames, TWT Implicit, TWT un-announced */
+	req_type |= ((exponent & 0x1f) << 10);
+	/* high bit is 'protection, leave it false for now */
+	wpabuf_put_u8(buf, req_type);
+	wpabuf_put_u8(buf, req_type >> 8);
+	/* Not sure exactly how this is used */
+	wpabuf_put_data(buf, targ_wait_time, sizeof(targ_wait_time));
+	wpabuf_put_u8(buf, min_twt); /* minimum twt wake duration */
+	wpabuf_put_u8(buf, mantissa);
+	wpabuf_put_u8(buf, mantissa >> 8);
+	wpabuf_put_u8(buf, 0); /* twt channel */
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to send TWT Setup Request");
+		wpabuf_free(buf);
+		return -ECANCELED;
+	}
+
+	wpabuf_free(buf);
+	return 0;
+}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b3e256b0f..b84670df9 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2942,6 +2942,12 @@ static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
 	return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
 }
 
+static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc,
+				 char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv);
+}
+
 
 static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -3822,6 +3828,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
 	  wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
 	  "[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
 	},
+	{ "twt_setup",
+	  wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
+	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>]"
+	},
 	{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
 	  "= flush ERP keys" },
 	{ "mac_rand_scan",
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index dfd8c61eb..705352c17 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1557,6 +1557,10 @@ void add_freq(int *freqs, int *num_freqs, int freq);
 
 int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
 			 u8 *op_class, u8 *chan, u8 *phy_type);
+
+int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
+			int dtok, int exponent, int mantissa, int min_twt);
+
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
 void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 				   const u8 *report, size_t report_len);
-- 
2.20.1



From greearb at candelatech.com  Sat Mar  6 16:18:39 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Sat,  6 Mar 2021 08:18:39 -0800
Subject: [PATCH 4/5] twt:  Support sending teardown action frame.
In-Reply-To: <20210306161840.16652-1-greearb@candelatech.com>
References: <20210306161840.16652-1-greearb@candelatech.com>
Message-ID: <20210306161840.16652-3-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

User can supply the 1-byte flags value.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 wpa_supplicant/ctrl_iface.c       | 18 ++++++++++++
 wpa_supplicant/twt.c              | 47 +++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_cli.c          |  9 ++++++
 wpa_supplicant/wpa_supplicant_i.h |  2 ++
 4 files changed, 76 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 1a1c2ca82..0fb84e435 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10134,6 +10134,21 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	return ret;
 }
 
+static int wpas_ctrl_iface_send_twt_teardown(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	int ret;
+	int flags = 0x1;
+
+	char* tok_s = os_strstr(cmd, "flags=");
+	if (tok_s)
+		flags = atoi(tok_s + strlen("flags="));
+
+	ret = wpas_twt_send_teardown(wpa_s, flags);
+
+	return ret;
+}
+
 
 static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
 {
@@ -11359,6 +11374,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 	} else if (os_strncmp(buf, "TWT_SETUP", 20) == 0) {
 		if (wpas_ctrl_iface_send_twt_setup(wpa_s, buf + 9))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TWT_TEARDOWN", 20) == 0) {
+		if (wpas_ctrl_iface_send_twt_teardown(wpa_s, buf + 9))
+			reply_len = -1;
 	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
 		wpas_ctrl_iface_erp_flush(wpa_s);
 	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index 6b62631b7..39fb5a629 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -88,3 +88,50 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
 	wpabuf_free(buf);
 	return 0;
 }
+
+/**
+ * wpas_twt_send_teardown - Send TWT teardown request to our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @flags: The byte that goes inside the teardown IE
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ */
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s,
+			   int flags)
+{
+	struct wpabuf *buf;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "TWT: No connection, no TWT.");
+		return -ENOTCONN;
+	}
+
+	/* 3 = action category + action code + flags */
+	buf = wpabuf_alloc(3);
+
+	if (buf == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to allocate TWT Teardown Request");
+		return -ENOMEM;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"TWT: Teardown request, flags: 0x%x",
+		flags);
+
+	wpabuf_put_u8(buf, WLAN_ACTION_S1G);
+	wpabuf_put_u8(buf, S1G_ACT_TWT_TEARDOWN);
+	wpabuf_put_u8(buf, flags);
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"TWT: Failed to send TWT Teardown Request");
+		wpabuf_free(buf);
+		return -ECANCELED;
+	}
+
+	wpabuf_free(buf);
+	return 0;
+}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index b84670df9..ba57d7d91 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2948,6 +2948,11 @@ static int wpa_cli_cmd_twt_setup(struct wpa_ctrl *ctrl, int argc,
 	return wpa_cli_cmd(ctrl, "TWT_SETUP", 0, argc, argv);
 }
 
+static int wpa_cli_cmd_twt_teardown(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TWT_TEARDOWN", 0, argc, argv);
+}
 
 static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -3832,6 +3837,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
 	  wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
 	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>]"
 	},
+	{ "twt_teardown",
+	  wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
+	  "[flags=<value>]"
+	},
 	{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
 	  "= flush ERP keys" },
 	{ "mac_rand_scan",
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 705352c17..0271c5e24 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1560,6 +1560,8 @@ int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
 
 int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
 			int dtok, int exponent, int mantissa, int min_twt);
+int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s,
+			   int flags);
 
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
 void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
-- 
2.20.1



From greearb at candelatech.com  Sat Mar  6 16:18:40 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Sat,  6 Mar 2021 08:18:40 -0800
Subject: [PATCH 5/5] twt:  Add more options for sending twt-request packets.
In-Reply-To: <20210306161840.16652-1-greearb@candelatech.com>
References: <20210306161840.16652-1-greearb@candelatech.com>
Message-ID: <20210306161840.16652-4-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

You can now specify every field.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 wpa_supplicant/ctrl_iface.c       | 49 ++++++++++++++++++++++++++++++-
 wpa_supplicant/twt.c              | 28 ++++++++++++------
 wpa_supplicant/wpa_cli.c          |  2 +-
 wpa_supplicant/wpa_supplicant_i.h |  4 ++-
 4 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0fb84e435..126dfabea 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10116,6 +10116,15 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	int exponent = 10;
 	int mantissa = 8192;
 	int min_twt = 255;
+	unsigned long long twt = 0;
+	int requestor = 1;
+	int setup_cmd = 0;
+	int trigger = 1;
+	int implicit = 1;
+	int flow_type = 1;
+	int flow_id = 0;
+	int protection = 0;
+	int twt_channel = 0;
 
 	char* tok_s = os_strstr(cmd, "dialog=");
 	if (tok_s)
@@ -10129,7 +10138,45 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	if (tok_s)
 		exponent = atoi(tok_s + strlen("mantissa="));
 
-	ret = wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt);
+	tok_s = os_strstr(cmd, "setup_cmd=");
+	if (tok_s)
+		setup_cmd = atoi(tok_s + strlen("setup_cmd="));
+
+	tok_s = os_strstr(cmd, "twt=");
+	if (tok_s)
+		sscanf(tok_s + strlen("twt="), "%llu", &twt);
+
+	tok_s = os_strstr(cmd, "requestor=");
+	if (tok_s)
+		requestor = atoi(tok_s + strlen("requestor="));
+
+	tok_s = os_strstr(cmd, "trigger=");
+	if (tok_s)
+		trigger = atoi(tok_s + strlen("trigger="));
+
+	tok_s = os_strstr(cmd, "implicit=");
+	if (tok_s)
+		implicit = atoi(tok_s + strlen("implicit="));
+
+	tok_s = os_strstr(cmd, "flow_type=");
+	if (tok_s)
+		flow_type = atoi(tok_s + strlen("flow_type="));
+
+	tok_s = os_strstr(cmd, "flow_id=");
+	if (tok_s)
+		flow_id = atoi(tok_s + strlen("flow_id="));
+
+	tok_s = os_strstr(cmd, "protection=");
+	if (tok_s)
+		protection = atoi(tok_s + strlen("protection="));
+
+	tok_s = os_strstr(cmd, "twt_channel=");
+	if (tok_s)
+		twt_channel = atoi(tok_s + strlen("twt_channel="));
+
+	ret = wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt, setup_cmd,
+				  twt, requestor, trigger, implicit, flow_type, flow_id,
+				  protection, twt_channel);
 
 	return ret;
 }
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index 39fb5a629..da54260fd 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -25,15 +25,18 @@
  * @exponent: TWT wake-interval exponent
  * @mantissa:  TWT wake-interval Mantissa
  * @min_twt:  TWT Minimum TWT Wake Duration.
+ * @setup_cmd: 0 == request, 1 == suggest, etc.  table 9-297
  * Returns: 0 in case of success, negative error code otherwise
  *
  */
 int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
-			int dtok, int exponent, int mantissa, int min_twt)
+			int dtok, int exponent, int mantissa, int min_twt, int setup_cmd,
+			u64 twt, int requestor, int trigger, int implicit, int flow_type, int flow_id,
+			int protection, int twt_channel)
 {
 	struct wpabuf *buf;
 	u16 req_type = 0;
-	unsigned char targ_wait_time[8] = {0};
+	int i;
 
 	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "TWT: No connection, no TWT.");
@@ -43,7 +46,7 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
 	/* 3 = action category + action code + dialog token */
 	/* 17 = target wait time IE */
 	buf = wpabuf_alloc(3 + 17);
-	
+
 	if (buf == NULL) {
 		wpa_dbg(wpa_s, MSG_DEBUG,
 			"TWT: Failed to allocate TWT Setup Request");
@@ -63,18 +66,25 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
 
 	wpabuf_put_u8(buf, 0x10); /* control field */
 
-	req_type |= (0x1); /* This STA is a TWT Requesting STA */
-	req_type |= (0x70); /* TWT SP includes trigger frames, TWT Implicit, TWT un-announced */
+	req_type |= (requestor & 0x1); /* This STA is a TWT Requesting STA */
+	req_type |= (setup_cmd & 0x7) << 1;
+	req_type |= (trigger & 0x1) << 4;
+	req_type |= (implicit & 0x1) << 5;
+	req_type |= (flow_type & 0x1) << 6;
+	req_type |= (flow_id & 0x7) << 7;
 	req_type |= ((exponent & 0x1f) << 10);
-	/* high bit is 'protection, leave it false for now */
+	req_type |= (protection & 0x1) << 15;
+
 	wpabuf_put_u8(buf, req_type);
 	wpabuf_put_u8(buf, req_type >> 8);
-	/* Not sure exactly how this is used */
-	wpabuf_put_data(buf, targ_wait_time, sizeof(targ_wait_time));
+
+	for (i = 0; i<8; i++) {
+		wpabuf_put_u8(buf, twt >> i);
+	}
 	wpabuf_put_u8(buf, min_twt); /* minimum twt wake duration */
 	wpabuf_put_u8(buf, mantissa);
 	wpabuf_put_u8(buf, mantissa >> 8);
-	wpabuf_put_u8(buf, 0); /* twt channel */
+	wpabuf_put_u8(buf, twt_channel); /* twt channel */
 
 	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
 				wpa_s->own_addr, wpa_s->bssid,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index ba57d7d91..942f64a9d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3835,7 +3835,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
 	},
 	{ "twt_setup",
 	  wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
-	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>]"
+	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>] [setup_cmd=<setup-cmd>] [twt=<u64>] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=<twt chanel id>]"
 	},
 	{ "twt_teardown",
 	  wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 0271c5e24..ce2586ac9 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1559,7 +1559,9 @@ int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
 			 u8 *op_class, u8 *chan, u8 *phy_type);
 
 int wpas_twt_send_setup(struct wpa_supplicant *wpa_s,
-			int dtok, int exponent, int mantissa, int min_twt);
+			int dtok, int exponent, int mantissa, int min_twt, int setup_cmd,
+			u64 twt, int requestor, int trigger, int implicit, int flow_type, int flow_id,
+			int protection, int channel);
 int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s,
 			   int flags);
 
-- 
2.20.1



From greearb at candelatech.com  Sat Mar  6 16:21:34 2021
From: greearb at candelatech.com (Ben Greear)
Date: Sat, 6 Mar 2021 08:21:34 -0800
Subject: [PATCH 1/5] supplicant: Support disabling HE for stations.
In-Reply-To: <20210306161840.16652-1-greearb@candelatech.com>
References: <20210306161840.16652-1-greearb@candelatech.com>
Message-ID: <30d708a0-69bb-6ecf-b4fe-14cbfa2f4baa@candelatech.com>

Just FYI, the 2/5 I skipped since it needs a kernel patch that I just posted
and which may not be accepted to the kernel...

Thanks,
Ben

On 3/6/21 8:18 AM, greearb at candelatech.com wrote:
> From: Ben Greear <greearb at candelatech.com>
> 
> Send a flag to the kernel with user has specified disable_he
> in supplicant config file.  Requires kernel patch to function
> as expected.
> 
> Signed-off-by: Ben Greear <greearb at candelatech.com>
> ---
>   src/drivers/driver_nl80211.c | 8 ++++++++
>   1 file changed, 8 insertions(+)
> 
> diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> index a9d5fe3d8..f32890d1d 100644
> --- a/src/drivers/driver_nl80211.c
> +++ b/src/drivers/driver_nl80211.c
> @@ -5913,6 +5913,14 @@ static int nl80211_ht_vht_overrides(struct nl_msg *msg,
>   	}
>   #endif /* CONFIG_VHT_OVERRIDES */
>   
> +#ifdef CONFIG_VHT_OVERRIDES
> +	if (params->disable_he) {
> +		wpa_printf(MSG_DEBUG, "  * HE disabled");
> +		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
> +			return -1;
> +	}
> +#endif
> +
>   	return 0;
>   }
>   
> 


-- 
Ben Greear <greearb at candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


From j at w1.fi  Sun Mar  7 16:01:56 2021
From: j at w1.fi (Jouni Malinen)
Date: Sun, 7 Mar 2021 18:01:56 +0200
Subject: [PATCH 1/5] supplicant:  Support disabling HE for stations.
In-Reply-To: <20210306161840.16652-1-greearb@candelatech.com>
References: <20210306161840.16652-1-greearb@candelatech.com>
Message-ID: <20210307160156.GA477525@w1.fi>

On Sat, Mar 06, 2021 at 08:18:37AM -0800, greearb at candelatech.com wrote:
> Send a flag to the kernel with user has specified disable_he
> in supplicant config file.  Requires kernel patch to function
> as expected.

What kernel patch is that referring to?

> diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> @@ -5913,6 +5913,14 @@ static int nl80211_ht_vht_overrides(struct nl_msg *msg,
>  	}
>  #endif /* CONFIG_VHT_OVERRIDES */
>  
> +#ifdef CONFIG_VHT_OVERRIDES
> +	if (params->disable_he) {
> +		wpa_printf(MSG_DEBUG, "  * HE disabled");
> +		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
> +			return -1;
> +	}
> +#endif

Shouldn't that use CONFIG_HE_OVERRIDES?

-- 
Jouni Malinen                                            PGP id EFC895FA


From andrei.otcheretianski at intel.com  Sun Mar  7 21:40:01 2021
From: andrei.otcheretianski at intel.com (Andrei Otcheretianski)
Date: Sun,  7 Mar 2021 23:40:01 +0200
Subject: [PATCH] wpa_supplicant: Don't process EAPOLs while disconnecting
Message-ID: <20210307214002.29126-1-andrei.otcheretianski@intel.com>

An EAPOL frame may be pending when the supplicant requests to
deauthenticate. At this stage the EAP SM cache is already cleaned by
calling eapol_sm_invalidate_cached_session(). Since at this stage the
wpa_supplicant's state is still set to associated, the EAPOL is
processed and results in a crash due to NULL dereference.
This wasn't seen previously as nl80211 wouldn't process the
NL80211_CMD_CONTROL_PORT_FRAME, since wpa_driver_nl80211_mlme() would
set the valid_handler to NULL. This behavior was changed in ab8929192
("nl80211: use the process_bss_event for the nl_connect handler"),
exposing this race.
Fix it by ignoring EAPOL frames while the deauthentication is in
progress.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 wpa_supplicant/wpa_supplicant.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6a02ed7c56..c8dcef21bd 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4773,6 +4773,11 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
 
+	if (wpa_s->own_disconnect_req) {
+		wpa_printf(MSG_DEBUG, "RX EAPOL - drop EAPOL frame as we are disconnecting");
+		return;
+	}
+
 #ifdef CONFIG_TESTING_OPTIONS
 	if (wpa_s->ignore_auth_resp) {
 		wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
-- 
2.28.0



From andrei.otcheretianski at intel.com  Sun Mar  7 21:40:02 2021
From: andrei.otcheretianski at intel.com (Andrei Otcheretianski)
Date: Sun,  7 Mar 2021 23:40:02 +0200
Subject: [PATCH] P2P: Clear pending_listen_freq when stopping listen
In-Reply-To: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
References: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
Message-ID: <20210307214002.29126-2-andrei.otcheretianski@intel.com>

If listen work never started, pending_listen_freq might be left
uncleared, preventing the subsequent listen to start.
This could happen in p2p_timeout_wait_peer_idle() after the commit
13256b8cf ("P2P: Stop old listen radio work before go to WAIT_PEER_IDLE
state") added a stop_listen() call there.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
 src/p2p/p2p.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 81bb937b36..b94274146e 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3994,6 +3994,7 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
 
 	p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+	p2p->pending_listen_freq = 0;
 	p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
 	p2p_listen_in_find(p2p, 0);
 }
-- 
2.28.0



From michal at plume.com  Mon Mar  8 08:45:19 2021
From: michal at plume.com (Michal Kazior)
Date: Mon, 8 Mar 2021 09:45:19 +0100
Subject: [PATCH] DPP: respond to GAS on the same channel it was received on
In-Reply-To: <20210306100345.GA25876@w1.fi>
References: <20210303095333.8420-1-kazikcz@gmail.com>
 <20210306100345.GA25876@w1.fi>
Message-ID: <CABqz6WxScXBzLu0uNX1rpr0-8na7-8iXWKGTqhsnbRrG9Lqm1A@mail.gmail.com>

On Sat, Mar 6, 2021 at 11:03 AM Jouni Malinen <j at w1.fi> wrote:
>
> On Wed, Mar 03, 2021 at 09:53:33AM +0000, Michal Kazior wrote:
> > When I was testing dpp_auth_init on an AP with
> > Enrollee on a different channel from the AP I was
> > getting failures. This happened on hwsim in UML
> > with time-travel for me. I don't recall seeing
> > this with real devices, presumably because of lax
> > offchan implementation.
>
> Is this with a hwsim test case that already exists in hostap.git?

No. It's part of my test script that I hacked up. I'm testing a bit
more than just raw wpa_s/hostapd.


> Does it fail every time in your test setup?

Yes, it fails every time.


> > The AP reported the following logs (grepped):
> >
> > > 1614762426.860212: RX_ACTION category 4 action 10 sa 02:00:00:00:01:00 da 02:00:00:00:00:00 len 227 freq 2412
> > > 1614762426.860212: wlan0: GAS: GAS Initial Request from 02:00:00:00:01:00 (dialog token 239)
> > > 1614762426.860233: DPP: Wait for Configuration Result
> > > 1614762426.860234: nl80211: Send Action frame (ifindex=5, freq=2462 MHz wait=0 ms no_cck=0 offchanok=0)
> > > 1614762428.861186: DPP: Timeout while waiting for Configuration Result
> > > 1614762428.861186: wlan0: DPP-CONF-FAILED
>
> Can you please share the full debug log for this? I'd like to understand
> what exactly happened with the channel negotiation here.

Attaching tarball with logs. I reworked the test script to just
exercise wpa_s/hostapd. It's in the tarball as well. Just run
./run-it.


Micha?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dpp-auth-offchan-gas-failure.tar.gz
Type: application/gzip
Size: 29174 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210308/a43b90d2/attachment-0001.gz>

From michal at plume.com  Mon Mar  8 12:57:51 2021
From: michal at plume.com (Michal Kazior)
Date: Mon, 8 Mar 2021 13:57:51 +0100
Subject: [PATCHv2] DPP: prevent processing dpp action frames when stopped
In-Reply-To: <20210306111716.GA454422@w1.fi>
References: <20210303102605.9891-1-kazikcz@gmail.com>
 <20210306111716.GA454422@w1.fi>
Message-ID: <CABqz6Wy4PtRQmShdb2LomgxEVugdnYx9CvCa0yGn2MZb2g=EKQ@mail.gmail.com>

On Sat, Mar 6, 2021 at 12:17 PM Jouni Malinen <j at w1.fi> wrote:
>
> On Wed, Mar 03, 2021 at 10:26:05AM +0000, Michal Kazior wrote:
> > diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
> > @@ -706,6 +706,7 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
> >
> >  void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
> >  {
> > +     hapd->dpp_allowed_roles = 0;
> >       hostapd_drv_dpp_listen(hapd, false);
> >       /* TODO: Stop listen operation on non-operating channel */
> >  }
>
> This breaks chirping mode since hostapd_dpp_chirp_next() calls
> hostapd_dpp_listen_stop() in the middle of the iteration. I don't think
> this approach in hostapd_dpp_listen_stop() changing dpp_allowed_roles is
> going to be acceptable.

Right, good point!


> I'm not sure I fully understood your use case, but please note that the
> DPP_STOP_LISTEN command is also calling hostapd_dpp_stop(). Would that
> function be more appropriate place for clearing dpp_allowed_roles?

Yes, hooking this up to hostapd_dpp_stop() should work for me.


> Or
> well, I'm not sure clearing dpp_allowed_roles is really the correct
> thing to do to address this issue, i.e., it might be safer to provide a
> different variable for tracking whether there should be any action
> taken based on received DPP Action frames.

As is hostapd allows itself to be configured in a multi-BSS case in a
way where you have race. An interface with an empty
dpp_configurator_params can get to respond to dpp auth or chirp first.
When that happens dpp auth eventually fails because it has no clue
what to do.

You could argue the system integrator calling hostapd cli should make
sure to configure dpp_configurator_params on BSSes interfaces all the
same.. DPP responder isn't all that much tied to a single BSS in the
first place anyway, right? It's giving out complete credentials
(ssid+whatever-akm-data) to whoever it ends up talking to. But then
why have dpp_configurator_params per BSS in the first place? And even
if there is a case, I fail to see how it could work reliably given the
race condition.

We could make dpp_configurator_params global, but this would break
prior expectations of the API. Given your previous remark on the
dpp_auth_init() you're probably not too keen on this approach, no?

I think I'll just try filling in dpp_configurator_params on all BSSes
hostapd is managing and see if this works for me.


Micha?


From Stefan.Paetow at jisc.ac.uk  Tue Mar  9 00:05:49 2021
From: Stefan.Paetow at jisc.ac.uk (Stefan Paetow)
Date: Tue, 9 Mar 2021 00:05:49 +0000
Subject: eapol_test on Windows ;-)
Message-ID: <9B60DC3B-B74B-4434-AE5E-063D5CC76B9B@jisc.ac.uk>

Hello Jouni et al, 

Please find attached a patch for eapol_test.c to allow eapol_test to be built on Windows. Without this tiny change, eapol_test simply refuses to work (it hangs attempting to connect).

With Kind Regards

Stefan Paetow
Federated Roaming Technical Specialist

t: +44 (0)1235 822 125
gpg: 0x3FCE5142
xmpp: stefanp at jabber.dev.ja.net
skype: stefan.paetow.janet


In line with government advice, at Jisc we?re now working from home and our offices are currently closed. Read our statement on coronavirus <https://www.jisc.ac.uk/about/corporate/coronavirus-statement>.

jisc.ac.uk

Jisc is a registered charity (number 1149740) and a company limited by guarantee which is registered in England under Company No. 5747339, VAT No. GB 197 0632 86. Jisc?s registered office is: One Castlepark, Tower Hill, Bristol, BS2 0JA. T 0203 697 5800.
 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: eapol_test.c.patch
Type: application/octet-stream
Size: 888 bytes
Desc: eapol_test.c.patch
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210309/f5fb0b11/attachment.obj>

From fionn.cleary at streamunlimited.com  Tue Mar  9 14:22:19 2021
From: fionn.cleary at streamunlimited.com (Fionn Cleary)
Date: Tue, 09 Mar 2021 14:22:19 +0000
Subject: [PATCH v2] dbus: Add NetworkTempDisabled & NetworkReenabled signals
Message-ID: <87czw8h0f8.fsf@tcd.ie>

From: Fionn Cleary <fionn.cleary at streamunlimited.com>

These can be used to determine if a particular network has incorrect
credentials, as the existing DisconnectReason signal is only useful
for determining that a network has a problem, but not which one.

Signed-off-by: Peter Malo <peter.malo at streamunlimited.com>
[Code formatting & adding NetworkReenabled]
Signed-off-by: Fionn Cleary <fionn.cleary at streamunlimited.com>
---
 doc/dbus.doxygen                |  20 ++++++
 wpa_supplicant/dbus/dbus_new.c  | 109 ++++++++++++++++++++++++++++++++
 wpa_supplicant/dbus/dbus_new.h  |  16 +++++
 wpa_supplicant/notify.c         |  12 ++++
 wpa_supplicant/notify.h         |   4 ++
 wpa_supplicant/wpa_supplicant.c |   4 ++
 6 files changed, 165 insertions(+)

diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 8231aac41..57b7c3b5a 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -1261,6 +1261,26 @@ fi.w1.wpa_supplicant1.CreateInterface.
 	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "addr", "dst", "bssid", "ies", "signal".</dd>
 	</dl>
       </li>
+
+      <li>
+	<h3>NetworkTempDisabled ( a{sv} : parameters )</h3>
+	<p>Notification of a network being temporarily disabled.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : parameters</dt>
+	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "network", "auth_failures", "reason".</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>NetworkReenabled ( a{sv} : paramaters )</h3>
+	<p>Notification that a network is being reenabled after it was temporarily disabled.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : parameters</dt>
+	  <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "network".</dd>
+	</dl>
+      </li>
     </ul>
 
 
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 2c01943f7..03d50d780 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1155,6 +1155,103 @@ static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s,
 				 FALSE);
 }
 
+/**
+ * wpas_dbus_signal_network_temp_disabled - Send a signal that a network been temporarily disabled
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: struct holding SSID related data
+ * @reason: reason why the network was disabled
+ *
+ * Notify listeners about a temporarily disabled network
+ */
+void wpas_dbus_signal_network_temp_disabled(struct wpa_supplicant *wpa_s,
+					    struct wpa_ssid *ssid,
+					    const char *reason)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL || !wpa_s->dbus_new_path)
+		return;
+
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "NetworkTempDisabled");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "network", path) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "auth_failures",
+					 ssid->auth_failures) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "reason",
+					 reason) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+nomem:
+	dbus_message_unref(msg);
+}
+
+/**
+ * wpas_dbus_signal_network_reenabled - Send a signal that a network has been reenabled
+ * @wpa_s: %wpa_supplicant network interface data
+ * @ssid: struct holding SSID related data
+ *
+ * Notify listeners about reenabled network
+ */
+void wpas_dbus_signal_network_reenabled(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter, dict_iter;
+	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL || !wpa_s->dbus_new_path)
+		return;
+
+	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
+		    wpa_s->dbus_new_path, ssid->id);
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "NetworkReenabled");
+
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
+		goto nomem;
+
+	if (!wpa_dbus_dict_append_object_path(&dict_iter, "network", path) ||
+		!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto nomem;
+	else
+		dbus_connection_send(iface->con, msg, NULL);
+nomem:
+	dbus_message_unref(msg);
+}
 
 #ifdef CONFIG_P2P
 
@@ -4137,6 +4234,18 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
 	  }
 	},
 #endif /* CONFIG_MESH */
+	{ "NetworkTempDisabled", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
+	{ "NetworkRenabled", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "properties", "a{sv}", ARG_OUT },
+		  END_ARGS
+	  }
+	},
 	{ NULL, NULL, { END_ARGS } }
 };
 
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 42db3892e..b22bd6e78 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -264,6 +264,11 @@ void wpas_dbus_signal_mesh_peer_connected(struct wpa_supplicant *wpa_s,
 					  const u8 *peer_addr);
 void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 					     const u8 *peer_addr, int reason);
+void wpas_dbus_signal_network_temp_disabled(struct wpa_supplicant *wpa_s,
+					    struct wpa_ssid *ssid,
+					    const char *reason);
+void wpas_dbus_signal_network_reenabled(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid);
 
 #else /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
@@ -616,6 +621,17 @@ void wpas_dbus_signal_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 {
 }
 
+static inline void wpas_dbus_signal_network_temp_disabled(struct wpa_supplicant *wpa_s,
+							  struct wpa_ssid *ssid,
+							  const char *reason)
+{
+}
+
+static inline void wpas_dbus_signal_network_reenabled(struct wpa_supplicant *wpa_s,
+						      struct wpa_ssid *ssid)
+{
+}
+
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
 
 #endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index e0e7e5433..6bd4bcb9f 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -937,3 +937,15 @@ void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 }
 
 #endif /* CONFIG_MESH */
+
+void wpas_notify_network_temp_disabled(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid, const char* reason)
+{
+	wpas_dbus_signal_network_temp_disabled(wpa_s, ssid, reason);
+}
+
+void wpas_notify_network_reenabled(struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid)
+{
+	wpas_dbus_signal_network_reenabled(wpa_s, ssid);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index e843aa124..7fa687282 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -156,5 +156,9 @@ void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s,
 				     const u8 *peer_addr);
 void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s,
 					const u8 *peer_addr, u16 reason_code);
+void wpas_notify_network_temp_disabled(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid, const char* reason);
+void wpas_notify_network_reenabled(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid);
 
 #endif /* NOTIFY_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6a02ed7c5..59f45a1d5 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -7804,6 +7804,8 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
 		"id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
 		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
 		ssid->auth_failures, dur, reason);
+
+	wpas_notify_network_temp_disabled(wpa_s, ssid, reason);
 }
 
 
@@ -7822,6 +7824,8 @@ void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
 	ssid->disabled_until.usec = 0;
 	if (clear_failures)
 		ssid->auth_failures = 0;
+
+	wpas_notify_network_reenabled(wpa_s, ssid);
 }
 
 
-- 
2.25.1



From clearyf at tcd.ie  Wed Mar 10 07:04:55 2021
From: clearyf at tcd.ie (Fionn Cleary)
Date: Wed, 10 Mar 2021 07:04:55 +0000
Subject: [PATCH v2] dbus: Add NetworkTempDisabled & NetworkReenabled
 signals
In-Reply-To: <87czw8h0f8.fsf@tcd.ie>
Message-ID: <878s6vh4ko.fsf@tcd.ie>

Just a small note on the v2 patch: there?s a typo in the introspection
data, "Renabled" when it should be "Reenabled".

Regards
Fionn


From Stefan.Paetow at jisc.ac.uk  Wed Mar 10 10:04:02 2021
From: Stefan.Paetow at jisc.ac.uk (Stefan Paetow)
Date: Wed, 10 Mar 2021 10:04:02 +0000
Subject: eapol_test on Windows ;-)
In-Reply-To: <9B60DC3B-B74B-4434-AE5E-063D5CC76B9B@jisc.ac.uk>
References: <9B60DC3B-B74B-4434-AE5E-063D5CC76B9B@jisc.ac.uk>
Message-ID: <98FA5919-E816-4CB3-92C5-CEFF0D592CC1@jisc.ac.uk>

Apparently that email didn't work. I've inlined the patch this time (and hoping it doesn't destroy the whitespace):

From 3bd16507e508fadd8987e38f72889a10fa7c2c4b Mon Sep 17 00:00:00 2001
From: Stefan Paetow <stefan.paetow at jisc.ac.uk>
Date: Tue, 9 Mar 2021 00:01:05 +0000
Subject: [PATCH] Add the address family when manually constructing IPv4
 addresses in eapol_test on Windows. Otherwise other functions fail miserably.
 Signed-off-by: Stefan Paetow <stefan.paetow at jisc.ac.uk>

---
 wpa_supplicant/eapol_test.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 9f69736..d137ad6 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1025,6 +1025,7 @@ static void wpa_init_conf(struct eapol_test_data *e,
 		*pos++ = a[1];
 		*pos++ = a[2];
 		*pos++ = a[3];
+		as->addr.af = AF_INET;
 	}
 #else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
 	if (hostapd_parse_ip_addr(authsrv, &as->addr) < 0) {
-- 
2.2.1


Stefan Paetow
Federated Roaming Technical Specialist

t: +44 (0)1235 822 125
gpg: 0x3FCE5142
xmpp: stefanp at jabber.dev.ja.net
skype: stefan.paetow.janet


In line with government advice, at Jisc we?re now working from home and our offices are currently closed. Read our statement on coronavirus <https://www.jisc.ac.uk/about/corporate/coronavirus-statement>.

jisc.ac.uk

Jisc is a registered charity (number 1149740) and a company limited by guarantee which is registered in England under Company No. 5747339, VAT No. GB 197 0632 86. Jisc?s registered office is: One Castlepark, Tower Hill, Bristol, BS2 0JA. T 0203 697 5800.
 

?On 09/03/2021, 00:05, "Stefan Paetow" <Stefan.Paetow at jisc.ac.uk> wrote:

    Hello Jouni et al, 
    
    Please find attached a patch for eapol_test.c to allow eapol_test to be built on Windows. Without this tiny change, eapol_test simply refuses to work (it hangs attempting to connect).
    
    With Kind Regards
    
    Stefan Paetow
    Federated Roaming Technical Specialist
    
    t: +44 (0)1235 822 125
    gpg: 0x3FCE5142
    xmpp: stefanp at jabber.dev.ja.net
    skype: stefan.paetow.janet
    
    
    In line with government advice, at Jisc we?re now working from home and our offices are currently closed. Read our statement on coronavirus <https://www.jisc.ac.uk/about/corporate/coronavirus-statement>.
    
    jisc.ac.uk
    
    Jisc is a registered charity (number 1149740) and a company limited by guarantee which is registered in England under Company No. 5747339, VAT No. GB 197 0632 86. Jisc?s registered office is: One Castlepark, Tower Hill, Bristol, BS2 0JA. T 0203 697 5800.
     
    
    


From greearb at candelatech.com  Wed Mar 10 17:27:54 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Wed, 10 Mar 2021 09:27:54 -0800
Subject: [PATCH-v2] supplicant:  Support disabling HE for stations.
Message-ID: <20210310172754.9192-1-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

Send a flag to the kernel with user has specified disable_he
in supplicant config file.  Requires kernel patch to function
as expected.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 src/drivers/driver_nl80211.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index f092bc753..5476ce9fc 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5926,6 +5926,14 @@ static int nl80211_ht_vht_overrides(struct nl_msg *msg,
 	}
 #endif /* CONFIG_VHT_OVERRIDES */
 
+#ifdef CONFIG_HE_OVERRIDES
+	if (params->disable_he) {
+		wpa_printf(MSG_DEBUG, "  * HE disabled");
+		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_HE))
+			return -1;
+	}
+#endif
+
 	return 0;
 }
 
-- 
2.26.2



From greearb at candelatech.com  Wed Mar 10 17:28:12 2021
From: greearb at candelatech.com (greearb at candelatech.com)
Date: Wed, 10 Mar 2021 09:28:12 -0800
Subject: [PATCH] twt:  Allow specifying control field in twt request.
Message-ID: <20210310172812.9237-1-greearb@candelatech.com>

From: Ben Greear <greearb at candelatech.com>

See ieee 802.11 spec table 9-687 for details.

Signed-off-by: Ben Greear <greearb at candelatech.com>
---
 wpa_supplicant/ctrl_iface.c       | 9 ++++++++-
 wpa_supplicant/twt.c              | 5 ++---
 wpa_supplicant/wpa_cli.c          | 2 +-
 wpa_supplicant/wpa_supplicant_i.h | 2 +-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4b9b5d1bf..c8f0ed241 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -9851,6 +9851,8 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	int flow_id = 0;
 	bool protection = false;
 	u8 twt_channel = 0;
+	u8 control = BIT(4); /* Control field:  Table 9-687
+			      * B4 = TWT Information Frame Disabled */
 	const char *tok_s;
 
 	tok_s = os_strstr(cmd, " dialog=");
@@ -9905,9 +9907,14 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s,
 	if (tok_s)
 		twt_channel = atoi(tok_s + os_strlen(" twt_channel="));
 
+	tok_s = os_strstr(cmd, " control=");
+	if (tok_s)
+		control = atoi(tok_s + os_strlen(" control="));
+
 	return wpas_twt_send_setup(wpa_s, dtok, exponent, mantissa, min_twt,
 				   setup_cmd, twt, requestor, trigger, implicit,
-				   flow_type, flow_id, protection, twt_channel);
+				   flow_type, flow_id, protection, twt_channel,
+				   control);
 }
 
 
diff --git a/wpa_supplicant/twt.c b/wpa_supplicant/twt.c
index d77cea227..8ec2c85ac 100644
--- a/wpa_supplicant/twt.c
+++ b/wpa_supplicant/twt.c
@@ -30,7 +30,7 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 			int mantissa, u8 min_twt, int setup_cmd, u64 twt,
 			bool requestor, bool trigger, bool implicit,
 			bool flow_type, u8 flow_id, bool protection,
-			u8 twt_channel)
+			u8 twt_channel, u8 control)
 {
 	struct wpabuf *buf;
 	u16 req_type = 0;
@@ -62,8 +62,7 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 	wpabuf_put_u8(buf, WLAN_EID_TWT);
 	wpabuf_put_u8(buf, 15); /* len */
 
-	wpabuf_put_u8(buf, BIT(4)); /* Control field:
-				     * B4 = TWT Information Frame Disabled */
+	wpabuf_put_u8(buf, control);
 
 	if (requestor)
 		req_type |= BIT(0); /* This STA is a TWT Requesting STA */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 2d63060e3..9099b0cbc 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3838,7 +3838,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
 	},
 	{ "twt_setup",
 	  wpa_cli_cmd_twt_setup, NULL, cli_cmd_flag_none,
-	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>] [min_twt=<Min TWT>] [setup_cmd=<setup-cmd>] [twt=<u64>] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=<twt chanel id>] = Send TWT Setup frame"
+	  "[dialog=<token>] [exponent=<exponent>] [mantissa=<mantissa>] [min_twt=<Min TWT>] [setup_cmd=<setup-cmd>] [twt=<u64>] [requestor=0|1] [trigger=0|1] [implicit=0|1] [flow_type=0|1] [flow_id=<3-bit-id>] [protection=0|1] [twt_channel=<twt chanel id>] [control=<control-u8>] = Send TWT Setup frame"
 	},
 	{ "twt_teardown",
 	  wpa_cli_cmd_twt_teardown, NULL, cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index df6de6b87..8847f483f 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1563,7 +1563,7 @@ int wpas_twt_send_setup(struct wpa_supplicant *wpa_s, u8 dtok, int exponent,
 			int mantissa, u8 min_twt, int setup_cmd, u64 twt,
 			bool requestor, bool trigger, bool implicit,
 			bool flow_type, u8 flow_id, bool protection,
-			u8 twt_channel);
+			u8 twt_channel, u8 control);
 int wpas_twt_send_teardown(struct wpa_supplicant *wpa_s, u8 flags);
 
 void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
-- 
2.26.2



From mike at guruce.com  Thu Mar 11 04:56:00 2021
From: mike at guruce.com (Michel Verhagen)
Date: Thu, 11 Mar 2021 17:56:00 +1300
Subject: Starting EAP sequence
Message-ID: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>

Hi,

I'm using the EAP library to implement EAPOL on an embedded device. Got 
it to go, with EAP-MD5 and EAP-TTLS and certificates, so all good. 
However, I'm trying to get the library to prepare me an EAPOL START 
packet. I'd like to initiate the start of the EAP handshake, because 
depending on the settings of the authenticator, it can take a long time 
before the EAP handshake sequence is initiated.

I thought setting _eap_ctx.eapRestart to 1 (true) or even 
eapTriggerStart to 1 and calling eap_peer_step would get me the packet 
data to send, but I can't see eapTriggerStart used anywhere in the code.

Does anybody know how to get the EAP library to prepare an EAP Start packet?

I can of course prepare and send that packet myself, but it looks like 
the EAP library should be able to do this as well...

Is there any detailed usage documentation somewhere of the EAP library 
that has more examples than just the very simplified and limited fake 
server/client code?

I'm also wondering if this is the correct and preferred way to reset the 
EAP state machine:

 ??????? // Reset state machine
 ??????? _eap_ctx.eapFail = false;
 ??????? _eap_ctx.eapRestart = true;
 ??????? eap_peer_step(...);





From rsadaram at cisco.com  Wed Mar 10 23:34:19 2021
From: rsadaram at cisco.com (RAGHAVENDRA SADARAMACHANDRA (rsadaram))
Date: Wed, 10 Mar 2021 23:34:19 +0000
Subject: Reg H2E without password identifier
In-Reply-To: <D4F34911-7E2E-4A38-B451-DE0D78D85E8D@contoso.com>
References: <D4F34911-7E2E-4A38-B451-DE0D78D85E8D@contoso.com>
Message-ID: <D7798AAE-B13E-4A8B-800E-BA5DBBE9FA42@cisco.com>

Hi All,
?
?? I am running latest hostapd in H2E only mode using following hostapd.conf.
? ?.
? sae_pwe=1
? sae_groups=19
? sae_password=example secret
? 
???Latest Wpa_supplicant is not connecting to H2E only mode AP, if I use wpa_supplicant.conf with only ?sae_password=example secret?
?
? Wpa_supplicant throws:
? 1615416250.587683: wlp5s0: Selecting BSS from priority group 0
? 1615416250.587690: wlp5s0: 0: f8:a2:d6:bc:d0:51 ssid='raghu-test-h2e' wpa_ie_len=0 rsn_ie_len=20 caps=0x411 level=-39 freq=2437
? 1615416250.587700: wlp5s0:??? selected based on RSN IE
? 1615416250.587704: wlp5s0:??? SAE H2E disabled
1615416250.587708: wlp5s0:??? skip - rate sets do not match 
???
?If I use password identifier then it works. Following config works.
Hostapd.conf:
sae_password=example secret|id=pw identifier
?
wpa_supplicant.conf:
sae_password="example secret"
sae_password_id="pw identifier"
?
Is there a way to test wpa_supplicant and hostapd without using pwd identifier?
?
-Raghu
?


From fionn.cleary at streamunlimited.com  Wed Mar 10 15:21:47 2021
From: fionn.cleary at streamunlimited.com (Fionn Cleary)
Date: Wed, 10 Mar 2021 15:21:47 +0000
Subject: Return value from D-Bus Interface.SignalPoll method
Message-ID: <87czw7japg.fsf@tcd.ie>

Hi,

As part of the new D-Bus additions I posted yesterday I have once again
noticed an oddity in the D-Bus introspection data, in particular the
SignalPoll method.  It?s listed as returning "a{sv}", that is, a dict of
string to variants, but if you look at what it actually returns on the
bus it?s a variant containing a "a{sv}", which is a variant, "v":

method call time=1615296463.836190 sender=:1.34 -> destination=fi.w1.wpa_supplicant1 serial=2 path=/fi/w1/wpa_supplicant1/Interfaces/0; interface=fi.w1.wpa_supplicant1.Interface; member=SignalPoll
method return time=1615296463.838788 sender=:1.25 -> destination=:1.34 serial=209 reply_serial=2
   variant       array [
         dict entry(
            string "rssi"
            variant                int32 -55
         )
         dict entry(
            string "linkspeed"
            variant                int32 65
         )
         dict entry(
            string "noise"
            variant                int32 -92
         )
         dict entry(
            string "frequency"
            variant                uint32 2462
         )
         dict entry(
            string "width"
            variant                string "40 MHz"
         )
      ]

In the Qt code I have which does the SignalPoll I have to manually
update the introspected xml, changing the "a{sv}" to "v" before I can
successfully extract the return value from SignalPoll.  If we look at
the relevant code in dbus_new.c (wpas_dbus_handler_signal_poll) it opens
a variant container and then opens a dict inside that:

        if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
                                              "a{sv}", &variant_iter) ||
            !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||

It would be cleaner to remove the outermost variant, but that would
break users of the existing API, so instead I would suggest changing the
SignalPoll return type to "v".  I presume I can?t be the only one who
has had to fight with this, but searching through the list archives for
"SignalPoll" gives me zero hits.

Any thoughts?  Changing the introspection data is a one-liner, just want
to see if anybody has any feedback before I post the patch.

Fionn


From aland at deployingradius.com  Thu Mar 11 12:23:06 2021
From: aland at deployingradius.com (Alan DeKok)
Date: Thu, 11 Mar 2021 07:23:06 -0500
Subject: Starting EAP sequence
In-Reply-To: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
Message-ID: <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>

On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
> I'm using the EAP library to implement EAPOL on an embedded device. Got it to go, with EAP-MD5 and EAP-TTLS and certificates, so all good. However, I'm trying to get the library to prepare me an EAPOL START packet. I'd like to initiate the start of the EAP handshake, because depending on the settings of the authenticator, it can take a long time before the EAP handshake sequence is initiated.

  I haven't used the library myself, but the problem, here is likely layering.

  i.e. you're using an EAP library.  EAP runs on EAPoL, PPP, PANA, RADIUS, Diameter, ..., where the library just does EAP.

  EAPoL is managed by the IEEE 802.1X state machine.  Which uses EAP, but isn't part of the EAP library.

> I thought setting _eap_ctx.eapRestart to 1 (true) or even eapTriggerStart to 1 and calling eap_peer_step would get me the packet data to send, but I can't see eapTriggerStart used anywhere in the code.

  See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL supplicant state machine.  It checks eapTriggerStart, and ends up calling eapol_sm_txStart().

> Does anybody know how to get the EAP library to prepare an EAP Start packet?

  You can't.  EAP isn't the same as the Ethernet layer EAPoL state machine.

> I can of course prepare and send that packet myself, but it looks like the EAP library should be able to do this as well...

  No.  The EAP library does EAP.  The 802.1X / supplicant state machine does Ethernet, and EAPoL.

  Alan DeKok.



From j at w1.fi  Thu Mar 11 17:33:46 2021
From: j at w1.fi (Jouni Malinen)
Date: Thu, 11 Mar 2021 19:33:46 +0200
Subject: Reg H2E without password identifier
In-Reply-To: <D7798AAE-B13E-4A8B-800E-BA5DBBE9FA42@cisco.com>
References: <D4F34911-7E2E-4A38-B451-DE0D78D85E8D@contoso.com>
 <D7798AAE-B13E-4A8B-800E-BA5DBBE9FA42@cisco.com>
Message-ID: <20210311173346.GA38052@w1.fi>

On Wed, Mar 10, 2021 at 11:34:19PM +0000, RAGHAVENDRA SADARAMACHANDRA (rsadaram) wrote:
> ?? I am running latest hostapd in H2E only mode using following hostapd.conf.
> ? ?.
> ? sae_pwe=1
> ? sae_groups=19
> ? sae_password=example secret
> ? 
> ???Latest Wpa_supplicant is not connecting to H2E only mode AP, if I use wpa_supplicant.conf with only ?sae_password=example secret?

Are you leaving the sae_pwe to its default value, i.e., H2E disabled, in
wpa_supplicant configutation?

> ? Wpa_supplicant throws:
> ? 1615416250.587683: wlp5s0: Selecting BSS from priority group 0
> ? 1615416250.587690: wlp5s0: 0: f8:a2:d6:bc:d0:51 ssid='raghu-test-h2e' wpa_ie_len=0 rsn_ie_len=20 caps=0x411 level=-39 freq=2437
> ? 1615416250.587700: wlp5s0:??? selected based on RSN IE
> ? 1615416250.587704: wlp5s0:??? SAE H2E disabled
> 1615416250.587708: wlp5s0:??? skip - rate sets do not match 

This indicates that wpa_supplicant has SAE H2E disabled and cannot join
the network that mandates use of H2E.

> ?If I use password identifier then it works. Following config works.
> Hostapd.conf:
> sae_password=example secret|id=pw identifier
> ?
> wpa_supplicant.conf:
> sae_password="example secret"
> sae_password_id="pw identifier"

Specifying SAE Password Identifier will automatically enable H2E since
the standard allows password identifier to be used only with H2E.

> Is there a way to test wpa_supplicant and hostapd without using pwd identifier?

Yes, you'll just need to enable SAE H2E in wpa_supplicant configuration
(sae_pwe=1 or sae_pwe=2).

-- 
Jouni Malinen                                            PGP id EFC895FA


From rsadaram at cisco.com  Thu Mar 11 18:27:02 2021
From: rsadaram at cisco.com (RAGHAVENDRA SADARAMACHANDRA (rsadaram))
Date: Thu, 11 Mar 2021 18:27:02 +0000
Subject: Reg H2E without password identifier
In-Reply-To: <20210311173346.GA38052@w1.fi>
References: <D4F34911-7E2E-4A38-B451-DE0D78D85E8D@contoso.com>
 <D7798AAE-B13E-4A8B-800E-BA5DBBE9FA42@cisco.com>
 <20210311173346.GA38052@w1.fi>
Message-ID: <90D032E8-34C0-4023-B687-B70DCC47DDC6@cisco.com>

Hi Jouni,

  Thanks for the response.
  If I use " sae_pwe=1" in wpa_supplicant.conf, I am getting below error.

 1615485670.169695: Line 14: unknown network field 'sae_pwe'.

Also tried to tweak code in wpa_supplicant.c as below and tried. Still failed to connect.
//      if (ssid->sae_password_id && sae_pwe != 3)
                sae_pwe = 1;

-Raghu

?On 3/11/21, 9:34 AM, "Jouni Malinen" <j at w1.fi> wrote:

    On Wed, Mar 10, 2021 at 11:34:19PM +0000, RAGHAVENDRA SADARAMACHANDRA (rsadaram) wrote:
    >    I am running latest hostapd in H2E only mode using following hostapd.conf.
    >   ?.
    >   sae_pwe=1
    >   sae_groups=19
    >   sae_password=example secret
    >   
    >    Latest Wpa_supplicant is not connecting to H2E only mode AP, if I use wpa_supplicant.conf with only ?sae_password=example secret?

    Are you leaving the sae_pwe to its default value, i.e., H2E disabled, in
    wpa_supplicant configutation?

    >   Wpa_supplicant throws:
    >   1615416250.587683: wlp5s0: Selecting BSS from priority group 0
    >   1615416250.587690: wlp5s0: 0: f8:a2:d6:bc:d0:51 ssid='raghu-test-h2e' wpa_ie_len=0 rsn_ie_len=20 caps=0x411 level=-39 freq=2437
    >   1615416250.587700: wlp5s0:    selected based on RSN IE
    >   1615416250.587704: wlp5s0:    SAE H2E disabled
    > 1615416250.587708: wlp5s0:    skip - rate sets do not match 

    This indicates that wpa_supplicant has SAE H2E disabled and cannot join
    the network that mandates use of H2E.

    >  If I use password identifier then it works. Following config works.
    > Hostapd.conf:
    > sae_password=example secret|id=pw identifier
    >  
    > wpa_supplicant.conf:
    > sae_password="example secret"
    > sae_password_id="pw identifier"

    Specifying SAE Password Identifier will automatically enable H2E since
    the standard allows password identifier to be used only with H2E.

    > Is there a way to test wpa_supplicant and hostapd without using pwd identifier?

    Yes, you'll just need to enable SAE H2E in wpa_supplicant configuration
    (sae_pwe=1 or sae_pwe=2).

    -- 
    Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Thu Mar 11 18:32:59 2021
From: j at w1.fi (Jouni Malinen)
Date: Thu, 11 Mar 2021 20:32:59 +0200
Subject: Reg H2E without password identifier
In-Reply-To: <90D032E8-34C0-4023-B687-B70DCC47DDC6@cisco.com>
References: <D4F34911-7E2E-4A38-B451-DE0D78D85E8D@contoso.com>
 <D7798AAE-B13E-4A8B-800E-BA5DBBE9FA42@cisco.com>
 <20210311173346.GA38052@w1.fi>
 <90D032E8-34C0-4023-B687-B70DCC47DDC6@cisco.com>
Message-ID: <20210311183259.GA39645@w1.fi>

On Thu, Mar 11, 2021 at 06:27:02PM +0000, RAGHAVENDRA SADARAMACHANDRA (rsadaram) wrote:
>   If I use " sae_pwe=1" in wpa_supplicant.conf, I am getting below error.
> 
>  1615485670.169695: Line 14: unknown network field 'sae_pwe'.

sae_pwe is a global parameter in wpa_supplicant.conf, i.e., it is
outside any of the network={...} blocks.

-- 
Jouni Malinen                                            PGP id EFC895FA


From oss at eons.net  Thu Mar 11 18:47:36 2021
From: oss at eons.net (Stefan Paetow (OpenSource))
Date: Thu, 11 Mar 2021 18:47:36 +0000
Subject: [PATCH] Add the address family when manually constructing IPv4
 addresses
In-Reply-To: <400153D5-20C4-48A1-A500-EF54900647C8@jisc.ac.uk>
References: <400153D5-20C4-48A1-A500-EF54900647C8@jisc.ac.uk>
Message-ID: <CAGmwA8pDjc4nqc1j09fwOez-itrHNRcSD0OrWorUzZ1RL76hng@mail.gmail.com>

From: Stefan Paetow <oss at eons.net>

Add the address family when manually constructing IPv4 addresses in eapol_test
on Windows. See CONFIG_NATIVE_WINDOWS define lines 1018-1027. Otherwise
other functions, like hostapd_ip_txt() in src/utils/ip_addr.c, that
rely on addr->af being
set fail miserably.

Signed-off-by: Stefan Paetow <oss at eons.net>

---
wpa_supplicant/eapol_test.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 9f69736..d137ad6 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1025,6 +1025,7 @@ static void wpa_init_conf(struct eapol_test_data *e,
                *pos++ = a[1];
                *pos++ = a[2];
                *pos++ = a[3];
+               as->addr.af = AF_INET;
        }
#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
        if (hostapd_parse_ip_addr(authsrv, &as->addr) < 0) {
--
2.2.1


From astrand at lysator.liu.se  Thu Mar 11 20:58:48 2021
From: astrand at lysator.liu.se (=?UTF-8?Q?Peter_=C3=85strand?=)
Date: Thu, 11 Mar 2021 21:58:48 +0100 (CET)
Subject: [PATCH] Restore station mode on deinit only if station when
 started
Message-ID: <9cbfd8d4-bce2-61ad-adf0-233b1b926f58@lysator.liu.se>


With the earlier code, a mesh interface was changed to station after
deinit.

Signed-off-by: Peter Astrand <peter.astrand at etteplan.com>
---
 src/drivers/driver_nl80211.c | 10 +++++-----
 src/drivers/driver_nl80211.h |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index df12941e1..61633f4da 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2839,8 +2839,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
 				set_addr)))
 		return -1;
 
-	if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
-		drv->start_mode_ap = 1;
+	if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_STATION)
+		drv->start_mode_sta = 1;
 
 	if (drv->hostapd || bss->static_ap)
 		nlmode = NL80211_IFTYPE_AP;
@@ -3005,7 +3005,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
 	}
 
 	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
-		if (!drv->hostapd || !drv->start_mode_ap)
+		if (drv->start_mode_sta)
 			wpa_driver_nl80211_set_mode(bss,
 						    NL80211_IFTYPE_STATION);
 		nl80211_mgmt_unsubscribe(bss, "deinit");
@@ -10542,8 +10542,8 @@ static int wpa_driver_nl80211_leave_mesh(void *priv)
 			   "nl80211: mesh leave request send successfully");
 	}
 
-	if (wpa_driver_nl80211_set_mode(drv->first_bss,
-					NL80211_IFTYPE_STATION)) {
+	if (drv->start_mode_sta && wpa_driver_nl80211_set_mode(drv->first_bss,
+							       NL80211_IFTYPE_STATION)) {
 		wpa_printf(MSG_INFO,
 			   "nl80211: Failed to set interface into station mode");
 	}
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 945015bf2..9d61c1d69 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -149,7 +149,7 @@ struct wpa_driver_nl80211_data {
 	unsigned int ignore_next_local_disconnect:1;
 	unsigned int ignore_next_local_deauth:1;
 	unsigned int hostapd:1;
-	unsigned int start_mode_ap:1;
+	unsigned int start_mode_sta:1;
 	unsigned int start_iface_up:1;
 	unsigned int test_use_roc_tx:1;
 	unsigned int ignore_deauth_event:1;
-- 
2.17.1



Br,
Peter ?strand

From mike at guruce.com  Thu Mar 11 21:10:07 2021
From: mike at guruce.com (Michel Verhagen)
Date: Fri, 12 Mar 2021 10:10:07 +1300
Subject: Starting EAP sequence
In-Reply-To: <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
 <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
Message-ID: <05027065-c8e1-1e8f-733d-10be1e972eb1@guruce.com>

Thanks Alan!

That does make sense indeed. I'll try to use eapol_supp for better 
handling of the EAPOL layer on top of EAP. I hope this code can be used 
with just the code I ported for the EAP library to compile.

Is there any documentation explaining what all the context parameters do 
(see test_eapol function in eapol_test.c), which are required and for 
which functionality etc? All I need is to implement an EAPOL client with 
certificates, so no WPA/WEP or any of the wireless stuff.

I'll come back with more questions probably, thanks for pointing me in 
the right direction!

Regards,

Michel Verhagen
Microsoft eMVP

  GuruCE Limited
  Microsoft Embedded Partner
  NXP Gold Partner
  https://guruce.com
  240 Ohiwa Harbour Road
  RD2
  Opotiki, 3198
  New Zealand
  Ph.  +64 (0)7  929 5807
  Mob. +64 (0)21 104 6208


  CONFIDENTIALITY NOTICE: The information contained in this message and attachments, if any, is confidential and is
  intended solely for the use of the individual or entity to whom it is addressed. You should not copy, disclose or
  distribute this communication without the authority of GuruCE Ltd. GuruCE Ltd. is neither liable for the proper and
  complete transmission of the information contained in this communication nor for any delay in its receipt. GuruCE Ltd.
  does not guarantee that the integrity of this communication has been maintained nor that the communication is free of
  viruses, interceptions or interference. If you are not the intended recipient of this communication please return the
  communication to the sender and delete and destroy all copies. If you are not the intended recipient, you are hereby
  notified that any use, dissemination, copying, or storage of this message or its attachments is strictly prohibited.

On 12/03/2021 01:23, Alan DeKok wrote:
> On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
>> I'm using the EAP library to implement EAPOL on an embedded device. Got it to go, with EAP-MD5 and EAP-TTLS and certificates, so all good. However, I'm trying to get the library to prepare me an EAPOL START packet. I'd like to initiate the start of the EAP handshake, because depending on the settings of the authenticator, it can take a long time before the EAP handshake sequence is initiated.
>    I haven't used the library myself, but the problem, here is likely layering.
>
>    i.e. you're using an EAP library.  EAP runs on EAPoL, PPP, PANA, RADIUS, Diameter, ..., where the library just does EAP.
>
>    EAPoL is managed by the IEEE 802.1X state machine.  Which uses EAP, but isn't part of the EAP library.
>
>> I thought setting _eap_ctx.eapRestart to 1 (true) or even eapTriggerStart to 1 and calling eap_peer_step would get me the packet data to send, but I can't see eapTriggerStart used anywhere in the code.
>    See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL supplicant state machine.  It checks eapTriggerStart, and ends up calling eapol_sm_txStart().
>
>> Does anybody know how to get the EAP library to prepare an EAP Start packet?
>    You can't.  EAP isn't the same as the Ethernet layer EAPoL state machine.
>
>> I can of course prepare and send that packet myself, but it looks like the EAP library should be able to do this as well...
>    No.  The EAP library does EAP.  The 802.1X / supplicant state machine does Ethernet, and EAPoL.
>
>    Alan DeKok.
>



From mike at guruce.com  Thu Mar 11 21:10:19 2021
From: mike at guruce.com (Michel Verhagen)
Date: Fri, 12 Mar 2021 10:10:19 +1300
Subject: Starting EAP sequence
In-Reply-To: <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
 <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
Message-ID: <f7ad988a-7178-8cd3-36aa-0cdfb6e957f3@guruce.com>

Thanks Alan!

That does make sense indeed. I'll try to use eapol_supp for better 
handling of the EAPOL layer on top of EAP. I hope this code can be used 
with just the code I ported for the EAP library to compile.

Is there any documentation explaining what all the context parameters do 
(see test_eapol function in eapol_test.c), which are required and for 
which functionality etc? All I need is to implement an EAPOL client with 
certificates, so no WPA/WEP or any of the wireless stuff.

I'll come back with more questions probably, thanks for pointing me in 
the right direction!


On 12/03/2021 01:23, Alan DeKok wrote:
> On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
>> I'm using the EAP library to implement EAPOL on an embedded device. Got it to go, with EAP-MD5 and EAP-TTLS and certificates, so all good. However, I'm trying to get the library to prepare me an EAPOL START packet. I'd like to initiate the start of the EAP handshake, because depending on the settings of the authenticator, it can take a long time before the EAP handshake sequence is initiated.
>    I haven't used the library myself, but the problem, here is likely layering.
>
>    i.e. you're using an EAP library.  EAP runs on EAPoL, PPP, PANA, RADIUS, Diameter, ..., where the library just does EAP.
>
>    EAPoL is managed by the IEEE 802.1X state machine.  Which uses EAP, but isn't part of the EAP library.
>
>> I thought setting _eap_ctx.eapRestart to 1 (true) or even eapTriggerStart to 1 and calling eap_peer_step would get me the packet data to send, but I can't see eapTriggerStart used anywhere in the code.
>    See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL supplicant state machine.  It checks eapTriggerStart, and ends up calling eapol_sm_txStart().
>
>> Does anybody know how to get the EAP library to prepare an EAP Start packet?
>    You can't.  EAP isn't the same as the Ethernet layer EAPoL state machine.
>
>> I can of course prepare and send that packet myself, but it looks like the EAP library should be able to do this as well...
>    No.  The EAP library does EAP.  The 802.1X / supplicant state machine does Ethernet, and EAPoL.
>
>    Alan DeKok.
>



From j at w1.fi  Fri Mar 12 09:50:33 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:50:33 +0200
Subject: [PATCH] wpa_supplicant: Don't process EAPOLs while disconnecting
In-Reply-To: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
References: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
Message-ID: <20210312095033.GA467489@w1.fi>

On Sun, Mar 07, 2021 at 11:40:01PM +0200, Andrei Otcheretianski wrote:
> An EAPOL frame may be pending when the supplicant requests to
> deauthenticate. At this stage the EAP SM cache is already cleaned by
> calling eapol_sm_invalidate_cached_session(). Since at this stage the
> wpa_supplicant's state is still set to associated, the EAPOL is
> processed and results in a crash due to NULL dereference.
> This wasn't seen previously as nl80211 wouldn't process the
> NL80211_CMD_CONTROL_PORT_FRAME, since wpa_driver_nl80211_mlme() would
> set the valid_handler to NULL. This behavior was changed in ab8929192
> ("nl80211: use the process_bss_event for the nl_connect handler"),
> exposing this race.
> Fix it by ignoring EAPOL frames while the deauthentication is in
> progress.

Thanks, applied. However, I was unable to reproduce that NULL
dereference by trying to add calls to
eapol_sm_invalidate_cached_session() in inconvenient places. Can you
please provide more details on that crash and which pointer is being
dereferenced? I'd like to add more protection against unexpected cases,
but cannot do that here since I could not figure out where this NULL
dereferencing could have happened.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 12 09:50:45 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:50:45 +0200
Subject: [PATCH] P2P: Clear pending_listen_freq when stopping listen
In-Reply-To: <20210307214002.29126-2-andrei.otcheretianski@intel.com>
References: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
 <20210307214002.29126-2-andrei.otcheretianski@intel.com>
Message-ID: <20210312095045.GB467489@w1.fi>

On Sun, Mar 07, 2021 at 11:40:02PM +0200, Andrei Otcheretianski wrote:
> If listen work never started, pending_listen_freq might be left
> uncleared, preventing the subsequent listen to start.
> This could happen in p2p_timeout_wait_peer_idle() after the commit
> 13256b8cf ("P2P: Stop old listen radio work before go to WAIT_PEER_IDLE
> state") added a stop_listen() call there.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 12 09:51:00 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:51:00 +0200
Subject: [PATCH-v2] supplicant:  Support disabling HE for stations.
In-Reply-To: <20210310172754.9192-1-greearb@candelatech.com>
References: <20210310172754.9192-1-greearb@candelatech.com>
Message-ID: <20210312095100.GC467489@w1.fi>

On Wed, Mar 10, 2021 at 09:27:54AM -0800, greearb at candelatech.com wrote:
> Send a flag to the kernel with user has specified disable_he
> in supplicant config file.  Requires kernel patch to function
> as expected.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 12 09:51:18 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:51:18 +0200
Subject: [PATCH] twt:  Allow specifying control field in twt request.
In-Reply-To: <20210310172812.9237-1-greearb@candelatech.com>
References: <20210310172812.9237-1-greearb@candelatech.com>
Message-ID: <20210312095118.GD467489@w1.fi>

On Wed, Mar 10, 2021 at 09:28:12AM -0800, greearb at candelatech.com wrote:
> See ieee 802.11 spec table 9-687 for details.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 12 09:51:33 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:51:33 +0200
Subject: [PATCH] Add the address family when manually constructing IPv4
 addresses
In-Reply-To: <CAGmwA8pDjc4nqc1j09fwOez-itrHNRcSD0OrWorUzZ1RL76hng@mail.gmail.com>
References: <400153D5-20C4-48A1-A500-EF54900647C8@jisc.ac.uk>
 <CAGmwA8pDjc4nqc1j09fwOez-itrHNRcSD0OrWorUzZ1RL76hng@mail.gmail.com>
Message-ID: <20210312095133.GE467489@w1.fi>

On Thu, Mar 11, 2021 at 06:47:36PM +0000, Stefan Paetow (OpenSource) wrote:
> Add the address family when manually constructing IPv4 addresses in eapol_test
> on Windows. See CONFIG_NATIVE_WINDOWS define lines 1018-1027. Otherwise
> other functions, like hostapd_ip_txt() in src/utils/ip_addr.c, that
> rely on addr->af being
> set fail miserably.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 12 09:51:49 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 12 Mar 2021 11:51:49 +0200
Subject: [PATCH] Restore station mode on deinit only if station when
 started
In-Reply-To: <9cbfd8d4-bce2-61ad-adf0-233b1b926f58@lysator.liu.se>
References: <9cbfd8d4-bce2-61ad-adf0-233b1b926f58@lysator.liu.se>
Message-ID: <20210312095149.GF467489@w1.fi>

On Thu, Mar 11, 2021 at 09:58:48PM +0100, Peter ?strand wrote:
> With the earlier code, a mesh interface was changed to station after
> deinit.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From andrei.otcheretianski at intel.com  Sun Mar 14 09:25:28 2021
From: andrei.otcheretianski at intel.com (Otcheretianski, Andrei)
Date: Sun, 14 Mar 2021 09:25:28 +0000
Subject: [PATCH] wpa_supplicant: Don't process EAPOLs while disconnecting
In-Reply-To: <20210312095033.GA467489@w1.fi>
References: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
 <20210312095033.GA467489@w1.fi>
Message-ID: <SJ0PR11MB494122219AB34D22E8B54183F56D9@SJ0PR11MB4941.namprd11.prod.outlook.com>

> Thanks, applied. However, I was unable to reproduce that NULL dereference
> by trying to add calls to
> eapol_sm_invalidate_cached_session() in inconvenient places. Can you
> please provide more details on that crash and which pointer is being
> dereferenced? I'd like to add more protection against unexpected cases, but
> cannot do that here since I could not figure out where this NULL
> dereferencing could have happened.

Hi,
I was able to reproduce it rerunning eap_tls_errors() several times..
Here's the stack trace:

1615712557.476359: WPA_TRACE: eloop SIGSEGV - START
1615712557.476676: [1]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(+0x708d0) [0x55ca0fdcd8d0]
1615712557.476699:      eloop_sigsegv_handler() ../src/utils/eloop.c:123
1615712557.476709: [2]: /lib/x86_64-linux-gnu/libc.so.6(+0x3ef20) [0x7f2a23cfef20]
1615712557.476723: [3]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(+0x15c369) [0x55ca0feb9369]
1615712557.476734:      sm_EAP_SUCCESS_Enter() ../src/eap_peer/eap.c:1072
1615712557.476746: [4]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(eap_peer_sm_step+0x346) [0x55ca0feba206]
1615712557.476757:      eap_peer_sm_step_idle() ../src/eap_peer/eap.c:1152
1615712557.476765:      eap_peer_sm_step_local() ../src/eap_peer/eap.c:1280
1615712557.476773:      sm_EAP_Step() ../src/eap_peer/eap.c:1365
1615712557.476781:      eap_peer_sm_step() ../src/eap_peer/eap.c:2237
1615712557.476791: [5]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(eapol_sm_step+0x13c) [0x55ca0feb69dc]
1615712557.476802:      eapol_sm_step() ../src/eapol_supp/eapol_supp_sm.c:999
1615712557.476812: [6]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(eapol_sm_rx_eapol+0x138) [0x55ca0feb7428]
1615712557.476840:      eapol_sm_rx_eapol() ../src/eapol_supp/eapol_supp_sm.c:1293
1615712557.476852: [7]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(wpa_supplicant_rx_eapol+0x3d5) [0x55ca0ff6f1a5]
1615712557.476862:      wpa_supplicant_rx_eapol() wpa_supplicant.c:4894
1615712557.476873: [8]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(wpa_supplicant_event+0xbf3) [0x55ca0ff829e3]
1615712557.476884:      wpa_supplicant_event() events.c:5223
1615712557.476895: [9]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(process_bss_event+0x358) [0x55ca0ffa9f88]
1615712557.476905:      drv_event_eapol_rx() ../src/drivers/driver.h:6068
1615712557.476913:      nl80211_control_port_frame() ../src/drivers/driver_nl80211_event.c:2792
1615712557.476920:      process_bss_event() ../src/drivers/driver_nl80211_event.c:3164
1615712557.476930: [10]: /lib/x86_64-linux-gnu/libnl-3.so.200(nl_recvmsgs_report+0x3cc) [0x7f2a2500ac1c]
1615712557.476941: [11]: /lib/x86_64-linux-gnu/libnl-3.so.200(nl_recvmsgs+0x9) [0x7f2a2500b049]
1615712557.476954: [12]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(+0x232cab) [0x55ca0ff8fcab]
1615712557.476966:      send_and_recv() ../src/drivers/driver_nl80211.c:450
1615712557.476978: [13]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(wpa_driver_nl80211_mlme+0xcf) [0x55ca0ff9c9af]
1615712557.476988:      wpa_driver_nl80211_mlme() ../src/drivers/driver_nl80211.c:3577
1615712557.476999: [14]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(+0x240a40) [0x55ca0ff9da40]
1615712557.477010:      wpa_driver_nl80211_deauthenticate() ../src/drivers/driver_nl80211.c:3635
1615712557.477021: [15]: /home/tester/devel/iwlwifi-hostap/tests/hwsim/../../wpa_supplicant/wpa_supplicant(wpa_supplicant_deauthenticate+0x1e7) [0x55ca0ff71da7]
1615712557.477033:      memset() usr/include/x86_64-linux-gnu/bits/string_fortified.h:71
1615712557.477043:      wpa_supplicant_deauthenticate() wpa_supplicant.c:4022
1615712557.477051: WPA_TRACE: eloop SIGSEGV - END

The full log is attached.

Thanks,
Andrei
> 
> --
> Jouni Malinen                                            PGP id EFC895FA
-------------- next part --------------
A non-text attachment was scrubbed...
Name: eap_tls_errors.log0
Type: application/octet-stream
Size: 280740 bytes
Desc: eap_tls_errors.log0
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210314/cefdf721/attachment-0001.obj>

From johannes at sipsolutions.net  Sun Mar 14 15:31:29 2021
From: johannes at sipsolutions.net (Johannes Berg)
Date: Sun, 14 Mar 2021 16:31:29 +0100
Subject: mac80211_hwsim: AP and Mesh on same phy?
In-Reply-To: <5b5aeb1b-a350-9d79-f71c-154134c3bcea@lysator.liu.se>
References: <5b5aeb1b-a350-9d79-f71c-154134c3bcea@lysator.liu.se>
Message-ID: <4a4c55122ef64ae05f44beb103c06f58bf6d0727.camel@sipsolutions.net>

On Fri, 2021-03-05 at 15:39 +0100, Peter ?strand wrote:
> 
> This is with kernel 5.4. mac80211_hwsim loaded with channels=3. Is this a 
> known limitation with mac80211_hwsim?

It shouldn't be, but then again that kernel already feels old to me.

What does "iw list" say about the interface combinations?

johannes



From j at w1.fi  Sun Mar 14 22:54:34 2021
From: j at w1.fi (Jouni Malinen)
Date: Mon, 15 Mar 2021 00:54:34 +0200
Subject: [PATCH] wpa_supplicant: Don't process EAPOLs while disconnecting
In-Reply-To: <SJ0PR11MB494122219AB34D22E8B54183F56D9@SJ0PR11MB4941.namprd11.prod.outlook.com>
References: <20210307214002.29126-1-andrei.otcheretianski@intel.com>
 <20210312095033.GA467489@w1.fi>
 <SJ0PR11MB494122219AB34D22E8B54183F56D9@SJ0PR11MB4941.namprd11.prod.outlook.com>
Message-ID: <20210314225434.GA1860788@w1.fi>

On Sun, Mar 14, 2021 at 09:25:28AM +0000, Otcheretianski, Andrei wrote:
> I was able to reproduce it rerunning eap_tls_errors() several times..
> Here's the stack trace:

> 1615712557.476734:      sm_EAP_SUCCESS_Enter() ../src/eap_peer/eap.c:1072

Thanks. I was not really able to reproduce this with eap_tls_errors no
matter what I tried, but I did manage to change the timing both in the
test script and wpa_supplicant to be able to trigger this.

The real issue here was caused by an earlier change where code was moved
to the EAP SUCCESS state handler without including the same checks for
the context state still being present before deferencing the pointers in
that location. Your patch is fine as-is, but it is just hiding the real
issue, so I'll add a fix for this regression as well so that this cannot
be triggered again regardless of how the code that calls into the EAP
state machine behaves with call and event order.

-- 
Jouni Malinen                                            PGP id EFC895FA


From ilan.peer at intel.com  Mon Mar 15 12:56:59 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:56:59 +0200
Subject: [PATCH 01/15] AP: Fix setting frame and data lengths in PASN response
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-2-ilan.peer@intel.com>

Frame length and data length can exceed 256 so need to use size_t
instead of u8.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1c01241bcf..2c3832960d 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2881,11 +2881,11 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 {
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
 	u8 mic[WPA_PASN_MAX_MIC_LEN];
-	u8 mic_len, frame_len, data_len;
+	u8 mic_len;
 	u8 *ptr;
 	const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
 	u8 *data_buf = NULL;
-	size_t rsn_ie_len;
+	size_t rsn_ie_len, frame_len, data_len;
 	int ret;
 
 	wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:56:58 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:56:58 +0200
Subject: [PATCH 00/15] Add additional PASN features
Message-ID: <20210315125713.23355-1-ilan.peer@intel.com>

The patch set includes few bug fixes for the PASN implementation, and in
addition support for the following features:

- Testing support for corrupted MIC
- PASN comeback flows, based on previously submitted patches and comments.
- PASN deauthentication.

Ilan Peer (15):
  AP: Fix setting frame and data lengths in PASN response
  AP: Include PMKID in RSNIE in PASN response
  PASN: Properly set the public key
  tests: pasn: configure the nid before sending the command
  PASN: For testing purposes allow to corrupt MIC
  tests: Add test coverage for PASN with MIC errors
  AP: Rename SAE anti clogging variables and functions
  AP: Enable anti clogging handling code in PASN builds without SAE
  AP: Add support for PASN comeback flow
  PASN: Add support for comeback flow to the wpa_supplicant
  tests: Add PASN tests with comeback flow
  AP: Handle deauthentication frame from PASN station
  nl80211: Allow sending deauthentication frame with off channel
  PASN: Add support for deauthentication flow
  tests: Add coverage for PASN deauthentication

 hostapd/config_file.c             |   9 +-
 hostapd/hostapd.conf              |   3 +-
 src/ap/ap_config.c                |   7 +-
 src/ap/ap_config.h                |  11 +-
 src/ap/hostapd.h                  |   8 +-
 src/ap/ieee802_11.c               | 211 ++++++++++++++++++++++++------
 src/common/wpa_common.c           |  22 +++-
 src/common/wpa_common.h           |   7 +-
 src/drivers/driver_nl80211.c      |  13 ++
 tests/hwsim/test_pasn.py          | 141 +++++++++++++++++++-
 wpa_supplicant/config.c           |   1 +
 wpa_supplicant/config.h           |   4 +
 wpa_supplicant/ctrl_iface.c       |  49 ++++++-
 wpa_supplicant/pasn_supplicant.c  | 192 ++++++++++++++++++++++++---
 wpa_supplicant/wpa_cli.c          |   9 ++
 wpa_supplicant/wpa_supplicant_i.h |   8 +-
 16 files changed, 616 insertions(+), 79 deletions(-)

-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:00 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:00 +0200
Subject: [PATCH 02/15] AP: Include PMKID in RSNIE in PASN response
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-3-ilan.peer@intel.com>

As defined in Draft P802.11az_D3.0, section 12.12.3.2.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 2c3832960d..c378a1c95b 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2887,6 +2887,7 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 	u8 *data_buf = NULL;
 	size_t rsn_ie_len, frame_len, data_len;
 	int ret;
+	const u8 *pmkid = NULL;
 
 	wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
 
@@ -2900,7 +2901,22 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 	if (status != WLAN_STATUS_SUCCESS)
 		goto done;
 
-	if (wpa_pasn_add_rsne(buf, pmksa ? pmksa->pmkid : NULL,
+	if (pmksa) {
+		pmkid = pmksa->pmkid;
+#ifdef CONFIG_SAE_AP
+	} else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+		wpa_printf(MSG_DEBUG, "PASN: use SAE PMKID");
+		pmkid = sta->pasn->sae.pmkid;
+#endif /* CONFIG_SAE_AP */
+#ifdef CONFIG_FILS
+	} else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+		   sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+		wpa_printf(MSG_DEBUG, "PASN: use FILS ERP PMKID");
+		pmkid = sta->pasn->fils.erp_pmkid;
+#endif /* CONFIG_FILS */
+	}
+
+	if (wpa_pasn_add_rsne(buf, pmkid,
 			      sta->pasn->akmp, sta->pasn->cipher) < 0)
 		goto fail;
 
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:02 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:02 +0200
Subject: [PATCH 04/15] tests: pasn: configure the nid before sending the
 command
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-5-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index 55aee9ef6f..579625b00d 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -65,10 +65,11 @@ def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
 
     cmd = "PASN_START bssid=%s akmp=%s cipher=%s group=%s" % (hapd.own_addr(), akmp, cipher, group)
 
-    resp = dev.request(cmd)
     if nid != "":
         cmd += " nid=%s" % nid
 
+    resp = dev.request(cmd)
+
     if fail:
         if "OK" in resp:
             raise Exception("Unexpected success to start PASN authentication")
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:01 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:01 +0200
Subject: [PATCH 03/15] PASN: Properly set the public key
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-4-ilan.peer@intel.com>

When a public key is included in the PASN parameters element,
it should be encoded using RFC 5480 conventions, and thus the
first octet of the public key should indicate if the public
key is compressed or not.

Fix the implementation to properly adhere to the convention
requirements (for both wpa_supplicant and hostapd).

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c              | 23 ++++++++++++++++++-----
 src/common/wpa_common.c          | 22 ++++++++++++++++++----
 src/common/wpa_common.h          |  7 ++++++-
 wpa_supplicant/pasn_supplicant.c | 24 ++++++++++++++++++------
 4 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index c378a1c95b..cc83ce6e02 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2937,7 +2937,7 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 
 	wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
 				  sta->pasn->wrapped_data_format,
-				  pubkey, NULL, 0);
+				  pubkey, 1, NULL, 0);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -3034,7 +3034,7 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 	const int *groups = hapd->conf->pasn_groups;
 	static const int default_groups[] = { 19, 0 };
 	u16 status = WLAN_STATUS_SUCCESS;
-	int ret;
+	int ret, inc_y;
 	bool derive_keys;
 	u32 i;
 
@@ -3118,9 +3118,22 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 
 	sta->pasn->group = pasn_params.group;
 
-	secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0,
-					 pasn_params.pubkey,
-					 pasn_params.pubkey_len);
+	if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+		inc_y = 1;
+	} else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+		   pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+		inc_y = 0;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid first octet in pubkey=0x%x",
+			   pasn_params.pubkey[0]);
+		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto send_resp;
+	}
+
+	secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y,
+					 pasn_params.pubkey + 1,
+					 pasn_params.pubkey_len - 1);
 	if (!secret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 04d49ee4cd..600ffc8379 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3419,13 +3419,16 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
  * @pasn_group: Finite Cyclic Group ID for PASN authentication
  * @wrapped_data_format: Format of the data in the Wrapped Data IE
  * @pubkey: A buffer holding the local public key. Can be NULL
+ * @compressed: In case pubkey is included, indicates if the public key is
+ *     compressed (only x coordinate is included) or not (both x and y
+ *     coordinates are included)
  * @comeback: A buffer holding the comeback token. Can be NULL
  * @after: If comeback is set, defined the comeback time in seconds. -1 to not
  *	include the Comeback After field (frames from non-AP STA).
  */
 void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 			       u8 wrapped_data_format,
-			       struct wpabuf *pubkey,
+			       struct wpabuf *pubkey, bool compressed,
 			       struct wpabuf *comeback, int after)
 {
 	struct pasn_parameter_ie *params;
@@ -3465,13 +3468,24 @@ void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 
 		/*
 		 * 2 octets for the finite cyclic group + 2 octets public key
-		 * length + the actual key
+		 * length + 1 octet for the compressed/uncompressed indication +
+		 * the actual key.
 		 */
-		params->len += 2 + 1 + wpabuf_len(pubkey);
+		params->len += 2 + 1 + 1 + wpabuf_len(pubkey);
 		params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
 
 		wpabuf_put_le16(buf, pasn_group);
-		wpabuf_put_u8(buf, wpabuf_len(pubkey));
+
+		/*
+		 * The first octet should indicate if the public key is
+		 * compressed or not, as defined in RFC 5480 section 2.2.
+		 */
+		wpabuf_put_u8(buf, wpabuf_len(pubkey) + 1);
+		if (compressed)
+			wpabuf_put_u8(buf, WPA_PASN_PUBKEY_COMPRESSED_0);
+		else
+			wpabuf_put_u8(buf, WPA_PASN_PUBKEY_UNCOMPRESSED);
+
 		wpabuf_put_buf(buf, pubkey);
 	}
 }
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 0e9f252ad4..55352d9996 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -546,6 +546,11 @@ struct wpa_pasn_params_data {
 	const u8 *pubkey;
 };
 
+/* See RFC 5480 section 2.2 */
+#define WPA_PASN_PUBKEY_COMPRESSED_0 0x2
+#define WPA_PASN_PUBKEY_COMPRESSED_1 0x3
+#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x4
+
 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
 		     int use_sha384);
 
@@ -657,7 +662,7 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
 
 void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
 			       u8 wrapped_data_format,
-			       struct wpabuf *pubkey,
+			       struct wpabuf *pubkey, bool compressed,
 			       struct wpabuf *comeback, int after);
 
 int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 4f5ac589b9..a18fd96f44 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -680,7 +680,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, NULL, -1);
+				  pubkey, 1, NULL, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -753,7 +753,7 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  NULL, NULL, -1);
+				  NULL, 0, NULL, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -1226,7 +1226,7 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 	u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
 	u8 mic_len;
 	u16 status;
-	int ret;
+	int ret, inc_y;
 	u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
 			      (WLAN_FC_STYPE_AUTH << 4));
 
@@ -1344,9 +1344,21 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	secret = crypto_ecdh_set_peerkey(pasn->ecdh, 0,
-					 pasn_params.pubkey,
-					 pasn_params.pubkey_len);
+	if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
+		inc_y = 1;
+	} else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
+		   pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
+		inc_y = 0;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Invalid first octet in pubkey=0x%x",
+			   pasn_params.pubkey[0]);
+		goto fail;
+	}
+
+	secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
+					 pasn_params.pubkey + 1,
+					 pasn_params.pubkey_len - 1);
 
 	if (!secret) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:03 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:03 +0200
Subject: [PATCH 05/15] PASN: For testing purposes allow to corrupt MIC
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-6-ilan.peer@intel.com>

For testing purposes, add support for corrupting the MIC
in PASN authentication frames for both wpa_supplicant
and hostapd.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/config_file.c            | 2 ++
 src/ap/ap_config.h               | 3 +++
 src/ap/ieee802_11.c              | 7 +++++++
 wpa_supplicant/config.c          | 1 +
 wpa_supplicant/config.h          | 4 ++++
 wpa_supplicant/pasn_supplicant.c | 7 +++++++
 6 files changed, 24 insertions(+)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 80842b8f49..eabf61be07 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4664,6 +4664,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
 		bss->force_kdk_derivation = atoi(pos);
+	} else if (os_strcmp(buf, "pasn_corrupt_mic") == 0) {
+		bss->pasn_corrupt_mic = atoi(pos);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strcmp(buf, "pasn_groups") == 0) {
 		if (hostapd_parse_intlist(&bss->pasn_groups, pos)) {
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 88200c688d..e2bd5e9358 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -874,6 +874,9 @@ struct hostapd_bss_config {
 	 * secure LTF. Allow forcing KDK derivation for testing purposes.
 	 */
 	int force_kdk_derivation;
+
+	/* If set, corrupt the MIC in the 2rd authentication frame of PASN */
+	int pasn_corrupt_mic;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	int *pasn_groups;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index cc83ce6e02..f88c8b3c21 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2995,6 +2995,13 @@ static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 		goto fail;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->conf->pasn_corrupt_mic) {
+		wpa_printf(MSG_DEBUG, "PASN: frame 2: corrupt MIC");
+		mic[0] = ~mic[0];
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	os_memcpy(ptr, mic, mic_len);
 
 done:
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index ce5c80d02e..e8e9fd4326 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -5208,6 +5208,7 @@ static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_PASN
 #ifdef CONFIG_TESTING_OPTIONS
 	{ INT_RANGE(force_kdk_derivation, 0, 1), 0 },
+	{ INT_RANGE(pasn_corrupt_mic, 0, 1), 0 },
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN */
 };
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index aac4a9dffb..bbe14b477e 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1648,6 +1648,10 @@ struct wpa_config {
 	 * secure LTF. Allow forcing KDK derivation for testing purposes.
 	 */
 	int force_kdk_derivation;
+
+	/* If set, corrupt the MIC in the 3rd authentication frame of PASN */
+	int pasn_corrupt_mic;
+
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN*/
 };
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index a18fd96f44..303d791504 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -779,6 +779,13 @@ static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
 		goto fail;
 	}
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->conf->pasn_corrupt_mic) {
+		wpa_printf(MSG_DEBUG, "PASN: frame 3: corrupt MIC");
+		mic[0] = ~mic[0];
+	}
+
+#endif /* CONFIG_TESTING_OPTIONS */
 	os_memcpy(ptr, mic, mic_len);
 
 	pasn->trans_seq++;
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:06 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:06 +0200
Subject: [PATCH 08/15] AP: Enable anti clogging handling code in PASN builds
 without SAE
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-9-ilan.peer@intel.com>

The anti-clogging code was under CONFIG_SAE. Change this so it can be
used both with CONFIG_SAE and CONFIG_PSAN.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 689a51fe51..0b95a3d5c1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -687,6 +687,10 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
 	return reply_res;
 }
 
+#endif /* CONFIG_SAE */
+
+
+#if defined(CONFIG_SAE) || defined(CONFIG_PASN)
 
 static int use_anti_clogging(struct hostapd_data *hapd)
 {
@@ -697,22 +701,26 @@ static int use_anti_clogging(struct hostapd_data *hapd)
 		return 1;
 
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
+#ifdef CONFIG_SAE
 		if (!sta->sae)
 			continue;
 		if (sta->sae->state != SAE_COMMITTED &&
 		    sta->sae->state != SAE_CONFIRMED)
 			continue;
 		open++;
+#endif /* CONFIG_SAE */
 		if (open >= hapd->conf->anti_clogging_threshold)
 			return 1;
 	}
 
+#ifdef CONFIG_SAE
 	/* In addition to already existing open SAE sessions, check whether
 	 * there are enough pending commit messages in the processing queue to
 	 * potentially result in too many open sessions. */
 	if (open + dl_list_len(&hapd->sae_commit_queue) >=
 	    hapd->conf->anti_clogging_threshold)
 		return 1;
+#endif /* CONFIG_SAE */
 
 	return 0;
 }
@@ -835,6 +843,10 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 	return buf;
 }
 
+#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
+
+
+#ifdef CONFIG_SAE
 
 static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta)
 {
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:05 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:05 +0200
Subject: [PATCH 07/15] AP: Rename SAE anti clogging variables and functions
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-8-ilan.peer@intel.com>

PASN authentication mandates support for comeback flow, which
among others can be used for anti-clogging purposes.

As the SAE support for anti clogging can also be used for PASN,
start modifying the source code so the anti clogging support
can be used for both SAE and PASN.

As a start, rename some variables/functions etc. so that they
would not be SAE specific.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/config_file.c |  5 ++--
 hostapd/hostapd.conf  |  3 +-
 src/ap/ap_config.c    |  2 +-
 src/ap/ap_config.h    |  2 +-
 src/ap/hostapd.h      |  8 ++---
 src/ap/ieee802_11.c   | 70 +++++++++++++++++++++++--------------------
 6 files changed, 49 insertions(+), 41 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index eabf61be07..fd9bc0e9fc 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4276,8 +4276,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "assocresp_elements") == 0) {
 		if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
 			return 1;
-	} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
-		bss->sae_anti_clogging_threshold = atoi(pos);
+	} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0 ||
+		   os_strcmp(buf, "anti_clogging_threshold") == 0) {
+		bss->anti_clogging_threshold = atoi(pos);
 	} else if (os_strcmp(buf, "sae_sync") == 0) {
 		bss->sae_sync = atoi(pos);
 	} else if (os_strcmp(buf, "sae_groups") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 842639649f..e3ee8b2a0c 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1886,7 +1886,8 @@ own_ip_addr=127.0.0.1
 # SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
 # This parameter defines how many open SAE instances can be in progress at the
 # same time before the anti-clogging mechanism is taken into use.
-#sae_anti_clogging_threshold=5
+#sae_anti_clogging_threshold=5 (deprecated)
+#anti_clogging_threshold=5
 
 # Maximum number of SAE synchronization errors (dot11RSNASAESync)
 # The offending SAE peer will be disconnected if more than this many
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 611fa2e2c2..452386b7e5 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -121,7 +121,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 
 	bss->radius_das_time_window = 300;
 
-	bss->sae_anti_clogging_threshold = 5;
+	bss->anti_clogging_threshold = 5;
 	bss->sae_sync = 5;
 
 	bss->gas_frag_limit = 1400;
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index e2bd5e9358..25b0a6a5c8 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -655,7 +655,7 @@ struct hostapd_bss_config {
 	struct wpabuf *vendor_elements;
 	struct wpabuf *assocresp_elements;
 
-	unsigned int sae_anti_clogging_threshold;
+	unsigned int anti_clogging_threshold;
 	unsigned int sae_sync;
 	int sae_require_mfp;
 	int sae_confirm_immediate;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 0736f451df..44f566a424 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -326,10 +326,10 @@ struct hostapd_data {
 
 #ifdef CONFIG_SAE
 	/** Key used for generating SAE anti-clogging tokens */
-	u8 sae_token_key[8];
-	struct os_reltime last_sae_token_key_update;
-	u16 sae_token_idx;
-	u16 sae_pending_token_idx[256];
+	u8 comeback_key[8];
+	struct os_reltime last_comeback_key_update;
+	u16 comeback_idx;
+	u16 comeback_pending_idx[256];
 	int dot11RSNASAERetransPeriod; /* msec */
 	struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */
 #endif /* CONFIG_SAE */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index f88c8b3c21..689a51fe51 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -688,12 +688,12 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd,
 }
 
 
-static int use_sae_anti_clogging(struct hostapd_data *hapd)
+static int use_anti_clogging(struct hostapd_data *hapd)
 {
 	struct sta_info *sta;
 	unsigned int open = 0;
 
-	if (hapd->conf->sae_anti_clogging_threshold == 0)
+	if (hapd->conf->anti_clogging_threshold == 0)
 		return 1;
 
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
@@ -703,7 +703,7 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
 		    sta->sae->state != SAE_CONFIRMED)
 			continue;
 		open++;
-		if (open >= hapd->conf->sae_anti_clogging_threshold)
+		if (open >= hapd->conf->anti_clogging_threshold)
 			return 1;
 	}
 
@@ -711,18 +711,19 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd)
 	 * there are enough pending commit messages in the processing queue to
 	 * potentially result in too many open sessions. */
 	if (open + dl_list_len(&hapd->sae_commit_queue) >=
-	    hapd->conf->sae_anti_clogging_threshold)
+	    hapd->conf->anti_clogging_threshold)
 		return 1;
 
 	return 0;
 }
 
 
-static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
+static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr,
+			       u8 *idx)
 {
 	u8 hash[SHA256_MAC_LEN];
 
-	if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+	if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key),
 			addr, ETH_ALEN, hash) < 0)
 		return -1;
 	*idx = hash[0];
@@ -730,8 +731,8 @@ static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx)
 }
 
 
-static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *token, size_t token_len)
+static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr,
+				const u8 *token, size_t token_len)
 {
 	u8 mac[SHA256_MAC_LEN];
 	const u8 *addrs[2];
@@ -739,11 +740,13 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
 	u16 token_idx;
 	u8 idx;
 
-	if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0)
+	if (token_len != SHA256_MAC_LEN ||
+	    comeback_token_hash(hapd, addr, &idx) < 0)
 		return -1;
-	token_idx = hapd->sae_pending_token_idx[idx];
+	token_idx = hapd->comeback_pending_idx[idx];
 	if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
-		wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from "
+		wpa_printf(MSG_DEBUG,
+			   "Comeback: Invalid anti-clogging token from "
 			   MACSTR " - token_idx 0x%04x, expected 0x%04x",
 			   MAC2STR(addr), WPA_GET_BE16(token), token_idx);
 		return -1;
@@ -753,12 +756,12 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
 	len[0] = ETH_ALEN;
 	addrs[1] = token;
 	len[1] = 2;
-	if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+	if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
 			       2, addrs, len, mac) < 0 ||
 	    os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
 		return -1;
 
-	hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */
+	hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */
 
 	return 0;
 }
@@ -777,18 +780,19 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 	u16 token_idx;
 
 	os_get_reltime(&now);
-	if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
-	    os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) ||
-	    hapd->sae_token_idx == 0xffff) {
-		if (random_get_bytes(hapd->sae_token_key,
-				     sizeof(hapd->sae_token_key)) < 0)
+	if (!os_reltime_initialized(&hapd->last_comeback_key_update) ||
+	    os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) ||
+	    hapd->comeback_idx == 0xffff) {
+		if (random_get_bytes(hapd->comeback_key,
+				     sizeof(hapd->comeback_key)) < 0)
 			return NULL;
-		wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
-			    hapd->sae_token_key, sizeof(hapd->sae_token_key));
-		hapd->last_sae_token_key_update = now;
-		hapd->sae_token_idx = 0;
-		os_memset(hapd->sae_pending_token_idx, 0,
-			  sizeof(hapd->sae_pending_token_idx));
+		wpa_hexdump(MSG_DEBUG,
+			    "Comeback: Updated token key",
+			    hapd->comeback_key, sizeof(hapd->comeback_key));
+		hapd->last_comeback_key_update = now;
+		hapd->comeback_idx = 0;
+		os_memset(hapd->comeback_pending_idx, 0,
+			  sizeof(hapd->comeback_pending_idx));
 	}
 
 	buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
@@ -804,15 +808,16 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 		wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
 	}
 
-	if (sae_token_hash(hapd, addr, &p_idx) < 0) {
+	if (comeback_token_hash(hapd, addr, &p_idx) < 0) {
 		wpabuf_free(buf);
 		return NULL;
 	}
-	token_idx = hapd->sae_pending_token_idx[p_idx];
+
+	token_idx = hapd->comeback_pending_idx[p_idx];
 	if (!token_idx) {
-		hapd->sae_token_idx++;
-		token_idx = hapd->sae_token_idx;
-		hapd->sae_pending_token_idx[p_idx] = token_idx;
+		hapd->comeback_idx++;
+		token_idx = hapd->comeback_idx;
+		hapd->comeback_pending_idx[p_idx] = token_idx;
 	}
 	WPA_PUT_BE16(idx, token_idx);
 	token = wpabuf_put(buf, SHA256_MAC_LEN);
@@ -820,7 +825,7 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 	len[0] = ETH_ALEN;
 	addrs[1] = idx;
 	len[1] = sizeof(idx);
-	if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+	if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key),
 			       2, addrs, len, token) < 0) {
 		wpabuf_free(buf);
 		return NULL;
@@ -1452,7 +1457,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 			goto remove_sta;
 		}
 
-		if (token && check_sae_token(hapd, sta->addr, token, token_len)
+		if (token &&
+		    check_comeback_token(hapd, sta->addr, token, token_len)
 		    < 0) {
 			wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
 				   "incorrect token from " MACSTR,
@@ -1469,7 +1475,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 			goto reply;
 		}
 
-		if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
+		if (!token && use_anti_clogging(hapd) && !allow_reuse) {
 			int h2e = 0;
 
 			wpa_printf(MSG_DEBUG,
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:04 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:04 +0200
Subject: [PATCH 06/15] tests: Add test coverage for PASN with MIC errors
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-7-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index 579625b00d..69e0509c72 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -46,10 +46,12 @@ def start_pasn_ap(apdev, params):
             raise HwsimSkip("PASN not supported")
         raise
 
-def check_pasn_ptk(dev, hapd, cipher):
+def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0):
     sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
     ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
     if not (sta_ptksa and ap_ptksa):
+        if fail_ptk == 1:
+            return
         raise Exception("Could not get PTKSA entry")
 
     logger.info("sta: TK: %s KDK: %s" % (sta_ptksa['tk'], sta_ptksa['kdk']))
@@ -57,9 +59,11 @@ def check_pasn_ptk(dev, hapd, cipher):
 
     if sta_ptksa['tk'] != ap_ptksa['tk'] or sta_ptksa['kdk'] != ap_ptksa['kdk']:
         raise Exception("TK/KDK mismatch")
+    elif fail_ptk == 1:
+        raise Exception("TK/KDK match although key derivation should have failed")
 
 def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
-                           group="19", status=0, fail=0, nid=""):
+                           group="19", status=0, fail=0, nid="", fail_ptk=0):
     dev.flush_scan_cache()
     dev.scan(type="ONLY", freq=2412)
 
@@ -88,7 +92,7 @@ def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
     if status:
         return
 
-    check_pasn_ptk(dev, hapd, cipher)
+    check_pasn_ptk(dev, hapd, cipher, fail_ptk)
 
 @remote_compatible
 def test_pasn_ccmp(dev, apdev):
@@ -636,3 +640,30 @@ def test_pasn_ft_eap_sha384(dev, apdev):
         pasn_hapd = hapd0
 
     check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP-SHA384", "CCMP")
+
+def test_pasn_sta_mic_error(dev, apdev):
+    """PASN authentication with WPA2/CCMP AP with corrupted MIC on station"""
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    try:
+        # When forcing MIC corruption, the exchange would be still successful on the station side,
+        # but the AP would fail the exchange and would not store the keys.
+        dev[0].request("SET pasn_corrupt_mic 1")
+        check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail_ptk=1)
+    finally:
+        dev[0].request("SET pasn_corrupt_mic 0")
+
+    # Now verify the successful case
+    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+def test_pasn_ap_mic_error(dev, apdev):
+    """PASN authentication with WPA2/CCMP AP with corrupted MIC on AP"""
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    hapd0 = hostapd.add_ap(apdev[0], params)
+
+    params['pasn_corrupt_mic'] = "1"
+    hapd1 = hostapd.add_ap(apdev[1], params)
+
+    check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
+    check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:07 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:07 +0200
Subject: [PATCH 09/15] AP: Add support for PASN comeback flow
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-10-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/config_file.c |  2 ++
 src/ap/ap_config.c    |  5 +++
 src/ap/ap_config.h    |  6 ++++
 src/ap/ieee802_11.c   | 72 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index fd9bc0e9fc..d73a737821 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
+		bss->pasn_comeback_after = atoi(pos);
 #endif /* CONFIG_PASN */
 	} else {
 		wpa_printf(MSG_ERROR,
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 452386b7e5..7b6249bbe5 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #ifdef CONFIG_TESTING_OPTIONS
 	bss->sae_commit_status = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_PASN
+	/* comeback after 10 TUs */
+	bss->pasn_comeback_after = 10;
+#endif /* CONFIG_PASN */
 }
 
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 25b0a6a5c8..6243c2570b 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -880,6 +880,12 @@ struct hostapd_bss_config {
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	int *pasn_groups;
+
+	/*
+	 * The time in TUs after which the non-AP STA is requested to retry the
+	 * PASN authentication
+	 */
+	u16 pasn_comeback_after;
 #endif /* CONFIG_PASN */
 
 	unsigned int unsol_bcast_probe_resp_interval;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 0b95a3d5c1..4f9a0c2d6e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -709,6 +709,10 @@ static int use_anti_clogging(struct hostapd_data *hapd)
 			continue;
 		open++;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_PASN
+		if (sta->pasn && sta->pasn->ecdh)
+			open++;
+#endif /* CONFIG_PASN */
 		if (open >= hapd->conf->anti_clogging_threshold)
 			return 1;
 	}
@@ -2892,6 +2896,53 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
+				      struct sta_info *sta)
+{
+	struct wpabuf *buf, *comeback;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: Building comeback frame 2. Comeback after=%u",
+		   hapd->conf->pasn_comeback_after);
+
+	buf = wpabuf_alloc(1500);
+	if (!buf)
+		return;
+
+	wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+				   sta->addr, 2,
+				   WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
+
+	comeback = auth_build_token_req(hapd, sta->pasn->group, sta->addr, 0);
+	if (!comeback) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed sending auth with comeback");
+
+		wpabuf_free(buf);
+		return;
+	}
+
+	wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+				  WPA_PASN_WRAPPED_DATA_NO,
+				  NULL, 0, comeback,
+				  hapd->conf->pasn_comeback_after);
+
+	wpabuf_free(comeback);
+	comeback = NULL;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
+
+	ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+				    NULL, 0, 0);
+	if (ret)
+		wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
+
+	wpabuf_free(buf);
+}
+
+
 static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 				 struct sta_info *sta,
 				 struct rsn_pmksa_cache_entry *pmksa,
@@ -3134,6 +3185,27 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 		goto send_resp;
 	}
 
+	if (pasn_params.comeback) {
+		wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
+
+		/* The token includes 2 bytes for the group, so skip them */
+		ret = check_comeback_token(hapd, sta->addr,
+					   pasn_params.comeback + 2,
+					   pasn_params.comeback_len - 2);
+
+		if (ret) {
+			wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto send_resp;
+		}
+	} else if (use_anti_clogging(hapd)) {
+		wpa_printf(MSG_DEBUG, "PASN: Response with comeback");
+
+		handle_auth_pasn_comeback(hapd, sta);
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
 	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
 	if (!sta->pasn->ecdh) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:08 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:08 +0200
Subject: [PATCH 10/15] PASN: Add support for comeback flow to the
 wpa_supplicant
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-11-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 wpa_supplicant/ctrl_iface.c       |  26 +++++++-
 wpa_supplicant/pasn_supplicant.c  | 107 +++++++++++++++++++++++++++---
 wpa_supplicant/wpa_supplicant_i.h |   6 +-
 3 files changed, 126 insertions(+), 13 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index c05175822c..8ca758e27b 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10598,7 +10598,9 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 	u8 bssid[ETH_ALEN];
 	int akmp = -1, cipher = -1, got_bssid = 0;
 	u16 group = 0xFFFF;
-	int id = 0;
+	u8 *comeback = NULL;
+	size_t comeback_len = 0;
+	int id = 0, ret;
 
 	/*
 	 * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
@@ -10640,6 +10642,21 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 			group = atoi(token + 6);
 		} else if (os_strncmp(token, "nid=", 4) == 0) {
 			id = atoi(token + 4);
+		} else if (os_strncmp(token, "comeback=", 9) == 0) {
+			comeback_len = os_strlen(token + 9);
+
+			if (!comeback_len || comeback_len % 2)
+				return -1;
+
+			comeback_len /= 2;
+			comeback = os_malloc(comeback_len);
+			if (!comeback)
+				return -1;
+
+			if (hexstr2bin(token + 9, comeback, comeback_len)) {
+				os_free(comeback);
+				return -1;
+			}
 		} else {
 			wpa_printf(MSG_DEBUG,
 				   "CTRL: PASN Invalid parameter: '%s'",
@@ -10650,10 +10667,15 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 
 	if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
 		wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+		os_free(comeback);
 		return -1;
 	}
 
-	return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id);
+	ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
+				   comeback, comeback_len);
+
+	os_free(comeback);
+	return ret;
 }
 #endif /* CONFIG_PASN */
 
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 303d791504..f820d03643 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -33,6 +33,7 @@ struct wpa_pasn_auth_work {
 	int cipher;
 	u16 group;
 	int network_id;
+	struct wpabuf *comeback;
 };
 
 
@@ -56,8 +57,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
 
 
 static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
-				  int akmp, int cipher, u8 status)
+				  int akmp, int cipher, u8 status,
+				  struct wpabuf *comeback,
+				  u16 comeback_after)
 {
+	if (comeback) {
+		size_t comeback_len = wpabuf_len(comeback);
+		char *comeback_txt = os_malloc(comeback_len * 2 + 1);
+
+		if (comeback_txt) {
+			wpa_snprintf_hex(comeback_txt, comeback_len * 2 + 1,
+					 wpabuf_head(comeback), comeback_len);
+
+			wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+				" akmp=%s, status=%u comeback_after=%u"
+				" comeback=%s",
+				MAC2STR(bssid),
+				wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+				status, comeback_after, comeback_txt);
+
+			os_free(comeback_txt);
+			return;
+		}
+	}
+
 	wpa_msg(wpa_s, MSG_INFO,
 		PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
 		MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
@@ -612,7 +635,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
 }
 
 
-static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
+static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
+					      struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
@@ -680,7 +704,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, 1, NULL, -1);
+				  pubkey, 1, comeback, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -828,6 +852,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
 	wpabuf_free(pasn->beacon_rsne_rsnxe);
 	pasn->beacon_rsne_rsnxe = NULL;
 
+	wpabuf_free(pasn->comeback);
+	pasn->comeback = NULL;
+	pasn->comeback_after = 0;
+
 #ifdef CONFIG_SAE
 	sae_clear_data(&pasn->sae);
 #endif /* CONFIG_SAE */
@@ -946,7 +974,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   int akmp, int cipher, u16 group, int freq,
 			   const u8 *beacon_rsne, u8 beacon_rsne_len,
 			   const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
-			   int network_id)
+			   int network_id, struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpa_ssid *ssid = NULL;
@@ -1023,7 +1051,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		   MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
 		   pasn->group);
 
-	frame = wpas_pasn_build_auth_1(wpa_s);
+	frame = wpas_pasn_build_auth_1(wpa_s, comeback);
 	if (!frame) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
 		goto fail;
@@ -1105,6 +1133,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 					     wpa_s, NULL);
 			wpa_s->pasn_auth_work = NULL;
 		}
+
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return;
 	}
@@ -1132,16 +1162,22 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
 			      awork->group, bss->freq, rsne, *(rsne + 1) + 2,
 			      rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
-			      awork->network_id);
+			      awork->network_id, awork->comeback);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Failed to start PASN authentication");
 		goto fail;
 	}
 
+	/* comeback token is no longer needed at this stage */
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
+
 	wpa_s->pasn_auth_work = work;
 	return;
 fail:
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
 	os_free(awork);
 	work->ctx = NULL;
 	radio_work_done(work);
@@ -1149,7 +1185,8 @@ fail:
 
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			 int akmp, int cipher, u16 group, int network_id)
+			 int akmp, int cipher, u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len)
 {
 	struct wpa_pasn_auth_work *awork;
 	struct wpa_bss *bss;
@@ -1195,8 +1232,19 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	awork->group = group;
 	awork->network_id = network_id;
 
+	if (comeback && comeback_len) {
+		awork->comeback = wpabuf_alloc(comeback_len);
+		if (!awork->comeback) {
+			os_free(awork);
+			return -1;
+		}
+
+		wpabuf_put_data(awork->comeback, comeback, comeback_len);
+	}
+
 	if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
 			   wpas_pasn_auth_start_cb, awork) < 0) {
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return -1;
 	}
@@ -1216,7 +1264,8 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
 	wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
 
 	wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
-			      pasn->status);
+			      pasn->status, pasn->comeback,
+			      pasn->comeback_after);
 
 	wpas_pasn_reset(wpa_s);
 }
@@ -1315,10 +1364,44 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	/* TODO: handle comeback flow */
 	if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Authentication temporarily rejected");
+
+		if (pasn_params.comeback && pasn_params.comeback_len) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Comeback token available. After=%u",
+				   pasn_params.after);
+
+			if (!pasn_params.after) {
+				int akmp = pasn->akmp;
+				int cipher = pasn->cipher;
+				u16 group = pasn->group;
+				u8 bssid[ETH_ALEN];
+				int network_id =
+					pasn->ssid ? pasn->ssid->id : 0;
+
+				wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
+				os_memcpy(bssid, pasn->bssid, ETH_ALEN);
+				wpas_pasn_reset(wpa_s);
+
+				return wpas_pasn_auth_start(wpa_s, bssid, akmp,
+							    cipher, group,
+							    network_id,
+							    pasn_params.comeback,
+							    pasn_params.comeback_len);
+			}
+
+			pasn->comeback = wpabuf_alloc(pasn_params.comeback_len);
+			if (pasn->comeback) {
+				wpabuf_put_data(pasn->comeback,
+						pasn_params.comeback,
+						pasn_params.comeback_len);
+				pasn->comeback_after = pasn_params.after;
+			}
+		}
+
+		pasn->status = status;
 		goto fail;
 	}
 
@@ -1456,7 +1539,11 @@ fail:
 	 * the frame and terminate the authentication exchange. However, better
 	 * reply to the AP with an error status.
 	 */
-	pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (status == WLAN_STATUS_SUCCESS)
+		pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	else
+		pasn->status = status;
+
 	wpas_pasn_auth_stop(wpa_s);
 	return -1;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 68d78c11fd..e46309190c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -554,6 +554,9 @@ struct wpas_pasn {
 	struct wpa_ptk ptk;
 	struct crypto_ecdh *ecdh;
 
+	struct wpabuf *comeback;
+	u16 comeback_after;
+
 #ifdef CONFIG_SAE
 	struct sae_data sae;
 #endif /* CONFIG_SAE */
@@ -1730,7 +1733,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 			 const u8 *bssid, int akmp, int cipher,
-			 u16 group, int network_id);
+			 u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len);
 void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
 int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 			     const u8 *data, size_t data_len, u8 acked);
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:09 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:09 +0200
Subject: [PATCH 11/15] tests: Add PASN tests with comeback flow
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-12-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 83 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index 69e0509c72..ee6e6c8016 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -13,6 +13,7 @@ logger = logging.getLogger()
 import socket
 import struct
 import subprocess
+import re
 
 import hwsim_utils
 import hostapd
@@ -667,3 +668,85 @@ def test_pasn_ap_mic_error(dev, apdev):
 
     check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
     check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback(dev, apdev, params):
+    """ PASN authentication with comeback flow """
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['sae_anti_clogging_threshold'] = '0'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan(type="ONLY", freq=2412)
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % (hapd.own_addr())
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=30 comeback_after=" not in ev:
+        raise Exception("PASN: unexpected status")
+
+    comeback = re.split("comeback=", ev)[1]
+
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \
+            (hapd.own_addr(), comeback)
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=0" not in ev:
+        raise Exception("PASN: unexpected status with comeback token")
+
+    check_pasn_ptk(dev[0], hapd, "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0(dev, apdev, params):
+    """ PASN authentication with comeback flow with comeback after set to 0"""
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0_sae(dev, apdev):
+    """  PASN authentication with SAE, with comeback flow where comeback after is set to 0  """
+    check_pasn_capab(dev[0])
+    check_sae_capab(dev[0])
+
+    params = hostapd.wpa2_params(ssid="test-pasn-sae",
+                                 passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE PASN'
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
+                   only_add_network=True)
+
+    # first test with a valid PSK
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
+
+    # And now with PMKSA caching
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
+
+    # And now with a wrong passphrase
+    if "FAIL" in dev[0].request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+
+    dev[0].set_network_quoted(0, "psk", "12345678787")
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:10 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:10 +0200
Subject: [PATCH 12/15] AP: Handle deauthentication frame from PASN station
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-13-ilan.peer@intel.com>

When a deauthentication frame is received, clear the
corresponding PTKSA cache entry for the given station,
to invalidate previous PTK information.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 4f9a0c2d6e..1ffdd262b3 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -5910,6 +5910,11 @@ static void handle_deauth(struct hostapd_data *hapd,
 		" reason_code=%d",
 		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
 
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Flushing PTKSA cache for: " MACSTR,
+		MAC2STR(mgmt->sa));
+
+	ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE);
+
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:11 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:11 +0200
Subject: [PATCH 13/15] nl80211: Allow sending deauthentication frame with off
 channel
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-14-ilan.peer@intel.com>

To allow for a PASN station to deauthenticate from an AP,
extend nl80211 to allow sending a deuathentication frame with
off channel enabled.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/drivers/driver_nl80211.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a67bef9a30..2c0f536817 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4040,6 +4040,19 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 		}
 	}
 
+#ifdef CONFIG_PASN
+	if (is_sta_interface(drv->nlmode) &&
+	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+	     WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_DEAUTH) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: send_mlme: allow deauth");
+
+		use_cookie = 0;
+		offchanok = 1;
+		goto send_frame_cmd;
+	}
+#endif /* CONFIG_PASN */
+
 	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
 		freq = nl80211_get_assoc_freq(drv);
 		wpa_printf(MSG_DEBUG,
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:12 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:12 +0200
Subject: [PATCH 14/15] PASN: Add support for deauthentication flow
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-15-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 wpa_supplicant/ctrl_iface.c       | 23 +++++++++++++
 wpa_supplicant/pasn_supplicant.c  | 56 +++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_cli.c          |  9 +++++
 wpa_supplicant/wpa_supplicant_i.h |  2 ++
 4 files changed, 90 insertions(+)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8ca758e27b..a94f250d7a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10677,6 +10677,26 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 	os_free(comeback);
 	return ret;
 }
+
+
+static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s,
+					       char *cmd)
+{
+	u8 bssid[ETH_ALEN];
+
+	if (os_strncmp(cmd, "bssid=", 6)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL: PASN_DEAUTH bssid=<bssid>");
+		return -1;
+	}
+
+	if (hwaddr_aton(cmd + 6, bssid))
+		return -1;
+
+
+	return wpas_pasn_deauthenticate(wpa_s, bssid);
+}
+
 #endif /* CONFIG_PASN */
 
 
@@ -11598,6 +11618,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 		wpas_pasn_auth_stop(wpa_s);
 	} else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
 		reply_len = ptksa_cache_list(wpa_s->ptksa, reply, reply_size);
+	} else if (os_strncmp(buf, "PASN_DEAUTH ", 12) == 0) {
+		if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0)
+			reply_len = -1;
 #endif /* CONFIG_PASN */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index f820d03643..51f16bd78e 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -1613,3 +1613,59 @@ int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 
 	return 0;
 }
+
+
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_bss *bss;
+	struct wpabuf *buf;
+	struct ieee80211_mgmt *deauth;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "PASN: deauth: " MACSTR, MAC2STR(bssid));
+	if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Cannot deauthenticate from current BSS.");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries");
+	ptksa_cache_flush(wpa_s->ptksa, bssid, WPA_CIPHER_NONE);
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found");
+		return -1;
+	}
+
+	buf = wpabuf_alloc(64);
+	if (!buf) {
+		wpa_printf(MSG_DEBUG, "PASN: deauth: Failed wpabuf allocate");
+		return -1;
+	}
+
+	deauth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+					  u.deauth.variable));
+
+	deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+					     (WLAN_FC_STYPE_DEAUTH << 4));
+
+	os_memcpy(deauth->da, bssid, ETH_ALEN);
+	os_memcpy(deauth->sa, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(deauth->bssid, bssid, ETH_ALEN);
+	deauth->u.deauth.reason_code =
+		host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+	/*
+	 * Since we do not expect any response from the AP, implement the deauth
+	 * frame transmission using direct call to the driver without a radio
+	 * work.
+	 */
+	ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
+				bss->freq, 0);
+
+	wpabuf_free(buf);
+	wpa_printf(MSG_DEBUG, "PASN: deauth: ret=%d", ret);
+
+	return ret;
+}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 95608971fa..b4b9a35973 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3210,6 +3210,12 @@ static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc,
 	return wpa_cli_cmd(ctrl, "PTKSA_CACHE_LIST", 0, argc, argv);
 }
 
+static int wpa_cli_cmd_pasn_deauth(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "PASN_DEAUTH", 1, argc, argv);
+}
+
 #endif /* CONFIG_PASN */
 
 
@@ -3913,6 +3919,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
 	{ "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL,
 	  cli_cmd_flag_none,
 	  "= Get the PTKSA Cache" },
+	{ "pasn_deauth", wpa_cli_cmd_pasn_deauth, NULL,
+	  cli_cmd_flag_none,
+	  "bssid=<BSSID>" },
 #endif /* CONFIG_PASN */
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index e46309190c..8813ddb710 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1741,4 +1741,6 @@ int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		      const struct ieee80211_mgmt *mgmt, size_t len);
 
+int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid);
+
 #endif /* WPA_SUPPLICANT_I_H */
-- 
2.17.1



From ilan.peer at intel.com  Mon Mar 15 12:57:13 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Mon, 15 Mar 2021 14:57:13 +0200
Subject: [PATCH 15/15] tests: Add coverage for PASN deauthentication
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210315125713.23355-16-ilan.peer@intel.com>

Change-Id: Idf612f7761290da0fd388846b7083228f7bf7663
---
 tests/hwsim/test_pasn.py | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index ee6e6c8016..f7bc72e59d 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -47,9 +47,10 @@ def start_pasn_ap(apdev, params):
             raise HwsimSkip("PASN not supported")
         raise
 
-def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0):
+def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0, clear_keys=1):
     sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
     ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
+
     if not (sta_ptksa and ap_ptksa):
         if fail_ptk == 1:
             return
@@ -62,6 +63,17 @@ def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0):
         raise Exception("TK/KDK mismatch")
     elif fail_ptk == 1:
         raise Exception("TK/KDK match although key derivation should have failed")
+    elif clear_keys == 1:
+        cmd = "PASN_DEAUTH bssid=%s" % hapd.own_addr()
+        dev.request(cmd)
+
+        # Wait a little to let the AP process the deauth
+        time.sleep(0.2)
+
+        sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
+        ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
+        if sta_ptksa or ap_ptksa:
+            raise Exception("TK/KDK not deleted as expected")
 
 def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
                            group="19", status=0, fail=0, nid="", fail_ptk=0):
@@ -293,7 +305,7 @@ def test_pasn_sae_kdk(dev, apdev):
         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
                        scan_freq="2412")
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
     finally:
         dev[0].set("force_kdk_derivation", "0")
 
@@ -328,7 +340,7 @@ def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
         hapd.wait_sta()
         hwsim_utils.test_connectivity(dev[0], hapd)
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
 
         dev[0].request("DISCONNECT")
         dev[0].wait_disconnected()
@@ -348,7 +360,7 @@ def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
         hapd.wait_sta()
         hwsim_utils.test_connectivity(dev[0], hapd)
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
     finally:
         dev[0].set("force_kdk_derivation", "0")
 
-- 
2.17.1



From j at w1.fi  Tue Mar 16 09:20:22 2021
From: j at w1.fi (Jouni Malinen)
Date: Tue, 16 Mar 2021 11:20:22 +0200
Subject: [PATCH 15/15] tests: Add coverage for PASN deauthentication
In-Reply-To: <20210315125713.23355-16-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
 <20210315125713.23355-16-ilan.peer@intel.com>
Message-ID: <20210316092022.GA4346@w1.fi>

On Mon, Mar 15, 2021 at 02:57:13PM +0200, Ilan Peer wrote:
> Change-Id: Idf612f7761290da0fd388846b7083228f7bf7663
> ---

I need to get a Signed-off-by: line for this one.

-- 
Jouni Malinen                                            PGP id EFC895FA


From ilan.peer at intel.com  Tue Mar 16 09:43:04 2021
From: ilan.peer at intel.com (Peer, Ilan)
Date: Tue, 16 Mar 2021 09:43:04 +0000
Subject: [PATCH 15/15] tests: Add coverage for PASN deauthentication
In-Reply-To: <20210316092022.GA4346@w1.fi>
References: <20210315125713.23355-1-ilan.peer@intel.com>
 <20210315125713.23355-16-ilan.peer@intel.com> <20210316092022.GA4346@w1.fi>
Message-ID: <BN7PR11MB26101C068FC391967D593C8AE96B9@BN7PR11MB2610.namprd11.prod.outlook.com>

> -----Original Message-----
> From: Jouni Malinen <j at w1.fi>
> Sent: Tuesday, March 16, 2021 11:20
> To: Peer, Ilan <ilan.peer at intel.com>
> Cc: hostap at lists.infradead.org
> Subject: Re: [PATCH 15/15] tests: Add coverage for PASN deauthentication
> 
> On Mon, Mar 15, 2021 at 02:57:13PM +0200, Ilan Peer wrote:
> > Change-Id: Idf612f7761290da0fd388846b7083228f7bf7663
> > ---
> 
> I need to get a Signed-off-by: line for this one.

Sure .. sorry ?

Ilan.

From ilan.peer at intel.com  Tue Mar 16 09:43:23 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Tue, 16 Mar 2021 11:43:23 +0200
Subject: [PATCH v2 15/15] tests: Add coverage for PASN deauthentication
Message-ID: <20210316094323.16229-1-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index ee6e6c8016..f7bc72e59d 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -47,9 +47,10 @@ def start_pasn_ap(apdev, params):
             raise HwsimSkip("PASN not supported")
         raise
 
-def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0):
+def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0, clear_keys=1):
     sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
     ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
+
     if not (sta_ptksa and ap_ptksa):
         if fail_ptk == 1:
             return
@@ -62,6 +63,17 @@ def check_pasn_ptk(dev, hapd, cipher, fail_ptk=0):
         raise Exception("TK/KDK mismatch")
     elif fail_ptk == 1:
         raise Exception("TK/KDK match although key derivation should have failed")
+    elif clear_keys == 1:
+        cmd = "PASN_DEAUTH bssid=%s" % hapd.own_addr()
+        dev.request(cmd)
+
+        # Wait a little to let the AP process the deauth
+        time.sleep(0.2)
+
+        sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
+        ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
+        if sta_ptksa or ap_ptksa:
+            raise Exception("TK/KDK not deleted as expected")
 
 def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
                            group="19", status=0, fail=0, nid="", fail_ptk=0):
@@ -293,7 +305,7 @@ def test_pasn_sae_kdk(dev, apdev):
         dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
                        scan_freq="2412")
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
     finally:
         dev[0].set("force_kdk_derivation", "0")
 
@@ -328,7 +340,7 @@ def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
         hapd.wait_sta()
         hwsim_utils.test_connectivity(dev[0], hapd)
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
 
         dev[0].request("DISCONNECT")
         dev[0].wait_disconnected()
@@ -348,7 +360,7 @@ def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
         hapd.wait_sta()
         hwsim_utils.test_connectivity(dev[0], hapd)
 
-        check_pasn_ptk(dev[0], hapd, "CCMP")
+        check_pasn_ptk(dev[0], hapd, "CCMP", clear_keys=0)
     finally:
         dev[0].set("force_kdk_derivation", "0")
 
-- 
2.17.1



From jeff.isaacs.ext at nokia.com  Tue Mar 16 15:00:50 2021
From: jeff.isaacs.ext at nokia.com (Isaacs, Jeff (EXT - US/Murray Hill))
Date: Tue, 16 Mar 2021 15:00:50 +0000
Subject: RFC: Perform active scanning on secondary interface (wpa_supplicant)
Message-ID: <CO2PR0801MB2296C7CF591EE8616EE273B2BB6B9@CO2PR0801MB2296.namprd08.prod.outlook.com>


WiFi clients using wpa_supplicant maintain a table of available BSSs for each interface managed. Entries in this table are populated by performing active scanning on each interface. Entries not seen for a certain number of scans or a certain amount of time expire and are removed from the table. When the RSSI of an active connection drops too low and the quality of the connection is very poor, the interface performs a scan, which further degrades the connection quality.

In environments with high density networks, mobile clients can get caught in this cycle of letting the connection quality get very bad, then scanning, then reconnecting to a better AP. In the wpa_cli, there is the roam command, which allows clients to move to another AP in the same SSID. The roam command requires the BSSID to be in the BSS table of the interface performing the command. This means that the interface still needs to perform disruptive scanning to roam to other APs.

In applications where high throughput and low latency are required, roaming between access points without disruption is not possible. To achieve this, the interface would need to be constantly scanning for a better AP, which decreases throughput and increase latency. If a client has multiple WiFi interfaces, one interface could be designated as the secondary scanning interface and be used to perform periodic scanning in small intervals (every 5 seconds). The results of scans on the secondary interface could be made available to the primary interface. This would allow wpa_cli roam to be used to its full potential and open the door to seamless roaming in enterprise and industrial environments. The mechanism that decides when to execute handoffs is application based and would be up to the user to implement using the CLI.

I have attached a patch that introduces a global config parameter "is_secondary_scan_iface" that can be set for each interface. When an interface performs a scan, if the is_secondary_scan_iface is set to 1, the results from the scan are used to update the BSS tables of all other interfaces whose is_secondary_scan_iface parameter is set to 0.

To test this feature, you'll need two WiFi adapters. Add is_secondary_scan_iface=1 to the config file of the secondary interface. Startup wpa_supplicant using the two interfaces. Flush the BSS table of the primary interface, then verify that it is empty. Next, perform a scan on the secondary interface. You'll see that the results of this scan are populated in the BSS table of the primary interface.

An obvious limitation of this feature as it is implemented right now would be lack of capabilities matching. For instance, if the secondary scan interface can see 5GHz but the primary interface cannot, those results should not be made available to the primary interface.

I am interested in your comments, concerns, and questions.

Thank you,
Jeffrey Isaacs
-------------- next part --------------
A non-text attachment was scrubbed...
Name: is_secondary_scan_iface.patch
Type: text/x-patch
Size: 7589 bytes
Desc: is_secondary_scan_iface.patch
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210316/16e0197f/attachment.bin>

From j at w1.fi  Tue Mar 16 16:23:44 2021
From: j at w1.fi (Jouni Malinen)
Date: Tue, 16 Mar 2021 18:23:44 +0200
Subject: [PATCH 09/15] AP: Add support for PASN comeback flow
In-Reply-To: <20210315125713.23355-10-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
 <20210315125713.23355-10-ilan.peer@intel.com>
Message-ID: <20210316162344.GA467262@w1.fi>

On Mon, Mar 15, 2021 at 02:57:07PM +0200, Ilan Peer wrote:
>  hostapd/config_file.c |  2 ++
>  src/ap/ap_config.c    |  5 +++
>  src/ap/ap_config.h    |  6 ++++
>  src/ap/ieee802_11.c   | 72 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 85 insertions(+)

> diff --git a/hostapd/config_file.c b/hostapd/config_file.c
> @@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
> +	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
> +		bss->pasn_comeback_after = atoi(pos);

This should be documented in hostapd/hostapd.conf.

> diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
> index 0b95a3d5c1..4f9a0c2d6e 100644
> --- a/src/ap/ieee802_11.c
> +++ b/src/ap/ieee802_11.c
> @@ -709,6 +709,10 @@ static int use_anti_clogging(struct hostapd_data *hapd)
>  			continue;
>  		open++;
>  #endif /* CONFIG_SAE */
> +#ifdef CONFIG_PASN
> +		if (sta->pasn && sta->pasn->ecdh)
> +			open++;
> +#endif /* CONFIG_PASN */
>  		if (open >= hapd->conf->anti_clogging_threshold)
>  			return 1;
>  	}

Is this PASN case specifically dependent on sta->sae != NULL? This code
will not be reached unless there is a pending SAE authentication, so
this does not look correct to me.. Should this be something like
following instead?

#ifdef CONFIG_SAE
	if (sta->sae &&
	    (sta->sae->state == SAE_COMMITTED ||
	     sta->sae->state == SAE_CONFIRMED))
		open++;
#endif /* CONFIG_SAE */
#ifdef CONFIG_PASN
	if (sta->pasn && sta->pasn->ecdh)
		open++;
#endif /* CONFIG_PASN */
	if (open >= hapd->conf->anti_clogging_threshold)
		return 1;

-- 
Jouni Malinen                                            PGP id EFC895FA


From matthewmwang at chromium.org  Tue Mar 16 20:15:52 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Tue, 16 Mar 2021 13:15:52 -0700
Subject: [PATCH] CHROMIUM: hwsim: update misbehaving MBO AP test to include
 roam
Message-ID: <20210316201552.3246364-1-matthewmwang@chromium.org>

APs PMF capabilities can differ. wpa_supplicant should be able to
disable and enable MBO when roaming to and from a misbehaving MBO AP
that doesn't support PMF.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
---
 tests/hwsim/test_mbo.py | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/tests/hwsim/test_mbo.py b/tests/hwsim/test_mbo.py
index 65d446b7ee2..532365f52ff 100644
--- a/tests/hwsim/test_mbo.py
+++ b/tests/hwsim/test_mbo.py
@@ -543,15 +543,32 @@ def test_mbo_without_pmf(dev, apdev):
 def test_mbo_without_pmf_workaround(dev, apdev):
     """MBO and WPA2 without PMF on misbehaving AP"""
     ssid = "test-wnm-mbo"
-    params = {'ssid': ssid, "wpa": '2',
+    params0 = {'ssid': ssid, "wpa": '2',
               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
               "wpa_passphrase": "12345678",
               "vendor_elements": "dd07506f9a16010100"}
-    hapd = hostapd.add_ap(apdev[0], params)
+    params1 = {'ssid': ssid, "mbo": '1', "wpa": '2',
+              "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+              "wpa_passphrase": "12345678", "ieee80211w": "1"}
+    hapd0 = hostapd.add_ap(apdev[0], params0)
     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
                    proto="WPA2", ieee80211w="1", scan_freq="2412")
-    hapd.wait_sta()
-    sta = hapd.get_sta(dev[0].own_addr())
+    hapd0.wait_sta()
+    sta = hapd0.get_sta(dev[0].own_addr())
+    ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
+    if ext_capab[2] & 0x08:
+        raise Exception("STA did not disable BSS Transition capability")
+    hapd1 = hostapd.add_ap(apdev[1], params1)
+    dev[0].scan(type="ONLY")
+    dev[0].roam(apdev[1]['bssid'])
+    hapd1.wait_sta()
+    sta = hapd1.get_sta(dev[0].own_addr())
+    ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
+    if not ext_capab[2] & 0x08:
+        raise Exception("STA disabled BSS Transition capability")
+    dev[0].roam(apdev[0]['bssid'])
+    hapd0.wait_sta()
+    sta = hapd0.get_sta(dev[0].own_addr())
     ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
     if ext_capab[2] & 0x08:
         raise Exception("STA did not disable BSS Transition capability")
-- 
2.29.2



From matthewmwang at chromium.org  Tue Mar 16 20:19:55 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Tue, 16 Mar 2021 13:19:55 -0700
Subject: [PATCH v2] hwsim: update misbehaving MBO AP test to include roam
Message-ID: <20210316201955.3246649-1-matthewmwang@chromium.org>

APs PMF capabilities can differ. wpa_supplicant should be able to
disable and enable MBO when roaming to and from a misbehaving MBO AP
that doesn't support PMF.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
---
 tests/hwsim/test_mbo.py | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/tests/hwsim/test_mbo.py b/tests/hwsim/test_mbo.py
index 65d446b7ee2..532365f52ff 100644
--- a/tests/hwsim/test_mbo.py
+++ b/tests/hwsim/test_mbo.py
@@ -543,15 +543,32 @@ def test_mbo_without_pmf(dev, apdev):
 def test_mbo_without_pmf_workaround(dev, apdev):
     """MBO and WPA2 without PMF on misbehaving AP"""
     ssid = "test-wnm-mbo"
-    params = {'ssid': ssid, "wpa": '2',
+    params0 = {'ssid': ssid, "wpa": '2',
               "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
               "wpa_passphrase": "12345678",
               "vendor_elements": "dd07506f9a16010100"}
-    hapd = hostapd.add_ap(apdev[0], params)
+    params1 = {'ssid': ssid, "mbo": '1', "wpa": '2',
+              "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
+              "wpa_passphrase": "12345678", "ieee80211w": "1"}
+    hapd0 = hostapd.add_ap(apdev[0], params0)
     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
                    proto="WPA2", ieee80211w="1", scan_freq="2412")
-    hapd.wait_sta()
-    sta = hapd.get_sta(dev[0].own_addr())
+    hapd0.wait_sta()
+    sta = hapd0.get_sta(dev[0].own_addr())
+    ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
+    if ext_capab[2] & 0x08:
+        raise Exception("STA did not disable BSS Transition capability")
+    hapd1 = hostapd.add_ap(apdev[1], params1)
+    dev[0].scan(type="ONLY")
+    dev[0].roam(apdev[1]['bssid'])
+    hapd1.wait_sta()
+    sta = hapd1.get_sta(dev[0].own_addr())
+    ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
+    if not ext_capab[2] & 0x08:
+        raise Exception("STA disabled BSS Transition capability")
+    dev[0].roam(apdev[0]['bssid'])
+    hapd0.wait_sta()
+    sta = hapd0.get_sta(dev[0].own_addr())
     ext_capab = bytearray(binascii.unhexlify(sta['ext_capab']))
     if ext_capab[2] & 0x08:
         raise Exception("STA did not disable BSS Transition capability")
-- 
2.29.2



From j at w1.fi  Tue Mar 16 21:30:32 2021
From: j at w1.fi (Jouni Malinen)
Date: Tue, 16 Mar 2021 23:30:32 +0200
Subject: [PATCH 00/15] Add additional PASN features
In-Reply-To: <20210315125713.23355-1-ilan.peer@intel.com>
References: <20210315125713.23355-1-ilan.peer@intel.com>
Message-ID: <20210316213032.GA1276115@w1.fi>

On Mon, Mar 15, 2021 at 02:56:58PM +0200, Ilan Peer wrote:
> The patch set includes few bug fixes for the PASN implementation, and in
> addition support for the following features:
> 
> - Testing support for corrupted MIC
> - PASN comeback flows, based on previously submitted patches and comments.
> - PASN deauthentication.
> 
> Ilan Peer (15):
>   AP: Fix setting frame and data lengths in PASN response
>   AP: Include PMKID in RSNIE in PASN response
>   PASN: Properly set the public key
>   tests: pasn: configure the nid before sending the command
>   PASN: For testing purposes allow to corrupt MIC
>   tests: Add test coverage for PASN with MIC errors
>   AP: Rename SAE anti clogging variables and functions
>   AP: Enable anti clogging handling code in PASN builds without SAE
>   AP: Add support for PASN comeback flow
>   PASN: Add support for comeback flow to the wpa_supplicant
>   tests: Add PASN tests with comeback flow
>   AP: Handle deauthentication frame from PASN station
>   nl80211: Allow sending deauthentication frame with off channel
>   PASN: Add support for deauthentication flow
>   tests: Add coverage for PASN deauthentication

Thanks, I applied patches 1-8 and 12-15 with some cleanup. I have open
comments on 9/15 and with that, I also left the related 10/15 and 11/15
waiting for that to be resolved.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From ilan.peer at intel.com  Wed Mar 17 16:13:27 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Wed, 17 Mar 2021 18:13:27 +0200
Subject: [PATCH 1/3] AP: Add support for PASN comeback flow
Message-ID: <20210317161329.3694-1-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/config_file.c |  2 ++
 hostapd/hostapd.conf  |  7 ++++
 src/ap/ap_config.c    |  5 +++
 src/ap/ap_config.h    |  6 ++++
 src/ap/ieee802_11.c   | 82 +++++++++++++++++++++++++++++++++++++++----
 5 files changed, 96 insertions(+), 6 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index fd9bc0e9fc..d73a737821 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
+		bss->pasn_comeback_after = atoi(pos);
 #endif /* CONFIG_PASN */
 	} else {
 		wpa_printf(MSG_ERROR,
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index e3ee8b2a0c..f1b379260a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2038,6 +2038,13 @@ own_ip_addr=127.0.0.1
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
 #pasn_groups=19 20 21
 
+# PASN comeback after.
+# In case the AP is temporally unable to handle a PASN authentication exchange,
+# this value would indicate to the peer after how many TUs it can try comeback
+# and try the PASN exchange again.
+# (default: 10 TUs)
+# pasn_comeback_after=10
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 452386b7e5..7b6249bbe5 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #ifdef CONFIG_TESTING_OPTIONS
 	bss->sae_commit_status = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_PASN
+	/* comeback after 10 TUs */
+	bss->pasn_comeback_after = 10;
+#endif /* CONFIG_PASN */
 }
 
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8aeb03107a..26bdaf1317 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -880,6 +880,12 @@ struct hostapd_bss_config {
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	int *pasn_groups;
+
+	/*
+	 * The time in TUs after which the non-AP STA is requested to retry the
+	 * PASN authentication
+	 */
+	u16 pasn_comeback_after;
 #endif /* CONFIG_PASN */
 
 	unsigned int unsol_bcast_probe_resp_interval;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 72d102f44e..d8d52368fb 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -702,13 +702,15 @@ static int use_anti_clogging(struct hostapd_data *hapd)
 
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
 #ifdef CONFIG_SAE
-		if (!sta->sae)
-			continue;
-		if (sta->sae->state != SAE_COMMITTED &&
-		    sta->sae->state != SAE_CONFIRMED)
-			continue;
-		open++;
+		if (sta->sae &&
+		    (sta->sae->state == SAE_COMMITTED ||
+		     sta->sae->state == SAE_CONFIRMED))
+			open++;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_PASN
+		if (sta->pasn && sta->pasn->ecdh)
+			open++;
+#endif /* CONFIG_PASN */
 		if (open >= hapd->conf->anti_clogging_threshold)
 			return 1;
 	}
@@ -2891,6 +2893,53 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
+				      struct sta_info *sta)
+{
+	struct wpabuf *buf, *comeback;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: Building comeback frame 2. Comeback after=%u",
+		   hapd->conf->pasn_comeback_after);
+
+	buf = wpabuf_alloc(1500);
+	if (!buf)
+		return;
+
+	wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+				   sta->addr, 2,
+				   WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
+
+	comeback = auth_build_token_req(hapd, sta->pasn->group, sta->addr, 0);
+	if (!comeback) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed sending auth with comeback");
+
+		wpabuf_free(buf);
+		return;
+	}
+
+	wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+				  WPA_PASN_WRAPPED_DATA_NO,
+				  NULL, 0, comeback,
+				  hapd->conf->pasn_comeback_after);
+
+	wpabuf_free(comeback);
+	comeback = NULL;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
+
+	ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+				    NULL, 0, 0);
+	if (ret)
+		wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
+
+	wpabuf_free(buf);
+}
+
+
 static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 				 struct sta_info *sta,
 				 struct rsn_pmksa_cache_entry *pmksa,
@@ -3133,6 +3182,27 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 		goto send_resp;
 	}
 
+	if (pasn_params.comeback) {
+		wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
+
+		/* The token includes 2 bytes for the group, so skip them */
+		ret = check_comeback_token(hapd, sta->addr,
+					   pasn_params.comeback + 2,
+					   pasn_params.comeback_len - 2);
+
+		if (ret) {
+			wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto send_resp;
+		}
+	} else if (use_anti_clogging(hapd)) {
+		wpa_printf(MSG_DEBUG, "PASN: Response with comeback");
+
+		handle_auth_pasn_comeback(hapd, sta);
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
 	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
 	if (!sta->pasn->ecdh) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
-- 
2.17.1



From ilan.peer at intel.com  Wed Mar 17 16:12:59 2021
From: ilan.peer at intel.com (Peer, Ilan)
Date: Wed, 17 Mar 2021 16:12:59 +0000
Subject: [PATCH 00/15] Add additional PASN features
In-Reply-To: <20210316213032.GA1276115@w1.fi>
References: <20210315125713.23355-1-ilan.peer@intel.com>
 <20210316213032.GA1276115@w1.fi>
Message-ID: <BN7PR11MB261017563273EA206B86BBA0E96A9@BN7PR11MB2610.namprd11.prod.outlook.com>

Hi,

> Thanks, I applied patches 1-8 and 12-15 with some cleanup. I have open
> comments on 9/15 and with that, I also left the related 10/15 and 11/15
> waiting for that to be resolved.
> 

Thanks!

Ilan.


From ilan.peer at intel.com  Wed Mar 17 16:13:28 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Wed, 17 Mar 2021 18:13:28 +0200
Subject: [PATCH 2/3] PASN: Add support for comeback flow to the wpa_supplicant
In-Reply-To: <20210317161329.3694-1-ilan.peer@intel.com>
References: <20210317161329.3694-1-ilan.peer@intel.com>
Message-ID: <20210317161329.3694-2-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 wpa_supplicant/ctrl_iface.c       |  26 +++++++-
 wpa_supplicant/pasn_supplicant.c  | 107 +++++++++++++++++++++++++++---
 wpa_supplicant/wpa_supplicant_i.h |   6 +-
 3 files changed, 126 insertions(+), 13 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index b54d7d4968..44fd8afea4 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10598,7 +10598,9 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 	u8 bssid[ETH_ALEN];
 	int akmp = -1, cipher = -1, got_bssid = 0;
 	u16 group = 0xFFFF;
-	int id = 0;
+	u8 *comeback = NULL;
+	size_t comeback_len = 0;
+	int id = 0, ret;
 
 	/*
 	 * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
@@ -10640,6 +10642,21 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 			group = atoi(token + 6);
 		} else if (os_strncmp(token, "nid=", 4) == 0) {
 			id = atoi(token + 4);
+		} else if (os_strncmp(token, "comeback=", 9) == 0) {
+			comeback_len = os_strlen(token + 9);
+
+			if (!comeback_len || comeback_len % 2)
+				return -1;
+
+			comeback_len /= 2;
+			comeback = os_malloc(comeback_len);
+			if (!comeback)
+				return -1;
+
+			if (hexstr2bin(token + 9, comeback, comeback_len)) {
+				os_free(comeback);
+				return -1;
+			}
 		} else {
 			wpa_printf(MSG_DEBUG,
 				   "CTRL: PASN Invalid parameter: '%s'",
@@ -10650,10 +10667,15 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 
 	if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
 		wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+		os_free(comeback);
 		return -1;
 	}
 
-	return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id);
+	ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
+				   comeback, comeback_len);
+
+	os_free(comeback);
+	return ret;
 }
 
 
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index e6adf73f3e..1df8cfad24 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -33,6 +33,7 @@ struct wpa_pasn_auth_work {
 	int cipher;
 	u16 group;
 	int network_id;
+	struct wpabuf *comeback;
 };
 
 
@@ -56,8 +57,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
 
 
 static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
-				  int akmp, int cipher, u8 status)
+				  int akmp, int cipher, u8 status,
+				  struct wpabuf *comeback,
+				  u16 comeback_after)
 {
+	if (comeback) {
+		size_t comeback_len = wpabuf_len(comeback);
+		char *comeback_txt = os_malloc(comeback_len * 2 + 1);
+
+		if (comeback_txt) {
+			wpa_snprintf_hex(comeback_txt, comeback_len * 2 + 1,
+					 wpabuf_head(comeback), comeback_len);
+
+			wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+				" akmp=%s, status=%u comeback_after=%u"
+				" comeback=%s",
+				MAC2STR(bssid),
+				wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+				status, comeback_after, comeback_txt);
+
+			os_free(comeback_txt);
+			return;
+		}
+	}
+
 	wpa_msg(wpa_s, MSG_INFO,
 		PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
 		MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
@@ -612,7 +635,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
 }
 
 
-static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
+static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
+					      struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
@@ -680,7 +704,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, true, NULL, -1);
+				  pubkey, true, comeback, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -828,6 +852,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
 	wpabuf_free(pasn->beacon_rsne_rsnxe);
 	pasn->beacon_rsne_rsnxe = NULL;
 
+	wpabuf_free(pasn->comeback);
+	pasn->comeback = NULL;
+	pasn->comeback_after = 0;
+
 #ifdef CONFIG_SAE
 	sae_clear_data(&pasn->sae);
 #endif /* CONFIG_SAE */
@@ -946,7 +974,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   int akmp, int cipher, u16 group, int freq,
 			   const u8 *beacon_rsne, u8 beacon_rsne_len,
 			   const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
-			   int network_id)
+			   int network_id, struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpa_ssid *ssid = NULL;
@@ -1023,7 +1051,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		   MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
 		   pasn->group);
 
-	frame = wpas_pasn_build_auth_1(wpa_s);
+	frame = wpas_pasn_build_auth_1(wpa_s, comeback);
 	if (!frame) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
 		goto fail;
@@ -1105,6 +1133,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 					     wpa_s, NULL);
 			wpa_s->pasn_auth_work = NULL;
 		}
+
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return;
 	}
@@ -1132,16 +1162,22 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
 			      awork->group, bss->freq, rsne, *(rsne + 1) + 2,
 			      rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
-			      awork->network_id);
+			      awork->network_id, awork->comeback);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Failed to start PASN authentication");
 		goto fail;
 	}
 
+	/* comeback token is no longer needed at this stage */
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
+
 	wpa_s->pasn_auth_work = work;
 	return;
 fail:
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
 	os_free(awork);
 	work->ctx = NULL;
 	radio_work_done(work);
@@ -1149,7 +1185,8 @@ fail:
 
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			 int akmp, int cipher, u16 group, int network_id)
+			 int akmp, int cipher, u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len)
 {
 	struct wpa_pasn_auth_work *awork;
 	struct wpa_bss *bss;
@@ -1195,8 +1232,19 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	awork->group = group;
 	awork->network_id = network_id;
 
+	if (comeback && comeback_len) {
+		awork->comeback = wpabuf_alloc(comeback_len);
+		if (!awork->comeback) {
+			os_free(awork);
+			return -1;
+		}
+
+		wpabuf_put_data(awork->comeback, comeback, comeback_len);
+	}
+
 	if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
 			   wpas_pasn_auth_start_cb, awork) < 0) {
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return -1;
 	}
@@ -1216,7 +1264,8 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
 	wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
 
 	wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
-			      pasn->status);
+			      pasn->status, pasn->comeback,
+			      pasn->comeback_after);
 
 	wpas_pasn_reset(wpa_s);
 }
@@ -1315,10 +1364,44 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	/* TODO: handle comeback flow */
 	if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Authentication temporarily rejected");
+
+		if (pasn_params.comeback && pasn_params.comeback_len) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Comeback token available. After=%u",
+				   pasn_params.after);
+
+			if (!pasn_params.after) {
+				int akmp = pasn->akmp;
+				int cipher = pasn->cipher;
+				u16 group = pasn->group;
+				u8 bssid[ETH_ALEN];
+				int network_id =
+					pasn->ssid ? pasn->ssid->id : 0;
+
+				wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
+				os_memcpy(bssid, pasn->bssid, ETH_ALEN);
+				wpas_pasn_reset(wpa_s);
+
+				return wpas_pasn_auth_start(wpa_s, bssid, akmp,
+							    cipher, group,
+							    network_id,
+							    pasn_params.comeback,
+							    pasn_params.comeback_len);
+			}
+
+			pasn->comeback = wpabuf_alloc(pasn_params.comeback_len);
+			if (pasn->comeback) {
+				wpabuf_put_data(pasn->comeback,
+						pasn_params.comeback,
+						pasn_params.comeback_len);
+				pasn->comeback_after = pasn_params.after;
+			}
+		}
+
+		pasn->status = status;
 		goto fail;
 	}
 
@@ -1456,7 +1539,11 @@ fail:
 	 * the frame and terminate the authentication exchange. However, better
 	 * reply to the AP with an error status.
 	 */
-	pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (status == WLAN_STATUS_SUCCESS)
+		pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	else
+		pasn->status = status;
+
 	wpas_pasn_auth_stop(wpa_s);
 	return -1;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7ed8c0ee4d..8813ddb710 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -554,6 +554,9 @@ struct wpas_pasn {
 	struct wpa_ptk ptk;
 	struct crypto_ecdh *ecdh;
 
+	struct wpabuf *comeback;
+	u16 comeback_after;
+
 #ifdef CONFIG_SAE
 	struct sae_data sae;
 #endif /* CONFIG_SAE */
@@ -1730,7 +1733,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 			 const u8 *bssid, int akmp, int cipher,
-			 u16 group, int network_id);
+			 u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len);
 void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
 int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 			     const u8 *data, size_t data_len, u8 acked);
-- 
2.17.1



From ilan.peer at intel.com  Wed Mar 17 16:13:29 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Wed, 17 Mar 2021 18:13:29 +0200
Subject: [PATCH 3/3] tests: Add PASN tests with comeback flow
In-Reply-To: <20210317161329.3694-1-ilan.peer@intel.com>
References: <20210317161329.3694-1-ilan.peer@intel.com>
Message-ID: <20210317161329.3694-3-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 120 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index f2c7b3b221..578b445d98 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -13,6 +13,7 @@ logger = logging.getLogger()
 import socket
 import struct
 import subprocess
+import re
 
 import hwsim_utils
 import hostapd
@@ -681,3 +682,122 @@ def test_pasn_ap_mic_error(dev, apdev):
 
     check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
     check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback(dev, apdev, params):
+    """ PASN authentication with comeback flow """
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['sae_anti_clogging_threshold'] = '0'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan(type="ONLY", freq=2412)
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % (hapd.own_addr())
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=30 comeback_after=" not in ev:
+        raise Exception("PASN: unexpected status")
+
+    comeback = re.split("comeback=", ev)[1]
+
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \
+            (hapd.own_addr(), comeback)
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=0" not in ev:
+        raise Exception("PASN: unexpected status with comeback token")
+
+    check_pasn_ptk(dev[0], hapd, "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0(dev, apdev, params):
+    """ PASN authentication with comeback flow with comeback after set to 0"""
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0_sae(dev, apdev):
+    """  PASN authentication with SAE, with comeback flow where comeback after is set to 0  """
+    check_pasn_capab(dev[0])
+    check_sae_capab(dev[0])
+
+    params = hostapd.wpa2_params(ssid="test-pasn-sae",
+                                 passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE PASN'
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
+                   only_add_network=True)
+
+    # first test with a valid PSK
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
+
+    # And now with PMKSA caching
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
+
+    # And now with a wrong passphrase
+    if "FAIL" in dev[0].request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+
+    dev[0].set_network_quoted(0, "psk", "12345678787")
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
+
+ at remote_compatible
+def test_pasn_comeback_multi(dev, apdev):
+    """  PASN authentication with SAE, with multiple stations with comeback"""
+    check_pasn_capab(dev[0])
+    check_sae_capab(dev[0])
+
+    params = hostapd.wpa2_params(ssid="test-pasn-sae",
+                                 passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE PASN'
+    params['anti_clogging_threshold'] = '1'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    id = {}
+    for i in range(0, 2):
+        dev[i].flush_scan_cache()
+        dev[i].scan(type="ONLY", freq=2412)
+        id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                               scan_freq="2412", only_add_network=True)
+
+    for i in range(0, 2):
+        cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (hapd.own_addr(), id[i])
+        resp = dev[i].request(cmd)
+
+        if "OK" not in resp:
+            raise Exception("Failed to start pasn authentication")
+
+    for i in range(0, 2):
+        ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3)
+        if not ev:
+            raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+        if hapd.own_addr() + " akmp=PASN, status=0" not in ev:
+            raise Exception("PASN: unexpected status")
+
+        check_pasn_ptk(dev[i], hapd, "CCMP")
-- 
2.17.1



From ilan.peer at intel.com  Wed Mar 17 16:12:21 2021
From: ilan.peer at intel.com (Peer, Ilan)
Date: Wed, 17 Mar 2021 16:12:21 +0000
Subject: [PATCH 09/15] AP: Add support for PASN comeback flow
In-Reply-To: <20210316162344.GA467262@w1.fi>
References: <20210315125713.23355-1-ilan.peer@intel.com>
 <20210315125713.23355-10-ilan.peer@intel.com> <20210316162344.GA467262@w1.fi>
Message-ID: <BN7PR11MB2610BF746E8A295699E0CF2BE96A9@BN7PR11MB2610.namprd11.prod.outlook.com>

Hi,

> -----Original Message-----
> From: Jouni Malinen <j at w1.fi>
> Sent: Tuesday, March 16, 2021 18:24
> To: Peer, Ilan <ilan.peer at intel.com>
> Cc: hostap at lists.infradead.org
> Subject: Re: [PATCH 09/15] AP: Add support for PASN comeback flow
> 
> On Mon, Mar 15, 2021 at 02:57:07PM +0200, Ilan Peer wrote:
> >  hostapd/config_file.c |  2 ++
> >  src/ap/ap_config.c    |  5 +++
> >  src/ap/ap_config.h    |  6 ++++
> >  src/ap/ieee802_11.c   | 72
> +++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 85 insertions(+)
> 
> > diff --git a/hostapd/config_file.c b/hostapd/config_file.c @@ -4675,6
> > +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
> > +	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
> > +		bss->pasn_comeback_after = atoi(pos);
> 
> This should be documented in hostapd/hostapd.conf.
> 

Done.

> > diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index
> > 0b95a3d5c1..4f9a0c2d6e 100644
> > --- a/src/ap/ieee802_11.c
> > +++ b/src/ap/ieee802_11.c
> > @@ -709,6 +709,10 @@ static int use_anti_clogging(struct hostapd_data
> *hapd)
> >  			continue;
> >  		open++;
> >  #endif /* CONFIG_SAE */
> > +#ifdef CONFIG_PASN
> > +		if (sta->pasn && sta->pasn->ecdh)
> > +			open++;
> > +#endif /* CONFIG_PASN */
> >  		if (open >= hapd->conf->anti_clogging_threshold)
> >  			return 1;
> >  	}
> 
> Is this PASN case specifically dependent on sta->sae != NULL? This code will
> not be reached unless there is a pending SAE authentication, so this does not
> look correct to me.. Should this be something like following instead?
> 
> #ifdef CONFIG_SAE
> 	if (sta->sae &&
> 	    (sta->sae->state == SAE_COMMITTED ||
> 	     sta->sae->state == SAE_CONFIRMED))
> 		open++;
> #endif /* CONFIG_SAE */
> #ifdef CONFIG_PASN
> 	if (sta->pasn && sta->pasn->ecdh)
> 		open++;
> #endif /* CONFIG_PASN */
> 	if (open >= hapd->conf->anti_clogging_threshold)
> 		return 1;
> 

Agree. The testing did not cover this since anti_clogging_threshold that was used was always 0.

Sending the fixes soon.

Thanks,

Ilan.


From mauricio.oliveira at beegol.com  Fri Mar 19 04:41:38 2021
From: mauricio.oliveira at beegol.com (Mauricio de Oliveira)
Date: Fri, 19 Mar 2021 01:41:38 -0300
Subject: About DPP QR Code "I:" field
Message-ID: <CAGcWnvZUCH-4HypeVV=YMFV+hOf3OTwvXvQA0kbvgu-kuRyaGA@mail.gmail.com>

Hi,

I'm wondering if anyone knows if I can use the information or "I:"
field of DPP as I wish.

I saw on Wi-Fi Alliance's spec an example where they embedded
the serial number of the AP in it, so I'm wondering if I can actually
put something different there, not related to SN or similar
and still work.

I reckon this isn't too much about hostapd but don't know where else to ask.
I did have a look at hostapd's implementation, for example, here
https://w1.fi/cgit/hostap/tree/src/common/dpp.c#n203
and it does seem it's only required the information field to not have a
semicolumn and be between 0x20 and 0x7e as the spec says.

Thank you

Mauricio


From j at w1.fi  Fri Mar 19 15:12:15 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 19 Mar 2021 17:12:15 +0200
Subject: About DPP QR Code "I:" field
In-Reply-To: <CAGcWnvZUCH-4HypeVV=YMFV+hOf3OTwvXvQA0kbvgu-kuRyaGA@mail.gmail.com>
References: <CAGcWnvZUCH-4HypeVV=YMFV+hOf3OTwvXvQA0kbvgu-kuRyaGA@mail.gmail.com>
Message-ID: <20210319151215.GA408718@w1.fi>

On Fri, Mar 19, 2021 at 01:41:38AM -0300, Mauricio de Oliveira wrote:
> I'm wondering if anyone knows if I can use the information or "I:"
> field of DPP as I wish.
> 
> I saw on Wi-Fi Alliance's spec an example where they embedded
> the serial number of the AP in it, so I'm wondering if I can actually
> put something different there, not related to SN or similar
> and still work.

The Wi-Fi Easy Connect Specification describes this as "freeform
information". There is no other constraint on the contents or formatting
beyond some control characters and semicolons not being allowed.

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 19 16:27:33 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 19 Mar 2021 18:27:33 +0200
Subject: [PATCH 1/3] AP: Add support for PASN comeback flow
In-Reply-To: <20210317161329.3694-1-ilan.peer@intel.com>
References: <20210317161329.3694-1-ilan.peer@intel.com>
Message-ID: <20210319162733.GB408718@w1.fi>

On Wed, Mar 17, 2021 at 06:13:27PM +0200, Ilan Peer wrote:
> diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
> +static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
> +				      struct sta_info *sta)

> +	wpa_printf(MSG_DEBUG,
> +		   "PASN: Building comeback frame 2. Comeback after=%u",
> +		   hapd->conf->pasn_comeback_after);

> +	comeback = auth_build_token_req(hapd, sta->pasn->group, sta->addr, 0);

sta->pasn->group seems to be 0 here.. Shouldn't the cookie value use the
group number that the station proposed?

> @@ -3133,6 +3182,27 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
>  		goto send_resp;
> +	if (pasn_params.comeback) {
> +		wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
> +
> +		/* The token includes 2 bytes for the group, so skip them */

Why would it be fine to skip them? Shouldn't we verify that the correct
value is provided? If this is not verified, there is no point in
including the group in the cookie value in the first place.

> +		ret = check_comeback_token(hapd, sta->addr,
> +					   pasn_params.comeback + 2,
> +					   pasn_params.comeback_len - 2);

That is really problematic.. pasn_params.comeback_len can be 1 here and
that would result in (size_t)-1 going to the check_comeback_token()
function and just by chance, this does not result in a security
vulnerability due to the check against SHA256_MAC_LEN.. In other words,
this really should very that pasn_params.comeback_len >= 2 before
decrementing that by 2.

> +	} else if (use_anti_clogging(hapd)) {
> +		wpa_printf(MSG_DEBUG, "PASN: Response with comeback");
> +
> +		handle_auth_pasn_comeback(hapd, sta);
> +		ap_free_sta(hapd, sta);
> +		return;
> +	}
> +
>  	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
...

And this would be followed by setting sta->pasn->group which explains
the 0 value noted above. Maybe it would be better to add
pasn_params.group as a new argument to handle_auth_pasn_comeback() so
that the correct group gets used in the token without changes sta->pasn
in this case?

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Fri Mar 19 19:32:03 2021
From: j at w1.fi (Jouni Malinen)
Date: Fri, 19 Mar 2021 21:32:03 +0200
Subject: [PATCH v2] hwsim: update misbehaving MBO AP test to include roam
In-Reply-To: <20210316201955.3246649-1-matthewmwang@chromium.org>
References: <20210316201955.3246649-1-matthewmwang@chromium.org>
Message-ID: <20210319193203.GA1229394@w1.fi>

On Tue, Mar 16, 2021 at 01:19:55PM -0700, Matthew Wang wrote:
> APs PMF capabilities can differ. wpa_supplicant should be able to
> disable and enable MBO when roaming to and from a misbehaving MBO AP
> that doesn't support PMF.

Thanks, applied.
 
-- 
Jouni Malinen                                            PGP id EFC895FA


From ilan.peer at intel.com  Sun Mar 21 11:51:23 2021
From: ilan.peer at intel.com (Peer, Ilan)
Date: Sun, 21 Mar 2021 11:51:23 +0000
Subject: [PATCH 1/3] AP: Add support for PASN comeback flow
In-Reply-To: <20210319162733.GB408718@w1.fi>
References: <20210317161329.3694-1-ilan.peer@intel.com>
 <20210319162733.GB408718@w1.fi>
Message-ID: <BN7PR11MB261027AFCA4CCE8773241EB1E9669@BN7PR11MB2610.namprd11.prod.outlook.com>

Hi,

> -----Original Message-----
> From: Jouni Malinen <j at w1.fi>
> Sent: Friday, March 19, 2021 18:28
> To: Peer, Ilan <ilan.peer at intel.com>
> Cc: hostap at lists.infradead.org
> Subject: Re: [PATCH 1/3] AP: Add support for PASN comeback flow
> 
> On Wed, Mar 17, 2021 at 06:13:27PM +0200, Ilan Peer wrote:
> > diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
> > +static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
> > +				      struct sta_info *sta)
> 
> > +	wpa_printf(MSG_DEBUG,
> > +		   "PASN: Building comeback frame 2. Comeback after=%u",
> > +		   hapd->conf->pasn_comeback_after);
> 
> > +	comeback = auth_build_token_req(hapd, sta->pasn->group, sta-
> >addr,
> > +0);
> 
> sta->pasn->group seems to be 0 here.. Shouldn't the cookie value use the
> group number that the station proposed?
> 

I'm removing the group from the cookie, since as you noted below it is not
used.

> > @@ -3133,6 +3182,27 @@ static void handle_auth_pasn_1(struct
> hostapd_data *hapd, struct sta_info *sta,
> >  		goto send_resp;
> > +	if (pasn_params.comeback) {
> > +		wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback
> token");
> > +
> > +		/* The token includes 2 bytes for the group, so skip them */
> 
> Why would it be fine to skip them? Shouldn't we verify that the correct value
> is provided? If this is not verified, there is no point in including the group in
> the cookie value in the first place.
>

Agree. I'm removing the group from the token. 

> > +		ret = check_comeback_token(hapd, sta->addr,
> > +					   pasn_params.comeback + 2,
> > +					   pasn_params.comeback_len - 2);
> 
> That is really problematic.. pasn_params.comeback_len can be 1 here and
> that would result in (size_t)-1 going to the check_comeback_token()
> function and just by chance, this does not result in a security vulnerability
> due to the check against SHA256_MAC_LEN.. In other words, this really
> should very that pasn_params.comeback_len >= 2 before decrementing that
> by 2.
> 

With the removal of the group from the token, this would no longer be an issue.

> > +	} else if (use_anti_clogging(hapd)) {
> > +		wpa_printf(MSG_DEBUG, "PASN: Response with
> comeback");
> > +
> > +		handle_auth_pasn_comeback(hapd, sta);
> > +		ap_free_sta(hapd, sta);
> > +		return;
> > +	}
> > +
> >  	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
> ...
> 
> And this would be followed by setting sta->pasn->group which explains the 0
> value noted above. Maybe it would be better to add pasn_params.group as a
> new argument to handle_auth_pasn_comeback() so that the correct group
> gets used in the token without changes sta->pasn in this case?
> 

Thanks for the review and comments. Sending the fixed version shortly.

Ilan.


From ilan.peer at intel.com  Sun Mar 21 11:55:09 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Sun, 21 Mar 2021 13:55:09 +0200
Subject: [PATCH v2 2/3] PASN: Add support for comeback flow to the
 wpa_supplicant
In-Reply-To: <20210321115510.31582-1-ilan.peer@intel.com>
References: <20210321115510.31582-1-ilan.peer@intel.com>
Message-ID: <20210321115510.31582-2-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 wpa_supplicant/ctrl_iface.c       |  26 +++++++-
 wpa_supplicant/pasn_supplicant.c  | 107 +++++++++++++++++++++++++++---
 wpa_supplicant/wpa_supplicant_i.h |   6 +-
 3 files changed, 126 insertions(+), 13 deletions(-)

diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index b54d7d4968..44fd8afea4 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -10598,7 +10598,9 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 	u8 bssid[ETH_ALEN];
 	int akmp = -1, cipher = -1, got_bssid = 0;
 	u16 group = 0xFFFF;
-	int id = 0;
+	u8 *comeback = NULL;
+	size_t comeback_len = 0;
+	int id = 0, ret;
 
 	/*
 	 * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
@@ -10640,6 +10642,21 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 			group = atoi(token + 6);
 		} else if (os_strncmp(token, "nid=", 4) == 0) {
 			id = atoi(token + 4);
+		} else if (os_strncmp(token, "comeback=", 9) == 0) {
+			comeback_len = os_strlen(token + 9);
+
+			if (!comeback_len || comeback_len % 2)
+				return -1;
+
+			comeback_len /= 2;
+			comeback = os_malloc(comeback_len);
+			if (!comeback)
+				return -1;
+
+			if (hexstr2bin(token + 9, comeback, comeback_len)) {
+				os_free(comeback);
+				return -1;
+			}
 		} else {
 			wpa_printf(MSG_DEBUG,
 				   "CTRL: PASN Invalid parameter: '%s'",
@@ -10650,10 +10667,15 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
 
 	if (!got_bssid || akmp == -1 || cipher == -1 || group == 0xFFFF) {
 		wpa_printf(MSG_DEBUG,"CTRL: PASN missing parameter");
+		os_free(comeback);
 		return -1;
 	}
 
-	return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id);
+	ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id,
+				   comeback, comeback_len);
+
+	os_free(comeback);
+	return ret;
 }
 
 
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index e6adf73f3e..1df8cfad24 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -33,6 +33,7 @@ struct wpa_pasn_auth_work {
 	int cipher;
 	u16 group;
 	int network_id;
+	struct wpabuf *comeback;
 };
 
 
@@ -56,8 +57,30 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
 
 
 static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
-				  int akmp, int cipher, u8 status)
+				  int akmp, int cipher, u8 status,
+				  struct wpabuf *comeback,
+				  u16 comeback_after)
 {
+	if (comeback) {
+		size_t comeback_len = wpabuf_len(comeback);
+		char *comeback_txt = os_malloc(comeback_len * 2 + 1);
+
+		if (comeback_txt) {
+			wpa_snprintf_hex(comeback_txt, comeback_len * 2 + 1,
+					 wpabuf_head(comeback), comeback_len);
+
+			wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+				" akmp=%s, status=%u comeback_after=%u"
+				" comeback=%s",
+				MAC2STR(bssid),
+				wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+				status, comeback_after, comeback_txt);
+
+			os_free(comeback_txt);
+			return;
+		}
+	}
+
 	wpa_msg(wpa_s, MSG_INFO,
 		PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
 		MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
@@ -612,7 +635,8 @@ static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
 }
 
 
-static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
+static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
+					      struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
@@ -680,7 +704,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s)
 		wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
 
 	wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
-				  pubkey, true, NULL, -1);
+				  pubkey, true, comeback, -1);
 
 	if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
 		goto fail;
@@ -828,6 +852,10 @@ static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
 	wpabuf_free(pasn->beacon_rsne_rsnxe);
 	pasn->beacon_rsne_rsnxe = NULL;
 
+	wpabuf_free(pasn->comeback);
+	pasn->comeback = NULL;
+	pasn->comeback_after = 0;
+
 #ifdef CONFIG_SAE
 	sae_clear_data(&pasn->sae);
 #endif /* CONFIG_SAE */
@@ -946,7 +974,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   int akmp, int cipher, u16 group, int freq,
 			   const u8 *beacon_rsne, u8 beacon_rsne_len,
 			   const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
-			   int network_id)
+			   int network_id, struct wpabuf *comeback)
 {
 	struct wpas_pasn *pasn = &wpa_s->pasn;
 	struct wpa_ssid *ssid = NULL;
@@ -1023,7 +1051,7 @@ static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 		   MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
 		   pasn->group);
 
-	frame = wpas_pasn_build_auth_1(wpa_s);
+	frame = wpas_pasn_build_auth_1(wpa_s, comeback);
 	if (!frame) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
 		goto fail;
@@ -1105,6 +1133,8 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 					     wpa_s, NULL);
 			wpa_s->pasn_auth_work = NULL;
 		}
+
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return;
 	}
@@ -1132,16 +1162,22 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
 	ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher,
 			      awork->group, bss->freq, rsne, *(rsne + 1) + 2,
 			      rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
-			      awork->network_id);
+			      awork->network_id, awork->comeback);
 	if (ret) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Failed to start PASN authentication");
 		goto fail;
 	}
 
+	/* comeback token is no longer needed at this stage */
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
+
 	wpa_s->pasn_auth_work = work;
 	return;
 fail:
+	wpabuf_free(awork->comeback);
+	awork->comeback = NULL;
 	os_free(awork);
 	work->ctx = NULL;
 	radio_work_done(work);
@@ -1149,7 +1185,8 @@ fail:
 
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
-			 int akmp, int cipher, u16 group, int network_id)
+			 int akmp, int cipher, u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len)
 {
 	struct wpa_pasn_auth_work *awork;
 	struct wpa_bss *bss;
@@ -1195,8 +1232,19 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid,
 	awork->group = group;
 	awork->network_id = network_id;
 
+	if (comeback && comeback_len) {
+		awork->comeback = wpabuf_alloc(comeback_len);
+		if (!awork->comeback) {
+			os_free(awork);
+			return -1;
+		}
+
+		wpabuf_put_data(awork->comeback, comeback, comeback_len);
+	}
+
 	if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
 			   wpas_pasn_auth_start_cb, awork) < 0) {
+		wpabuf_free(awork->comeback);
 		os_free(awork);
 		return -1;
 	}
@@ -1216,7 +1264,8 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
 	wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
 
 	wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
-			      pasn->status);
+			      pasn->status, pasn->comeback,
+			      pasn->comeback_after);
 
 	wpas_pasn_reset(wpa_s);
 }
@@ -1315,10 +1364,44 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
 		goto fail;
 	}
 
-	/* TODO: handle comeback flow */
 	if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
 		wpa_printf(MSG_DEBUG,
 			   "PASN: Authentication temporarily rejected");
+
+		if (pasn_params.comeback && pasn_params.comeback_len) {
+			wpa_printf(MSG_DEBUG,
+				   "PASN: Comeback token available. After=%u",
+				   pasn_params.after);
+
+			if (!pasn_params.after) {
+				int akmp = pasn->akmp;
+				int cipher = pasn->cipher;
+				u16 group = pasn->group;
+				u8 bssid[ETH_ALEN];
+				int network_id =
+					pasn->ssid ? pasn->ssid->id : 0;
+
+				wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
+				os_memcpy(bssid, pasn->bssid, ETH_ALEN);
+				wpas_pasn_reset(wpa_s);
+
+				return wpas_pasn_auth_start(wpa_s, bssid, akmp,
+							    cipher, group,
+							    network_id,
+							    pasn_params.comeback,
+							    pasn_params.comeback_len);
+			}
+
+			pasn->comeback = wpabuf_alloc(pasn_params.comeback_len);
+			if (pasn->comeback) {
+				wpabuf_put_data(pasn->comeback,
+						pasn_params.comeback,
+						pasn_params.comeback_len);
+				pasn->comeback_after = pasn_params.after;
+			}
+		}
+
+		pasn->status = status;
 		goto fail;
 	}
 
@@ -1456,7 +1539,11 @@ fail:
 	 * the frame and terminate the authentication exchange. However, better
 	 * reply to the AP with an error status.
 	 */
-	pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (status == WLAN_STATUS_SUCCESS)
+		pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	else
+		pasn->status = status;
+
 	wpas_pasn_auth_stop(wpa_s);
 	return -1;
 }
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7ed8c0ee4d..8813ddb710 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -554,6 +554,9 @@ struct wpas_pasn {
 	struct wpa_ptk ptk;
 	struct crypto_ecdh *ecdh;
 
+	struct wpabuf *comeback;
+	u16 comeback_after;
+
 #ifdef CONFIG_SAE
 	struct sae_data sae;
 #endif /* CONFIG_SAE */
@@ -1730,7 +1733,8 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
 
 int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
 			 const u8 *bssid, int akmp, int cipher,
-			 u16 group, int network_id);
+			 u16 group, int network_id,
+			 const u8 *comeback, size_t comeback_len);
 void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s);
 int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
 			     const u8 *data, size_t data_len, u8 acked);
-- 
2.17.1



From ilan.peer at intel.com  Sun Mar 21 11:55:08 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Sun, 21 Mar 2021 13:55:08 +0200
Subject: [PATCH v2 1/3] AP: Add support for PASN comeback flow
Message-ID: <20210321115510.31582-1-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 hostapd/config_file.c |  2 +
 hostapd/hostapd.conf  |  7 ++++
 src/ap/ap_config.c    |  5 +++
 src/ap/ap_config.h    |  6 +++
 src/ap/ieee802_11.c   | 88 +++++++++++++++++++++++++++++++++++++++----
 5 files changed, 101 insertions(+), 7 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index fd9bc0e9fc..d73a737821 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "pasn_comeback_after") == 0) {
+		bss->pasn_comeback_after = atoi(pos);
 #endif /* CONFIG_PASN */
 	} else {
 		wpa_printf(MSG_ERROR,
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index d19db5a154..bb532763b5 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2051,6 +2051,13 @@ own_ip_addr=127.0.0.1
 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
 #pasn_groups=19 20 21
 
+# PASN comeback after.
+# In case the AP is temporally unable to handle a PASN authentication exchange,
+# this value would indicate to the peer after how many TUs it can try comeback
+# and try the PASN exchange again.
+# (default: 10 TUs)
+# pasn_comeback_after=10
+
 ##### IEEE 802.11r configuration ##############################################
 
 # Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 452386b7e5..7b6249bbe5 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
 #ifdef CONFIG_TESTING_OPTIONS
 	bss->sae_commit_status = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_PASN
+	/* comeback after 10 TUs */
+	bss->pasn_comeback_after = 10;
+#endif /* CONFIG_PASN */
 }
 
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8aeb03107a..26bdaf1317 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -880,6 +880,12 @@ struct hostapd_bss_config {
 #endif /* CONFIG_TESTING_OPTIONS */
 
 	int *pasn_groups;
+
+	/*
+	 * The time in TUs after which the non-AP STA is requested to retry the
+	 * PASN authentication
+	 */
+	u16 pasn_comeback_after;
 #endif /* CONFIG_PASN */
 
 	unsigned int unsol_bcast_probe_resp_interval;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 72d102f44e..e31e4710da 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -702,13 +702,15 @@ static int use_anti_clogging(struct hostapd_data *hapd)
 
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
 #ifdef CONFIG_SAE
-		if (!sta->sae)
-			continue;
-		if (sta->sae->state != SAE_COMMITTED &&
-		    sta->sae->state != SAE_CONFIRMED)
-			continue;
-		open++;
+		if (sta->sae &&
+		    (sta->sae->state == SAE_COMMITTED ||
+		     sta->sae->state == SAE_CONFIRMED))
+			open++;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_PASN
+		if (sta->pasn && sta->pasn->ecdh)
+			open++;
+#endif /* CONFIG_PASN */
 		if (open >= hapd->conf->anti_clogging_threshold)
 			return 1;
 	}
@@ -806,7 +808,8 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+	if (group)
+		wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
 
 	if (h2e) {
 		/* Encapsulate Anti-clogging Token field in a container IE */
@@ -2891,6 +2894,57 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+static void handle_auth_pasn_comeback(struct hostapd_data *hapd,
+				      struct sta_info *sta, u16 group)
+{
+	struct wpabuf *buf, *comeback;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: Building comeback frame 2. Comeback after=%u",
+		   hapd->conf->pasn_comeback_after);
+
+	buf = wpabuf_alloc(1500);
+	if (!buf)
+		return;
+
+	wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+				   sta->addr, 2,
+				   WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY);
+
+	/*
+	 * Do not include the group as part of the token since it is not going
+	 * to be used
+	 */
+	comeback = auth_build_token_req(hapd, 0, sta->addr, 0);
+	if (!comeback) {
+		wpa_printf(MSG_DEBUG,
+			   "PASN: Failed sending auth with comeback");
+
+		wpabuf_free(buf);
+		return;
+	}
+
+	wpa_pasn_add_parameter_ie(buf, group,
+				  WPA_PASN_WRAPPED_DATA_NO,
+				  NULL, 0, comeback,
+				  hapd->conf->pasn_comeback_after);
+
+	wpabuf_free(comeback);
+	comeback = NULL;
+
+	wpa_printf(MSG_DEBUG,
+		   "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr));
+
+	ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+				    NULL, 0, 0);
+	if (ret)
+		wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
+
+	wpabuf_free(buf);
+}
+
+
 static int handle_auth_pasn_resp(struct hostapd_data *hapd,
 				 struct sta_info *sta,
 				 struct rsn_pmksa_cache_entry *pmksa,
@@ -3133,6 +3187,26 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
 		goto send_resp;
 	}
 
+	if (pasn_params.comeback) {
+		wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token");
+
+		ret = check_comeback_token(hapd, sta->addr,
+					   pasn_params.comeback,
+					   pasn_params.comeback_len);
+
+		if (ret) {
+			wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto send_resp;
+		}
+	} else if (use_anti_clogging(hapd)) {
+		wpa_printf(MSG_DEBUG, "PASN: Response with comeback");
+
+		handle_auth_pasn_comeback(hapd, sta, pasn_params.group);
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
 	sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
 	if (!sta->pasn->ecdh) {
 		wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
-- 
2.17.1



From ilan.peer at intel.com  Sun Mar 21 11:55:10 2021
From: ilan.peer at intel.com (Ilan Peer)
Date: Sun, 21 Mar 2021 13:55:10 +0200
Subject: [PATCH v2 3/3] tests: Add PASN tests with comeback flow
In-Reply-To: <20210321115510.31582-1-ilan.peer@intel.com>
References: <20210321115510.31582-1-ilan.peer@intel.com>
Message-ID: <20210321115510.31582-3-ilan.peer@intel.com>

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 tests/hwsim/test_pasn.py | 120 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
index f2c7b3b221..578b445d98 100644
--- a/tests/hwsim/test_pasn.py
+++ b/tests/hwsim/test_pasn.py
@@ -13,6 +13,7 @@ logger = logging.getLogger()
 import socket
 import struct
 import subprocess
+import re
 
 import hwsim_utils
 import hostapd
@@ -681,3 +682,122 @@ def test_pasn_ap_mic_error(dev, apdev):
 
     check_pasn_akmp_cipher(dev[0], hapd1, "PASN", "CCMP", status=1)
     check_pasn_akmp_cipher(dev[0], hapd0, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback(dev, apdev, params):
+    """ PASN authentication with comeback flow """
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['sae_anti_clogging_threshold'] = '0'
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    dev[0].scan(type="ONLY", freq=2412)
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19" % (hapd.own_addr())
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=30 comeback_after=" not in ev:
+        raise Exception("PASN: unexpected status")
+
+    comeback = re.split("comeback=", ev)[1]
+
+    cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19 comeback=%s" % \
+            (hapd.own_addr(), comeback)
+
+    resp = dev[0].request(cmd)
+    if "OK" not in resp:
+        raise Exception("Failed to start PASN authentication")
+
+    ev = dev[0].wait_event(["PASN-AUTH-STATUS"], 3)
+    if not ev:
+        raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+    if hapd.own_addr() + " akmp=PASN, status=0" not in ev:
+        raise Exception("PASN: unexpected status with comeback token")
+
+    check_pasn_ptk(dev[0], hapd, "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0(dev, apdev, params):
+    """ PASN authentication with comeback flow with comeback after set to 0"""
+    check_pasn_capab(dev[0])
+
+    params = pasn_ap_params("PASN", "CCMP", "19")
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+ at remote_compatible
+def test_pasn_comeback_after_0_sae(dev, apdev):
+    """  PASN authentication with SAE, with comeback flow where comeback after is set to 0  """
+    check_pasn_capab(dev[0])
+    check_sae_capab(dev[0])
+
+    params = hostapd.wpa2_params(ssid="test-pasn-sae",
+                                 passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE PASN'
+    params['anti_clogging_threshold'] = '0'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
+                   only_add_network=True)
+
+    # first test with a valid PSK
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
+
+    # And now with PMKSA caching
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
+
+    # And now with a wrong passphrase
+    if "FAIL" in dev[0].request("PMKSA_FLUSH"):
+        raise Exception("PMKSA_FLUSH failed")
+
+    dev[0].set_network_quoted(0, "psk", "12345678787")
+    check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
+
+ at remote_compatible
+def test_pasn_comeback_multi(dev, apdev):
+    """  PASN authentication with SAE, with multiple stations with comeback"""
+    check_pasn_capab(dev[0])
+    check_sae_capab(dev[0])
+
+    params = hostapd.wpa2_params(ssid="test-pasn-sae",
+                                 passphrase="12345678")
+    params['wpa_key_mgmt'] = 'SAE PASN'
+    params['anti_clogging_threshold'] = '1'
+    params['pasn_comeback_after'] = '0'
+    hapd = start_pasn_ap(apdev[0], params)
+
+    id = {}
+    for i in range(0, 2):
+        dev[i].flush_scan_cache()
+        dev[i].scan(type="ONLY", freq=2412)
+        id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
+                               scan_freq="2412", only_add_network=True)
+
+    for i in range(0, 2):
+        cmd = "PASN_START bssid=%s akmp=PASN cipher=CCMP group=19, nid=%s" % (hapd.own_addr(), id[i])
+        resp = dev[i].request(cmd)
+
+        if "OK" not in resp:
+            raise Exception("Failed to start pasn authentication")
+
+    for i in range(0, 2):
+        ev = dev[i].wait_event(["PASN-AUTH-STATUS"], 3)
+        if not ev:
+            raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+        if hapd.own_addr() + " akmp=PASN, status=0" not in ev:
+            raise Exception("PASN: unexpected status")
+
+        check_pasn_ptk(dev[i], hapd, "CCMP")
-- 
2.17.1



From j at w1.fi  Sun Mar 21 23:02:45 2021
From: j at w1.fi (Jouni Malinen)
Date: Mon, 22 Mar 2021 01:02:45 +0200
Subject: [PATCH v2 1/3] AP: Add support for PASN comeback flow
In-Reply-To: <20210321115510.31582-1-ilan.peer@intel.com>
References: <20210321115510.31582-1-ilan.peer@intel.com>
Message-ID: <20210321230245.GA1365008@w1.fi>

Thanks, all three patches applied with some cleanup.

-- 
Jouni Malinen                                            PGP id EFC895FA


From ilan.peer at intel.com  Mon Mar 22 07:03:45 2021
From: ilan.peer at intel.com (Peer, Ilan)
Date: Mon, 22 Mar 2021 07:03:45 +0000
Subject: [PATCH v2 1/3] AP: Add support for PASN comeback flow
In-Reply-To: <20210321230245.GA1365008@w1.fi>
References: <20210321115510.31582-1-ilan.peer@intel.com>
 <20210321230245.GA1365008@w1.fi>
Message-ID: <BN7PR11MB2610CA19214244EE5734B719E9659@BN7PR11MB2610.namprd11.prod.outlook.com>

> -----Original Message-----
> From: Jouni Malinen <j at w1.fi>
> Sent: Monday, March 22, 2021 01:03
> To: Peer, Ilan <ilan.peer at intel.com>
> Cc: hostap at lists.infradead.org
> Subject: Re: [PATCH v2 1/3] AP: Add support for PASN comeback flow
> 
> Thanks, all three patches applied with some cleanup.
> 

Thanks!

Ilan.


From isaacchiou at google.com  Tue Mar 23 09:05:15 2021
From: isaacchiou at google.com (Isaac Chiou)
Date: Tue, 23 Mar 2021 17:05:15 +0800
Subject: [PATCH] Wifi: Support NVT-ASCII in passphrase
Message-ID: <CAOJGChDzNh7EbWM9kw-0zCzD9rT0Sf9XT5ERkYaPfdRGZ7RK8g@mail.gmail.com>

Hi,

In this patch, we create a new function has_non_nvt_ascii_char which
allows the following control characters to be a part of a PSK
passphrase.

7 (Bell)
8 (Backspace)
9 (Horizontal tab)
10 (Line feed)
11 (Vertical tab)
12 (Form feed)
13 (Carriage return)

Best regards,
Isaac
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Wifi-Support-NVT-ASCII-in-passphrase.patch
Type: text/x-patch
Size: 1677 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20210323/318a3112/attachment.bin>

From michael.yartys at protonmail.com  Tue Mar 23 16:42:13 2021
From: michael.yartys at protonmail.com (Michael Yartys)
Date: Tue, 23 Mar 2021 16:42:13 +0000
Subject: Unable to enable H2E in wpa_supplicant
Message-ID: <MdUXVXxjoV9TdndHzPyA6sPI7ZuyGEGA7XiNVFsYhEzerCxwVJXGjoPj7mPVgxNnQ0wplzmnHwiNPlWqF8pxliIM2AhoTY_Mv3jooB6YS88=@protonmail.com>

Hi, all

I'm testing the hash-to-element implementation on my OpenWrt router, and I need to set sae_pwe=2 in my wpa_supplicant config to be able to connect to it. The problem is that I'm getting the following error:

Line 9: unknown global field 'sae_pwe=2'.
Line 9: Invalid configuration line 'sae_pwe=2'.

My config is as follows (I saw the previous emails on the list about the parameter being a global parameter, and I have made sure it's outside the network block):

ctrl_interface=/var/run/wpa_supplicant
sae_pwe=2

network={
	ssid="OpenWrt_test"
	key_mgmt=SAE
	sae_password="redacted"
	ieee80211w=2
}

I'm running wpa_supplicant on Fedora 33 and the version is listed as 1:2.9-8.fc33.

Michael


From j at w1.fi  Tue Mar 23 17:25:21 2021
From: j at w1.fi (Jouni Malinen)
Date: Tue, 23 Mar 2021 19:25:21 +0200
Subject: Unable to enable H2E in wpa_supplicant
In-Reply-To: <MdUXVXxjoV9TdndHzPyA6sPI7ZuyGEGA7XiNVFsYhEzerCxwVJXGjoPj7mPVgxNnQ0wplzmnHwiNPlWqF8pxliIM2AhoTY_Mv3jooB6YS88=@protonmail.com>
References: <MdUXVXxjoV9TdndHzPyA6sPI7ZuyGEGA7XiNVFsYhEzerCxwVJXGjoPj7mPVgxNnQ0wplzmnHwiNPlWqF8pxliIM2AhoTY_Mv3jooB6YS88=@protonmail.com>
Message-ID: <20210323172521.GA13895@w1.fi>

On Tue, Mar 23, 2021 at 04:42:13PM +0000, Michael Yartys wrote:
> I'm testing the hash-to-element implementation on my OpenWrt router, and I need to set sae_pwe=2 in my wpa_supplicant config to be able to connect to it. The problem is that I'm getting the following error:
> 
> Line 9: unknown global field 'sae_pwe=2'.
> Line 9: Invalid configuration line 'sae_pwe=2'.
> 
> My config is as follows (I saw the previous emails on the list about the parameter being a global parameter, and I have made sure it's outside the network block):
> 
> ctrl_interface=/var/run/wpa_supplicant
> sae_pwe=2

This is correct.

> I'm running wpa_supplicant on Fedora 33 and the version is listed as 1:2.9-8.fc33.

But SAE H2E support was added after the 2.9 release, so you will need to
use a newer snapshot for this functionality.

-- 
Jouni Malinen                                            PGP id EFC895FA


From j at w1.fi  Tue Mar 23 17:30:13 2021
From: j at w1.fi (Jouni Malinen)
Date: Tue, 23 Mar 2021 19:30:13 +0200
Subject: [PATCH] Wifi: Support NVT-ASCII in passphrase
In-Reply-To: <CAOJGChDzNh7EbWM9kw-0zCzD9rT0Sf9XT5ERkYaPfdRGZ7RK8g@mail.gmail.com>
References: <CAOJGChDzNh7EbWM9kw-0zCzD9rT0Sf9XT5ERkYaPfdRGZ7RK8g@mail.gmail.com>
Message-ID: <20210323173013.GB13895@w1.fi>

On Tue, Mar 23, 2021 at 05:05:15PM +0800, Isaac Chiou wrote:
> In this patch, we create a new function has_non_nvt_ascii_char which
> allows the following control characters to be a part of a PSK
> passphrase.
> 
> 7 (Bell)
> 8 (Backspace)
> 9 (Horizontal tab)
> 10 (Line feed)
> 11 (Vertical tab)
> 12 (Form feed)
> 13 (Carriage return)

This patch does not really change anything in passphrase validation,
i.e., it is only adding a new unused validation function. That said, why
would this direction be needed? What kind of use case needs such control
characters in a passphrase? None of those listed values are valid
characters in a passphrase as far as the standard is concerned.

IEEE Std 802.11-2020, Annex J.4.1: "Each character in the pass-phrase
has an encoding in the range 32 to 126 (decimal)."

-- 
Jouni Malinen                                            PGP id EFC895FA


From michael.yartys at protonmail.com  Tue Mar 23 17:32:37 2021
From: michael.yartys at protonmail.com (Michael Yartys)
Date: Tue, 23 Mar 2021 17:32:37 +0000
Subject: Unable to enable H2E in wpa_supplicant
In-Reply-To: <20210323172521.GA13895@w1.fi>
References: <MdUXVXxjoV9TdndHzPyA6sPI7ZuyGEGA7XiNVFsYhEzerCxwVJXGjoPj7mPVgxNnQ0wplzmnHwiNPlWqF8pxliIM2AhoTY_Mv3jooB6YS88=@protonmail.com>
 <20210323172521.GA13895@w1.fi>
Message-ID: <GnwFZWIIowngTOk1I7ZdU6NRMk5AuE1WYwa2PAW9fEOhjZFq5t2iwI1gyU8gH3vy7SAHNmZmHZMN71D07vvXRdjLU-S3Lx4SGCkevLpDxfc=@protonmail.com>



??????? Original Message ???????

On Tuesday, March 23rd, 2021 at 18:25, Jouni Malinen <j at w1.fi> wrote:

> On Tue, Mar 23, 2021 at 04:42:13PM +0000, Michael Yartys wrote:
>
> > I'm testing the hash-to-element implementation on my OpenWrt router, and I need to set sae_pwe=2 in my wpa_supplicant config to be able to connect to it. The problem is that I'm getting the following error:
> >
> > Line 9: unknown global field 'sae_pwe=2'.
> >
> > Line 9: Invalid configuration line 'sae_pwe=2'.
> >
> > My config is as follows (I saw the previous emails on the list about the parameter being a global parameter, and I have made sure it's outside the network block):
> >
> > ctrl_interface=/var/run/wpa_supplicant
> >
> > sae_pwe=2
>
> This is correct.
>
> > I'm running wpa_supplicant on Fedora 33 and the version is listed as 1:2.9-8.fc33.
>
> But SAE H2E support was added after the 2.9 release, so you will need to
>
> use a newer snapshot for this functionality.

Yeah, I was just about to reply that I made a stupid mistake in not checking that my version actually supports those parameters. But thanks for getting back to me!

Just out of curiosity, are you planing to make a new stable release in the near future?

>
> -------------------------------------------------------------------------------------------------------------------------
>
> Jouni Malinen PGP id EFC895FA


From matus.vlcek at gmail.com  Fri Mar 26 08:23:02 2021
From: matus.vlcek at gmail.com (=?UTF-8?B?TWF0w7rFoSBWbMSNZWs=?=)
Date: Fri, 26 Mar 2021 09:23:02 +0100
Subject: Hostapd in monitor mode
Message-ID: <CACkr=P3_6yrS2rrebX1Xmbprs6TYZm07FQhshSFVi76ti5BVjw@mail.gmail.com>

Hello everyone,

I'm trying to avoid the problem of maximum virtual interfaces for APs
on my AR9271 with ath9k_htc driver and firmware. I would like to
create just one monitor interface, where I get all the traffic and
then make my own management frames logic. Filter frames according to
multiple destination addresses in frame header(simulation of multiple
APs) and then send my own management frames like association response,
authentication, beacons...

Do you know if it's possible to change hostapd to use a monitor
interface so I get all the frames from air to hostapd instead of just
frames destined to my real interface?

Thanks for the answer


From nick at portercomputing.co.uk  Fri Mar 26 10:17:00 2021
From: nick at portercomputing.co.uk (Nick Porter)
Date: Fri, 26 Mar 2021 10:17:00 +0000
Subject: [PATCH] Add a --conf option to eapol_test.py
Message-ID: <20210326101700.28866-1-nick@portercomputing.co.uk>

The --conf option specifies a file containing a list of options
to configure the network used for running the test which will be
used in place of the defaults built into the script.

Signed-off-by: Nick Porter <nick at portercomputing.co.uk>
---
 wpa_supplicant/eapol_test.py | 37 ++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/wpa_supplicant/eapol_test.py b/wpa_supplicant/eapol_test.py
index 734428d29..635378e04 100755
--- a/wpa_supplicant/eapol_test.py
+++ b/wpa_supplicant/eapol_test.py
@@ -72,7 +72,7 @@ class eapol_test:
                 break
         return None
 
-def run(ifname, count, no_fast_reauth, res):
+def run(ifname, count, no_fast_reauth, res, conf):
     et = eapol_test(ifname)
 
     et.request("AP_SCAN 0")
@@ -81,14 +81,20 @@ def run(ifname, count, no_fast_reauth, res):
     else:
         et.request("SET fast_reauth 1")
     id = et.add_network()
-    et.set_network(id, "key_mgmt", "IEEE8021X")
-    et.set_network(id, "eapol_flags", "0")
-    et.set_network(id, "eap", "TLS")
-    et.set_network_quoted(id, "identity", "user")
-    et.set_network_quoted(id, "ca_cert", 'ca.pem')
-    et.set_network_quoted(id, "client_cert", 'client.pem')
-    et.set_network_quoted(id, "private_key", 'client.key')
-    et.set_network_quoted(id, "private_key_passwd", 'whatever')
+
+    if len(conf):
+        for item in conf:
+            et.set_network(id, item, conf[item])
+    else:
+        et.set_network(id, "key_mgmt", "IEEE8021X")
+        et.set_network(id, "eapol_flags", "0")
+        et.set_network(id, "eap", "TLS")
+        et.set_network_quoted(id, "identity", "user")
+        et.set_network_quoted(id, "ca_cert", 'ca.pem')
+        et.set_network_quoted(id, "client_cert", 'client.pem')
+        et.set_network_quoted(id, "private_key", 'client.key')
+        et.set_network_quoted(id, "private_key_passwd", 'whatever')
+
     et.set_network(id, "disabled", "0")
 
     fail = False
@@ -114,6 +120,7 @@ def main():
     parser.add_argument('--no-fast-reauth', action='store_true',
                         dest='no_fast_reauth',
                         help='disable TLS session resumption')
+    parser.add_argument('--conf', help='file of network conf items')
     args = parser.parse_args()
 
     num = int(args.num)
@@ -122,12 +129,22 @@ def main():
         global wpas_ctrl
         wpas_ctrl = args.ctrl
 
+    conf = {}
+    if args.conf:
+        f = open(args.conf, "r")
+        for line in f:
+            confitem = line.split("=")
+            if len(confitem) == 2:
+                conf[confitem[0].strip()] = confitem[1].strip()
+        f.close()
+
     t = {}
     res = {}
     for i in range(num):
         res[i] = Queue.Queue()
         t[i] = threading.Thread(target=run, args=(str(i), iter,
-                                                  args.no_fast_reauth, res[i]))
+                                                  args.no_fast_reauth, res[i]),
+                                                  conf)
     for i in range(num):
         t[i].start()
     for i in range(num):
-- 
2.25.1



From kazikcz at gmail.com  Mon Mar 29 15:03:11 2021
From: kazikcz at gmail.com (Michal Kazior)
Date: Mon, 29 Mar 2021 14:03:11 +0000
Subject: [PATCH] DPP: expose enrollee pubkey hash for identification
Message-ID: <20210329140311.897-1-kazikcz@gmail.com>

From: Michal Kazior <michal at plume.com>

Just like with WPA-PSK and keyids it may be
desired to identify connecting clients to provide
additional network filtering.

This does:

 - adds a new control event generated during DPP
   Auth so that the AP side can learn what the
   resulting public key hash is

 - store public key hash in PMKSA from DPP Network
   Intro for later use

 - extend sta mib to print out the stored
   dpp_pkhash from PMKSA if present

 - extend AP_STA_CONNECTED to print out the stored
   dpp_pkhash from PMKSA if present

Signed-off-by: Michal Kazior <michal at plume.com>
---
Open question:

I'm not sure if it's really necessary to salt the
public key hash for this purpose. Chirping does it
because it's exposing public key which can be used
to initiate DPP Auth. Control interface is local
to a system and this is the ephemeral key derived
from DPP Auth itself, so it can't be abused like
the other public key can.

Thoughts?


 src/ap/ctrl_iface_ap.c          |  8 +++++++
 src/ap/dpp_hostapd.c            | 10 ++++++---
 src/ap/pmksa_cache_auth.c       |  1 +
 src/ap/pmksa_cache_auth.h       |  1 +
 src/ap/sta_info.c               | 24 +++++++++++++++++----
 src/ap/sta_info.h               |  2 ++
 src/ap/wpa_auth.c               | 33 ++++++++++++++++++++++++++++
 src/ap/wpa_auth.h               |  4 ++++
 src/common/dpp.c                |  8 +++++--
 src/common/dpp.h                |  2 +-
 src/common/dpp_auth.c           |  5 +++++
 src/common/dpp_crypto.c         | 38 +++++++++++++++++++++++++++++++++
 src/common/dpp_i.h              |  1 +
 src/common/wpa_ctrl.h           |  1 +
 wpa_supplicant/dpp_supplicant.c |  2 +-
 15 files changed, 129 insertions(+), 11 deletions(-)

diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 28e40ba9c..e663a60cb 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -208,6 +208,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 {
 	int len, res, ret, i;
 	const char *keyid;
+	const char *dpp_pkhash;
 
 	if (!sta)
 		return 0;
@@ -377,6 +378,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 			len += ret;
 	}
 
+	dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
+	if (dpp_pkhash) {
+		ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=%s\n", dpp_pkhash);
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
 	return len;
 }
 
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index aaeb94c2f..955df86ea 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1588,6 +1588,8 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 	os_time_t expire;
 	int expiration;
 	enum dpp_status_error res;
+	EVP_PKEY *peer_key = NULL;
+	char hex[SHA256_MAC_LEN*2 + 1];
 
 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
 		   MAC2STR(src));
@@ -1632,7 +1634,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 			     wpabuf_len(hapd->conf->dpp_netaccesskey),
 			     wpabuf_head(hapd->conf->dpp_csign),
 			     wpabuf_len(hapd->conf->dpp_csign),
-			     connector, connector_len, &expire);
+			     connector, connector_len, &expire, &peer_key);
 	if (res == 255) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Network Introduction protocol resulted in internal failure (peer "
@@ -1655,9 +1657,11 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 	else
 		expiration = 0;
 
-	if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+	dpp_get_pubkey_hash(peer_key, hex, sizeof(hex), "hostap");
+
+	if (wpa_auth_pmksa_add3(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
 				intro.pmkid, expiration,
-				WPA_KEY_MGMT_DPP) < 0) {
+				WPA_KEY_MGMT_DPP, hex) < 0) {
 		wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
 		return;
 	}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index fe5f81717..29d2b500a 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 {
 	os_free(entry->vlan_desc);
 	os_free(entry->identity);
+	os_free(entry->dpp_pkhash);
 	wpabuf_free(entry->cui);
 #ifndef CONFIG_NO_RADIUS
 	radius_free_class(&entry->radius_class);
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 2ef217435..c80c0e720 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -23,6 +23,7 @@ struct rsn_pmksa_cache_entry {
 	int akmp; /* WPA_KEY_MGMT_* */
 	u8 spa[ETH_ALEN];
 
+	u8 *dpp_pkhash;
 	u8 *identity;
 	size_t identity_len;
 	struct wpabuf *cui;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index ccd1ed931..9a80efd4d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1260,6 +1260,13 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
 }
 
 
+const char * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	return wpa_auth_get_dpp_pkhash(sta->wpa_sm);
+}
+
+
 void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 			   int authorized)
 {
@@ -1298,10 +1305,13 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 					sta->addr, authorized, dev_addr);
 
 	if (authorized) {
+		const char *dpp_pkhash;
 		const char *keyid;
+		char dpp_pkhash_buf[100];
 		char keyid_buf[100];
 		char ip_addr[100];
 
+		dpp_pkhash_buf[0] = '\0';
 		keyid_buf[0] = '\0';
 		ip_addr[0] = '\0';
 #ifdef CONFIG_P2P
@@ -1319,14 +1329,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 				    " keyid=%s", keyid);
 		}
 
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
-			buf, ip_addr, keyid_buf);
+		dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
+		if (dpp_pkhash) {
+			os_snprintf(dpp_pkhash_buf, sizeof(dpp_pkhash_buf),
+				    " dpp_pkhash=%s", dpp_pkhash);
+		}
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
+			buf, ip_addr, keyid_buf, dpp_pkhash_buf);
 
 		if (hapd->msg_ctx_parent &&
 		    hapd->msg_ctx_parent != hapd->msg_ctx)
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
-					  AP_STA_CONNECTED "%s%s%s",
-					  buf, ip_addr, keyid_buf);
+					  AP_STA_CONNECTED "%s%s%s%s",
+					  buf, ip_addr, keyid_buf, dpp_pkhash_buf);
 	} else {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index efa48e7e3..7f9ef3cc4 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -384,6 +384,8 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
 const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
 				  struct sta_info *sta);
+const char * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
+				       struct sta_info *sta);
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *addr, u16 reason);
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index ef0595c57..d5b446abb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -4683,6 +4683,16 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
 }
 
 
+const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm)
+{
+	if (!sm)
+		return NULL;
+	if (!sm->pmksa)
+		return NULL;
+	return sm->pmksa->dpp_pkhash;
+}
+
+
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
 {
 	if (!sm)
@@ -4844,6 +4854,29 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 }
 
 
+int wpa_auth_pmksa_add3(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+			int session_timeout, int akmp, const u8 *dpp_pkhash)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	if (wpa_auth->conf.disable_pmksa_caching)
+		return -1;
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
+	entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+				 NULL, 0, wpa_auth->addr, addr, session_timeout,
+				 NULL, akmp);
+	if (!entry)
+		return -1;
+
+	if (dpp_pkhash)
+		entry->dpp_pkhash = os_strdup(dpp_pkhash);
+
+	return 0;
+}
+
+
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index eaa2cafc8..b9fd005f7 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -401,6 +401,7 @@ void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
 int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
 int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
 const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
+const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm);
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
 int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
@@ -425,6 +426,9 @@ void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp);
+int wpa_auth_pmksa_add3(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+			int session_timeout, int akmp, const u8 *dpp_pkhash);
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr);
 int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 3c8c7682d..e32580212 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -3665,7 +3665,8 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 	       const u8 *net_access_key, size_t net_access_key_len,
 	       const u8 *csign_key, size_t csign_key_len,
 	       const u8 *peer_connector, size_t peer_connector_len,
-	       os_time_t *expiry)
+	       os_time_t *expiry,
+	       EVP_PKEY **peer_key_out)
 {
 	struct json_token *root = NULL, *netkey, *token;
 	struct json_token *own_root = NULL;
@@ -3778,7 +3779,10 @@ fail:
 	os_free(info.payload);
 	EVP_PKEY_free(own_key);
 	wpabuf_free(own_key_pub);
-	EVP_PKEY_free(peer_key);
+	if (!peer_key_out)
+		EVP_PKEY_free(peer_key);
+	else
+		*peer_key_out = peer_key;
 	json_free(root);
 	json_free(own_root);
 	return ret;
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 65ee905a7..98aa8cbf9 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -594,7 +594,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 	       const u8 *net_access_key, size_t net_access_key_len,
 	       const u8 *csign_key, size_t csign_key_len,
 	       const u8 *peer_connector, size_t peer_connector_len,
-	       os_time_t *expiry);
+	       os_time_t *expiry, EVP_PKEY **peer_key_out);
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
 				const char *identifier,
diff --git a/src/common/dpp_auth.c b/src/common/dpp_auth.c
index 0cabd647f..b43bdf04f 100644
--- a/src/common/dpp_auth.c
+++ b/src/common/dpp_auth.c
@@ -1408,6 +1408,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
 	EVP_PKEY *pr;
 	size_t secret_len;
 	const u8 *addr[2];
+	u8 hex[SHA256_MAC_LEN*2 + 1];
 	size_t len[2];
 	u8 *unwrapped = NULL, *unwrapped2 = NULL;
 	size_t unwrapped_len = 0, unwrapped2_len = 0;
@@ -1563,6 +1564,10 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
 	}
 	dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
 
+	os_memset(hex, 0, sizeof(hex));
+	dpp_get_pubkey_hash(pr, hex, sizeof(hex), "hostap");
+	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_PK_HASH "%s", hex);
+
 	if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
 		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
 		goto fail;
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index c75fc7871..1f2c3fc0a 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -520,6 +520,44 @@ EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len)
 }
 
 
+int dpp_get_pubkey_hash(EVP_PKEY *key, u8 *hexstr, size_t len, const char *salt)
+{
+	unsigned char *der = NULL;
+	const u8 *args[2];
+	size_t lens[2];
+	char buf[SHA256_MAC_LEN];
+	EC_KEY *eckey;
+	int der_len;
+	int res = 0;
+
+	os_memset(buf, 0, sizeof(buf));
+
+	eckey = EVP_PKEY_get1_EC_KEY(key);
+	if (!eckey)
+		return -1;
+
+	if (!salt)
+		salt = "";
+
+	der_len = i2d_EC_PUBKEY(eckey, &der);
+	if (der_len > 0) {
+		args[0] = salt;
+		lens[0] = strlen(salt);
+		args[1] = der;
+		lens[1] = der_len;
+
+		if (sha256_vector(2, args, lens, buf) < 0)
+			res = -1;
+
+	}
+	OPENSSL_free(der);
+	EC_KEY_free(eckey);
+
+	wpa_snprintf_hex(hexstr, len, buf, sizeof(buf));
+	return res;
+}
+
+
 EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
 {
 	EVP_PKEY_CTX *kctx = NULL;
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index af12467a5..418cf3fab 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -81,6 +81,7 @@ EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
 				      const u8 *buf_x, const u8 *buf_y,
 				      size_t len);
 EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len);
+int dpp_get_pubkey_hash(EVP_PKEY *key, u8 *hexstr, size_t len, const char *salt);
 int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len);
 int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
 		    const char *label, u8 *out, size_t outlen);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 126a7892c..58a554225 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -173,6 +173,7 @@ extern "C" {
 #define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
 #define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
 #define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
+#define DPP_EVENT_AUTH_PK_HASH "DPP-AUTH-PK-HASH "
 #define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
 #define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
 #define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 2bcf10b4e..70367b95b 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -2437,7 +2437,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
 			     ssid->dpp_netaccesskey_len,
 			     ssid->dpp_csign,
 			     ssid->dpp_csign_len,
-			     connector, connector_len, &expiry);
+			     connector, connector_len, &expiry, NULL);
 	if (res != DPP_STATUS_OK) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Network Introduction protocol resulted in failure");
-- 
2.27.0



From mike at guruce.com  Tue Mar 30 05:04:23 2021
From: mike at guruce.com (Michel Verhagen)
Date: Tue, 30 Mar 2021 17:04:23 +1300
Subject: Starting EAP sequence
In-Reply-To: <f7ad988a-7178-8cd3-36aa-0cdfb6e957f3@guruce.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
 <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
 <f7ad988a-7178-8cd3-36aa-0cdfb6e957f3@guruce.com>
Message-ID: <99cdfa00-251b-9f69-38c3-6d0564576f8e@guruce.com>

We are running into an issue where calling eapol_sm_init results in a 
write to a null pointer in dl_list_add:

    static inline void dl_list_add(struct dl_list *list, struct dl_list
    *item)
    {
     ??? item->next = list->next;
     ??? item->prev = list;
     ??? list->next->prev = item;
     ??? list->next = item;
    }

item->next is null in the above when called from function 
eloop_register_timeout through macro dl_list_for_each in line 273:

     ??? /* Maintain timeouts in order of increasing time */
     ??? dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
     ??? ??? if (os_reltime_before(&timeout->time, &tmp->time)) {
     ??? ??? ??? dl_list_add(tmp->list.prev, &timeout->list);
     ??? ??? ??? return 0;
     ??? ??? }
     ??? }

    #define dl_list_for_each(item, list, type, member) \
     ??? for (item = dl_list_entry((list)->next, type, member); \
     ??? ???? &item->member != (list); \
     ??? ???? item = dl_list_entry(item->member.next, type, member))


So, the code is:

    for (tmp = dl_list_entry((&loop.timeout)->next, struct
    eloop_timeout, list); \
     ??? ???? &tmp->list != (&loop.timeout); \
     ??? ???? tmp = dl_list_entry(tmp->list.next, struct eloop_timeout,
    list))


And eloop.timeout.next is NULL.

We are implementing EAPOL authentication using the hostap eap library 
and eapol state machine code. We only need EAPOL over wired LAN, so no 
WPA or WPS needed. Our initialization looks like this:

     ??????? if (ERROR_SUCCESS != EAPRegisterMethods())
     ??????????? break;

     ??????? os_memset(&_eap_ctx, 0, sizeof(_eap_ctx));

     ??????? _eap_ctx.eap_config.identity = (u8 *)os_strdup("Identity");
     ??????? _eap_ctx.eap_config.identity_len = strlen((const
    char*)_eap_ctx.eap_config.identity);
     ??????? _eap_ctx.eap_config.password = (u8 *)os_strdup("password");
     ??????? _eap_ctx.eap_config.password_len = strlen((const
    char*)_eap_ctx.eap_config.password);
     ??????? _eap_ctx.eap_config.ca_cert = os_strdup("\\Windows\\ca.pem");
     ??????? //_eap_ctx.eap_config.ca_path = os_strdup("\\Windows");
     ??????? _eap_ctx.eap_config.fragment_size = 1398;

     ??????? os_memset(&_eap_cb, 0, sizeof(_eap_cb));
     ??????? _eap_cb.get_config = peer_get_config;
     ??????? _eap_cb.get_bool = (Boolean(__cdecl *)(void *,
    eapol_bool_var))peer_get_bool;
     ??????? _eap_cb.set_bool = (void(__cdecl *)(void *, eapol_bool_var,
    Boolean))peer_set_bool;
     ??????? _eap_cb.get_int = peer_get_int;
     ??????? _eap_cb.set_int = peer_set_int;
     ??????? _eap_cb.get_eapReqData = peer_get_eapReqData;
     ??????? _eap_cb.set_config_blob = peer_set_config_blob;
     ??????? _eap_cb.get_config_blob = peer_get_config_blob;
     ??????? _eap_cb.notify_pending = peer_notify_pending;

     ??????? os_memset(&_eap_conf, 0, sizeof(_eap_conf));
     ??????? _eap_ctx.eap = eap_peer_sm_init(&_eap_ctx, &_eap_cb,
    &_eap_ctx, &_eap_conf);
     ??????? if (_eap_ctx.eap == NULL)
     ??????????? break;

     ??????? /* Enable "port" to allow authentication */
     ??????? _eap_ctx.portEnabled = true;

     ??????? os_memset(&_eapol_ctx, 0, sizeof(_eapol_ctx));
     ??????? _eapol_ctx.ctx = this;????????????????? // This can be
    pointing to any structure we define as context
     ??????? _eapol_ctx.preauth = 0;???????????????? // Not using IEEE
    802.11i/RSN pre-authentication
     ??????? _eapol_ctx.cb = NULL;?????????????????? // Not using IEEE
    802.11i/RSN pre-authentication, so no need for this callback
     ??????? _eapol_ctx.cb_ctx = NULL;?????????????? // Not using IEEE
    802.11i/RSN pre-authentication, so no need for context
     ??????? _eapol_ctx.msg_ctx = this;????????????? // Callback context
    for wpa_msg() calls
     ??????? _eapol_ctx.scard_ctx = NULL;??????????? // Callback context
    for PC/SC scard_*() function calls
     ??????? _eapol_ctx.eapol_send_ctx = this;?????? // Callback context
    for eapol_send() calls
     ??????? _eapol_ctx.eapol_done_cb = eapol_done_cb;
     ??????? _eapol_ctx.eapol_send = eapol_send;
     ??????? _eapol_ctx.set_wep_key = NULL;????????? // Not using WEP
     ??????? _eapol_ctx.set_config_blob = NULL;
     ??????? _eapol_ctx.get_config_blob = NULL;
     ??????? _eapol_ctx.aborted_cached = NULL;

     ??????? _eapol_ctx.opensc_engine_path = NULL;?? // No idea what to
    set here
     ??????? _eapol_ctx.pkcs11_engine_path = NULL;?? // No idea what to
    set here
     ??????? _eapol_ctx.pkcs11_module_path = NULL;?? // No idea what to
    set here
     ??????? _eapol_ctx.openssl_ciphers = NULL;????? // No idea what to
    set here

     ??????? _eapol_ctx.wps = NULL;????????????????? // Not using WPS

     ??????? _eapol_ctx.eap_param_needed = NULL;???? // Not using WEP

     ??????? _eapol_ctx.port_cb = port_cb;
     ??????? _eapol_ctx.cert_cb = cert_cb;
     ??????? _eapol_ctx.cert_in_cb = 1;
     ??????? _eapol_ctx.status_cb = status_cb;
     ??????? _eapol_ctx.eap_error_cb = eap_error_cb;

     ??????? _eapol_ctx.set_anon_id = NULL;????????? // Not sure this is
    needed
     ??????? _eapol_ctx.confirm_auth_cb = NULL;????? // Not sure this is
    needed

     ??????? _peapol_sm = eapol_sm_init(&_eapol_ctx);
     ??????? if (!_peapol_sm)
     ??????????? break;

     ??????? os_memset(&_eapol_conf, 0, sizeof(_eapol_conf));
     ??????? _eapol_conf.accept_802_1x_keys = 0;
     ??????? _eapol_conf.required_keys = 0;????????? //
    EAPOL_REQUIRE_KEY_UNICAST | EAPOL_REQUIRE_KEY_BROADCAST
     ??????? _eapol_conf.fast_reauth = 1;
     ??????? _eapol_conf.workaround = 0;
     ??????? _eapol_conf.eap_disabled = 0;
     ??????? _eapol_conf.external_sim = 0;
     ??????? _eapol_conf.wps = 0;
     ??????? eapol_sm_notify_config(_peapol_sm, &_eap_ctx.eap_config,
    &_eapol_conf);

    eapol_sm_notify_portValid(_peapol_sm, false);
    eapol_sm_notify_portEnabled(_peapol_sm, true);


As you can see, not everything is clear so I'm probably just missing 
something. In the above code we don't get past the call to 
eapol_sm_init. Hope somebody can shed some light or point me in the 
right direction...

Many thanks in advance!

Regards,

Michel Verhagen

On 12/03/2021 10:10, Michel Verhagen wrote:
> Thanks Alan!
>
> That does make sense indeed. I'll try to use eapol_supp for better 
> handling of the EAPOL layer on top of EAP. I hope this code can be 
> used with just the code I ported for the EAP library to compile.
>
> Is there any documentation explaining what all the context parameters 
> do (see test_eapol function in eapol_test.c), which are required and 
> for which functionality etc? All I need is to implement an EAPOL 
> client with certificates, so no WPA/WEP or any of the wireless stuff.
>
> I'll come back with more questions probably, thanks for pointing me in 
> the right direction!
>
>
> On 12/03/2021 01:23, Alan DeKok wrote:
>> On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
>>> I'm using the EAP library to implement EAPOL on an embedded device. 
>>> Got it to go, with EAP-MD5 and EAP-TTLS and certificates, so all 
>>> good. However, I'm trying to get the library to prepare me an EAPOL 
>>> START packet. I'd like to initiate the start of the EAP handshake, 
>>> because depending on the settings of the authenticator, it can take 
>>> a long time before the EAP handshake sequence is initiated.
>> ?? I haven't used the library myself, but the problem, here is likely 
>> layering.
>>
>> ?? i.e. you're using an EAP library.? EAP runs on EAPoL, PPP, PANA, 
>> RADIUS, Diameter, ..., where the library just does EAP.
>>
>> ?? EAPoL is managed by the IEEE 802.1X state machine.? Which uses 
>> EAP, but isn't part of the EAP library.
>>
>>> I thought setting _eap_ctx.eapRestart to 1 (true) or even 
>>> eapTriggerStart to 1 and calling eap_peer_step would get me the 
>>> packet data to send, but I can't see eapTriggerStart used anywhere 
>>> in the code.
>> ?? See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL 
>> supplicant state machine.? It checks eapTriggerStart, and ends up 
>> calling eapol_sm_txStart().
>>
>>> Does anybody know how to get the EAP library to prepare an EAP Start 
>>> packet?
>> ?? You can't.? EAP isn't the same as the Ethernet layer EAPoL state 
>> machine.
>>
>>> I can of course prepare and send that packet myself, but it looks 
>>> like the EAP library should be able to do this as well...
>> ?? No.? The EAP library does EAP.? The 802.1X / supplicant state 
>> machine does Ethernet, and EAPoL.
>>
>> ?? Alan DeKok.
>>
>
>
> _______________________________________________
> Hostap mailing list
> Hostap at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap



From mike at guruce.com  Tue Mar 30 05:53:40 2021
From: mike at guruce.com (Michel Verhagen)
Date: Tue, 30 Mar 2021 17:53:40 +1300
Subject: Starting EAP sequence
In-Reply-To: <99cdfa00-251b-9f69-38c3-6d0564576f8e@guruce.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
 <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
 <f7ad988a-7178-8cd3-36aa-0cdfb6e957f3@guruce.com>
 <99cdfa00-251b-9f69-38c3-6d0564576f8e@guruce.com>
Message-ID: <a62f6149-aa65-4d4d-da6d-e8683f47a78f@guruce.com>

Issue resolved; problem was missing call to eloop_init.

Regards,

Michel Verhagen

On 30/03/2021 17:04, Michel Verhagen wrote:.
> We are running into an issue where calling eapol_sm_init results in a 
> write to a null pointer in dl_list_add:
>
> ?? static inline void dl_list_add(struct dl_list *list, struct dl_list
> ?? *item)
> ?? {
> ??? ??? item->next = list->next;
> ??? ??? item->prev = list;
> ??? ??? list->next->prev = item;
> ??? ??? list->next = item;
> ?? }
>
> item->next is null in the above when called from function 
> eloop_register_timeout through macro dl_list_for_each in line 273:
>
> ??? ??? /* Maintain timeouts in order of increasing time */
> ??? ??? dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, 
> list) {
> ??? ??? ??? if (os_reltime_before(&timeout->time, &tmp->time)) {
> ??? ??? ??? ??? dl_list_add(tmp->list.prev, &timeout->list);
> ??? ??? ??? ??? return 0;
> ??? ??? ??? }
> ??? ??? }
>
> ?? #define dl_list_for_each(item, list, type, member) \
> ??? ??? for (item = dl_list_entry((list)->next, type, member); \
> ??? ??? ???? &item->member != (list); \
> ??? ??? ???? item = dl_list_entry(item->member.next, type, member))
>
>
> So, the code is:
>
> ?? for (tmp = dl_list_entry((&loop.timeout)->next, struct
> ?? eloop_timeout, list); \
> ??? ??? ???? &tmp->list != (&loop.timeout); \
> ??? ??? ???? tmp = dl_list_entry(tmp->list.next, struct eloop_timeout,
> ?? list))
>
>
> And eloop.timeout.next is NULL.
>
> We are implementing EAPOL authentication using the hostap eap library 
> and eapol state machine code. We only need EAPOL over wired LAN, so no 
> WPA or WPS needed. Our initialization looks like this:
>
> ??? ??????? if (ERROR_SUCCESS != EAPRegisterMethods())
> ??? ??????????? break;
>
> ??? ??????? os_memset(&_eap_ctx, 0, sizeof(_eap_ctx));
>
> ??? ??????? _eap_ctx.eap_config.identity = (u8 *)os_strdup("Identity");
> ??? ??????? _eap_ctx.eap_config.identity_len = strlen((const
> ?? char*)_eap_ctx.eap_config.identity);
> ??? ??????? _eap_ctx.eap_config.password = (u8 *)os_strdup("password");
> ??? ??????? _eap_ctx.eap_config.password_len = strlen((const
> ?? char*)_eap_ctx.eap_config.password);
> ??? ??????? _eap_ctx.eap_config.ca_cert = os_strdup("\\Windows\\ca.pem");
> ??? ??????? //_eap_ctx.eap_config.ca_path = os_strdup("\\Windows");
> ??? ??????? _eap_ctx.eap_config.fragment_size = 1398;
>
> ??? ??????? os_memset(&_eap_cb, 0, sizeof(_eap_cb));
> ??? ??????? _eap_cb.get_config = peer_get_config;
> ??? ??????? _eap_cb.get_bool = (Boolean(__cdecl *)(void *,
> ?? eapol_bool_var))peer_get_bool;
> ??? ??????? _eap_cb.set_bool = (void(__cdecl *)(void *, eapol_bool_var,
> ?? Boolean))peer_set_bool;
> ??? ??????? _eap_cb.get_int = peer_get_int;
> ??? ??????? _eap_cb.set_int = peer_set_int;
> ??? ??????? _eap_cb.get_eapReqData = peer_get_eapReqData;
> ??? ??????? _eap_cb.set_config_blob = peer_set_config_blob;
> ??? ??????? _eap_cb.get_config_blob = peer_get_config_blob;
> ??? ??????? _eap_cb.notify_pending = peer_notify_pending;
>
> ??? ??????? os_memset(&_eap_conf, 0, sizeof(_eap_conf));
> ??? ??????? _eap_ctx.eap = eap_peer_sm_init(&_eap_ctx, &_eap_cb,
> ?? &_eap_ctx, &_eap_conf);
> ??? ??????? if (_eap_ctx.eap == NULL)
> ??? ??????????? break;
>
> ??? ??????? /* Enable "port" to allow authentication */
> ??? ??????? _eap_ctx.portEnabled = true;
>
> ??? ??????? os_memset(&_eapol_ctx, 0, sizeof(_eapol_ctx));
> ??? ??????? _eapol_ctx.ctx = this;????????????????? // This can be
> ?? pointing to any structure we define as context
> ??? ??????? _eapol_ctx.preauth = 0;???????????????? // Not using IEEE
> ?? 802.11i/RSN pre-authentication
> ??? ??????? _eapol_ctx.cb = NULL;?????????????????? // Not using IEEE
> ?? 802.11i/RSN pre-authentication, so no need for this callback
> ??? ??????? _eapol_ctx.cb_ctx = NULL;?????????????? // Not using IEEE
> ?? 802.11i/RSN pre-authentication, so no need for context
> ??? ??????? _eapol_ctx.msg_ctx = this;????????????? // Callback context
> ?? for wpa_msg() calls
> ??? ??????? _eapol_ctx.scard_ctx = NULL;??????????? // Callback context
> ?? for PC/SC scard_*() function calls
> ??? ??????? _eapol_ctx.eapol_send_ctx = this;?????? // Callback context
> ?? for eapol_send() calls
> ??? ??????? _eapol_ctx.eapol_done_cb = eapol_done_cb;
> ??? ??????? _eapol_ctx.eapol_send = eapol_send;
> ??? ??????? _eapol_ctx.set_wep_key = NULL;????????? // Not using WEP
> ??? ??????? _eapol_ctx.set_config_blob = NULL;
> ??? ??????? _eapol_ctx.get_config_blob = NULL;
> ??? ??????? _eapol_ctx.aborted_cached = NULL;
>
> ??? ??????? _eapol_ctx.opensc_engine_path = NULL;?? // No idea what to
> ?? set here
> ??? ??????? _eapol_ctx.pkcs11_engine_path = NULL;?? // No idea what to
> ?? set here
> ??? ??????? _eapol_ctx.pkcs11_module_path = NULL;?? // No idea what to
> ?? set here
> ??? ??????? _eapol_ctx.openssl_ciphers = NULL;????? // No idea what to
> ?? set here
>
> ??? ??????? _eapol_ctx.wps = NULL;????????????????? // Not using WPS
>
> ??? ??????? _eapol_ctx.eap_param_needed = NULL;???? // Not using WEP
>
> ??? ??????? _eapol_ctx.port_cb = port_cb;
> ??? ??????? _eapol_ctx.cert_cb = cert_cb;
> ??? ??????? _eapol_ctx.cert_in_cb = 1;
> ??? ??????? _eapol_ctx.status_cb = status_cb;
> ??? ??????? _eapol_ctx.eap_error_cb = eap_error_cb;
>
> ??? ??????? _eapol_ctx.set_anon_id = NULL;????????? // Not sure this is
> ?? needed
> ??? ??????? _eapol_ctx.confirm_auth_cb = NULL;????? // Not sure this is
> ?? needed
>
> ??? ??????? _peapol_sm = eapol_sm_init(&_eapol_ctx);
> ??? ??????? if (!_peapol_sm)
> ??? ??????????? break;
>
> ??? ??????? os_memset(&_eapol_conf, 0, sizeof(_eapol_conf));
> ??? ??????? _eapol_conf.accept_802_1x_keys = 0;
> ??? ??????? _eapol_conf.required_keys = 0;????????? //
> ?? EAPOL_REQUIRE_KEY_UNICAST | EAPOL_REQUIRE_KEY_BROADCAST
> ??? ??????? _eapol_conf.fast_reauth = 1;
> ??? ??????? _eapol_conf.workaround = 0;
> ??? ??????? _eapol_conf.eap_disabled = 0;
> ??? ??????? _eapol_conf.external_sim = 0;
> ??? ??????? _eapol_conf.wps = 0;
> ??? ??????? eapol_sm_notify_config(_peapol_sm, &_eap_ctx.eap_config,
> ?? &_eapol_conf);
>
> ?? eapol_sm_notify_portValid(_peapol_sm, false);
> ?? eapol_sm_notify_portEnabled(_peapol_sm, true);
>
>
> As you can see, not everything is clear so I'm probably just missing 
> something. In the above code we don't get past the call to 
> eapol_sm_init. Hope somebody can shed some light or point me in the 
> right direction...
>
> Many thanks in advance!
>
> Regards,
>
> Michel Verhagen
>
> On 12/03/2021 10:10, Michel Verhagen wrote:
>> Thanks Alan!
>>
>> That does make sense indeed. I'll try to use eapol_supp for better 
>> handling of the EAPOL layer on top of EAP. I hope this code can be 
>> used with just the code I ported for the EAP library to compile.
>>
>> Is there any documentation explaining what all the context parameters 
>> do (see test_eapol function in eapol_test.c), which are required and 
>> for which functionality etc? All I need is to implement an EAPOL 
>> client with certificates, so no WPA/WEP or any of the wireless stuff.
>>
>> I'll come back with more questions probably, thanks for pointing me 
>> in the right direction!
>>
>>
>> On 12/03/2021 01:23, Alan DeKok wrote:
>>> On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
>>>> I'm using the EAP library to implement EAPOL on an embedded device. 
>>>> Got it to go, with EAP-MD5 and EAP-TTLS and certificates, so all 
>>>> good. However, I'm trying to get the library to prepare me an EAPOL 
>>>> START packet. I'd like to initiate the start of the EAP handshake, 
>>>> because depending on the settings of the authenticator, it can take 
>>>> a long time before the EAP handshake sequence is initiated.
>>> ?? I haven't used the library myself, but the problem, here is 
>>> likely layering.
>>>
>>> ?? i.e. you're using an EAP library.? EAP runs on EAPoL, PPP, PANA, 
>>> RADIUS, Diameter, ..., where the library just does EAP.
>>>
>>> ?? EAPoL is managed by the IEEE 802.1X state machine.? Which uses 
>>> EAP, but isn't part of the EAP library.
>>>
>>>> I thought setting _eap_ctx.eapRestart to 1 (true) or even 
>>>> eapTriggerStart to 1 and calling eap_peer_step would get me the 
>>>> packet data to send, but I can't see eapTriggerStart used anywhere 
>>>> in the code.
>>> ?? See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL 
>>> supplicant state machine.? It checks eapTriggerStart, and ends up 
>>> calling eapol_sm_txStart().
>>>
>>>> Does anybody know how to get the EAP library to prepare an EAP 
>>>> Start packet?
>>> ?? You can't.? EAP isn't the same as the Ethernet layer EAPoL state 
>>> machine.
>>>
>>>> I can of course prepare and send that packet myself, but it looks 
>>>> like the EAP library should be able to do this as well...
>>> ?? No.? The EAP library does EAP.? The 802.1X / supplicant state 
>>> machine does Ethernet, and EAPoL.
>>>
>>> ?? Alan DeKok.
>>>
>>
>>
>> _______________________________________________
>> Hostap mailing list
>> Hostap at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/hostap
>
>
> _______________________________________________
> Hostap mailing list
> Hostap at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap




From mike at guruce.com  Tue Mar 30 08:14:10 2021
From: mike at guruce.com (Michel Verhagen)
Date: Tue, 30 Mar 2021 20:14:10 +1300
Subject: Starting EAP sequence
In-Reply-To: <a62f6149-aa65-4d4d-da6d-e8683f47a78f@guruce.com>
References: <ba035e36-f51b-2401-c4d7-11f9c7f0f032@guruce.com>
 <F3A9FA06-4CFE-4B54-9F04-E889BBED2289@deployingradius.com>
 <f7ad988a-7178-8cd3-36aa-0cdfb6e957f3@guruce.com>
 <99cdfa00-251b-9f69-38c3-6d0564576f8e@guruce.com>
 <a62f6149-aa65-4d4d-da6d-e8683f47a78f@guruce.com>
Message-ID: <fd2b924c-00e3-58bf-7fdd-d09bcf2bc91e@guruce.com>

Now that I have everything building and now that I am using the 
eapol_supp_sm state machine code, I'm back at my original question: How 
do I get the EAPOL state machine to generate an EAPOL START packet?

The eapol_supp_sm code will do this when eapTriggerStart is set, but 
this variable is not accessible from outside the eapol_supp_sm code. The 
struct containing this variable is not publicly defined and I simply 
can't set eapTriggerStart to 1 from my code (compiler error C2027: use 
of undefined type 'eapol_sm').

I've tried calling eapol_sm_request_reauth, but the code there only 
issues the EAPOL Start packet if sm->SUPP_PAE_state == 
SUPP_PAE_AUTHENTICATED, and of course when I am just starting the EAPOL 
state machine, the port status is NOT authenticated.

I also tried calling eapol_sm_notify_portControl with ForceAuthorized, 
but that sets m->SUPP_PAE_state to SUPP_PAE_S_FORCE_AUTH.

Surely there must be a way to get the EAPOL state machine to set 
eapTriggerStart so that when running the state machine the code ends up 
calling the send callback function with an EAPOL Start packet?

Any help would be much appreciated!

Regards,

Michel Verhagen

On 30/03/2021 17:53, Michel Verhagen wrote:
> Issue resolved; problem was missing call to eloop_init.
>
> Regards,
>
> Michel Verhagen
>
> On 30/03/2021 17:04, Michel Verhagen wrote:.
>> We are running into an issue where calling eapol_sm_init results in a 
>> write to a null pointer in dl_list_add:
>>
>> ?? static inline void dl_list_add(struct dl_list *list, struct dl_list
>> ?? *item)
>> ?? {
>> ??? ??? item->next = list->next;
>> ??? ??? item->prev = list;
>> ??? ??? list->next->prev = item;
>> ??? ??? list->next = item;
>> ?? }
>>
>> item->next is null in the above when called from function 
>> eloop_register_timeout through macro dl_list_for_each in line 273:
>>
>> ??? ??? /* Maintain timeouts in order of increasing time */
>> ??? ??? dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, 
>> list) {
>> ??? ??? ??? if (os_reltime_before(&timeout->time, &tmp->time)) {
>> ??? ??? ??? ??? dl_list_add(tmp->list.prev, &timeout->list);
>> ??? ??? ??? ??? return 0;
>> ??? ??? ??? }
>> ??? ??? }
>>
>> ?? #define dl_list_for_each(item, list, type, member) \
>> ??? ??? for (item = dl_list_entry((list)->next, type, member); \
>> ??? ??? ???? &item->member != (list); \
>> ??? ??? ???? item = dl_list_entry(item->member.next, type, member))
>>
>>
>> So, the code is:
>>
>> ?? for (tmp = dl_list_entry((&loop.timeout)->next, struct
>> ?? eloop_timeout, list); \
>> ??? ??? ???? &tmp->list != (&loop.timeout); \
>> ??? ??? ???? tmp = dl_list_entry(tmp->list.next, struct eloop_timeout,
>> ?? list))
>>
>>
>> And eloop.timeout.next is NULL.
>>
>> We are implementing EAPOL authentication using the hostap eap library 
>> and eapol state machine code. We only need EAPOL over wired LAN, so 
>> no WPA or WPS needed. Our initialization looks like this:
>>
>> ??? ??????? if (ERROR_SUCCESS != EAPRegisterMethods())
>> ??? ??????????? break;
>>
>> ??? ??????? os_memset(&_eap_ctx, 0, sizeof(_eap_ctx));
>>
>> ??? ??????? _eap_ctx.eap_config.identity = (u8 *)os_strdup("Identity");
>> ??? ??????? _eap_ctx.eap_config.identity_len = strlen((const
>> ?? char*)_eap_ctx.eap_config.identity);
>> ??? ??????? _eap_ctx.eap_config.password = (u8 *)os_strdup("password");
>> ??? ??????? _eap_ctx.eap_config.password_len = strlen((const
>> ?? char*)_eap_ctx.eap_config.password);
>> ??? ??????? _eap_ctx.eap_config.ca_cert = 
>> os_strdup("\\Windows\\ca.pem");
>> ??? ??????? //_eap_ctx.eap_config.ca_path = os_strdup("\\Windows");
>> ??? ??????? _eap_ctx.eap_config.fragment_size = 1398;
>>
>> ??? ??????? os_memset(&_eap_cb, 0, sizeof(_eap_cb));
>> ??? ??????? _eap_cb.get_config = peer_get_config;
>> ??? ??????? _eap_cb.get_bool = (Boolean(__cdecl *)(void *,
>> ?? eapol_bool_var))peer_get_bool;
>> ??? ??????? _eap_cb.set_bool = (void(__cdecl *)(void *, eapol_bool_var,
>> ?? Boolean))peer_set_bool;
>> ??? ??????? _eap_cb.get_int = peer_get_int;
>> ??? ??????? _eap_cb.set_int = peer_set_int;
>> ??? ??????? _eap_cb.get_eapReqData = peer_get_eapReqData;
>> ??? ??????? _eap_cb.set_config_blob = peer_set_config_blob;
>> ??? ??????? _eap_cb.get_config_blob = peer_get_config_blob;
>> ??? ??????? _eap_cb.notify_pending = peer_notify_pending;
>>
>> ??? ??????? os_memset(&_eap_conf, 0, sizeof(_eap_conf));
>> ??? ??????? _eap_ctx.eap = eap_peer_sm_init(&_eap_ctx, &_eap_cb,
>> ?? &_eap_ctx, &_eap_conf);
>> ??? ??????? if (_eap_ctx.eap == NULL)
>> ??? ??????????? break;
>>
>> ??? ??????? /* Enable "port" to allow authentication */
>> ??? ??????? _eap_ctx.portEnabled = true;
>>
>> ??? ??????? os_memset(&_eapol_ctx, 0, sizeof(_eapol_ctx));
>> ??? ??????? _eapol_ctx.ctx = this;????????????????? // This can be
>> ?? pointing to any structure we define as context
>> ??? ??????? _eapol_ctx.preauth = 0;???????????????? // Not using IEEE
>> ?? 802.11i/RSN pre-authentication
>> ??? ??????? _eapol_ctx.cb = NULL;?????????????????? // Not using IEEE
>> ?? 802.11i/RSN pre-authentication, so no need for this callback
>> ??? ??????? _eapol_ctx.cb_ctx = NULL;?????????????? // Not using IEEE
>> ?? 802.11i/RSN pre-authentication, so no need for context
>> ??? ??????? _eapol_ctx.msg_ctx = this;????????????? // Callback context
>> ?? for wpa_msg() calls
>> ??? ??????? _eapol_ctx.scard_ctx = NULL;??????????? // Callback context
>> ?? for PC/SC scard_*() function calls
>> ??? ??????? _eapol_ctx.eapol_send_ctx = this;?????? // Callback context
>> ?? for eapol_send() calls
>> ??? ??????? _eapol_ctx.eapol_done_cb = eapol_done_cb;
>> ??? ??????? _eapol_ctx.eapol_send = eapol_send;
>> ??? ??????? _eapol_ctx.set_wep_key = NULL;????????? // Not using WEP
>> ??? ??????? _eapol_ctx.set_config_blob = NULL;
>> ??? ??????? _eapol_ctx.get_config_blob = NULL;
>> ??? ??????? _eapol_ctx.aborted_cached = NULL;
>>
>> ??? ??????? _eapol_ctx.opensc_engine_path = NULL;?? // No idea what to
>> ?? set here
>> ??? ??????? _eapol_ctx.pkcs11_engine_path = NULL;?? // No idea what to
>> ?? set here
>> ??? ??????? _eapol_ctx.pkcs11_module_path = NULL;?? // No idea what to
>> ?? set here
>> ??? ??????? _eapol_ctx.openssl_ciphers = NULL;????? // No idea what to
>> ?? set here
>>
>> ??? ??????? _eapol_ctx.wps = NULL;????????????????? // Not using WPS
>>
>> ??? ??????? _eapol_ctx.eap_param_needed = NULL;???? // Not using WEP
>>
>> ??? ??????? _eapol_ctx.port_cb = port_cb;
>> ??? ??????? _eapol_ctx.cert_cb = cert_cb;
>> ??? ??????? _eapol_ctx.cert_in_cb = 1;
>> ??? ??????? _eapol_ctx.status_cb = status_cb;
>> ??? ??????? _eapol_ctx.eap_error_cb = eap_error_cb;
>>
>> ??? ??????? _eapol_ctx.set_anon_id = NULL;????????? // Not sure this is
>> ?? needed
>> ??? ??????? _eapol_ctx.confirm_auth_cb = NULL;????? // Not sure this is
>> ?? needed
>>
>> ??? ??????? _peapol_sm = eapol_sm_init(&_eapol_ctx);
>> ??? ??????? if (!_peapol_sm)
>> ??? ??????????? break;
>>
>> ??? ??????? os_memset(&_eapol_conf, 0, sizeof(_eapol_conf));
>> ??? ??????? _eapol_conf.accept_802_1x_keys = 0;
>> ??? ??????? _eapol_conf.required_keys = 0;????????? //
>> ?? EAPOL_REQUIRE_KEY_UNICAST | EAPOL_REQUIRE_KEY_BROADCAST
>> ??? ??????? _eapol_conf.fast_reauth = 1;
>> ??? ??????? _eapol_conf.workaround = 0;
>> ??? ??????? _eapol_conf.eap_disabled = 0;
>> ??? ??????? _eapol_conf.external_sim = 0;
>> ??? ??????? _eapol_conf.wps = 0;
>> ??? ??????? eapol_sm_notify_config(_peapol_sm, &_eap_ctx.eap_config,
>> ?? &_eapol_conf);
>>
>> ?? eapol_sm_notify_portValid(_peapol_sm, false);
>> ?? eapol_sm_notify_portEnabled(_peapol_sm, true);
>>
>>
>> As you can see, not everything is clear so I'm probably just missing 
>> something. In the above code we don't get past the call to 
>> eapol_sm_init. Hope somebody can shed some light or point me in the 
>> right direction...
>>
>> Many thanks in advance!
>>
>> Regards,
>>
>> Michel Verhagen
>>
>> On 12/03/2021 10:10, Michel Verhagen wrote:
>>> Thanks Alan!
>>>
>>> That does make sense indeed. I'll try to use eapol_supp for better 
>>> handling of the EAPOL layer on top of EAP. I hope this code can be 
>>> used with just the code I ported for the EAP library to compile.
>>>
>>> Is there any documentation explaining what all the context 
>>> parameters do (see test_eapol function in eapol_test.c), which are 
>>> required and for which functionality etc? All I need is to implement 
>>> an EAPOL client with certificates, so no WPA/WEP or any of the 
>>> wireless stuff.
>>>
>>> I'll come back with more questions probably, thanks for pointing me 
>>> in the right direction!
>>>
>>>
>>> On 12/03/2021 01:23, Alan DeKok wrote:
>>>> On Mar 10, 2021, at 11:56 PM, Michel Verhagen <mike at guruce.com> wrote:
>>>>> I'm using the EAP library to implement EAPOL on an embedded 
>>>>> device. Got it to go, with EAP-MD5 and EAP-TTLS and certificates, 
>>>>> so all good. However, I'm trying to get the library to prepare me 
>>>>> an EAPOL START packet. I'd like to initiate the start of the EAP 
>>>>> handshake, because depending on the settings of the authenticator, 
>>>>> it can take a long time before the EAP handshake sequence is 
>>>>> initiated.
>>>> ?? I haven't used the library myself, but the problem, here is 
>>>> likely layering.
>>>>
>>>> ?? i.e. you're using an EAP library.? EAP runs on EAPoL, PPP, PANA, 
>>>> RADIUS, Diameter, ..., where the library just does EAP.
>>>>
>>>> ?? EAPoL is managed by the IEEE 802.1X state machine.? Which uses 
>>>> EAP, but isn't part of the EAP library.
>>>>
>>>>> I thought setting _eap_ctx.eapRestart to 1 (true) or even 
>>>>> eapTriggerStart to 1 and calling eap_peer_step would get me the 
>>>>> packet data to send, but I can't see eapTriggerStart used anywhere 
>>>>> in the code.
>>>> ?? See src/eapol_supp/eapol_supp_sm.c, which runs the EAPoL 
>>>> supplicant state machine.? It checks eapTriggerStart, and ends up 
>>>> calling eapol_sm_txStart().
>>>>
>>>>> Does anybody know how to get the EAP library to prepare an EAP 
>>>>> Start packet?
>>>> ?? You can't.? EAP isn't the same as the Ethernet layer EAPoL state 
>>>> machine.
>>>>
>>>>> I can of course prepare and send that packet myself, but it looks 
>>>>> like the EAP library should be able to do this as well...
>>>> ?? No.? The EAP library does EAP.? The 802.1X / supplicant state 
>>>> machine does Ethernet, and EAPoL.
>>>>
>>>> ?? Alan DeKok.
>>>>
>>>
>>>
>>> _______________________________________________
>>> Hostap mailing list
>>> Hostap at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/hostap
>>
>>
>> _______________________________________________
>> Hostap mailing list
>> Hostap at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/hostap
>
>
>
> _______________________________________________
> Hostap mailing list
> Hostap at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap



From tom.isaacson at teknique.com  Wed Mar 31 00:30:35 2021
From: tom.isaacson at teknique.com (Tom Isaacson)
Date: Wed, 31 Mar 2021 12:30:35 +1300
Subject: When was WPA3 support released?
Message-ID: <CA+EiEZKkftV4vFfD6HhdyPhF7wf-K0PUV0qN6Jsb4cv8DBNvpA@mail.gmail.com>

Apologies if this has been asked before, but I'm wondering when WPA3
support was released. I found this
https://lists.infradead.org/pipermail/hostap/2018-March/038334.html
which suggests it was added to master before March 2018 but it's not
mentioned in the changelogs:
* https://w1.fi/cgit/hostap/plain/hostapd/ChangeLog
* https://w1.fi/cgit/hostap/plain/wpa_supplicant/ChangeLog

I can't check if it's been asked before because there's no mailing
list history from June 2018 until May 2020:
https://lists.infradead.org/pipermail/hostap/

Thanks.

-- 
Tom Isaacson


From matthewmwang at chromium.org  Wed Mar 31 19:52:21 2021
From: matthewmwang at chromium.org (Matthew Wang)
Date: Wed, 31 Mar 2021 11:52:21 -0700
Subject: [PATCH] Use default IEs in wpa_supplicant_trigger_scan
Message-ID: <20210331185221.61841-1-matthewmwang@chromium.org>

wpa_supplicant_trigger_scan previously wouldn't include any of the IEs
generated by wpa_supplicant_extra_ies. Instruct it to do so in most
cases. This is necessary because MBO STAs are required to include MBO
capabilities in their probe requests.

Signed-off-by: Matthew Wang <matthewmwang at chromium.org>
---
 doc/dbus.doxygen                        |  2 +-
 wpa_supplicant/bgscan_learn.c           |  2 +-
 wpa_supplicant/bgscan_simple.c          |  2 +-
 wpa_supplicant/dbus/dbus_new_handlers.c |  6 ++++--
 wpa_supplicant/rrm.c                    |  2 +-
 wpa_supplicant/scan.c                   | 27 ++++++++++++++++++++++---
 wpa_supplicant/scan.h                   |  4 +++-
 wpa_supplicant/sme.c                    |  2 +-
 8 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 8231aac4180..1d93a1d7899 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -206,7 +206,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
 	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
 	      <tr><td>Type</td><td>s</td><td>Type of the scan. Possible values: "active", "passive"</td><td>Yes</td>
 	      <tr><td>SSIDs</td><td>aay</td><td>Array of SSIDs to scan for (applies only if scan type is active)</td><td>No</td>
-	      <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active)</td><td>No</td>
+	      <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active). Default IEs will be used in absence of this option.</td><td>No</td>
 	      <tr><td>Channels</td><td>a(uu)</td><td>Array of frequencies to scan in form of (center, width) in MHz.</td><td>No</td>
 	      <tr><td>AllowRoam</td><td>b</td><td>TRUE (or absent) to allow a roaming decision based on the results of this scan, FALSE to prevent a roaming decision.</td><td>No</td>
 	    </table>
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index cb732f709b9..3d10d911853 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -305,7 +305,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 
 	wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
 		wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_learn_timeout, data, NULL);
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 41a26df0d63..4dd212b2197 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -49,7 +49,7 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
 	 */
 
 	wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
-	if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true)) {
 		wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
 		eloop_register_timeout(data->scan_interval, 0,
 				       bgscan_simple_timeout, data, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index db9f30c9aab..08be9da3b9e 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1371,6 +1371,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 	struct wpa_driver_scan_params params;
 	size_t i;
 	dbus_bool_t allow_roam = 1;
+	bool custom_ies = false;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -1397,6 +1398,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 			if (wpas_dbus_get_scan_ies(message, &variant_iter,
 						   &params, &reply) < 0)
 				goto out;
+			custom_ies = true;
 		} else if (os_strcmp(key, "Channels") == 0) {
 			if (wpas_dbus_get_scan_channels(message, &variant_iter,
 							&params, &reply) < 0)
@@ -1444,7 +1446,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 			if (params.freqs && params.freqs[0]) {
 				wpa_s->last_scan_req = MANUAL_SCAN_REQ;
 				if (wpa_supplicant_trigger_scan(wpa_s,
-								&params)) {
+								&params, false)) {
 					reply = wpas_dbus_error_scan_error(
 						message,
 						"Scan request rejected");
@@ -1470,7 +1472,7 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 		}
 
 		wpa_s->last_scan_req = MANUAL_SCAN_REQ;
-		if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+		if (wpa_supplicant_trigger_scan(wpa_s, &params, !custom_ies)) {
 			reply = wpas_dbus_error_scan_error(
 				message, "Scan request rejected");
 		}
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index cf107ebaf63..0e079380b73 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -1034,7 +1034,7 @@ static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	}
 	os_get_reltime(&wpa_s->beacon_rep_scan);
 	if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
-	    wpa_supplicant_trigger_scan(wpa_s, params))
+	    wpa_supplicant_trigger_scan(wpa_s, params, true))
 		wpas_rrm_refuse_request(wpa_s);
 	params->duration = prev_duration;
 }
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index c53474dae26..94231e417cd 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -278,19 +278,40 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
  * wpa_supplicant_trigger_scan - Request driver to start a scan
  * @wpa_s: Pointer to wpa_supplicant data
  * @params: Scan parameters
+ * @default_ies: Whether or not to use the default IEs in the probe request.
+ * Note that this will free any existing IEs set in @params, so this shouldn't
+ * be set if the IEs have already been set with wpa_supplicant_extra_ies.
+ * Otherwise, wpabuf_free will lead to a double-free.
  * Returns: 0 on success, -1 on failure
  */
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params)
+				struct wpa_driver_scan_params *params,
+				bool default_ies)
 {
 	struct wpa_driver_scan_params *ctx;
+	struct wpabuf *ies = NULL;
 
 	if (wpa_s->scan_work) {
 		wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending");
 		return -1;
 	}
 
+	if (default_ies) {
+		if (params->extra_ies_len) {
+			os_free((u8 *) params->extra_ies);
+		}
+		ies = wpa_supplicant_extra_ies(wpa_s);
+		if (ies) {
+			params->extra_ies = wpabuf_head(ies);
+			params->extra_ies_len = wpabuf_len(ies);
+		}
+	}
 	ctx = wpa_scan_clone_params(params);
+	if (ies) {
+		wpabuf_free(ies);
+		params->extra_ies = NULL;
+		params->extra_ies_len = 0;
+	}
 	if (!ctx ||
 	    radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
 	{
@@ -566,7 +587,7 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
 }
 
 
-static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
 {
 	struct wpabuf *extra_ie = NULL;
 	u8 ext_capab[18];
@@ -1339,7 +1360,7 @@ scan:
 	}
 #endif /* CONFIG_P2P */
 
-	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params, false);
 
 	if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
 	    !wpa_s->manual_scan_freqs) {
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 8eb5c73e275..d1f26eccec3 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -43,7 +43,8 @@ void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 				    int scanning);
 struct wpa_driver_scan_params;
 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
-				struct wpa_driver_scan_params *params);
+				struct wpa_driver_scan_params *params,
+				bool default_ies);
 struct wpa_scan_results *
 wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
 				struct scan_info *info, int new_scan);
@@ -90,5 +91,6 @@ int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
 			    enum hostapd_hw_mode band,
 			    struct wpa_driver_scan_params *params,
 			    bool is_6ghz);
+struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index dde80863a98..bf1576ac31f 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -2543,7 +2543,7 @@ static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 	params.low_priority = 1;
 	wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
 
-	if (wpa_supplicant_trigger_scan(wpa_s, &params))
+	if (wpa_supplicant_trigger_scan(wpa_s, &params, true))
 		wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan");
 	else
 		wpa_s->sme.sched_obss_scan = 1;
-- 
2.31.0.291.g576ba9dcdaf-goog



