hostapd: add Multi-AP patches and config options
Cherry-pick Multi-AP commits from uptream: 9c06f0f6a hostapd: Add Multi-AP protocol support 5abc7823b wpa_supplicant: Add Multi-AP backhaul STA support a1debd338 tests: Refactor test_multi_ap bfcdac1c8 Multi-AP: Don't reject backhaul STA on fronthaul BSS cb3c156e7 tests: Update multi_ap_fronthaul_on_ap to match implementation 56a2d788f WPS: Add multi_ap_subelem to wps_build_wfa_ext() 83ebf5586 wpa_supplicant: Support Multi-AP backhaul STA onboarding with WPS 66819b07b hostapd: Support Multi-AP backhaul STA onboarding with WPS 8682f384c hostapd: Add README-MULTI-AP b1daf498a tests: Multi-AP WPS provisioning Add support for Multi-AP to the UCI configuration. Every wifi-iface gets an option 'multi_ap'. For APs, its value can be 0 (multi-AP support disabled), 1 (backhaul AP), 2 (fronthaul AP), or 3 (fronthaul + backhaul AP). For STAs, it can be 0 (not a backhaul STA) or 1 (backhaul STA, can only associate with backhaul AP). Also add new optional parameter to wps_start ubus call of wpa_supplicant to indicate that a Multi-AP backhaul link is required. Signed-off-by: Daniel Golle <daniel@makrotopia.org> Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
This commit is contained in:
		 Arnout Vandecappelle (Essensium/Mind)
					Arnout Vandecappelle (Essensium/Mind)
				
			
				
					committed by
					
						 Daniel Golle
						Daniel Golle
					
				
			
			
				
	
			
			
			 Daniel Golle
						Daniel Golle
					
				
			
						parent
						
							8554982e1f
						
					
				
				
					commit
					2e0f41e73a
				
			| @@ -59,7 +59,7 @@ | |||||||
|  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, |  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, | ||||||
|  				       bool set_bw, bool is_ht40) |  				       bool set_bw, bool is_ht40) | ||||||
|  { |  { | ||||||
| @@ -8943,6 +8995,7 @@ static void rt2800_init_rfcsr_6352(struc | @@ -8956,6 +9008,7 @@ static void rt2800_init_rfcsr_6352(struc | ||||||
|  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); |  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); | ||||||
|  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); |  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); | ||||||
|   |   | ||||||
|   | |||||||
| @@ -161,7 +161,7 @@ | |||||||
|  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, |  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, | ||||||
|  				       bool set_bw, bool is_ht40) |  				       bool set_bw, bool is_ht40) | ||||||
|  { |  { | ||||||
| @@ -8995,6 +9149,7 @@ static void rt2800_init_rfcsr_6352(struc | @@ -9008,6 +9162,7 @@ static void rt2800_init_rfcsr_6352(struc | ||||||
|  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); |  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); | ||||||
|  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); |  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); | ||||||
|   |   | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ | |||||||
|  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, |  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, | ||||||
|  				       bool set_bw, bool is_ht40) |  				       bool set_bw, bool is_ht40) | ||||||
|  { |  { | ||||||
| @@ -9151,6 +9216,7 @@ static void rt2800_init_rfcsr_6352(struc | @@ -9164,6 +9229,7 @@ static void rt2800_init_rfcsr_6352(struc | ||||||
|   |   | ||||||
|  	rt2800_r_calibration(rt2x00dev); |  	rt2800_r_calibration(rt2x00dev); | ||||||
|  	rt2800_rf_self_txdc_cal(rt2x00dev); |  	rt2800_rf_self_txdc_cal(rt2x00dev); | ||||||
|   | |||||||
| @@ -387,7 +387,7 @@ | |||||||
|  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, |  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, | ||||||
|  				       bool set_bw, bool is_ht40) |  				       bool set_bw, bool is_ht40) | ||||||
|  { |  { | ||||||
| @@ -9219,6 +9599,7 @@ static void rt2800_init_rfcsr_6352(struc | @@ -9232,6 +9612,7 @@ static void rt2800_init_rfcsr_6352(struc | ||||||
|  	rt2800_rxdcoc_calibration(rt2x00dev); |  	rt2800_rxdcoc_calibration(rt2x00dev); | ||||||
|  	rt2800_bw_filter_calibration(rt2x00dev, true); |  	rt2800_bw_filter_calibration(rt2x00dev, true); | ||||||
|  	rt2800_bw_filter_calibration(rt2x00dev, false); |  	rt2800_bw_filter_calibration(rt2x00dev, false); | ||||||
|   | |||||||
| @@ -958,7 +958,7 @@ | |||||||
|  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, |  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, | ||||||
|  				       bool set_bw, bool is_ht40) |  				       bool set_bw, bool is_ht40) | ||||||
|  { |  { | ||||||
| @@ -9599,6 +10550,7 @@ static void rt2800_init_rfcsr_6352(struc | @@ -9612,6 +10563,7 @@ static void rt2800_init_rfcsr_6352(struc | ||||||
|  	rt2800_rxdcoc_calibration(rt2x00dev); |  	rt2800_rxdcoc_calibration(rt2x00dev); | ||||||
|  	rt2800_bw_filter_calibration(rt2x00dev, true); |  	rt2800_bw_filter_calibration(rt2x00dev, true); | ||||||
|  	rt2800_bw_filter_calibration(rt2x00dev, false); |  	rt2800_bw_filter_calibration(rt2x00dev, false); | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| include $(TOPDIR)/rules.mk | include $(TOPDIR)/rules.mk | ||||||
|  |  | ||||||
| PKG_NAME:=hostapd | PKG_NAME:=hostapd | ||||||
| PKG_RELEASE:=1 | PKG_RELEASE:=2 | ||||||
|  |  | ||||||
| PKG_SOURCE_URL:=http://w1.fi/hostap.git | PKG_SOURCE_URL:=http://w1.fi/hostap.git | ||||||
| PKG_SOURCE_PROTO:=git | PKG_SOURCE_PROTO:=git | ||||||
|   | |||||||
| @@ -212,9 +212,12 @@ hostapd_common_add_bss_config() { | |||||||
|  |  | ||||||
| 	config_add_string wpa_psk_file | 	config_add_string wpa_psk_file | ||||||
|  |  | ||||||
|  | 	config_add_int multi_ap | ||||||
|  |  | ||||||
| 	config_add_boolean wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 | 	config_add_boolean wps_pushbutton wps_label ext_registrar wps_pbc_in_m1 | ||||||
| 	config_add_int wps_ap_setup_locked wps_independent | 	config_add_int wps_ap_setup_locked wps_independent | ||||||
| 	config_add_string wps_device_type wps_device_name wps_manufacturer wps_pin | 	config_add_string wps_device_type wps_device_name wps_manufacturer wps_pin | ||||||
|  | 	config_add_string multi_ap_backhaul_ssid multi_ap_backhaul_key | ||||||
|  |  | ||||||
| 	config_add_boolean ieee80211v wnm_sleep_mode bss_transition | 	config_add_boolean ieee80211v wnm_sleep_mode bss_transition | ||||||
| 	config_add_int time_advertisement | 	config_add_int time_advertisement | ||||||
| @@ -261,7 +264,8 @@ hostapd_set_bss_options() { | |||||||
| 		macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \ | 		macfilter ssid utf8_ssid wmm uapsd hidden short_preamble rsn_preauth \ | ||||||
| 		iapp_interface eapol_version dynamic_vlan ieee80211w nasid \ | 		iapp_interface eapol_version dynamic_vlan ieee80211w nasid \ | ||||||
| 		acct_server acct_secret acct_port acct_interval \ | 		acct_server acct_secret acct_port acct_interval \ | ||||||
| 		bss_load_update_period chan_util_avg_period sae_require_mfp | 		bss_load_update_period chan_util_avg_period sae_require_mfp \ | ||||||
|  | 		multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key | ||||||
|  |  | ||||||
| 	set_default isolate 0 | 	set_default isolate 0 | ||||||
| 	set_default maxassoc 0 | 	set_default maxassoc 0 | ||||||
| @@ -278,6 +282,7 @@ hostapd_set_bss_options() { | |||||||
| 	set_default bss_load_update_period 60 | 	set_default bss_load_update_period 60 | ||||||
| 	set_default chan_util_avg_period 600 | 	set_default chan_util_avg_period 600 | ||||||
| 	set_default utf8_ssid 1 | 	set_default utf8_ssid 1 | ||||||
|  | 	set_default multi_ap 0 | ||||||
|  |  | ||||||
| 	append bss_conf "ctrl_interface=/var/run/hostapd" | 	append bss_conf "ctrl_interface=/var/run/hostapd" | ||||||
| 	if [ "$isolate" -gt 0 ]; then | 	if [ "$isolate" -gt 0 ]; then | ||||||
| @@ -298,6 +303,7 @@ hostapd_set_bss_options() { | |||||||
| 	append bss_conf "ignore_broadcast_ssid=$hidden" "$N" | 	append bss_conf "ignore_broadcast_ssid=$hidden" "$N" | ||||||
| 	append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N" | 	append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N" | ||||||
| 	append bss_conf "utf8_ssid=$utf8_ssid" "$N" | 	append bss_conf "utf8_ssid=$utf8_ssid" "$N" | ||||||
|  | 	append bss_conf "multi_ap=$multi_ap" "$N" | ||||||
|  |  | ||||||
| 	[ "$tdls_prohibit" -gt 0 ] && append bss_conf "tdls_prohibit=$tdls_prohibit" "$N" | 	[ "$tdls_prohibit" -gt 0 ] && append bss_conf "tdls_prohibit=$tdls_prohibit" "$N" | ||||||
|  |  | ||||||
| @@ -420,6 +426,9 @@ hostapd_set_bss_options() { | |||||||
| 	[ "$wps_pushbutton" -gt 0 ] && append config_methods push_button | 	[ "$wps_pushbutton" -gt 0 ] && append config_methods push_button | ||||||
| 	[ "$wps_label" -gt 0 ] && append config_methods label | 	[ "$wps_label" -gt 0 ] && append config_methods label | ||||||
|  |  | ||||||
|  | 	# WPS not possible on Multi-AP backhaul-only SSID | ||||||
|  | 	[ "$multi_ap" = 1 ] && wps_possible= | ||||||
|  |  | ||||||
| 	[ -n "$wps_possible" -a -n "$config_methods" ] && { | 	[ -n "$wps_possible" -a -n "$config_methods" ] && { | ||||||
| 		set_default ext_registrar 0 | 		set_default ext_registrar 0 | ||||||
| 		set_default wps_device_type "6-0050F204-1" | 		set_default wps_device_type "6-0050F204-1" | ||||||
| @@ -442,6 +451,19 @@ hostapd_set_bss_options() { | |||||||
| 		append bss_conf "wps_independent=$wps_independent" "$N" | 		append bss_conf "wps_independent=$wps_independent" "$N" | ||||||
| 		[ -n "$wps_ap_setup_locked" ] && append bss_conf "ap_setup_locked=$wps_ap_setup_locked" "$N" | 		[ -n "$wps_ap_setup_locked" ] && append bss_conf "ap_setup_locked=$wps_ap_setup_locked" "$N" | ||||||
| 		[ "$wps_pbc_in_m1" -gt 0 ] && append bss_conf "pbc_in_m1=$wps_pbc_in_m1" "$N" | 		[ "$wps_pbc_in_m1" -gt 0 ] && append bss_conf "pbc_in_m1=$wps_pbc_in_m1" "$N" | ||||||
|  | 		[ "$multi_ap" -gt 0 ] && [ -n "$multi_ap_backhaul_ssid" ] && { | ||||||
|  | 			append bss_conf "multi_ap_backhaul_ssid=\"$multi_ap_backhaul_ssid\"" "$N" | ||||||
|  | 			if [ -z "$multi_ap_backhaul_key" ]; then | ||||||
|  | 				: | ||||||
|  | 			elif [ ${#multi_ap_backhaul_key} -lt 8 ]; then | ||||||
|  | 				wireless_setup_vif_failed INVALID_WPA_PSK | ||||||
|  | 				return 1 | ||||||
|  | 			elif [ ${#multi_ap_backhaul_key} -eq 64 ]; then | ||||||
|  | 				append bss_conf "multi_ap_backhaul_wpa_psk=$multi_ap_backhaul_key" "$N" | ||||||
|  | 			else | ||||||
|  | 				append bss_conf "multi_ap_backhaul_wpa_passphrase=$multi_ap_backhaul_key" "$N" | ||||||
|  | 			fi | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	append bss_conf "ssid=$ssid" "$N" | 	append bss_conf "ssid=$ssid" "$N" | ||||||
| @@ -640,7 +662,7 @@ wpa_supplicant_prepare_interface() { | |||||||
|  |  | ||||||
| 	_wpa_supplicant_common "$1" | 	_wpa_supplicant_common "$1" | ||||||
|  |  | ||||||
| 	json_get_vars mode wds | 	json_get_vars mode wds multi_ap | ||||||
|  |  | ||||||
| 	[ -n "$network_bridge" ] && { | 	[ -n "$network_bridge" ] && { | ||||||
| 		fail= | 		fail= | ||||||
| @@ -649,7 +671,7 @@ wpa_supplicant_prepare_interface() { | |||||||
| 				fail=1 | 				fail=1 | ||||||
| 			;; | 			;; | ||||||
| 			sta) | 			sta) | ||||||
| 				[ "$wds" = 1 ] || fail=1 | 				[ "$wds" = 1 -o "$multi_ap" = 1 ] || fail=1 | ||||||
| 			;; | 			;; | ||||||
| 		esac | 		esac | ||||||
|  |  | ||||||
| @@ -675,6 +697,12 @@ wpa_supplicant_prepare_interface() { | |||||||
| 		country_str="country=$country" | 		country_str="country=$country" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	multiap_flag_file="${_config}.is_multiap" | ||||||
|  | 	if [ "$multi_ap" = "1" ]; then | ||||||
|  | 		touch "$multiap_flag_file" | ||||||
|  | 	else | ||||||
|  | 		[ -e "$multiap_flag_file" ] && rm "$multiap_flag_file" | ||||||
|  | 	fi | ||||||
| 	wpa_supplicant_teardown_interface "$ifname" | 	wpa_supplicant_teardown_interface "$ifname" | ||||||
| 	cat > "$_config" <<EOF | 	cat > "$_config" <<EOF | ||||||
| $ap_scan | $ap_scan | ||||||
| @@ -716,9 +744,11 @@ wpa_supplicant_add_network() { | |||||||
| 	json_get_vars \ | 	json_get_vars \ | ||||||
| 		ssid bssid key \ | 		ssid bssid key \ | ||||||
| 		basic_rate mcast_rate \ | 		basic_rate mcast_rate \ | ||||||
| 		ieee80211w ieee80211r | 		ieee80211w ieee80211r \ | ||||||
|  | 		multi_ap | ||||||
|  |  | ||||||
| 	set_default ieee80211r 0 | 	set_default ieee80211r 0 | ||||||
|  | 	set_default multi_ap 0 | ||||||
|  |  | ||||||
| 	local key_mgmt='NONE' | 	local key_mgmt='NONE' | ||||||
| 	local enc_str= | 	local enc_str= | ||||||
| @@ -752,6 +782,8 @@ wpa_supplicant_add_network() { | |||||||
|  |  | ||||||
| 	[ "$_w_mode" = "adhoc" -o "$_w_mode" = "mesh" ] && append network_data "$_w_modestr" "$N$T" | 	[ "$_w_mode" = "adhoc" -o "$_w_mode" = "mesh" ] && append network_data "$_w_modestr" "$N$T" | ||||||
|  |  | ||||||
|  | 	[ "$multi_ap" = 1 -a "$_w_mode" = "sta" ] && append network_data "multi_ap_backhaul_sta=1" "$N$T" | ||||||
|  |  | ||||||
| 	case "$auth_type" in | 	case "$auth_type" in | ||||||
| 		none) ;; | 		none) ;; | ||||||
| 		owe) | 		owe) | ||||||
|   | |||||||
| @@ -48,7 +48,13 @@ if [ "$ACTION" = "pressed" -a "$BUTTON" = "wps" ]; then | |||||||
| 	wps_done=0 | 	wps_done=0 | ||||||
| 	ubusobjs="$( ubus -S list wpa_supplicant.* )" | 	ubusobjs="$( ubus -S list wpa_supplicant.* )" | ||||||
| 	for ubusobj in $ubusobjs; do | 	for ubusobj in $ubusobjs; do | ||||||
|  | 		ifname="$(echo $ubusobj | cut -d'.' -f2 )" | ||||||
|  | 		multi_ap="" | ||||||
|  | 		if [ -e "/var/run/wpa_supplicant-${ifname}.conf.is_multiap" ]; then | ||||||
|  | 			ubus -S call $ubusobj wps_start '{ "multi_ap": true }' && wps_done=1 | ||||||
|  | 		else | ||||||
| 			ubus -S call $ubusobj wps_start && wps_done=1 | 			ubus -S call $ubusobj wps_start && wps_done=1 | ||||||
|  | 		fi | ||||||
| 	done | 	done | ||||||
| 	[ $wps_done = 0 ] || wps_catch_credentials & | 	[ $wps_done = 0 ] || wps_catch_credentials & | ||||||
| fi | fi | ||||||
|   | |||||||
| @@ -0,0 +1,306 @@ | |||||||
|  | From 9c06f0f6aed26c1628acaa74df0232dd7b345e9a Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Venkateswara Naralasetty <vnaralas@codeaurora.org> | ||||||
|  | Date: Wed, 5 Dec 2018 11:23:51 +0100 | ||||||
|  | Subject: [PATCH] hostapd: Add Multi-AP protocol support | ||||||
|  |  | ||||||
|  | The purpose of Multi-AP specification is to enable inter-operability | ||||||
|  | across Wi-Fi access points (APs) from different vendors. | ||||||
|  |  | ||||||
|  | This patch introduces one new configuration parameter 'multi_ap' to | ||||||
|  | enable Multi-AP functionality and to configure the BSS as a backhaul | ||||||
|  | and/or fronthaul BSS. | ||||||
|  |  | ||||||
|  | Advertise vendor specific Multi-AP capabilities in (Re)Association | ||||||
|  | Response frame, if Multi-AP functionality is enabled through the | ||||||
|  | configuration parameter. | ||||||
|  |  | ||||||
|  | A backhaul AP must support receiving both 3addr and 4addr frames from a | ||||||
|  | backhaul STA, so create a VLAN for it just like is done for WDS, i.e., | ||||||
|  | by calling hostapd_set_wds_sta(). Since Multi-AP requires WPA2 (never | ||||||
|  | WEP), we can safely call hostapd_set_wds_encryption() as well and we can | ||||||
|  | reuse the entire WDS condition. | ||||||
|  |  | ||||||
|  | To parse the Multi-AP Extension subelement, we use get_ie(): even though | ||||||
|  | that function is meant for parsing IEs, it works for subelements. | ||||||
|  |  | ||||||
|  | Signed-off-by: Venkateswara Naralasetty <vnaralas@codeaurora.org> | ||||||
|  | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  |  hostapd/config_file.c          | 10 +++++ | ||||||
|  |  hostapd/hostapd.conf           |  7 ++++ | ||||||
|  |  src/ap/ap_config.h             |  4 ++ | ||||||
|  |  src/ap/ieee802_11.c            | 77 +++++++++++++++++++++++++++++++++- | ||||||
|  |  src/ap/sta_info.c              |  2 +- | ||||||
|  |  src/ap/sta_info.h              |  1 + | ||||||
|  |  src/common/ieee802_11_common.c | 24 +++++++++++ | ||||||
|  |  src/common/ieee802_11_common.h |  4 ++ | ||||||
|  |  src/common/ieee802_11_defs.h   |  7 ++++ | ||||||
|  |  9 files changed, 134 insertions(+), 2 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/hostapd/config_file.c | ||||||
|  | +++ b/hostapd/config_file.c | ||||||
|  | @@ -4115,6 +4115,16 @@ static int hostapd_config_fill(struct ho | ||||||
|  |  	} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) { | ||||||
|  |  		bss->coloc_intf_reporting = atoi(pos); | ||||||
|  |  #endif /* CONFIG_OWE */ | ||||||
|  | +	} else if (os_strcmp(buf, "multi_ap") == 0) { | ||||||
|  | +		int val = atoi(pos); | ||||||
|  | + | ||||||
|  | +		if (val < 0 || val > 3) { | ||||||
|  | +			wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'", | ||||||
|  | +				   line, buf); | ||||||
|  | +			return -1; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		bss->multi_ap = val; | ||||||
|  |  	} else { | ||||||
|  |  		wpa_printf(MSG_ERROR, | ||||||
|  |  			   "Line %d: unknown configuration item '%s'", | ||||||
|  | --- a/hostapd/hostapd.conf | ||||||
|  | +++ b/hostapd/hostapd.conf | ||||||
|  | @@ -438,6 +438,13 @@ wmm_ac_vo_txop_limit=47 | ||||||
|  |  wmm_ac_vo_acm=0 | ||||||
|  |  # Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 | ||||||
|  |   | ||||||
|  | +# Enable Multi-AP functionality | ||||||
|  | +# 0 = disabled (default) | ||||||
|  | +# 1 = AP support backhaul BSS | ||||||
|  | +# 2 = AP support fronthaul BSS | ||||||
|  | +# 3 = AP supports both backhaul BSS and fronthaul BSS | ||||||
|  | +#multi_ap=0 | ||||||
|  | + | ||||||
|  |  # Static WEP key configuration | ||||||
|  |  # | ||||||
|  |  # The key number to use when transmitting. | ||||||
|  | --- a/src/ap/ap_config.h | ||||||
|  | +++ b/src/ap/ap_config.h | ||||||
|  | @@ -688,6 +688,10 @@ struct hostapd_bss_config { | ||||||
|  |  #endif /* CONFIG_OWE */ | ||||||
|  |   | ||||||
|  |  	int coloc_intf_reporting; | ||||||
|  | + | ||||||
|  | +#define BACKHAUL_BSS 1 | ||||||
|  | +#define FRONTHAUL_BSS 2 | ||||||
|  | +	int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */ | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | --- a/src/ap/ieee802_11.c | ||||||
|  | +++ b/src/ap/ieee802_11.c | ||||||
|  | @@ -62,6 +62,22 @@ prepare_auth_resp_fils(struct hostapd_da | ||||||
|  |  		       int *is_pub); | ||||||
|  |  #endif /* CONFIG_FILS */ | ||||||
|  |   | ||||||
|  | + | ||||||
|  | +u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid) | ||||||
|  | +{ | ||||||
|  | +	u8 multi_ap_val = 0; | ||||||
|  | + | ||||||
|  | +	if (!hapd->conf->multi_ap) | ||||||
|  | +		return eid; | ||||||
|  | +	if (hapd->conf->multi_ap & BACKHAUL_BSS) | ||||||
|  | +		multi_ap_val |= MULTI_AP_BACKHAUL_BSS; | ||||||
|  | +	if (hapd->conf->multi_ap & FRONTHAUL_BSS) | ||||||
|  | +		multi_ap_val |= MULTI_AP_FRONTHAUL_BSS; | ||||||
|  | + | ||||||
|  | +	return eid + add_multi_ap_ie(eid, 9, multi_ap_val); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) | ||||||
|  |  { | ||||||
|  |  	u8 *pos = eid; | ||||||
|  | @@ -2210,6 +2226,57 @@ static u16 check_wmm(struct hostapd_data | ||||||
|  |  	return WLAN_STATUS_SUCCESS; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta, | ||||||
|  | +			  const u8 *multi_ap_ie, size_t multi_ap_len) | ||||||
|  | +{ | ||||||
|  | +	u8 multi_ap_value = 0; | ||||||
|  | + | ||||||
|  | +	sta->flags &= ~WLAN_STA_MULTI_AP; | ||||||
|  | + | ||||||
|  | +	if (!hapd->conf->multi_ap) | ||||||
|  | +		return WLAN_STATUS_SUCCESS; | ||||||
|  | + | ||||||
|  | +	if (multi_ap_ie) { | ||||||
|  | +		const u8 *multi_ap_subelem; | ||||||
|  | + | ||||||
|  | +		multi_ap_subelem = get_ie(multi_ap_ie + 4, | ||||||
|  | +					  multi_ap_len - 4, | ||||||
|  | +					  MULTI_AP_SUB_ELEM_TYPE); | ||||||
|  | +		if (multi_ap_subelem && multi_ap_subelem[1] == 1) { | ||||||
|  | +			multi_ap_value = multi_ap_subelem[2]; | ||||||
|  | +		} else { | ||||||
|  | +			hostapd_logger(hapd, sta->addr, | ||||||
|  | +				       HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +				       HOSTAPD_LEVEL_INFO, | ||||||
|  | +				       "Multi-AP IE has missing or invalid Multi-AP subelement"); | ||||||
|  | +			return WLAN_STATUS_INVALID_IE; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (multi_ap_value == MULTI_AP_BACKHAUL_STA) | ||||||
|  | +		sta->flags |= WLAN_STA_MULTI_AP; | ||||||
|  | + | ||||||
|  | +	if ((hapd->conf->multi_ap & BACKHAUL_BSS) && | ||||||
|  | +	    multi_ap_value == MULTI_AP_BACKHAUL_STA) | ||||||
|  | +		return WLAN_STATUS_SUCCESS; | ||||||
|  | + | ||||||
|  | +	if (hapd->conf->multi_ap & FRONTHAUL_BSS) { | ||||||
|  | +		if (multi_ap_value == MULTI_AP_BACKHAUL_STA) { | ||||||
|  | +			hostapd_logger(hapd, sta->addr, | ||||||
|  | +				       HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +				       HOSTAPD_LEVEL_INFO, | ||||||
|  | +				       "Backhaul STA tries to associate with fronthaul-only BSS"); | ||||||
|  | +			return WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||||||
|  | +		} | ||||||
|  | +		return WLAN_STATUS_SUCCESS; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +		       HOSTAPD_LEVEL_INFO, | ||||||
|  | +		       "Non-Multi-AP STA tries to associate with backhaul-only BSS"); | ||||||
|  | +	return WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |   | ||||||
|  |  static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, | ||||||
|  |  			   struct ieee802_11_elems *elems) | ||||||
|  | @@ -2466,6 +2533,11 @@ static u16 check_assoc_ies(struct hostap | ||||||
|  |  	resp = copy_supp_rates(hapd, sta, &elems); | ||||||
|  |  	if (resp != WLAN_STATUS_SUCCESS) | ||||||
|  |  		return resp; | ||||||
|  | + | ||||||
|  | +	resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len); | ||||||
|  | +	if (resp != WLAN_STATUS_SUCCESS) | ||||||
|  | +		return resp; | ||||||
|  | + | ||||||
|  |  #ifdef CONFIG_IEEE80211N | ||||||
|  |  	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); | ||||||
|  |  	if (resp != WLAN_STATUS_SUCCESS) | ||||||
|  | @@ -2996,6 +3068,9 @@ static u16 send_assoc_resp(struct hostap | ||||||
|  |  	} | ||||||
|  |  #endif /* CONFIG_WPS */ | ||||||
|  |   | ||||||
|  | +	if (sta && (sta->flags & WLAN_STA_MULTI_AP)) | ||||||
|  | +		p = hostapd_eid_multi_ap(hapd, p); | ||||||
|  | + | ||||||
|  |  #ifdef CONFIG_P2P | ||||||
|  |  	if (sta && sta->p2p_ie && hapd->p2p_group) { | ||||||
|  |  		struct wpabuf *p2p_resp_ie; | ||||||
|  | @@ -4236,7 +4311,7 @@ static void handle_assoc_cb(struct hosta | ||||||
|  |  		sta->flags |= WLAN_STA_WDS; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	if (sta->flags & WLAN_STA_WDS) { | ||||||
|  | +	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) { | ||||||
|  |  		int ret; | ||||||
|  |  		char ifname_wds[IFNAMSIZ + 1]; | ||||||
|  |   | ||||||
|  | --- a/src/ap/sta_info.c | ||||||
|  | +++ b/src/ap/sta_info.c | ||||||
|  | @@ -166,7 +166,7 @@ void ap_free_sta(struct hostapd_data *ha | ||||||
|  |  	/* just in case */ | ||||||
|  |  	ap_sta_set_authorized(hapd, sta, 0); | ||||||
|  |   | ||||||
|  | -	if (sta->flags & WLAN_STA_WDS) | ||||||
|  | +	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) | ||||||
|  |  		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); | ||||||
|  |   | ||||||
|  |  	if (sta->ipaddr) | ||||||
|  | --- a/src/ap/sta_info.h | ||||||
|  | +++ b/src/ap/sta_info.h | ||||||
|  | @@ -36,6 +36,7 @@ | ||||||
|  |  #define WLAN_STA_VHT_OPMODE_ENABLED BIT(20) | ||||||
|  |  #define WLAN_STA_VENDOR_VHT BIT(21) | ||||||
|  |  #define WLAN_STA_PENDING_FILS_ERP BIT(22) | ||||||
|  | +#define WLAN_STA_MULTI_AP BIT(23) | ||||||
|  |  #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) | ||||||
|  |  #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) | ||||||
|  |  #define WLAN_STA_NONERP BIT(31) | ||||||
|  | --- a/src/common/ieee802_11_common.c | ||||||
|  | +++ b/src/common/ieee802_11_common.c | ||||||
|  | @@ -126,6 +126,10 @@ static int ieee802_11_parse_vendor_speci | ||||||
|  |  			elems->roaming_cons_sel = pos; | ||||||
|  |  			elems->roaming_cons_sel_len = elen; | ||||||
|  |  			break; | ||||||
|  | +		case MULTI_AP_OUI_TYPE: | ||||||
|  | +			elems->multi_ap = pos; | ||||||
|  | +			elems->multi_ap_len = elen; | ||||||
|  | +			break; | ||||||
|  |  		default: | ||||||
|  |  			wpa_printf(MSG_MSGDUMP, "Unknown WFA " | ||||||
|  |  				   "information element ignored " | ||||||
|  | @@ -1519,6 +1523,26 @@ size_t mbo_add_ie(u8 *buf, size_t len, c | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | +size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value) | ||||||
|  | +{ | ||||||
|  | +	u8 *pos = buf; | ||||||
|  | + | ||||||
|  | +	if (len < 9) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	*pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||||||
|  | +	*pos++ = 7; /* len */ | ||||||
|  | +	WPA_PUT_BE24(pos, OUI_WFA); | ||||||
|  | +	pos += 3; | ||||||
|  | +	*pos++ = MULTI_AP_OUI_TYPE; | ||||||
|  | +	*pos++ = MULTI_AP_SUB_ELEM_TYPE; | ||||||
|  | +	*pos++ = 1; /* len */ | ||||||
|  | +	*pos++ = value; | ||||||
|  | + | ||||||
|  | +	return pos - buf; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  static const struct country_op_class us_op_class[] = { | ||||||
|  |  	{ 1, 115 }, | ||||||
|  |  	{ 2, 118 }, | ||||||
|  | --- a/src/common/ieee802_11_common.h | ||||||
|  | +++ b/src/common/ieee802_11_common.h | ||||||
|  | @@ -84,6 +84,7 @@ struct ieee802_11_elems { | ||||||
|  |  	const u8 *power_capab; | ||||||
|  |  	const u8 *roaming_cons_sel; | ||||||
|  |  	const u8 *password_id; | ||||||
|  | +	const u8 *multi_ap; | ||||||
|  |   | ||||||
|  |  	u8 ssid_len; | ||||||
|  |  	u8 supp_rates_len; | ||||||
|  | @@ -130,6 +131,7 @@ struct ieee802_11_elems { | ||||||
|  |  	u8 power_capab_len; | ||||||
|  |  	u8 roaming_cons_sel_len; | ||||||
|  |  	u8 password_id_len; | ||||||
|  | +	u8 multi_ap_len; | ||||||
|  |   | ||||||
|  |  	struct mb_ies_info mb_ies; | ||||||
|  |  }; | ||||||
|  | @@ -189,6 +191,8 @@ const u8 * get_ie_ext(const u8 *ies, siz | ||||||
|  |   | ||||||
|  |  size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); | ||||||
|  |   | ||||||
|  | +size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value); | ||||||
|  | + | ||||||
|  |  struct country_op_class { | ||||||
|  |  	u8 country_op_class; | ||||||
|  |  	u8 global_op_class; | ||||||
|  | --- a/src/common/ieee802_11_defs.h | ||||||
|  | +++ b/src/common/ieee802_11_defs.h | ||||||
|  | @@ -1210,6 +1210,13 @@ struct ieee80211_ampe_ie { | ||||||
|  |  #define MBO_OUI_TYPE 22 | ||||||
|  |  #define OWE_IE_VENDOR_TYPE 0x506f9a1c | ||||||
|  |  #define OWE_OUI_TYPE 28 | ||||||
|  | +#define MULTI_AP_OUI_TYPE 0x1B | ||||||
|  | + | ||||||
|  | +#define MULTI_AP_SUB_ELEM_TYPE 0x06 | ||||||
|  | +#define MULTI_AP_TEAR_DOWN BIT(4) | ||||||
|  | +#define MULTI_AP_FRONTHAUL_BSS BIT(5) | ||||||
|  | +#define MULTI_AP_BACKHAUL_BSS BIT(6) | ||||||
|  | +#define MULTI_AP_BACKHAUL_STA BIT(7) | ||||||
|  |   | ||||||
|  |  #define WMM_OUI_TYPE 2 | ||||||
|  |  #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 | ||||||
| @@ -0,0 +1,311 @@ | |||||||
|  | From 5abc7823bd01f69b8afbe1fd19f65fff86137c44 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Venkateswara Naralasetty <vnaralas@codeaurora.org> | ||||||
|  | Date: Wed, 5 Dec 2018 11:23:53 +0100 | ||||||
|  | Subject: [PATCH] wpa_supplicant: Add Multi-AP backhaul STA support | ||||||
|  |  | ||||||
|  | Advertise vendor specific Multi-AP IE in (Re)Association Request frames | ||||||
|  | and process Multi-AP IE from (Re)Association Response frames if the user | ||||||
|  | enables Multi-AP fuctionality. If the (Re)Association Response frame | ||||||
|  | does not contain the Multi-AP IE, disassociate. | ||||||
|  |  | ||||||
|  | This adds a new configuration parameter 'multi_ap_backhaul_sta' to | ||||||
|  | enable/disable Multi-AP functionality. | ||||||
|  |  | ||||||
|  | Enable 4-address mode after association (if the Association Response | ||||||
|  | frame contains the Multi-AP IE). Also enable the bridge in that case. | ||||||
|  | This is necessary because wpa_supplicant only enables the bridge in | ||||||
|  | wpa_drv_if_add(), which only gets called when an interface is added | ||||||
|  | through the control interface, not when it is configured from the | ||||||
|  | command line. | ||||||
|  |  | ||||||
|  | Signed-off-by: Venkateswara Naralasetty <vnaralas@codeaurora.org> | ||||||
|  | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  |  src/drivers/driver.h               |  9 ++++++ | ||||||
|  |  src/drivers/driver_nl80211.c       | 44 ++++++++++++++++++++++++++ | ||||||
|  |  wpa_supplicant/config.c            |  1 + | ||||||
|  |  wpa_supplicant/config_ssid.h       |  7 +++++ | ||||||
|  |  wpa_supplicant/driver_i.h          |  8 +++++ | ||||||
|  |  wpa_supplicant/events.c            | 50 ++++++++++++++++++++++++++++++ | ||||||
|  |  wpa_supplicant/sme.c               | 16 ++++++++++ | ||||||
|  |  wpa_supplicant/wpa_supplicant.c    | 18 +++++++++++ | ||||||
|  |  wpa_supplicant/wpa_supplicant.conf |  7 +++++ | ||||||
|  |  wpa_supplicant/wpa_supplicant_i.h  |  1 + | ||||||
|  |  10 files changed, 161 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/src/drivers/driver.h | ||||||
|  | +++ b/src/drivers/driver.h | ||||||
|  | @@ -4100,6 +4100,15 @@ struct wpa_driver_ops { | ||||||
|  |  	 */ | ||||||
|  |  	int (*send_external_auth_status)(void *priv, | ||||||
|  |  					 struct external_auth *params); | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  | +	 * set_4addr_mode - Set 4-address mode | ||||||
|  | +	 * @priv: Private driver interface data | ||||||
|  | +	 * @bridge_ifname: Bridge interface name | ||||||
|  | +	 * @val: 0 - disable 4addr mode, 1 - enable 4addr mode | ||||||
|  | +	 * Returns: 0 on success, < 0 on failure | ||||||
|  | +	 */ | ||||||
|  | +	int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val); | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | --- a/src/drivers/driver_nl80211.c | ||||||
|  | +++ b/src/drivers/driver_nl80211.c | ||||||
|  | @@ -10728,6 +10728,49 @@ fail: | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | +static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname, | ||||||
|  | +				  int val) | ||||||
|  | +{ | ||||||
|  | +	struct i802_bss *bss = priv; | ||||||
|  | +	struct wpa_driver_nl80211_data *drv = bss->drv; | ||||||
|  | +	struct nl_msg *msg; | ||||||
|  | +	int ret = -ENOBUFS; | ||||||
|  | + | ||||||
|  | +	wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)", | ||||||
|  | +		   val ? "Enable" : "Disable", bridge_ifname); | ||||||
|  | + | ||||||
|  | +	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE); | ||||||
|  | +	if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val)) | ||||||
|  | +		goto fail; | ||||||
|  | + | ||||||
|  | +	if (bridge_ifname[0] && bss->added_if_into_bridge && !val) { | ||||||
|  | +		if (linux_br_del_if(drv->global->ioctl_sock, | ||||||
|  | +				    bridge_ifname, bss->ifname)) { | ||||||
|  | +			wpa_printf(MSG_ERROR, | ||||||
|  | +				   "nl80211: Failed to remove interface %s from bridge %s", | ||||||
|  | +				   bss->ifname, bridge_ifname); | ||||||
|  | +			return -1; | ||||||
|  | +		} | ||||||
|  | +		bss->added_if_into_bridge = 0; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = send_and_recv_msgs(drv, msg, NULL, NULL); | ||||||
|  | +	msg = NULL; | ||||||
|  | +	if (!ret) { | ||||||
|  | +		if (bridge_ifname[0] && val && | ||||||
|  | +		    i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0) | ||||||
|  | +			return -1; | ||||||
|  | +		return 0; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +fail: | ||||||
|  | +	nlmsg_free(msg); | ||||||
|  | +	wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr"); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  const struct wpa_driver_ops wpa_driver_nl80211_ops = { | ||||||
|  |  	.name = "nl80211", | ||||||
|  |  	.desc = "Linux nl80211/cfg80211", | ||||||
|  | @@ -10856,4 +10899,5 @@ const struct wpa_driver_ops wpa_driver_n | ||||||
|  |  	.get_ext_capab = nl80211_get_ext_capab, | ||||||
|  |  	.update_connect_params = nl80211_update_connection_params, | ||||||
|  |  	.send_external_auth_status = nl80211_send_external_auth_status, | ||||||
|  | +	.set_4addr_mode = nl80211_set_4addr_mode, | ||||||
|  |  }; | ||||||
|  | --- a/wpa_supplicant/config.c | ||||||
|  | +++ b/wpa_supplicant/config.c | ||||||
|  | @@ -2416,6 +2416,7 @@ static const struct parse_data ssid_fiel | ||||||
|  |  #endif /* CONFIG_DPP */ | ||||||
|  |  	{ INT_RANGE(owe_group, 0, 65535) }, | ||||||
|  |  	{ INT_RANGE(owe_only, 0, 1) }, | ||||||
|  | +	{ INT_RANGE(multi_ap_backhaul_sta, 0, 1) }, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  #undef OFFSET | ||||||
|  | --- a/wpa_supplicant/config_ssid.h | ||||||
|  | +++ b/wpa_supplicant/config_ssid.h | ||||||
|  | @@ -950,6 +950,13 @@ struct wpa_ssid { | ||||||
|  |  	 * the selection attempts for OWE BSS exceed the configured threshold. | ||||||
|  |  	 */ | ||||||
|  |  	int owe_transition_bss_select_count; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  | +	 * multi_ap_backhaul_sta - Multi-AP backhaul STA | ||||||
|  | +	 * 0 = normal (non-Multi-AP) station | ||||||
|  | +	 * 1 = Multi-AP backhaul station | ||||||
|  | +	 */ | ||||||
|  | +	int multi_ap_backhaul_sta; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  #endif /* CONFIG_SSID_H */ | ||||||
|  | --- a/wpa_supplicant/driver_i.h | ||||||
|  | +++ b/wpa_supplicant/driver_i.h | ||||||
|  | @@ -1046,4 +1046,12 @@ wpa_drv_send_external_auth_status(struct | ||||||
|  |  							params); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val) | ||||||
|  | +{ | ||||||
|  | +	if (!wpa_s->driver->set_4addr_mode) | ||||||
|  | +		return -1; | ||||||
|  | +	return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv, | ||||||
|  | +					     wpa_s->bridge_ifname, val); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  #endif /* DRIVER_I_H */ | ||||||
|  | --- a/wpa_supplicant/events.c | ||||||
|  | +++ b/wpa_supplicant/events.c | ||||||
|  | @@ -324,6 +324,9 @@ void wpa_supplicant_mark_disassoc(struct | ||||||
|  |  	os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk)); | ||||||
|  |  #endif /* CONFIG_TESTING_OPTIONS */ | ||||||
|  |  	wpa_s->ieee80211ac = 0; | ||||||
|  | + | ||||||
|  | +	if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) | ||||||
|  | +		wpa_s->enabled_4addr_mode = 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | @@ -2267,6 +2270,50 @@ static void interworking_process_assoc_r | ||||||
|  |  #endif /* CONFIG_INTERWORKING */ | ||||||
|  |   | ||||||
|  |   | ||||||
|  | +static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, | ||||||
|  | +					const u8 *ies, size_t ies_len) | ||||||
|  | +{ | ||||||
|  | +	struct ieee802_11_elems elems; | ||||||
|  | +	const u8 *map_sub_elem, *pos; | ||||||
|  | +	size_t len; | ||||||
|  | + | ||||||
|  | +	if (!wpa_s->current_ssid || | ||||||
|  | +	    !wpa_s->current_ssid->multi_ap_backhaul_sta || | ||||||
|  | +	    !ies || | ||||||
|  | +	    ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	if (!elems.multi_ap || elems.multi_ap_len < 7) { | ||||||
|  | +		wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol"); | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	pos = elems.multi_ap + 4; | ||||||
|  | +	len = elems.multi_ap_len - 4; | ||||||
|  | + | ||||||
|  | +	map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE); | ||||||
|  | +	if (!map_sub_elem || map_sub_elem[1] < 1) { | ||||||
|  | +		wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type"); | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) { | ||||||
|  | +		wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS"); | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) { | ||||||
|  | +		wpa_printf(MSG_ERROR, "Failed to set 4addr mode"); | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | +	wpa_s->enabled_4addr_mode = 1; | ||||||
|  | +	return; | ||||||
|  | + | ||||||
|  | +fail: | ||||||
|  | +	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  |  #ifdef CONFIG_FST | ||||||
|  |  static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s, | ||||||
|  |  				const u8 *ie, size_t ie_len) | ||||||
|  | @@ -2343,6 +2390,9 @@ static int wpa_supplicant_event_associnf | ||||||
|  |  		    get_ie(data->assoc_info.resp_ies, | ||||||
|  |  			   data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP)) | ||||||
|  |  			wpa_s->ieee80211ac = 1; | ||||||
|  | + | ||||||
|  | +		multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, | ||||||
|  | +					    data->assoc_info.resp_ies_len); | ||||||
|  |  	} | ||||||
|  |  	if (data->assoc_info.beacon_ies) | ||||||
|  |  		wpa_hexdump(MSG_DEBUG, "beacon_ies", | ||||||
|  | --- a/wpa_supplicant/sme.c | ||||||
|  | +++ b/wpa_supplicant/sme.c | ||||||
|  | @@ -1552,6 +1552,22 @@ void sme_associate(struct wpa_supplicant | ||||||
|  |  	} | ||||||
|  |  #endif /* CONFIG_OWE */ | ||||||
|  |   | ||||||
|  | +	if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) { | ||||||
|  | +		size_t multi_ap_ie_len; | ||||||
|  | + | ||||||
|  | +		multi_ap_ie_len = add_multi_ap_ie( | ||||||
|  | +			wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, | ||||||
|  | +			sizeof(wpa_s->sme.assoc_req_ie) - | ||||||
|  | +			wpa_s->sme.assoc_req_ie_len, | ||||||
|  | +			MULTI_AP_BACKHAUL_STA); | ||||||
|  | +		if (multi_ap_ie_len == 0) { | ||||||
|  | +			wpa_printf(MSG_ERROR, | ||||||
|  | +				   "Multi-AP: Failed to build Multi-AP IE"); | ||||||
|  | +			return; | ||||||
|  | +		} | ||||||
|  | +		wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	params.bssid = bssid; | ||||||
|  |  	params.ssid = wpa_s->sme.ssid; | ||||||
|  |  	params.ssid_len = wpa_s->sme.ssid_len; | ||||||
|  | --- a/wpa_supplicant/wpa_supplicant.c | ||||||
|  | +++ b/wpa_supplicant/wpa_supplicant.c | ||||||
|  | @@ -2893,6 +2893,21 @@ static u8 * wpas_populate_assoc_ies( | ||||||
|  |  	} | ||||||
|  |  #endif /* CONFIG_IEEE80211R */ | ||||||
|  |   | ||||||
|  | +	if (ssid->multi_ap_backhaul_sta) { | ||||||
|  | +		size_t multi_ap_ie_len; | ||||||
|  | + | ||||||
|  | +		multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len, | ||||||
|  | +						  max_wpa_ie_len - wpa_ie_len, | ||||||
|  | +						  MULTI_AP_BACKHAUL_STA); | ||||||
|  | +		if (multi_ap_ie_len == 0) { | ||||||
|  | +			wpa_printf(MSG_ERROR, | ||||||
|  | +				   "Multi-AP: Failed to build Multi-AP IE"); | ||||||
|  | +			os_free(wpa_ie); | ||||||
|  | +			return NULL; | ||||||
|  | +		} | ||||||
|  | +		wpa_ie_len += multi_ap_ie_len; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	params->wpa_ie = wpa_ie; | ||||||
|  |  	params->wpa_ie_len = wpa_ie_len; | ||||||
|  |  	params->auth_alg = algs; | ||||||
|  | @@ -3377,6 +3392,9 @@ void wpa_supplicant_deauthenticate(struc | ||||||
|  |  		zero_addr = 1; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) | ||||||
|  | +		wpa_s->enabled_4addr_mode = 0; | ||||||
|  | + | ||||||
|  |  #ifdef CONFIG_TDLS | ||||||
|  |  	wpa_tdls_teardown_peers(wpa_s->wpa); | ||||||
|  |  #endif /* CONFIG_TDLS */ | ||||||
|  | --- a/wpa_supplicant/wpa_supplicant.conf | ||||||
|  | +++ b/wpa_supplicant/wpa_supplicant.conf | ||||||
|  | @@ -1399,6 +1399,13 @@ fast_reauth=1 | ||||||
|  |  #  2: MCS 0-9 | ||||||
|  |  #  3: not supported | ||||||
|  |   | ||||||
|  | +# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality | ||||||
|  | +# 0 = normal STA (default) | ||||||
|  | +# 1 = backhaul STA | ||||||
|  | +# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not | ||||||
|  | +# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be | ||||||
|  | +# added to a bridge to allow forwarding frames over this backhaul link. | ||||||
|  | + | ||||||
|  |  ##### Fast Session Transfer (FST) support ##################################### | ||||||
|  |  # | ||||||
|  |  # The options in this section are only available when the build configuration | ||||||
|  | --- a/wpa_supplicant/wpa_supplicant_i.h | ||||||
|  | +++ b/wpa_supplicant/wpa_supplicant_i.h | ||||||
|  | @@ -1242,6 +1242,7 @@ struct wpa_supplicant { | ||||||
|  |  	unsigned int disable_fils:1; | ||||||
|  |  #endif /* CONFIG_FILS */ | ||||||
|  |  	unsigned int ieee80211ac:1; | ||||||
|  | +	unsigned int enabled_4addr_mode:1; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |   | ||||||
| @@ -0,0 +1,100 @@ | |||||||
|  | From 7488e0ade6dffb6df4c1fb6526a9f3ede0eb18ef Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Jouni Malinen <jouni@codeaurora.org> | ||||||
|  | Date: Thu, 20 Dec 2018 12:41:00 +0200 | ||||||
|  | Subject: [PATCH] tests: Multi-AP association | ||||||
|  |  | ||||||
|  | Signed-off-by: Jouni Malinen <jouni@codeaurora.org> | ||||||
|  | --- | ||||||
|  |  tests/hwsim/test_multi_ap.py | 73 ++++++++++++++++++++++++++++++++++++ | ||||||
|  |  tests/hwsim/wpasupplicant.py |  3 +- | ||||||
|  |  2 files changed, 75 insertions(+), 1 deletion(-) | ||||||
|  |  create mode 100644 tests/hwsim/test_multi_ap.py | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/tests/hwsim/test_multi_ap.py | ||||||
|  | @@ -0,0 +1,73 @@ | ||||||
|  | +# Test cases for Multi-AP | ||||||
|  | +# Copyright (c) 2018, The Linux Foundation | ||||||
|  | +# | ||||||
|  | +# This software may be distributed under the terms of the BSD license. | ||||||
|  | +# See README for more details. | ||||||
|  | + | ||||||
|  | +import hostapd | ||||||
|  | + | ||||||
|  | +def test_multi_ap_association(dev, apdev): | ||||||
|  | +    """Multi-AP association in backhaul BSS""" | ||||||
|  | +    run_multi_ap_association(dev, apdev, 1) | ||||||
|  | +    dev[1].connect("multi-ap", psk="12345678", scan_freq="2412", | ||||||
|  | +                   wait_connect=False) | ||||||
|  | +    ev = dev[1].wait_event([ "CTRL-EVENT-DISCONNECTED", | ||||||
|  | +                             "CTRL-EVENT-CONNECTED", | ||||||
|  | +                             "CTRL-EVENT-ASSOC-REJECT" ], | ||||||
|  | +                           timeout=5) | ||||||
|  | +    dev[1].request("DISCONNECT") | ||||||
|  | +    if ev is None: | ||||||
|  | +        raise Exception("Connection result not reported") | ||||||
|  | +    if "CTRL-EVENT-ASSOC-REJECT" not in ev: | ||||||
|  | +        raise Exception("Association rejection not reported") | ||||||
|  | +    if "status_code=12" not in ev: | ||||||
|  | +        raise Exception("Unexpected association status code: " + ev) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_association_shared_bss(dev, apdev): | ||||||
|  | +    """Multi-AP association in backhaul BSS (with fronthaul BSS enabled)""" | ||||||
|  | +    run_multi_ap_association(dev, apdev, 3) | ||||||
|  | +    dev[1].connect("multi-ap", psk="12345678", scan_freq="2412") | ||||||
|  | + | ||||||
|  | +def run_multi_ap_association(dev, apdev, multi_ap): | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | +    params["multi_ap"] = str(multi_ap) | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | + | ||||||
|  | +    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | +                   scan_freq="2412") | ||||||
|  | + | ||||||
|  | +def test_multi_ap_disabled_on_ap(dev, apdev): | ||||||
|  | +    """Multi-AP association attempt when disabled on AP""" | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | + | ||||||
|  | +    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | +                   scan_freq="2412", wait_connect=False) | ||||||
|  | +    ev = dev[0].wait_event([ "CTRL-EVENT-DISCONNECTED", | ||||||
|  | +                             "CTRL-EVENT-CONNECTED" ], | ||||||
|  | +                           timeout=5) | ||||||
|  | +    dev[0].request("DISCONNECT") | ||||||
|  | +    if ev is None: | ||||||
|  | +        raise Exception("Connection result not reported") | ||||||
|  | +    if "CTRL-EVENT-DISCONNECTED" not in ev: | ||||||
|  | +        raise Exception("Unexpected connection result") | ||||||
|  | + | ||||||
|  | +def test_multi_ap_fronthaul_on_ap(dev, apdev): | ||||||
|  | +    """Multi-AP association attempt when only fronthaul BSS on AP""" | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | +    params["multi_ap"] = "2" | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | + | ||||||
|  | +    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | +                   scan_freq="2412", wait_connect=False) | ||||||
|  | +    ev = dev[0].wait_event([ "CTRL-EVENT-DISCONNECTED", | ||||||
|  | +                             "CTRL-EVENT-CONNECTED", | ||||||
|  | +                             "CTRL-EVENT-ASSOC-REJECT" ], | ||||||
|  | +                           timeout=5) | ||||||
|  | +    dev[0].request("DISCONNECT") | ||||||
|  | +    if ev is None: | ||||||
|  | +        raise Exception("Connection result not reported") | ||||||
|  | +    if "CTRL-EVENT-ASSOC-REJECT" not in ev: | ||||||
|  | +        raise Exception("Association rejection not reported") | ||||||
|  | +    if "status_code=12" not in ev: | ||||||
|  | +        raise Exception("Unexpected association status code: " + ev) | ||||||
|  | --- a/tests/hwsim/wpasupplicant.py | ||||||
|  | +++ b/tests/hwsim/wpasupplicant.py | ||||||
|  | @@ -1031,7 +1031,8 @@ class WpaSupplicant: | ||||||
|  |                         "dpp_csign", "dpp_csign_expiry", | ||||||
|  |                         "dpp_netaccesskey", "dpp_netaccesskey_expiry", | ||||||
|  |                         "group_mgmt", "owe_group", | ||||||
|  | -                       "roaming_consortium_selection" ] | ||||||
|  | +                       "roaming_consortium_selection", "multi_ap_backhaul_sta" ] | ||||||
|  | + | ||||||
|  |          for field in not_quoted: | ||||||
|  |              if field in kwargs and kwargs[field]: | ||||||
|  |                  self.set_network(id, field, kwargs[field]) | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | From 0f5029ff41ef286aa7b3e4a3efd3f1a16be925e8 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Arnout Vandecappelle (Essensium/Mind)" <arnout@mind.be> | ||||||
|  | Date: Wed, 9 Jan 2019 18:41:08 +0100 | ||||||
|  | Subject: [PATCH] tests: refactor test_multi_ap | ||||||
|  |  | ||||||
|  | With just one additional argument, the run_multi_ap_association function | ||||||
|  | can be used for all tests. | ||||||
|  |  | ||||||
|  | While we're at it, also move it to the top of the file. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: new patch | ||||||
|  | --- | ||||||
|  |  tests/hwsim/test_multi_ap.py | 30 +++++++++++------------------- | ||||||
|  |  1 file changed, 11 insertions(+), 19 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/tests/hwsim/test_multi_ap.py | ||||||
|  | +++ b/tests/hwsim/test_multi_ap.py | ||||||
|  | @@ -6,6 +6,15 @@ | ||||||
|  |   | ||||||
|  |  import hostapd | ||||||
|  |   | ||||||
|  | +def run_multi_ap_association(dev, apdev, multi_ap, wait_connect=True): | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | +    if multi_ap: | ||||||
|  | +        params["multi_ap"] = str(multi_ap) | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | + | ||||||
|  | +    dev[0].connect("multi-ap", psk="12345678", scan_freq="2412", | ||||||
|  | +                   multi_ap_backhaul_sta="1", wait_connect=wait_connect) | ||||||
|  | + | ||||||
|  |  def test_multi_ap_association(dev, apdev): | ||||||
|  |      """Multi-AP association in backhaul BSS""" | ||||||
|  |      run_multi_ap_association(dev, apdev, 1) | ||||||
|  | @@ -28,21 +37,9 @@ def test_multi_ap_association_shared_bss | ||||||
|  |      run_multi_ap_association(dev, apdev, 3) | ||||||
|  |      dev[1].connect("multi-ap", psk="12345678", scan_freq="2412") | ||||||
|  |   | ||||||
|  | -def run_multi_ap_association(dev, apdev, multi_ap): | ||||||
|  | -    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | -    params["multi_ap"] = str(multi_ap) | ||||||
|  | -    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | - | ||||||
|  | -    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | -                   scan_freq="2412") | ||||||
|  | - | ||||||
|  |  def test_multi_ap_disabled_on_ap(dev, apdev): | ||||||
|  |      """Multi-AP association attempt when disabled on AP""" | ||||||
|  | -    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | -    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | - | ||||||
|  | -    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | -                   scan_freq="2412", wait_connect=False) | ||||||
|  | +    run_multi_ap_association(dev, apdev, 0, wait_connect=False) | ||||||
|  |      ev = dev[0].wait_event([ "CTRL-EVENT-DISCONNECTED", | ||||||
|  |                               "CTRL-EVENT-CONNECTED" ], | ||||||
|  |                             timeout=5) | ||||||
|  | @@ -54,12 +51,7 @@ def test_multi_ap_disabled_on_ap(dev, ap | ||||||
|  |   | ||||||
|  |  def test_multi_ap_fronthaul_on_ap(dev, apdev): | ||||||
|  |      """Multi-AP association attempt when only fronthaul BSS on AP""" | ||||||
|  | -    params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678") | ||||||
|  | -    params["multi_ap"] = "2" | ||||||
|  | -    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | - | ||||||
|  | -    dev[0].connect("multi-ap", psk="12345678", multi_ap_backhaul_sta="1", | ||||||
|  | -                   scan_freq="2412", wait_connect=False) | ||||||
|  | +    run_multi_ap_association(dev, apdev, 2, wait_connect=False) | ||||||
|  |      ev = dev[0].wait_event([ "CTRL-EVENT-DISCONNECTED", | ||||||
|  |                               "CTRL-EVENT-CONNECTED", | ||||||
|  |                               "CTRL-EVENT-ASSOC-REJECT" ], | ||||||
| @@ -0,0 +1,106 @@ | |||||||
|  | From 71b061b8a13791a1ed858d924e401541c8584030 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Arnout Vandecappelle (Essensium/Mind)" <arnout@mind.be> | ||||||
|  | Date: Wed, 9 Jan 2019 19:08:00 +0100 | ||||||
|  | Subject: [PATCH] multi_ap: don't reject backhaul STA on fronhaul BSS | ||||||
|  |  | ||||||
|  | The Multi-AP specification only specifies that information elements have | ||||||
|  | to be added to the association requests and responses; it doesn't | ||||||
|  | specify anything about what should be done in case they are missing. | ||||||
|  | Currently, we reject non-backhaul associations on a backhaul-only BSS, | ||||||
|  | and non-fronthaul associations on a fronthaul-only BSS. | ||||||
|  |  | ||||||
|  | However, this makes WPS fail when fronthaul and backhaul are separate | ||||||
|  | SSIDs. Indeed, WPS for the backhaul link is performed on the *fronthaul* | ||||||
|  | SSID. Thus, the association request used for WPS *will* contain the | ||||||
|  | Multi-AP IE indicating a backhaul STA. Rejecting that association makes | ||||||
|  | WPS fail. | ||||||
|  |  | ||||||
|  | Therefore, accept a multi-AP backhaul STA association request on a | ||||||
|  | fronthaul-only BSS. Still issue a warning about it, but only at level | ||||||
|  | DEBUG intead of INFO. Also change the condition checking to make it | ||||||
|  | clearer. | ||||||
|  |  | ||||||
|  | While we're at it, also fix the handling of unexpected bits in the | ||||||
|  | Multi-AP IE. 4 bits are reserved in the specification, so these | ||||||
|  | certainly have to be ignored. The specification also doesn't say that | ||||||
|  | setting one of the other bits is not allowed. Therefore, only report | ||||||
|  | unexpected values in the Multi-AP IE, don't reject because of it. | ||||||
|  | Note that a malformed IE (containing more than one byte) still triggers | ||||||
|  | a rejection. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: new patch | ||||||
|  |  | ||||||
|  | Cfr. discussion on http://lists.infradead.org/pipermail/hostap/2019-January/039232.html | ||||||
|  | and follow-ups. | ||||||
|  | --- | ||||||
|  |  src/ap/ieee802_11.c          | 38 +++++++++++++++++++----------------- | ||||||
|  |  tests/hwsim/test_multi_ap.py |  6 ++---- | ||||||
|  |  2 files changed, 22 insertions(+), 22 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/src/ap/ieee802_11.c | ||||||
|  | +++ b/src/ap/ieee802_11.c | ||||||
|  | @@ -2253,28 +2253,30 @@ static u16 check_multi_ap(struct hostapd | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	if (multi_ap_value == MULTI_AP_BACKHAUL_STA) | ||||||
|  | -		sta->flags |= WLAN_STA_MULTI_AP; | ||||||
|  | - | ||||||
|  | -	if ((hapd->conf->multi_ap & BACKHAUL_BSS) && | ||||||
|  | -	    multi_ap_value == MULTI_AP_BACKHAUL_STA) | ||||||
|  | -		return WLAN_STATUS_SUCCESS; | ||||||
|  | - | ||||||
|  | -	if (hapd->conf->multi_ap & FRONTHAUL_BSS) { | ||||||
|  | -		if (multi_ap_value == MULTI_AP_BACKHAUL_STA) { | ||||||
|  | -			hostapd_logger(hapd, sta->addr, | ||||||
|  | -				       HOSTAPD_MODULE_IEEE80211, | ||||||
|  | -				       HOSTAPD_LEVEL_INFO, | ||||||
|  | -				       "Backhaul STA tries to associate with fronthaul-only BSS"); | ||||||
|  | -			return WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||||||
|  | -		} | ||||||
|  | -		return WLAN_STATUS_SUCCESS; | ||||||
|  | +	if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA) | ||||||
|  | +		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +			       HOSTAPD_LEVEL_INFO, | ||||||
|  | +			       "Multi-AP IE with unexpected value 0x%02x", | ||||||
|  | +			       multi_ap_value); | ||||||
|  | + | ||||||
|  | +	if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) { | ||||||
|  | +		if (hapd->conf->multi_ap & FRONTHAUL_BSS) | ||||||
|  | +			return WLAN_STATUS_SUCCESS; | ||||||
|  | + | ||||||
|  | +		hostapd_logger(hapd, sta->addr, | ||||||
|  | +			       HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +			       HOSTAPD_LEVEL_INFO, | ||||||
|  | +			       "Non-Multi-AP STA tries to associate with backhaul-only BSS"); | ||||||
|  | +		return WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  | -		       HOSTAPD_LEVEL_INFO, | ||||||
|  | -		       "Non-Multi-AP STA tries to associate with backhaul-only BSS"); | ||||||
|  | -	return WLAN_STATUS_ASSOC_DENIED_UNSPEC; | ||||||
|  | +	if (!(hapd->conf->multi_ap & BACKHAUL_BSS)) | ||||||
|  | +		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  | +			       HOSTAPD_LEVEL_DEBUG, | ||||||
|  | +			       "Backhaul STA tries to associate with fronthaul-only BSS"); | ||||||
|  | + | ||||||
|  | +	sta->flags |= WLAN_STA_MULTI_AP; | ||||||
|  | +	return WLAN_STATUS_SUCCESS; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | --- a/tests/hwsim/test_multi_ap.py | ||||||
|  | +++ b/tests/hwsim/test_multi_ap.py | ||||||
|  | @@ -59,7 +59,5 @@ def test_multi_ap_fronthaul_on_ap(dev, a | ||||||
|  |      dev[0].request("DISCONNECT") | ||||||
|  |      if ev is None: | ||||||
|  |          raise Exception("Connection result not reported") | ||||||
|  | -    if "CTRL-EVENT-ASSOC-REJECT" not in ev: | ||||||
|  | -        raise Exception("Association rejection not reported") | ||||||
|  | -    if "status_code=12" not in ev: | ||||||
|  | -        raise Exception("Unexpected association status code: " + ev) | ||||||
|  | +    if "CTRL-EVENT-DISCONNECTED" not in ev: | ||||||
|  | +        raise Exception("Unexpected connection result") | ||||||
| @@ -0,0 +1,342 @@ | |||||||
|  | From ad3c6faca118c23cdafef418dc27b3cee7d0e06e Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Arnout Vandecappelle (Essensium/Mind)" <arnout@mind.be> | ||||||
|  | Date: Wed, 9 Jan 2019 19:19:26 +0100 | ||||||
|  | Subject: [PATCH] WPS: wps_build_wfa_ext(): add multi_ap_subelem parameter | ||||||
|  |  | ||||||
|  | The Multi-AP specification adds a new subelement to the WFA extension | ||||||
|  | element in the WPS exchange. Add an additional parameter to | ||||||
|  | wps_build_wfa_ext() to add this subelement. The subelement is only added | ||||||
|  | if the parameter is non-0. Note that we don't reuse the existing | ||||||
|  | MULTI_AP_SUB_ELEM_TYPE definition here, but rather define a new | ||||||
|  | WFA_ELEM_MULTI_AP, to make sure the enum of WFA subelement types remains | ||||||
|  | complete. | ||||||
|  |  | ||||||
|  | For now, all callers set the multi_ap_subelem parameter to 0. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: Split off from supplicant WPS patch | ||||||
|  |  | ||||||
|  | Since the original patch from Davina Lyu didn't have this extra | ||||||
|  | argument, I kept myself as the author of this patch. | ||||||
|  | --- | ||||||
|  |  src/p2p/p2p_build.c      |  2 +- | ||||||
|  |  src/wps/wps.c            |  6 +++--- | ||||||
|  |  src/wps/wps_attr_build.c | 11 ++++++++++- | ||||||
|  |  src/wps/wps_common.c     | 16 ++++++++-------- | ||||||
|  |  src/wps/wps_defs.h       |  3 ++- | ||||||
|  |  src/wps/wps_enrollee.c   | 10 +++++----- | ||||||
|  |  src/wps/wps_er.c         |  4 ++-- | ||||||
|  |  src/wps/wps_i.h          |  3 ++- | ||||||
|  |  src/wps/wps_registrar.c  | 14 +++++++------- | ||||||
|  |  src/wps/wps_upnp.c       |  2 +- | ||||||
|  |  10 files changed, 41 insertions(+), 30 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/src/p2p/p2p_build.c | ||||||
|  | +++ b/src/p2p/p2p_build.c | ||||||
|  | @@ -802,7 +802,7 @@ int p2p_build_wps_ie(struct p2p_data *p2 | ||||||
|  |  		wpabuf_put_be16(buf, p2p->cfg->config_methods); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) | ||||||
|  | +	if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0) | ||||||
|  |  		return -1; | ||||||
|  |   | ||||||
|  |  	if (all_attr && p2p->cfg->num_sec_dev_types) { | ||||||
|  | --- a/src/wps/wps.c | ||||||
|  | +++ b/src/wps/wps.c | ||||||
|  | @@ -430,7 +430,7 @@ struct wpabuf * wps_build_assoc_req_ie(e | ||||||
|  |   | ||||||
|  |  	if (wps_build_version(ie) || | ||||||
|  |  	    wps_build_req_type(ie, req_type) || | ||||||
|  | -	    wps_build_wfa_ext(ie, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(ie); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -464,7 +464,7 @@ struct wpabuf * wps_build_assoc_resp_ie( | ||||||
|  |   | ||||||
|  |  	if (wps_build_version(ie) || | ||||||
|  |  	    wps_build_resp_type(ie, WPS_RESP_AP) || | ||||||
|  | -	    wps_build_wfa_ext(ie, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(ie); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -516,7 +516,7 @@ struct wpabuf * wps_build_probe_req_ie(u | ||||||
|  |  	    wps_build_model_name(dev, ie) || | ||||||
|  |  	    wps_build_model_number(dev, ie) || | ||||||
|  |  	    wps_build_dev_name(dev, ie) || | ||||||
|  | -	    wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) || | ||||||
|  |  	    wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) | ||||||
|  |  	    || | ||||||
|  |  	    wps_build_secondary_dev_type(dev, ie) | ||||||
|  | --- a/src/wps/wps_attr_build.c | ||||||
|  | +++ b/src/wps/wps_attr_build.c | ||||||
|  | @@ -203,7 +203,8 @@ int wps_build_version(struct wpabuf *msg | ||||||
|  |   | ||||||
|  |   | ||||||
|  |  int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, | ||||||
|  | -		      const u8 *auth_macs, size_t auth_macs_count) | ||||||
|  | +		      const u8 *auth_macs, size_t auth_macs_count, | ||||||
|  | +		      u8 multi_ap_subelem) | ||||||
|  |  { | ||||||
|  |  	u8 *len; | ||||||
|  |   | ||||||
|  | @@ -244,6 +245,14 @@ int wps_build_wfa_ext(struct wpabuf *msg | ||||||
|  |  				   MAC2STR(&auth_macs[i * ETH_ALEN])); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (multi_ap_subelem) { | ||||||
|  | +		wpa_printf(MSG_DEBUG, "WPS:  * Multi-AP (0x%x)", | ||||||
|  | +			   multi_ap_subelem); | ||||||
|  | +		wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP); | ||||||
|  | +		wpabuf_put_u8(msg, 1); /* length */ | ||||||
|  | +		wpabuf_put_u8(msg, multi_ap_subelem); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2); | ||||||
|  |   | ||||||
|  |  #ifdef CONFIG_WPS_TESTING | ||||||
|  | --- a/src/wps/wps_common.c | ||||||
|  | +++ b/src/wps/wps_common.c | ||||||
|  | @@ -374,7 +374,7 @@ struct wpabuf * wps_get_oob_cred(struct | ||||||
|  |  	    (rf_band && wps_build_rf_bands_attr(plain, rf_band)) || | ||||||
|  |  	    (channel && wps_build_ap_channel(plain, channel)) || | ||||||
|  |  	    wps_build_mac_addr(plain, wps->dev.mac_addr) || | ||||||
|  | -	    wps_build_wfa_ext(plain, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(plain, 0, NULL, 0, 0)) { | ||||||
|  |  		os_free(data.new_psk); | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		return NULL; | ||||||
|  | @@ -421,7 +421,7 @@ struct wpabuf * wps_build_nfc_pw_token(u | ||||||
|  |   | ||||||
|  |  	if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey, | ||||||
|  |  				 wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || | ||||||
|  | -	    wps_build_wfa_ext(data, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(data, 0, NULL, 0, 0)) { | ||||||
|  |  		wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " | ||||||
|  |  			   "token"); | ||||||
|  |  		wpabuf_clear_free(data); | ||||||
|  | @@ -586,7 +586,7 @@ struct wpabuf * wps_build_wsc_ack(struct | ||||||
|  |  	    wps_build_msg_type(msg, WPS_WSC_ACK) || | ||||||
|  |  	    wps_build_enrollee_nonce(wps, msg) || | ||||||
|  |  	    wps_build_registrar_nonce(wps, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -610,7 +610,7 @@ struct wpabuf * wps_build_wsc_nack(struc | ||||||
|  |  	    wps_build_enrollee_nonce(wps, msg) || | ||||||
|  |  	    wps_build_registrar_nonce(wps, msg) || | ||||||
|  |  	    wps_build_config_error(msg, wps->config_error) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -726,7 +726,7 @@ struct wpabuf * wps_build_nfc_handover_r | ||||||
|  |  	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, | ||||||
|  |  				 nfc_dh_pubkey, NULL, 0) || | ||||||
|  |  	    wps_build_uuid_e(msg, ctx->uuid) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -809,7 +809,7 @@ struct wpabuf * wps_build_nfc_handover_s | ||||||
|  |  	    wps_build_ssid(msg, ctx) || | ||||||
|  |  	    wps_build_ap_freq(msg, freq) || | ||||||
|  |  	    (bssid && wps_build_mac_addr(msg, bssid)) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -848,7 +848,7 @@ struct wpabuf * wps_build_nfc_handover_r | ||||||
|  |  	    wps_build_rf_bands(&ctx->dev, msg, 0) || | ||||||
|  |  	    wps_build_serial_number(&ctx->dev, msg) || | ||||||
|  |  	    wps_build_uuid_e(msg, ctx->uuid) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -900,7 +900,7 @@ struct wpabuf * wps_build_nfc_handover_s | ||||||
|  |  	    wps_build_rf_bands(&ctx->dev, msg, 0) || | ||||||
|  |  	    wps_build_serial_number(&ctx->dev, msg) || | ||||||
|  |  	    wps_build_uuid_e(msg, ctx->uuid) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | --- a/src/wps/wps_defs.h | ||||||
|  | +++ b/src/wps/wps_defs.h | ||||||
|  | @@ -152,7 +152,8 @@ enum { | ||||||
|  |  	WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02, | ||||||
|  |  	WFA_ELEM_REQUEST_TO_ENROLL = 0x03, | ||||||
|  |  	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04, | ||||||
|  | -	WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05 | ||||||
|  | +	WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05, | ||||||
|  | +	WFA_ELEM_MULTI_AP = 0x06 | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /* Device Password ID */ | ||||||
|  | --- a/src/wps/wps_enrollee.c | ||||||
|  | +++ b/src/wps/wps_enrollee.c | ||||||
|  | @@ -152,7 +152,7 @@ static struct wpabuf * wps_build_m1(stru | ||||||
|  |  	    wps_build_dev_password_id(msg, wps->dev_pw_id) || | ||||||
|  |  	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) || | ||||||
|  |  	    wps_build_os_version(&wps->wps->dev, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  | @@ -190,7 +190,7 @@ static struct wpabuf * wps_build_m3(stru | ||||||
|  |  	    wps_build_msg_type(msg, WPS_M3) || | ||||||
|  |  	    wps_build_registrar_nonce(wps, msg) || | ||||||
|  |  	    wps_build_e_hash(wps, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  | @@ -223,7 +223,7 @@ static struct wpabuf * wps_build_m5(stru | ||||||
|  |  	    wps_build_e_snonce1(wps, plain) || | ||||||
|  |  	    wps_build_key_wrap_auth(wps, plain) || | ||||||
|  |  	    wps_build_encr_settings(wps, msg, plain) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  | @@ -393,7 +393,7 @@ static struct wpabuf * wps_build_m7(stru | ||||||
|  |  	    (wps->wps->ap && wps_build_ap_settings(wps, plain)) || | ||||||
|  |  	    wps_build_key_wrap_auth(wps, plain) || | ||||||
|  |  	    wps_build_encr_settings(wps, msg, plain) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  | @@ -430,7 +430,7 @@ static struct wpabuf * wps_build_wsc_don | ||||||
|  |  	    wps_build_msg_type(msg, WPS_WSC_DONE) || | ||||||
|  |  	    wps_build_enrollee_nonce(wps, msg) || | ||||||
|  |  	    wps_build_registrar_nonce(wps, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | --- a/src/wps/wps_er.c | ||||||
|  | +++ b/src/wps/wps_er.c | ||||||
|  | @@ -1530,7 +1530,7 @@ void wps_er_set_sel_reg(struct wps_er *e | ||||||
|  |  	    wps_er_build_selected_registrar(msg, sel_reg) || | ||||||
|  |  	    wps_er_build_dev_password_id(msg, dev_passwd_id) || | ||||||
|  |  	    wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, auth_macs, count) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, auth_macs, count, 0) || | ||||||
|  |  	    wps_er_build_uuid_r(msg, er->wps->uuid)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return; | ||||||
|  | @@ -2048,7 +2048,7 @@ struct wpabuf * wps_er_config_token_from | ||||||
|  |  	data.wps = wps; | ||||||
|  |  	data.use_cred = cred; | ||||||
|  |  	if (wps_build_cred(&data, ret) || | ||||||
|  | -	    wps_build_wfa_ext(ret, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(ret, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(ret); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | --- a/src/wps/wps_i.h | ||||||
|  | +++ b/src/wps/wps_i.h | ||||||
|  | @@ -163,7 +163,8 @@ int wps_build_encr_settings(struct wps_d | ||||||
|  |  			    struct wpabuf *plain); | ||||||
|  |  int wps_build_version(struct wpabuf *msg); | ||||||
|  |  int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, | ||||||
|  | -		      const u8 *auth_macs, size_t auth_macs_count); | ||||||
|  | +		      const u8 *auth_macs, size_t auth_macs_count, | ||||||
|  | +		      u8 multi_ap_subelem); | ||||||
|  |  int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type); | ||||||
|  |  int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg); | ||||||
|  |  int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg); | ||||||
|  | --- a/src/wps/wps_registrar.c | ||||||
|  | +++ b/src/wps/wps_registrar.c | ||||||
|  | @@ -1281,7 +1281,7 @@ static int wps_set_ie(struct wps_registr | ||||||
|  |  	    wps_build_sel_reg_config_methods(reg, beacon) || | ||||||
|  |  	    wps_build_sel_pbc_reg_uuid_e(reg, beacon) || | ||||||
|  |  	    (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || | ||||||
|  | -	    wps_build_wfa_ext(beacon, 0, auth_macs, count) || | ||||||
|  | +	    wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) || | ||||||
|  |  	    wps_build_vendor_ext(®->wps->dev, beacon)) { | ||||||
|  |  		wpabuf_free(beacon); | ||||||
|  |  		wpabuf_free(probe); | ||||||
|  | @@ -1311,7 +1311,7 @@ static int wps_set_ie(struct wps_registr | ||||||
|  |  	    wps_build_device_attrs(®->wps->dev, probe) || | ||||||
|  |  	    wps_build_probe_config_methods(reg, probe) || | ||||||
|  |  	    (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || | ||||||
|  | -	    wps_build_wfa_ext(probe, 0, auth_macs, count) || | ||||||
|  | +	    wps_build_wfa_ext(probe, 0, auth_macs, count, 0) || | ||||||
|  |  	    wps_build_vendor_ext(®->wps->dev, probe)) { | ||||||
|  |  		wpabuf_free(beacon); | ||||||
|  |  		wpabuf_free(probe); | ||||||
|  | @@ -1845,7 +1845,7 @@ static struct wpabuf * wps_build_m2(stru | ||||||
|  |  	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) || | ||||||
|  |  	    wps_build_dev_password_id(msg, wps->dev_pw_id) || | ||||||
|  |  	    wps_build_os_version(&wps->wps->dev, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -1913,7 +1913,7 @@ static struct wpabuf * wps_build_m2d(str | ||||||
|  |  	    wps_build_assoc_state(wps, msg) || | ||||||
|  |  	    wps_build_config_error(msg, err) || | ||||||
|  |  	    wps_build_os_version(&wps->wps->dev, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
|  | @@ -1949,7 +1949,7 @@ static struct wpabuf * wps_build_m4(stru | ||||||
|  |  	    wps_build_r_snonce1(wps, plain) || | ||||||
|  |  	    wps_build_key_wrap_auth(wps, plain) || | ||||||
|  |  	    wps_build_encr_settings(wps, msg, plain) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  | @@ -1984,7 +1984,7 @@ static struct wpabuf * wps_build_m6(stru | ||||||
|  |  	    wps_build_r_snonce2(wps, plain) || | ||||||
|  |  	    wps_build_key_wrap_auth(wps, plain) || | ||||||
|  |  	    wps_build_encr_settings(wps, msg, plain) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  | @@ -2021,7 +2021,7 @@ static struct wpabuf * wps_build_m8(stru | ||||||
|  |  	    (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || | ||||||
|  |  	    wps_build_key_wrap_auth(wps, plain) || | ||||||
|  |  	    wps_build_encr_settings(wps, msg, plain) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  |  	    wps_build_authenticator(wps, msg)) { | ||||||
|  |  		wpabuf_clear_free(plain); | ||||||
|  |  		wpabuf_clear_free(msg); | ||||||
|  | --- a/src/wps/wps_upnp.c | ||||||
|  | +++ b/src/wps/wps_upnp.c | ||||||
|  | @@ -599,7 +599,7 @@ static struct wpabuf * build_fake_wsc_ac | ||||||
|  |  	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); | ||||||
|  |  	wpabuf_put_be16(msg, WPS_NONCE_LEN); | ||||||
|  |  	wpabuf_put(msg, WPS_NONCE_LEN); | ||||||
|  | -	if (wps_build_wfa_ext(msg, 0, NULL, 0)) { | ||||||
|  | +	if (wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  |  	} | ||||||
| @@ -0,0 +1,217 @@ | |||||||
|  | From 6c4c98db9420a3321bbf091cfc254de5eba4b404 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Davina Lu <ylu@quantenna.com> | ||||||
|  | Date: Tue, 15 Jan 2019 19:17:51 +0100 | ||||||
|  | Subject: [PATCH] wpa_supplicant: support Multi-AP backhaul STA onboarding | ||||||
|  |  | ||||||
|  | The Wi-Fi Alliance Multi-AP Specification v1.0 allows onboarding of a | ||||||
|  | backhaul STA through WPS. To enable this, the backhaul STA needs to add | ||||||
|  | a Multi-AP IE to the WFA vendor extension element in the WSC M1 message | ||||||
|  | that indicates it supports the Multi-AP backhaul STA role. The registrar | ||||||
|  | (if it support Multi-AP onboarding) will respond to that with a WSC M8 | ||||||
|  | message that also contains the Multi-AP IE, and that contains the | ||||||
|  | credentials for the backhaul SSID (which may be different from the SSID | ||||||
|  | on which WPS is performed). | ||||||
|  |  | ||||||
|  | Introduce a new parameter to wpas_wps_start_pbc() and allow it to be | ||||||
|  | set via control interface's new multi_ap=1 parameter of WPS_PBC call. | ||||||
|  | multi_ap_backhaul_sta is set to 1 in the automatically created SSID. | ||||||
|  | Thus, if the AP does not support Multi-AP, association will fail and | ||||||
|  | WPS will be terminated. | ||||||
|  |  | ||||||
|  | Only wps_pbc is supported. | ||||||
|  |  | ||||||
|  | The multi_ap argument is only added to the socket interface, not to the | ||||||
|  | dbus interface. | ||||||
|  |  | ||||||
|  | Signed-off-by: Davina Lu <ylu@quantenna.com> | ||||||
|  | Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com> | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||||
|  | --- | ||||||
|  | v4: use argument to wps_pbc instead of a global configuration option | ||||||
|  |  (requested by Jouni) | ||||||
|  | --- | ||||||
|  |  src/eap_peer/eap_wsc.c                      | 3 +++ | ||||||
|  |  src/wps/wps.h                               | 6 ++++++ | ||||||
|  |  src/wps/wps_enrollee.c                      | 6 +++++- | ||||||
|  |  wpa_supplicant/ctrl_iface.c                 | 5 ++++- | ||||||
|  |  wpa_supplicant/dbus/dbus_new_handlers_wps.c | 2 +- | ||||||
|  |  wpa_supplicant/dbus/dbus_old_handlers_wps.c | 4 ++-- | ||||||
|  |  wpa_supplicant/events.c                     | 2 +- | ||||||
|  |  wpa_supplicant/p2p_supplicant.c             | 2 +- | ||||||
|  |  wpa_supplicant/wps_supplicant.c             | 9 +++++++-- | ||||||
|  |  wpa_supplicant/wps_supplicant.h             | 2 +- | ||||||
|  |  10 files changed, 31 insertions(+), 10 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/src/eap_peer/eap_wsc.c | ||||||
|  | +++ b/src/eap_peer/eap_wsc.c | ||||||
|  | @@ -274,6 +274,9 @@ static void * eap_wsc_init(struct eap_sm | ||||||
|  |  				      cfg.pin, cfg.pin_len, 0); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (os_strstr(phase1, "multi_ap=1")) | ||||||
|  | +		wps->multi_ap_backhaul_sta = 1; | ||||||
|  | + | ||||||
|  |  	/* Use reduced client timeout for WPS to avoid long wait */ | ||||||
|  |  	if (sm->ClientTimeout > 30) | ||||||
|  |  		sm->ClientTimeout = 30; | ||||||
|  | --- a/src/wps/wps.h | ||||||
|  | +++ b/src/wps/wps.h | ||||||
|  | @@ -613,6 +613,12 @@ struct wps_context { | ||||||
|  |  	int ap_setup_locked; | ||||||
|  |   | ||||||
|  |  	/** | ||||||
|  | +	 * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA | ||||||
|  | +	 * enrollee | ||||||
|  | +	 */ | ||||||
|  | +	int multi_ap_backhaul_sta; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  |  	 * uuid - Own UUID | ||||||
|  |  	 */ | ||||||
|  |  	u8 uuid[16]; | ||||||
|  | --- a/src/wps/wps_enrollee.c | ||||||
|  | +++ b/src/wps/wps_enrollee.c | ||||||
|  | @@ -105,6 +105,7 @@ static struct wpabuf * wps_build_m1(stru | ||||||
|  |  { | ||||||
|  |  	struct wpabuf *msg; | ||||||
|  |  	u16 config_methods; | ||||||
|  | +	u8 multi_ap_backhaul_sta = 0; | ||||||
|  |   | ||||||
|  |  	if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) | ||||||
|  |  		return NULL; | ||||||
|  | @@ -134,6 +135,9 @@ static struct wpabuf * wps_build_m1(stru | ||||||
|  |  				    WPS_CONFIG_PHY_PUSHBUTTON); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (wps->wps->multi_ap_backhaul_sta) | ||||||
|  | +		multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA; | ||||||
|  | + | ||||||
|  |  	if (wps_build_version(msg) || | ||||||
|  |  	    wps_build_msg_type(msg, WPS_M1) || | ||||||
|  |  	    wps_build_uuid_e(msg, wps->uuid_e) || | ||||||
|  | @@ -152,7 +156,7 @@ static struct wpabuf * wps_build_m1(stru | ||||||
|  |  	    wps_build_dev_password_id(msg, wps->dev_pw_id) || | ||||||
|  |  	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) || | ||||||
|  |  	    wps_build_os_version(&wps->wps->dev, msg) || | ||||||
|  | -	    wps_build_wfa_ext(msg, 0, NULL, 0, 0) || | ||||||
|  | +	    wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) || | ||||||
|  |  	    wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { | ||||||
|  |  		wpabuf_free(msg); | ||||||
|  |  		return NULL; | ||||||
|  | --- a/wpa_supplicant/ctrl_iface.c | ||||||
|  | +++ b/wpa_supplicant/ctrl_iface.c | ||||||
|  | @@ -1167,6 +1167,7 @@ static int wpa_supplicant_ctrl_iface_wps | ||||||
|  |  #ifdef CONFIG_AP | ||||||
|  |  	u8 *_p2p_dev_addr = NULL; | ||||||
|  |  #endif /* CONFIG_AP */ | ||||||
|  | +	int multi_ap = 0; | ||||||
|  |   | ||||||
|  |  	if (cmd == NULL || os_strcmp(cmd, "any") == 0) { | ||||||
|  |  		_bssid = NULL; | ||||||
|  | @@ -1184,6 +1185,8 @@ static int wpa_supplicant_ctrl_iface_wps | ||||||
|  |  		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", | ||||||
|  |  			   cmd); | ||||||
|  |  		return -1; | ||||||
|  | +	} else if (os_strncmp(cmd, "multi_ap=", 9) == 0) { | ||||||
|  | +		multi_ap = atoi(cmd + 9); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  #ifdef CONFIG_AP | ||||||
|  | @@ -1191,7 +1194,7 @@ static int wpa_supplicant_ctrl_iface_wps | ||||||
|  |  		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); | ||||||
|  |  #endif /* CONFIG_AP */ | ||||||
|  |   | ||||||
|  | -	return wpas_wps_start_pbc(wpa_s, _bssid, 0); | ||||||
|  | +	return wpas_wps_start_pbc(wpa_s, _bssid, 0, multi_ap); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | --- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c | ||||||
|  | +++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c | ||||||
|  | @@ -289,7 +289,7 @@ DBusMessage * wpas_dbus_handler_wps_star | ||||||
|  |  		if (ret > 0) | ||||||
|  |  			os_snprintf(npin, sizeof(npin), "%08d", ret); | ||||||
|  |  	} else { | ||||||
|  | -		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0); | ||||||
|  | +		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0, 0); | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	if (ret < 0) { | ||||||
|  | --- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c | ||||||
|  | +++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c | ||||||
|  | @@ -37,9 +37,9 @@ DBusMessage * wpas_dbus_iface_wps_pbc(DB | ||||||
|  |  		return wpas_dbus_new_invalid_opts_error(message, NULL); | ||||||
|  |   | ||||||
|  |  	if (os_strcmp(arg_bssid, "any") == 0) | ||||||
|  | -		ret = wpas_wps_start_pbc(wpa_s, NULL, 0); | ||||||
|  | +		ret = wpas_wps_start_pbc(wpa_s, NULL, 0, 0); | ||||||
|  |  	else if (!hwaddr_aton(arg_bssid, bssid)) | ||||||
|  | -		ret = wpas_wps_start_pbc(wpa_s, bssid, 0); | ||||||
|  | +		ret = wpas_wps_start_pbc(wpa_s, bssid, 0, 0); | ||||||
|  |  	else { | ||||||
|  |  		return wpas_dbus_new_invalid_opts_error(message, | ||||||
|  |  							"Invalid BSSID"); | ||||||
|  | --- a/wpa_supplicant/events.c | ||||||
|  | +++ b/wpa_supplicant/events.c | ||||||
|  | @@ -4816,7 +4816,7 @@ void supplicant_event(void *ctx, enum wp | ||||||
|  |  		break; | ||||||
|  |  	case EVENT_WPS_BUTTON_PUSHED: | ||||||
|  |  #ifdef CONFIG_WPS | ||||||
|  | -		wpas_wps_start_pbc(wpa_s, NULL, 0); | ||||||
|  | +		wpas_wps_start_pbc(wpa_s, NULL, 0, 0); | ||||||
|  |  #endif /* CONFIG_WPS */ | ||||||
|  |  		break; | ||||||
|  |  	case EVENT_AVOID_FREQUENCIES: | ||||||
|  | --- a/wpa_supplicant/p2p_supplicant.c | ||||||
|  | +++ b/wpa_supplicant/p2p_supplicant.c | ||||||
|  | @@ -1649,7 +1649,7 @@ static void wpas_start_wps_enrollee(stru | ||||||
|  |  	wpa_supplicant_ap_deinit(wpa_s); | ||||||
|  |  	wpas_copy_go_neg_results(wpa_s, res); | ||||||
|  |  	if (res->wps_method == WPS_PBC) { | ||||||
|  | -		wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1); | ||||||
|  | +		wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1, 0); | ||||||
|  |  #ifdef CONFIG_WPS_NFC | ||||||
|  |  	} else if (res->wps_method == WPS_NFC) { | ||||||
|  |  		wpas_wps_start_nfc(wpa_s, res->peer_device_addr, | ||||||
|  | --- a/wpa_supplicant/wps_supplicant.c | ||||||
|  | +++ b/wpa_supplicant/wps_supplicant.c | ||||||
|  | @@ -1137,9 +1137,10 @@ static void wpas_wps_reassoc(struct wpa_ | ||||||
|  |   | ||||||
|  |   | ||||||
|  |  int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, | ||||||
|  | -		       int p2p_group) | ||||||
|  | +		       int p2p_group, int multi_ap_backhaul_sta) | ||||||
|  |  { | ||||||
|  |  	struct wpa_ssid *ssid; | ||||||
|  | +	char phase1[32]; | ||||||
|  |   | ||||||
|  |  #ifdef CONFIG_AP | ||||||
|  |  	if (wpa_s->ap_iface) { | ||||||
|  | @@ -1177,10 +1178,14 @@ int wpas_wps_start_pbc(struct wpa_suppli | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  |  #endif /* CONFIG_P2P */ | ||||||
|  | -	if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0) | ||||||
|  | +	if (os_snprintf(phase1, sizeof(phase1), "pbc=1%s", | ||||||
|  | +			multi_ap_backhaul_sta ? " multi_ap=1" : "") || | ||||||
|  | +	    wpa_config_set_quoted(ssid, "phase1", phase1) < 0) | ||||||
|  |  		return -1; | ||||||
|  |  	if (wpa_s->wps_fragment_size) | ||||||
|  |  		ssid->eap.fragment_size = wpa_s->wps_fragment_size; | ||||||
|  | +	if (multi_ap_backhaul_sta) | ||||||
|  | +		ssid->multi_ap_backhaul_sta = 1; | ||||||
|  |  	wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL); | ||||||
|  |  	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, | ||||||
|  |  			       wpa_s, NULL); | ||||||
|  | --- a/wpa_supplicant/wps_supplicant.h | ||||||
|  | +++ b/wpa_supplicant/wps_supplicant.h | ||||||
|  | @@ -30,7 +30,7 @@ void wpas_wps_deinit(struct wpa_supplica | ||||||
|  |  int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s); | ||||||
|  |  enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid); | ||||||
|  |  int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, | ||||||
|  | -		       int p2p_group); | ||||||
|  | +		       int p2p_group, int multi_ap_backhaul_sta); | ||||||
|  |  int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, | ||||||
|  |  		       const char *pin, int p2p_group, u16 dev_pw_id); | ||||||
|  |  void wpas_wps_pbc_overlap(struct wpa_supplicant *wpa_s); | ||||||
| @@ -0,0 +1,339 @@ | |||||||
|  | From 8b04a4cddbd6dbadb24279713af7ac677e80d342 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Davina Lu <ylu@quantenna.com> | ||||||
|  | Date: Tue, 2 Oct 2018 18:34:14 -0700 | ||||||
|  | Subject: [PATCH] hostapd: support Multi-AP backhaul STA onboarding | ||||||
|  |  | ||||||
|  | The Wi-Fi Alliance Multi-AP Specification v1.0 allows onboarding of a | ||||||
|  | backhaul STA through WPS. To enable this, the WPS registrar offers a | ||||||
|  | different set of credentials (backhaul credentials instead of fronthaul | ||||||
|  | credentials) when the Multi-AP subelement is present in the WFA vendor | ||||||
|  | extension element of the WSC M1 message. | ||||||
|  |  | ||||||
|  | Add 3 new configuration options to specify the backhaul credentials for | ||||||
|  | the hostapd internal registrar: multi_ap_backhaul_ssid, | ||||||
|  | multi_ap_backhaul_wpa_psk, multi_ap_backhaul_wpa_passphrase. These are | ||||||
|  | only relevant for a fronthaul SSID, i.e. where multi_ap is set to 2 or | ||||||
|  | 3. When these options are set, pass the backhaul credentials instead of | ||||||
|  | the normal credentials when the Multi-AP subelement is present. | ||||||
|  |  | ||||||
|  | Ignore the Multi-AP subelement if the backhaul config options are not | ||||||
|  | set. Note that for an SSID which is fronthaul and backhaul at the same | ||||||
|  | time (i.e., multi_ap == 3), this results in the correct credentials | ||||||
|  | being sent anyway. | ||||||
|  |  | ||||||
|  | The security to be used for the backaul BSS is fixed to WPA2PSK. The | ||||||
|  | Multi-AP Specification only allows Open and WPA2PSK networks to be | ||||||
|  | configured. Although not stated explicitly, the backhaul link is | ||||||
|  | intended to be always encrypted, hence WPA2PSK. | ||||||
|  |  | ||||||
|  | To build the credentials, the credential-building code is essentially | ||||||
|  | copied and simplified. Indeed, the backhaul credentials are always | ||||||
|  | WPA2PSK and never use per-device PSK. All the options set for the | ||||||
|  | fronthaul BSS WPS are simply ignored. | ||||||
|  |  | ||||||
|  | Signed-off-by: Davina Lu <ylu@quantenna.com> | ||||||
|  | Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com> | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: no change | ||||||
|  | --- | ||||||
|  |  hostapd/config_file.c    | 47 ++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  hostapd/hostapd.conf     |  9 ++++++++ | ||||||
|  |  src/ap/ap_config.c       |  2 ++ | ||||||
|  |  src/ap/ap_config.h       |  1 + | ||||||
|  |  src/ap/wps_hostapd.c     | 26 ++++++++++++++++++++++ | ||||||
|  |  src/wps/wps.h            | 32 +++++++++++++++++++++++++++ | ||||||
|  |  src/wps/wps_attr_parse.c | 11 ++++++++++ | ||||||
|  |  src/wps/wps_attr_parse.h |  1 + | ||||||
|  |  src/wps/wps_dev_attr.c   |  5 +++++ | ||||||
|  |  src/wps/wps_dev_attr.h   |  1 + | ||||||
|  |  src/wps/wps_registrar.c  | 25 ++++++++++++++++++++- | ||||||
|  |  11 files changed, 159 insertions(+), 1 deletion(-) | ||||||
|  |  | ||||||
|  | --- a/hostapd/config_file.c | ||||||
|  | +++ b/hostapd/config_file.c | ||||||
|  | @@ -3479,6 +3479,53 @@ static int hostapd_config_fill(struct ho | ||||||
|  |  				   line, pos); | ||||||
|  |  			return 1; | ||||||
|  |  		} | ||||||
|  | +	} else if (os_strcmp(buf, "multi_ap_backhaul_ssid") == 0) { | ||||||
|  | +		size_t slen; | ||||||
|  | +		char *str = wpa_config_parse_string(pos, &slen); | ||||||
|  | + | ||||||
|  | +		if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) { | ||||||
|  | +			wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'", | ||||||
|  | +				   line, pos); | ||||||
|  | +			os_free(str); | ||||||
|  | +			return 1; | ||||||
|  | +		} | ||||||
|  | +		os_memcpy(bss->multi_ap_backhaul_ssid.ssid, str, slen); | ||||||
|  | +		bss->multi_ap_backhaul_ssid.ssid_len = slen; | ||||||
|  | +		bss->multi_ap_backhaul_ssid.ssid_set = 1; | ||||||
|  | +		os_free(str); | ||||||
|  | +	} else if (os_strcmp(buf, "multi_ap_backhaul_wpa_passphrase") == 0) { | ||||||
|  | +		int len = os_strlen(pos); | ||||||
|  | + | ||||||
|  | +		if (len < 8 || len > 63) { | ||||||
|  | +			wpa_printf(MSG_ERROR, | ||||||
|  | +				   "Line %d: invalid WPA passphrase length %d (expected 8..63)", | ||||||
|  | +				   line, len); | ||||||
|  | +			return 1; | ||||||
|  | +		} | ||||||
|  | +		os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase); | ||||||
|  | +		bss->multi_ap_backhaul_ssid.wpa_passphrase = os_strdup(pos); | ||||||
|  | +		if (bss->multi_ap_backhaul_ssid.wpa_passphrase) { | ||||||
|  | +			hostapd_config_clear_wpa_psk(&bss->multi_ap_backhaul_ssid.wpa_psk); | ||||||
|  | +			bss->multi_ap_backhaul_ssid.wpa_passphrase_set = 1; | ||||||
|  | +		} | ||||||
|  | +	} else if (os_strcmp(buf, "multi_ap_backhaul_wpa_psk") == 0) { | ||||||
|  | +		hostapd_config_clear_wpa_psk(&bss->multi_ap_backhaul_ssid.wpa_psk); | ||||||
|  | +		bss->multi_ap_backhaul_ssid.wpa_psk = | ||||||
|  | +			os_zalloc(sizeof(struct hostapd_wpa_psk)); | ||||||
|  | +		if (bss->multi_ap_backhaul_ssid.wpa_psk == NULL) | ||||||
|  | +			return 1; | ||||||
|  | +		if (hexstr2bin(pos, bss->multi_ap_backhaul_ssid.wpa_psk->psk, | ||||||
|  | +			       PMK_LEN) || | ||||||
|  | +		    pos[PMK_LEN * 2] != '\0') { | ||||||
|  | +			wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", | ||||||
|  | +				   line, pos); | ||||||
|  | +			hostapd_config_clear_wpa_psk(&bss->multi_ap_backhaul_ssid.wpa_psk); | ||||||
|  | +			return 1; | ||||||
|  | +		} | ||||||
|  | +		bss->multi_ap_backhaul_ssid.wpa_psk->group = 1; | ||||||
|  | +		os_free(bss->multi_ap_backhaul_ssid.wpa_passphrase); | ||||||
|  | +		bss->multi_ap_backhaul_ssid.wpa_passphrase = NULL; | ||||||
|  | +		bss->multi_ap_backhaul_ssid.wpa_psk_set = 1; | ||||||
|  |  	} else if (os_strcmp(buf, "upnp_iface") == 0) { | ||||||
|  |  		os_free(bss->upnp_iface); | ||||||
|  |  		bss->upnp_iface = os_strdup(pos); | ||||||
|  | --- a/hostapd/hostapd.conf | ||||||
|  | +++ b/hostapd/hostapd.conf | ||||||
|  | @@ -1852,6 +1852,15 @@ own_ip_addr=127.0.0.1 | ||||||
|  |  # attribute. | ||||||
|  |  #ap_settings=hostapd.ap_settings | ||||||
|  |   | ||||||
|  | +# Multi-AP backhaul BSS config | ||||||
|  | +# Used in WPS when multi_ap=2 or 3. Defines "backhaul BSS" credentials. | ||||||
|  | +# These are passed in WPS M8 instead of the normal (fronthaul) credentials | ||||||
|  | +# if the enrollee has the Multi-AP subelement set. Backhaul SSID is formatted | ||||||
|  | +# like ssid2. The key is set like wpa_psk or wpa_passphrase. | ||||||
|  | +#multi_ap_backhaul_ssid="backhaul" | ||||||
|  | +#multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef | ||||||
|  | +#multi_ap_backhaul_wpa_passphrase=secret passphrase | ||||||
|  | + | ||||||
|  |  # WPS UPnP interface | ||||||
|  |  # If set, support for external Registrars is enabled. | ||||||
|  |  #upnp_iface=br0 | ||||||
|  | --- a/src/ap/ap_config.c | ||||||
|  | +++ b/src/ap/ap_config.c | ||||||
|  | @@ -582,6 +582,8 @@ void hostapd_config_free_bss(struct host | ||||||
|  |  	os_free(conf->ap_pin); | ||||||
|  |  	os_free(conf->extra_cred); | ||||||
|  |  	os_free(conf->ap_settings); | ||||||
|  | +	hostapd_config_clear_wpa_psk(&conf->multi_ap_backhaul_ssid.wpa_psk); | ||||||
|  | +	str_clear_free(conf->multi_ap_backhaul_ssid.wpa_passphrase); | ||||||
|  |  	os_free(conf->upnp_iface); | ||||||
|  |  	os_free(conf->friendly_name); | ||||||
|  |  	os_free(conf->manufacturer_url); | ||||||
|  | --- a/src/ap/ap_config.h | ||||||
|  | +++ b/src/ap/ap_config.h | ||||||
|  | @@ -456,6 +456,7 @@ struct hostapd_bss_config { | ||||||
|  |  	int force_per_enrollee_psk; | ||||||
|  |  	u8 *ap_settings; | ||||||
|  |  	size_t ap_settings_len; | ||||||
|  | +	struct hostapd_ssid multi_ap_backhaul_ssid; | ||||||
|  |  	char *upnp_iface; | ||||||
|  |  	char *friendly_name; | ||||||
|  |  	char *manufacturer_url; | ||||||
|  | --- a/src/ap/wps_hostapd.c | ||||||
|  | +++ b/src/ap/wps_hostapd.c | ||||||
|  | @@ -962,6 +962,7 @@ static void hostapd_free_wps(struct wps_ | ||||||
|  |  		wpabuf_free(wps->dev.vendor_ext[i]); | ||||||
|  |  	wps_device_data_free(&wps->dev); | ||||||
|  |  	os_free(wps->network_key); | ||||||
|  | +	os_free(wps->multi_ap_backhaul_network_key); | ||||||
|  |  	hostapd_wps_nfc_clear(wps); | ||||||
|  |  	wpabuf_free(wps->dh_pubkey); | ||||||
|  |  	wpabuf_free(wps->dh_privkey); | ||||||
|  | @@ -1131,6 +1132,31 @@ int hostapd_init_wps(struct hostapd_data | ||||||
|  |  		wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (hapd->conf->multi_ap & FRONTHAUL_BSS && | ||||||
|  | +	    hapd->conf->multi_ap_backhaul_ssid.ssid_len) { | ||||||
|  | +		wps->multi_ap_backhaul_ssid_len = | ||||||
|  | +			hapd->conf->multi_ap_backhaul_ssid.ssid_len; | ||||||
|  | +		os_memcpy(wps->multi_ap_backhaul_ssid, | ||||||
|  | +			  hapd->conf->multi_ap_backhaul_ssid.ssid, | ||||||
|  | +			  wps->multi_ap_backhaul_ssid_len); | ||||||
|  | +		if (conf->multi_ap_backhaul_ssid.wpa_passphrase) { | ||||||
|  | +			wps->multi_ap_backhaul_network_key = | ||||||
|  | +				(u8 *) os_strdup(conf->multi_ap_backhaul_ssid.wpa_passphrase); | ||||||
|  | +			wps->multi_ap_backhaul_network_key_len = | ||||||
|  | +				os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase); | ||||||
|  | +		} else if (conf->multi_ap_backhaul_ssid.wpa_psk) { | ||||||
|  | +			wps->multi_ap_backhaul_network_key = | ||||||
|  | +				os_malloc(2 * PMK_LEN + 1); | ||||||
|  | +			if (wps->multi_ap_backhaul_network_key == NULL) | ||||||
|  | +				goto fail; | ||||||
|  | +			wpa_snprintf_hex((char *) wps->multi_ap_backhaul_network_key, | ||||||
|  | +					 2 * PMK_LEN + 1, | ||||||
|  | +					 conf->multi_ap_backhaul_ssid.wpa_psk->psk, | ||||||
|  | +					 PMK_LEN); | ||||||
|  | +			wps->multi_ap_backhaul_network_key_len = 2 * PMK_LEN; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	wps->ap_settings = conf->ap_settings; | ||||||
|  |  	wps->ap_settings_len = conf->ap_settings_len; | ||||||
|  |   | ||||||
|  | --- a/src/wps/wps.h | ||||||
|  | +++ b/src/wps/wps.h | ||||||
|  | @@ -100,6 +100,7 @@ struct wps_device_data { | ||||||
|  |  	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; | ||||||
|  |   | ||||||
|  |  	int p2p; | ||||||
|  | +	u8 multi_ap_ext; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | @@ -730,6 +731,37 @@ struct wps_context { | ||||||
|  |  	int psk_set; | ||||||
|  |   | ||||||
|  |  	/** | ||||||
|  | +	 * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul | ||||||
|  | +	 * enrollee | ||||||
|  | +	 * | ||||||
|  | +	 * This SSID is used by the Registrar to fill in information for | ||||||
|  | +	 * Credentials when the enrollee advertises it is a Multi-AP backhaul | ||||||
|  | +	 * STA. | ||||||
|  | +	 */ | ||||||
|  | +	u8 multi_ap_backhaul_ssid[SSID_MAX_LEN]; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  | +	 * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in | ||||||
|  | +	 * octets | ||||||
|  | +	 */ | ||||||
|  | +	size_t multi_ap_backhaul_ssid_len; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  | +	 * multi_ap_backhaul_network_key - The Network Key (PSK) for the | ||||||
|  | +	 * Multi-AP backhaul enrollee. | ||||||
|  | +	 * | ||||||
|  | +	 * This key can be either the ASCII passphrase (8..63 characters) or the | ||||||
|  | +	 * 32-octet PSK (64 hex characters). | ||||||
|  | +	 */ | ||||||
|  | +	u8 *multi_ap_backhaul_network_key; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  | +	 * multi_ap_backhaul_network_key_len - Length of | ||||||
|  | +	 * multi_ap_backhaul_network_key in octets | ||||||
|  | +	 */ | ||||||
|  | +	size_t multi_ap_backhaul_network_key_len; | ||||||
|  | + | ||||||
|  | +	/** | ||||||
|  |  	 * ap_settings - AP Settings override for M7 (only used at AP) | ||||||
|  |  	 * | ||||||
|  |  	 * If %NULL, AP Settings attributes will be generated based on the | ||||||
|  | --- a/src/wps/wps_attr_parse.c | ||||||
|  | +++ b/src/wps/wps_attr_parse.c | ||||||
|  | @@ -67,6 +67,17 @@ static int wps_set_vendor_ext_wfa_subele | ||||||
|  |  		} | ||||||
|  |  		attr->registrar_configuration_methods = pos; | ||||||
|  |  		break; | ||||||
|  | +	case WFA_ELEM_MULTI_AP: | ||||||
|  | +		if (len != 1) { | ||||||
|  | +			wpa_printf(MSG_DEBUG, | ||||||
|  | +				   "WPS: Invalid Multi-AP Extension length %u", | ||||||
|  | +				   len); | ||||||
|  | +			return -1; | ||||||
|  | +		} | ||||||
|  | +		attr->multi_ap_ext = *pos; | ||||||
|  | +		wpa_printf(MSG_DEBUG, "WPS: Multi-AP Extension 0x%02x", | ||||||
|  | +			   attr->multi_ap_ext); | ||||||
|  | +		break; | ||||||
|  |  	default: | ||||||
|  |  		wpa_printf(MSG_MSGDUMP, "WPS: Skipped unknown WFA Vendor " | ||||||
|  |  			   "Extension subelement %u", id); | ||||||
|  | --- a/src/wps/wps_attr_parse.h | ||||||
|  | +++ b/src/wps/wps_attr_parse.h | ||||||
|  | @@ -97,6 +97,7 @@ struct wps_parse_attr { | ||||||
|  |  	const u8 *cred[MAX_CRED_COUNT]; | ||||||
|  |  	const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT]; | ||||||
|  |  	const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT]; | ||||||
|  | +	u8 multi_ap_ext; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr); | ||||||
|  | --- a/src/wps/wps_dev_attr.c | ||||||
|  | +++ b/src/wps/wps_dev_attr.c | ||||||
|  | @@ -389,6 +389,11 @@ int wps_process_os_version(struct wps_de | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext) | ||||||
|  | +{ | ||||||
|  | +	dev->multi_ap_ext = ext; | ||||||
|  | +	wpa_printf(MSG_DEBUG, "WPS: Multi-AP extension value %02x", dev->multi_ap_ext); | ||||||
|  | +} | ||||||
|  |   | ||||||
|  |  int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands) | ||||||
|  |  { | ||||||
|  | --- a/src/wps/wps_dev_attr.h | ||||||
|  | +++ b/src/wps/wps_dev_attr.h | ||||||
|  | @@ -29,6 +29,7 @@ int wps_build_dev_name(struct wps_device | ||||||
|  |  int wps_process_device_attrs(struct wps_device_data *dev, | ||||||
|  |  			     struct wps_parse_attr *attr); | ||||||
|  |  int wps_process_os_version(struct wps_device_data *dev, const u8 *ver); | ||||||
|  | +void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext); | ||||||
|  |  int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); | ||||||
|  |  void wps_device_data_free(struct wps_device_data *dev); | ||||||
|  |  int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); | ||||||
|  | --- a/src/wps/wps_registrar.c | ||||||
|  | +++ b/src/wps/wps_registrar.c | ||||||
|  | @@ -1588,7 +1588,6 @@ int wps_build_credential_wrap(struct wpa | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | - | ||||||
|  |  int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) | ||||||
|  |  { | ||||||
|  |  	struct wpabuf *cred; | ||||||
|  | @@ -1603,6 +1602,29 @@ int wps_build_cred(struct wps_data *wps, | ||||||
|  |  	} | ||||||
|  |  	os_memset(&wps->cred, 0, sizeof(wps->cred)); | ||||||
|  |   | ||||||
|  | +	if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA && | ||||||
|  | +	    wps->wps->multi_ap_backhaul_ssid_len) { | ||||||
|  | +		wpa_printf(MSG_DEBUG, "WPS: Use backhaul STA credentials"); | ||||||
|  | +		os_memcpy(wps->cred.ssid, wps->wps->multi_ap_backhaul_ssid, | ||||||
|  | +			  wps->wps->multi_ap_backhaul_ssid_len); | ||||||
|  | +		wps->cred.ssid_len = wps->wps->multi_ap_backhaul_ssid_len; | ||||||
|  | +		/* Backhaul is always WPA2PSK */ | ||||||
|  | +		wps->cred.auth_type = WPS_AUTH_WPA2PSK; | ||||||
|  | +		wps->cred.encr_type = WPS_ENCR_AES; | ||||||
|  | +		/* Set MAC address in the Credential to be the Enrollee's MAC | ||||||
|  | +		 * address | ||||||
|  | +		 */ | ||||||
|  | +		os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN); | ||||||
|  | +		if (wps->wps->multi_ap_backhaul_network_key) { | ||||||
|  | +			os_memcpy(wps->cred.key, | ||||||
|  | +				  wps->wps->multi_ap_backhaul_network_key, | ||||||
|  | +				  wps->wps->multi_ap_backhaul_network_key_len); | ||||||
|  | +			wps->cred.key_len = | ||||||
|  | +				wps->wps->multi_ap_backhaul_network_key_len; | ||||||
|  | +		} | ||||||
|  | +		goto use_provided; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len); | ||||||
|  |  	wps->cred.ssid_len = wps->wps->ssid_len; | ||||||
|  |   | ||||||
|  | @@ -2705,6 +2727,7 @@ static enum wps_process_res wps_process_ | ||||||
|  |  		wps->use_psk_key = 1; | ||||||
|  |  	} | ||||||
|  |  #endif /* WPS_WORKAROUNDS */ | ||||||
|  | +	wps_process_vendor_ext_m1(&wps->peer_dev, attr->multi_ap_ext); | ||||||
|  |   | ||||||
|  |  	wps->state = SEND_M2; | ||||||
|  |  	return WPS_CONTINUE; | ||||||
| @@ -0,0 +1,181 @@ | |||||||
|  | From bd733055a22c8ca3bcd7648bf716da2713b3d9f1 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Arnout Vandecappelle (Essensium/Mind)" <arnout@mind.be> | ||||||
|  | Date: Mon, 21 Jan 2019 16:44:06 +0100 | ||||||
|  | Subject: [PATCH] hostapd: add README-MULTI-AP | ||||||
|  |  | ||||||
|  | Document what hostapd and wpa_supplicant do for Multi-AP. | ||||||
|  |  | ||||||
|  | This is only included in hostapd, since a Multi-AP device is always an | ||||||
|  | access point so it should have hostapd. | ||||||
|  |  | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: wps_pbc has multi_ap as a parameter instead of config option. | ||||||
|  | --- | ||||||
|  |  hostapd/README-MULTI-AP | 160 ++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 160 insertions(+) | ||||||
|  |  create mode 100644 hostapd/README-MULTI-AP | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/hostapd/README-MULTI-AP | ||||||
|  | @@ -0,0 +1,160 @@ | ||||||
|  | +hostapd, wpa_supplicant and the Multi-AP Specification | ||||||
|  | +====================================================== | ||||||
|  | + | ||||||
|  | +This document describes how hostapd and wpa_supplicant can be configured to | ||||||
|  | +support the Multi-AP Specification. | ||||||
|  | + | ||||||
|  | +Introduction to Multi-AP | ||||||
|  | +------------------------ | ||||||
|  | + | ||||||
|  | +The Wi-Fi Alliance Multi-AP Specification is the technical specification for | ||||||
|  | +Wi-Fi CERTIFIED EasyMesh(TM) [1], the Wi-Fi Alliance® certification program for | ||||||
|  | +Multi-AP. It defines control protocols between Wi-Fi® access points (APs) to | ||||||
|  | +join them into a network with centralized control and operation. It is targeted | ||||||
|  | +only at routers (repeaters, gateways, ...), not at clients. Clients are not | ||||||
|  | +involved at all in the protocols. | ||||||
|  | + | ||||||
|  | +Most of the Multi-AP specification falls outside of the scope of | ||||||
|  | +hostapd/wpa_supplicant. hostapd/wpa_supplicant is only involved for the items | ||||||
|  | +summarized below. The rest of the protocol must be implemented by a separate | ||||||
|  | +daemon, e.g. prplMesh [2]. That daemon also needs to communicate with hostapd, | ||||||
|  | +e.g. to get a list of associated clients, but this can be done using the normal | ||||||
|  | +hostapd interfaces. | ||||||
|  | + | ||||||
|  | +hostapd/wpa_supplicant needs to be configured specifically to support: | ||||||
|  | +- the WPS onboarding process; | ||||||
|  | +- configuring backhaul links. | ||||||
|  | + | ||||||
|  | +The text below refers to "Multi-AP Specification v1.0" [3]. | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +Fronthaul and backhaul links | ||||||
|  | +---------------------------- | ||||||
|  | + | ||||||
|  | +In a Multi-AP network, the central controller can configure the SSIDs on the | ||||||
|  | +devices that are joined into the network. These are called fronthaul SSIDs. | ||||||
|  | +From the point of view of hostapd, there is nothing special about these | ||||||
|  | +fronthaul SSIDs. | ||||||
|  | + | ||||||
|  | +In addition to fronthaul SSIDs, the controller can also configure backhaul | ||||||
|  | +links. A backhaul link is a link between two access point devices, giving | ||||||
|  | +internet access to access point devices that don't have a wired link. The | ||||||
|  | +Multi-AP specification doesn't dictate this, but typically the backhaul link | ||||||
|  | +will be bridged into a LAN together with (one of) the fronthaul SSID(s) and the | ||||||
|  | +wired Ethernet ports. | ||||||
|  | + | ||||||
|  | +A backhaul link must be treated specially by hostapd and wpa_supplicant. One | ||||||
|  | +side of the backhaul link is configured through the Multi-AP protocol as the | ||||||
|  | +"backhaul STA", i.e. the client side of the link. A backhaul STA is like any | ||||||
|  | +station and is handled appropriately by wpa_supplicant, but two additional | ||||||
|  | +features are required. It must send an additional information element in each | ||||||
|  | +(Re-)Association Request ([3], section 5.2, paragraph 4). In addition, it must | ||||||
|  | +use 4-address mode for all frames sent over this link ([3], section 14). | ||||||
|  | +Therefore, wpa_supplicant must be configured explicitly as the backhaul STA | ||||||
|  | +role, by setting 'multi_ap_backhaul_sta=1' in the network configuration block | ||||||
|  | +or when configuring the SSID through the client socket. When | ||||||
|  | +'multi_ap_backhaul_sta=1', wpa_supplicant includes the Multi-AP IE in | ||||||
|  | +(Re-)Association Request messages and verifies that it is included in the | ||||||
|  | +(Re-)Association Response. If it is not, association fails. If it is, | ||||||
|  | +wpa_supplicant sets 4-address mode for this interface through a driver | ||||||
|  | +callback. | ||||||
|  | + | ||||||
|  | +The AP side of the backhaul link is called a "backhaul SSID". Such an SSID must | ||||||
|  | +be handled specially by hostapd, because it must add an additional information | ||||||
|  | +element in each (Re-)Association Response, but only to stations that have | ||||||
|  | +identified themselves as backhaul stations ([3], section 5.2, paragraph 5-6). | ||||||
|  | +This is important because it is possible to use the same BSS and SSID for | ||||||
|  | +fronthaul and backhaul at the same time. The additional information element must | ||||||
|  | +only be used for frames sent to a backhaul STA, not to a normal STA. Also, | ||||||
|  | +frames sent to a backhaul STA must use 4-address mode, while frames sent to a | ||||||
|  | +normal STA (fronthaul, when it's a fronthaul and backhaul SSID) must use | ||||||
|  | +3-address mode. | ||||||
|  | + | ||||||
|  | +An SSID is configured in Multi-AP mode in hostapd by setting the 'multi_ap' | ||||||
|  | +configuration option to 1 (backhaul SSID), 2 (fronthaul SSID) or 3 | ||||||
|  | +(simultaneous backhaul and fronthaul SSID). If this option is set, hostapd | ||||||
|  | +parses the Multi-AP information element in the Association Request. If the | ||||||
|  | +station is a backhaul STA and the SSID is configured as a backhaul SSID, | ||||||
|  | +hostapd sets up 4-address mode. Since there may be multiple stations connected | ||||||
|  | +simultaneously, and each of them has a different RA (receiver address), a VLAN | ||||||
|  | +is created for each backhaul STA and it is automatically added to a bridge. | ||||||
|  | +This is the same behavior as for WDS, and the relevant option ('bridge' or | ||||||
|  | +'wds_bridge') applies here as well. | ||||||
|  | + | ||||||
|  | +If 'multi_ap' is 1 (backhaul SSID only), any station that tries to associate | ||||||
|  | +without the Multi-AP information element will be denied. | ||||||
|  | + | ||||||
|  | +If 'multi_ap' is 2 (fronthaul SSID only), any station that tries to associate | ||||||
|  | +with the Multi-AP information element will be denied. That is also the only | ||||||
|  | +difference with 'multi_ap' set to 0: in the latter case, the Multi-AP | ||||||
|  | +information element is simply ignored. | ||||||
|  | + | ||||||
|  | +In summary, this is the end-to-end behaviour for a backhaul BSS (i.e., | ||||||
|  | +multi_ap_backhaul_sta=1 in wpa_supplicant on STA, and multi_ap=1 or 3 in | ||||||
|  | +hostapd on AP). Note that point 1 means that hostapd must not be configured | ||||||
|  | +with WPS support on the backhaul BSS (multi_ap=1). hostapd does not check for | ||||||
|  | +that. | ||||||
|  | + | ||||||
|  | +1. Backhaul BSS beacons do not advertise WPS support (other than that, nothing | ||||||
|  | +   multi-ap specific). | ||||||
|  | +2. STA sends authentication req (nothing multi-ap specific). | ||||||
|  | +3. AP sends authentication resp (nothing multi-ap specific). | ||||||
|  | +4. STA sends association req with Multi-AP IE. | ||||||
|  | +5. AP send association resp with Multi-AP IE. | ||||||
|  | +6. STA and AP both use 4-address mode for data. | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +WPS support | ||||||
|  | +----------- | ||||||
|  | + | ||||||
|  | +WPS requires more special handling. WPS must only be advertised on fronthaul | ||||||
|  | +SSIDs, not on backhaul SSIDs, so WPS should not be enabled on a backhaul-only | ||||||
|  | +SSID in hostapd.conf. The WPS configuration purely works on the fronthaul SSID. | ||||||
|  | +When a WPS M1 message has an additional subelement that indicates a request for | ||||||
|  | +a multi-AP backhaul link, hostapd must not respond with the normal fronthaul | ||||||
|  | +SSID credentials; instead, it should respond with the (potentially different) | ||||||
|  | +backhaul SSID credentials. | ||||||
|  | + | ||||||
|  | +To support this, hostapd has the 'multi_ap_backhaul_ssid', | ||||||
|  | +'multi_ap_backhaul_wpa_psk' and 'multi_ap_backhaul_wpa_passphrase' options. | ||||||
|  | +When these are set on an SSID with WPS, they are used instead of the normal | ||||||
|  | +credentials when hostapd receives a WPS M1 message with the Multi-AP IE. Only | ||||||
|  | +WPA2 Personal is supported in the Multi-AP specification, so there is no need | ||||||
|  | +to specify authentication or encryption options. For the backhaul credentials, | ||||||
|  | +per-device PSK is not supported. | ||||||
|  | + | ||||||
|  | +If the SSID is a simultaneous backhaul and fronthaul SSID, there is no need to | ||||||
|  | +specify the backhaul credentials, since the backhaul and fronthaul credentials | ||||||
|  | +are identical. | ||||||
|  | + | ||||||
|  | +To enable the Multi-AP backhaul STA feature when it performs WPS, a new | ||||||
|  | +parameter has been introduced to the WPS_PBC control interface call. | ||||||
|  | +When this option is set, it adds the multi-AP backhaul subelement to | ||||||
|  | +the association and M1 messages. It then configures the new SSID with | ||||||
|  | +'multi_ap_backhaul_sta=1'. Note that this means that if the AP does not | ||||||
|  | +follow the Multi-AP specification, wpa_supplicant will fail to | ||||||
|  | +associate. | ||||||
|  | + | ||||||
|  | +In summary, this is the end-to-end behaviour for WPS of a backhaul link (i.e., | ||||||
|  | +multi_ap=1 option is given in the wps_pbc call on the STA side, and multi_ap=2 | ||||||
|  | +and multi_ap_backhaul_ssid and either multi_ap_backhaul_wpa_psk or | ||||||
|  | +multi_ap_backhaul_wpa_passphrase are set to the credentials of a backhaul SSID | ||||||
|  | +in hostapd on registrar AP). | ||||||
|  | + | ||||||
|  | +1. Fronthaul BSS beacons advertise WPS support (nothing multi-ap specific). | ||||||
|  | +2. Enrollee sends authentication req (nothing multi-ap specific). | ||||||
|  | +3. AP sends authentication resp (nothing multi-ap specific). | ||||||
|  | +4. Enrollee sends association req with Multi-AP IE. | ||||||
|  | +5. AP send association resp with Multi-AP IE. | ||||||
|  | +6. Enrollee sends M1 with additional Multi-AP subelement | ||||||
|  | +7. AP sends M8 with backhaul instead of fronthaul credentials. | ||||||
|  | +8. Enrollee sends Deauth. | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +References | ||||||
|  | +---------- | ||||||
|  | + | ||||||
|  | +[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh | ||||||
|  | +[2] https://github.com/prplfoundation/prplMesh | ||||||
|  | +[3] https://www.wi-fi.org/file/multi-ap-specification-v10 | ||||||
|  | +    (requires registration) | ||||||
| @@ -0,0 +1,182 @@ | |||||||
|  | From 0729e01f5830ebf4701f0b1b7ff1bd2a2eedae40 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Arnout Vandecappelle (Essensium/Mind)" <arnout@mind.be> | ||||||
|  | Date: Tue, 12 Feb 2019 11:02:42 +0100 | ||||||
|  | Subject: [PATCH] tests: add WPS tests to multi_ap hwsim tests | ||||||
|  |  | ||||||
|  | Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be> | ||||||
|  | --- | ||||||
|  | v4: new patch | ||||||
|  | --- | ||||||
|  |  tests/hwsim/test_multi_ap.py | 164 +++++++++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 164 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/tests/hwsim/test_multi_ap.py | ||||||
|  | +++ b/tests/hwsim/test_multi_ap.py | ||||||
|  | @@ -61,3 +61,167 @@ def test_multi_ap_fronthaul_on_ap(dev, a | ||||||
|  |          raise Exception("Connection result not reported") | ||||||
|  |      if "CTRL-EVENT-DISCONNECTED" not in ev: | ||||||
|  |          raise Exception("Unexpected connection result") | ||||||
|  | + | ||||||
|  | +def run_multi_ap_wps(dev, apdev, params, multi_ap_bssid = None): | ||||||
|  | +    """Helper for running Multi-AP WPS tests | ||||||
|  | + | ||||||
|  | +    dev[0] does multi_ap WPS, dev[1] does normal WPS. apdev[0] is the fronthaul | ||||||
|  | +    BSS. If there is a separate backhaul BSS, it must have been set up by the | ||||||
|  | +    caller. params are the normal SSID parameters, they will be extended with | ||||||
|  | +    the WPS parameters. multi_ap_bssid must be given if it is not equal to the | ||||||
|  | +    fronthaul BSSID.""" | ||||||
|  | + | ||||||
|  | +    if multi_ap_bssid is None: | ||||||
|  | +        multi_ap_bssid = apdev[0]['bssid'] | ||||||
|  | +    params.update({"wps_state": "2", "eap_server": "1"}) | ||||||
|  | + | ||||||
|  | +    # WPS with multi-ap station dev[0] | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | +    hapd.request("WPS_PBC") | ||||||
|  | +    if "PBC Status: Active" not in hapd.request("WPS_GET_STATUS"): | ||||||
|  | +        raise Exception("PBC status not shown correctly") | ||||||
|  | + | ||||||
|  | +    dev[0].request("WPS_PBC multi_ap=1") | ||||||
|  | +    dev[0].wait_connected(timeout=20) | ||||||
|  | +    status = dev[0].get_status() | ||||||
|  | +    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != multi_ap_bssid: | ||||||
|  | +        raise Exception("Not fully connected") | ||||||
|  | +    if status['ssid'] != params['multi_ap_backhaul_ssid'].strip('"'): | ||||||
|  | +        raise Exception("Unexpected SSID %s != %s" % (status['ssid'], params["multi_ap_backhaul_ssid"])) | ||||||
|  | +    if status['pairwise_cipher'] != 'CCMP': | ||||||
|  | +        raise Exception("Unexpected encryption configuration %s" % status['pairwise_cipher']) | ||||||
|  | +    if status['key_mgmt'] != 'WPA2-PSK': | ||||||
|  | +        raise Exception("Unexpected key_mgmt") | ||||||
|  | + | ||||||
|  | +    status = hapd.request("WPS_GET_STATUS") | ||||||
|  | +    if "PBC Status: Disabled" not in status: | ||||||
|  | +        raise Exception("PBC status not shown correctly") | ||||||
|  | +    if "Last WPS result: Success" not in status: | ||||||
|  | +        raise Exception("Last WPS result not shown correctly") | ||||||
|  | +    if "Peer Address: " + dev[0].p2p_interface_addr() not in status: | ||||||
|  | +        raise Exception("Peer address not shown correctly") | ||||||
|  | + | ||||||
|  | +    if len(dev[0].list_networks()) != 1: | ||||||
|  | +        raise Exception("Unexpected number of network blocks") | ||||||
|  | + | ||||||
|  | +    # WPS with non-multi-ap station dev[1] | ||||||
|  | +    hapd.request("WPS_PBC") | ||||||
|  | +    if "PBC Status: Active" not in hapd.request("WPS_GET_STATUS"): | ||||||
|  | +        raise Exception("PBC status not shown correctly") | ||||||
|  | + | ||||||
|  | +    dev[1].request("WPS_PBC") | ||||||
|  | +    dev[1].wait_connected(timeout=20) | ||||||
|  | +    status = dev[1].get_status() | ||||||
|  | +    if status['wpa_state'] != 'COMPLETED' or status['bssid'] != apdev[0]['bssid']: | ||||||
|  | +        raise Exception("Not fully connected") | ||||||
|  | +    if status['ssid'] != params["ssid"]: | ||||||
|  | +        raise Exception("Unexpected SSID") | ||||||
|  | +    # Fronthaul may be something else than WPA2-PSK so don't test it. | ||||||
|  | + | ||||||
|  | +    status = hapd.request("WPS_GET_STATUS") | ||||||
|  | +    if "PBC Status: Disabled" not in status: | ||||||
|  | +        raise Exception("PBC status not shown correctly") | ||||||
|  | +    if "Last WPS result: Success" not in status: | ||||||
|  | +        raise Exception("Last WPS result not shown correctly") | ||||||
|  | +    if "Peer Address: " + dev[1].p2p_interface_addr() not in status: | ||||||
|  | +        raise Exception("Peer address not shown correctly") | ||||||
|  | + | ||||||
|  | +    if len(dev[1].list_networks()) != 1: | ||||||
|  | +        raise Exception("Unexpected number of network blocks") | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_shared(dev, apdev): | ||||||
|  | +    """WPS on shared fronthaul/backhaul AP""" | ||||||
|  | +    ssid = "multi-ap-wps" | ||||||
|  | +    passphrase = "12345678" | ||||||
|  | +    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase) | ||||||
|  | +    params.update({"multi_ap": "3", | ||||||
|  | +                   "multi_ap_backhaul_ssid": '"%s"' % ssid, | ||||||
|  | +                   "multi_ap_backhaul_wpa_passphrase": passphrase}) | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_shared_psk(dev, apdev): | ||||||
|  | +    """WPS on shared fronthaul/backhaul AP using PSK""" | ||||||
|  | +    ssid = "multi-ap-wps" | ||||||
|  | +    psk = "1234567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef" | ||||||
|  | +    params = hostapd.wpa2_params(ssid=ssid) | ||||||
|  | +    params.update({"wpa_psk": psk, "multi_ap": "3", | ||||||
|  | +                   "multi_ap_backhaul_ssid": '"%s"' % ssid, | ||||||
|  | +                   "multi_ap_backhaul_wpa_psk": psk}) | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_split(dev, apdev): | ||||||
|  | +    """WPS on split fronthaul and backhaul AP""" | ||||||
|  | +    backhaul_ssid = "multi-ap-backhaul-wps" | ||||||
|  | +    backhaul_passphrase = "87654321" | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap-fronthaul-wps", passphrase="12345678") | ||||||
|  | +    params.update({"multi_ap": "2", | ||||||
|  | +                   "multi_ap_backhaul_ssid": '"%s"' % backhaul_ssid, | ||||||
|  | +                   "multi_ap_backhaul_wpa_passphrase": backhaul_passphrase}) | ||||||
|  | +    params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid, passphrase=backhaul_passphrase) | ||||||
|  | +    params_backhaul.update({"multi_ap": "1"}) | ||||||
|  | +    hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul) | ||||||
|  | + | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr()) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_split_psk(dev, apdev): | ||||||
|  | +    """WPS on split fronthaul and backhaul AP""" | ||||||
|  | +    backhaul_ssid = "multi-ap-backhaul-wps" | ||||||
|  | +    backhaul_psk = "1234567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef" | ||||||
|  | +    params = hostapd.wpa2_params(ssid="multi-ap-fronthaul-wps", passphrase="12345678") | ||||||
|  | +    params.update({"multi_ap": "2", | ||||||
|  | +                   "multi_ap_backhaul_ssid": '"%s"' % backhaul_ssid, | ||||||
|  | +                   "multi_ap_backhaul_wpa_psk": backhaul_psk}) | ||||||
|  | +    params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid) | ||||||
|  | +    params_backhaul.update({"multi_ap": "1", "wpa_psk": backhaul_psk}) | ||||||
|  | +    hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul) | ||||||
|  | + | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr()) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_split_mixed(dev, apdev): | ||||||
|  | +    """WPS on split fronthaul and backhaul AP with mixed-mode fronthaul""" | ||||||
|  | +    backhaul_ssid = "multi-ap-backhaul-wps" | ||||||
|  | +    backhaul_passphrase = "87654321" | ||||||
|  | +    params = hostapd.wpa_mixed_params(ssid="multi-ap-fronthaul-wps", passphrase="12345678") | ||||||
|  | +    params.update({"multi_ap": "2", | ||||||
|  | +                   "multi_ap_backhaul_ssid": '"%s"' % backhaul_ssid, | ||||||
|  | +                   "multi_ap_backhaul_wpa_passphrase": backhaul_passphrase}) | ||||||
|  | +    params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid, passphrase=backhaul_passphrase) | ||||||
|  | +    params_backhaul.update({"multi_ap": "1"}) | ||||||
|  | +    hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul) | ||||||
|  | + | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr()) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_split_open(dev, apdev): | ||||||
|  | +    """WPS on split fronthaul and backhaul AP with open fronthaul""" | ||||||
|  | +    backhaul_ssid = "multi-ap-backhaul-wps" | ||||||
|  | +    backhaul_passphrase = "87654321" | ||||||
|  | +    params = {"ssid": "multi-ap-wps-fronthaul", "multi_ap": "2", | ||||||
|  | +              "multi_ap_backhaul_ssid": '"%s"' % backhaul_ssid, | ||||||
|  | +              "multi_ap_backhaul_wpa_passphrase": backhaul_passphrase} | ||||||
|  | +    params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid, passphrase=backhaul_passphrase) | ||||||
|  | +    params_backhaul.update({"multi_ap": "1"}) | ||||||
|  | +    hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul) | ||||||
|  | + | ||||||
|  | +    run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr()) | ||||||
|  | + | ||||||
|  | +def test_multi_ap_wps_fail_non_multi_ap(dev, apdev): | ||||||
|  | +    """Multi-AP WPS on non-WPS AP fails""" | ||||||
|  | + | ||||||
|  | +    params = hostapd.wpa2_params(ssid="non-multi-ap-wps", passphrase="12345678") | ||||||
|  | +    params.update({"wps_state": "2", "eap_server": "1"}) | ||||||
|  | + | ||||||
|  | +    hapd = hostapd.add_ap(apdev[0], params) | ||||||
|  | +    hapd.request("WPS_PBC") | ||||||
|  | +    if "PBC Status: Active" not in hapd.request("WPS_GET_STATUS"): | ||||||
|  | +        raise Exception("PBC status not shown correctly") | ||||||
|  | + | ||||||
|  | +    dev[0].request("WPS_PBC multi_ap=1") | ||||||
|  | +    # Since we will fail to associate and WPS doesn't even get started, there | ||||||
|  | +    # isn't much we can do except wait for timeout. For PBC, it is not possible | ||||||
|  | +    # to change the timeout from 2 minutes. Instead of waiting for the timeout, | ||||||
|  | +    # just check that WPS doesn't finish within reasonable time. | ||||||
|  | +    ev = dev[0].wait_event(["WPS-SUCCESS", "WPS-FAIL"], timeout=20) | ||||||
|  | +    if ev: | ||||||
|  | +        raise Exception("WPS operation completed: " + ev) | ||||||
|  | +    dev[0].request("WPS_CANCEL") | ||||||
| @@ -92,7 +92,7 @@ | |||||||
|  		   __func__, driver, drv_priv); |  		   __func__, driver, drv_priv); | ||||||
| --- a/src/ap/ieee802_11.c | --- a/src/ap/ieee802_11.c | ||||||
| +++ b/src/ap/ieee802_11.c | +++ b/src/ap/ieee802_11.c | ||||||
| @@ -1743,12 +1743,13 @@ ieee802_11_set_radius_info(struct hostap | @@ -1759,12 +1759,13 @@ ieee802_11_set_radius_info(struct hostap | ||||||
|   |   | ||||||
|   |   | ||||||
|  static void handle_auth(struct hostapd_data *hapd, |  static void handle_auth(struct hostapd_data *hapd, | ||||||
| @@ -108,7 +108,7 @@ | |||||||
|  	u16 fc; |  	u16 fc; | ||||||
|  	const u8 *challenge = NULL; |  	const u8 *challenge = NULL; | ||||||
|  	u32 session_timeout, acct_interim_interval; |  	u32 session_timeout, acct_interim_interval; | ||||||
| @@ -1759,6 +1760,11 @@ static void handle_auth(struct hostapd_d | @@ -1775,6 +1776,11 @@ static void handle_auth(struct hostapd_d | ||||||
|  	char *identity = NULL; |  	char *identity = NULL; | ||||||
|  	char *radius_cui = NULL; |  	char *radius_cui = NULL; | ||||||
|  	u16 seq_ctrl; |  	u16 seq_ctrl; | ||||||
| @@ -120,7 +120,7 @@ | |||||||
|   |   | ||||||
|  	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { |  	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { | ||||||
|  		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", |  		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", | ||||||
| @@ -1919,6 +1925,13 @@ static void handle_auth(struct hostapd_d | @@ -1935,6 +1941,13 @@ static void handle_auth(struct hostapd_d | ||||||
|  		resp = WLAN_STATUS_UNSPECIFIED_FAILURE; |  		resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
|  		goto fail; |  		goto fail; | ||||||
|  	} |  	} | ||||||
| @@ -134,7 +134,7 @@ | |||||||
|  	if (res == HOSTAPD_ACL_PENDING) |  	if (res == HOSTAPD_ACL_PENDING) | ||||||
|  		return; |  		return; | ||||||
|   |   | ||||||
| @@ -3210,12 +3223,12 @@ void fils_hlp_timeout(void *eloop_ctx, v | @@ -3287,12 +3300,12 @@ void fils_hlp_timeout(void *eloop_ctx, v | ||||||
|   |   | ||||||
|  static void handle_assoc(struct hostapd_data *hapd, |  static void handle_assoc(struct hostapd_data *hapd, | ||||||
|  			 const struct ieee80211_mgmt *mgmt, size_t len, |  			 const struct ieee80211_mgmt *mgmt, size_t len, | ||||||
| @@ -149,7 +149,7 @@ | |||||||
|  	struct sta_info *sta; |  	struct sta_info *sta; | ||||||
|  	u8 *tmp = NULL; |  	u8 *tmp = NULL; | ||||||
|  	struct hostapd_sta_wpa_psk_short *psk = NULL; |  	struct hostapd_sta_wpa_psk_short *psk = NULL; | ||||||
| @@ -3224,6 +3237,11 @@ static void handle_assoc(struct hostapd_ | @@ -3301,6 +3314,11 @@ static void handle_assoc(struct hostapd_ | ||||||
|  #ifdef CONFIG_FILS |  #ifdef CONFIG_FILS | ||||||
|  	int delay_assoc = 0; |  	int delay_assoc = 0; | ||||||
|  #endif /* CONFIG_FILS */ |  #endif /* CONFIG_FILS */ | ||||||
| @@ -161,7 +161,7 @@ | |||||||
|   |   | ||||||
|  	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : |  	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : | ||||||
|  				      sizeof(mgmt->u.assoc_req))) { |  				      sizeof(mgmt->u.assoc_req))) { | ||||||
| @@ -3395,6 +3413,14 @@ static void handle_assoc(struct hostapd_ | @@ -3472,6 +3490,14 @@ static void handle_assoc(struct hostapd_ | ||||||
|  	} |  	} | ||||||
|  #endif /* CONFIG_MBO */ |  #endif /* CONFIG_MBO */ | ||||||
|   |   | ||||||
| @@ -176,7 +176,7 @@ | |||||||
|  	/* |  	/* | ||||||
|  	 * sta->capability is used in check_assoc_ies() for RRM enabled |  	 * sta->capability is used in check_assoc_ies() for RRM enabled | ||||||
|  	 * capability element. |  	 * capability element. | ||||||
| @@ -3608,6 +3634,7 @@ static void handle_disassoc(struct hosta | @@ -3685,6 +3711,7 @@ static void handle_disassoc(struct hosta | ||||||
|  	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", |  	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", | ||||||
|  		   MAC2STR(mgmt->sa), |  		   MAC2STR(mgmt->sa), | ||||||
|  		   le_to_host16(mgmt->u.disassoc.reason_code)); |  		   le_to_host16(mgmt->u.disassoc.reason_code)); | ||||||
| @@ -184,7 +184,7 @@ | |||||||
|   |   | ||||||
|  	sta = ap_get_sta(hapd, mgmt->sa); |  	sta = ap_get_sta(hapd, mgmt->sa); | ||||||
|  	if (sta == NULL) { |  	if (sta == NULL) { | ||||||
| @@ -3673,6 +3700,8 @@ static void handle_deauth(struct hostapd | @@ -3750,6 +3777,8 @@ static void handle_deauth(struct hostapd | ||||||
|  		" reason_code=%d", |  		" reason_code=%d", | ||||||
|  		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); |  		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); | ||||||
|   |   | ||||||
| @@ -193,7 +193,7 @@ | |||||||
|  	sta = ap_get_sta(hapd, mgmt->sa); |  	sta = ap_get_sta(hapd, mgmt->sa); | ||||||
|  	if (sta == NULL) { |  	if (sta == NULL) { | ||||||
|  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " |  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " | ||||||
| @@ -4000,7 +4029,7 @@ int ieee802_11_mgmt(struct hostapd_data | @@ -4077,7 +4106,7 @@ int ieee802_11_mgmt(struct hostapd_data | ||||||
|   |   | ||||||
|   |   | ||||||
|  	if (stype == WLAN_FC_STYPE_PROBE_REQ) { |  	if (stype == WLAN_FC_STYPE_PROBE_REQ) { | ||||||
| @@ -202,7 +202,7 @@ | |||||||
|  		return 1; |  		return 1; | ||||||
|  	} |  	} | ||||||
|   |   | ||||||
| @@ -4020,17 +4049,17 @@ int ieee802_11_mgmt(struct hostapd_data | @@ -4097,17 +4126,17 @@ int ieee802_11_mgmt(struct hostapd_data | ||||||
|  	switch (stype) { |  	switch (stype) { | ||||||
|  	case WLAN_FC_STYPE_AUTH: |  	case WLAN_FC_STYPE_AUTH: | ||||||
|  		wpa_printf(MSG_DEBUG, "mgmt::auth"); |  		wpa_printf(MSG_DEBUG, "mgmt::auth"); | ||||||
| @@ -368,7 +368,7 @@ | |||||||
|  CFLAGS += -DCONFIG_WNM_AP |  CFLAGS += -DCONFIG_WNM_AP | ||||||
| --- a/wpa_supplicant/wpa_supplicant.c | --- a/wpa_supplicant/wpa_supplicant.c | ||||||
| +++ b/wpa_supplicant/wpa_supplicant.c | +++ b/wpa_supplicant/wpa_supplicant.c | ||||||
| @@ -6062,6 +6062,8 @@ struct wpa_supplicant * wpa_supplicant_a | @@ -6080,6 +6080,8 @@ struct wpa_supplicant * wpa_supplicant_a | ||||||
|  	} |  	} | ||||||
|  #endif /* CONFIG_P2P */ |  #endif /* CONFIG_P2P */ | ||||||
|   |   | ||||||
| @@ -377,7 +377,7 @@ | |||||||
|  	return wpa_s; |  	return wpa_s; | ||||||
|  } |  } | ||||||
|   |   | ||||||
| @@ -6088,6 +6090,8 @@ int wpa_supplicant_remove_iface(struct w | @@ -6106,6 +6108,8 @@ int wpa_supplicant_remove_iface(struct w | ||||||
|  	struct wpa_supplicant *parent = wpa_s->parent; |  	struct wpa_supplicant *parent = wpa_s->parent; | ||||||
|  #endif /* CONFIG_MESH */ |  #endif /* CONFIG_MESH */ | ||||||
|   |   | ||||||
|   | |||||||
| @@ -96,6 +96,15 @@ wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj, | |||||||
| } | } | ||||||
|  |  | ||||||
| #ifdef CONFIG_WPS | #ifdef CONFIG_WPS | ||||||
|  | enum { | ||||||
|  | 	WPS_START_MULTI_AP, | ||||||
|  | 	__WPS_START_MAX | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct blobmsg_policy wps_start_policy[] = { | ||||||
|  | 	[WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL }, | ||||||
|  | }; | ||||||
|  |  | ||||||
| static int | static int | ||||||
| wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj, | wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj, | ||||||
| 			struct ubus_request_data *req, const char *method, | 			struct ubus_request_data *req, const char *method, | ||||||
| @@ -103,8 +112,15 @@ wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj, | |||||||
| { | { | ||||||
| 	int rc; | 	int rc; | ||||||
| 	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); | 	struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); | ||||||
|  | 	struct blob_attr *tb[__WPS_START_MAX], *cur; | ||||||
|  | 	int multi_ap = 0; | ||||||
|  |  | ||||||
| 	rc = wpas_wps_start_pbc(wpa_s, NULL, 0); | 	blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); | ||||||
|  |  | ||||||
|  | 	if (tb[WPS_START_MULTI_AP]) | ||||||
|  | 		multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]); | ||||||
|  |  | ||||||
|  | 	rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap); | ||||||
|  |  | ||||||
| 	if (rc != 0) | 	if (rc != 0) | ||||||
| 		return UBUS_STATUS_NOT_SUPPORTED; | 		return UBUS_STATUS_NOT_SUPPORTED; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user