Browse Source

Merge remote-tracking branch 'hostap/master' into research

Mathy Vanhoef 7 years ago
parent
commit
1e2fd20fda

+ 41 - 0
hostapd/config_file.c

@@ -1376,6 +1376,44 @@ static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
 }
 
 
+static int parse_venue_url(struct hostapd_bss_config *bss, char *pos,
+			    int line)
+{
+	char *sep;
+	size_t nlen;
+	struct hostapd_venue_url *url;
+	int ret = -1;
+
+	sep = os_strchr(pos, ':');
+	if (!sep)
+		goto fail;
+	*sep++ = '\0';
+
+	nlen = os_strlen(sep);
+	if (nlen > 254)
+		goto fail;
+
+	url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1,
+			       sizeof(struct hostapd_venue_url));
+	if (!url)
+		goto fail;
+
+	bss->venue_url = url;
+	url = &bss->venue_url[bss->venue_url_count++];
+
+	url->venue_number = atoi(pos);
+	url->url_len = nlen;
+	os_memcpy(url->url, sep, nlen);
+
+	ret = 0;
+fail:
+	if (ret)
+		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'",
+			   line, pos);
+	return ret;
+}
+
+
 static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
 			       int line)
 {
@@ -3380,6 +3418,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "venue_name") == 0) {
 		if (parse_venue_name(bss, pos, line) < 0)
 			return 1;
+	} else if (os_strcmp(buf, "venue_url") == 0) {
+		if (parse_venue_url(bss, pos, line) < 0)
+			return 1;
 	} else if (os_strcmp(buf, "network_auth_type") == 0) {
 		u8 auth_type;
 		u16 redirect_url_len;

+ 9 - 0
hostapd/hostapd.conf

@@ -1972,6 +1972,15 @@ wpa_group_rekey=8640000
 # (double quoted string, printf-escaped string)
 #venue_name=P"eng:Example\nvenue"
 
+# Venue URL information
+# This parameter can be used to configure one or more Venue URL Duples to
+# provide additional information corresponding to Venue Name information.
+# Each entry has a Venue Number value separated by colon from the Venue URL
+# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
+# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
+#venue_url=1:http://www.example.com/info-eng
+#venue_url=2:http://www.example.com/info-fin
+
 # Network Authentication Type
 # This parameter indicates what type of network authentication is used in the
 # network.

+ 1 - 0
src/ap/ap_config.c

@@ -577,6 +577,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 
 	os_free(conf->roaming_consortium);
 	os_free(conf->venue_name);
+	os_free(conf->venue_url);
 	os_free(conf->nai_realm_data);
 	os_free(conf->network_auth_type);
 	os_free(conf->anqp_3gpp_cell_net);

+ 10 - 0
src/ap/ap_config.h

@@ -201,6 +201,12 @@ struct hostapd_lang_string {
 	u8 name[252];
 };
 
+struct hostapd_venue_url {
+	u8 venue_number;
+	u8 url_len;
+	u8 url[254];
+};
+
 #define MAX_NAI_REALMS 10
 #define MAX_NAI_REALMLEN 255
 #define MAX_NAI_EAP_METHODS 5
@@ -504,6 +510,10 @@ struct hostapd_bss_config {
 	unsigned int venue_name_count;
 	struct hostapd_lang_string *venue_name;
 
+	/* Venue URL duples */
+	unsigned int venue_url_count;
+	struct hostapd_venue_url *venue_url;
+
 	/* IEEE 802.11u - Network Authentication Type */
 	u8 *network_auth_type;
 	size_t network_auth_type_len;

+ 32 - 2
src/ap/gas_serv.c

@@ -288,7 +288,7 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
 #endif /* CONFIG_FILS */
 	if (get_anqp_elem(hapd, ANQP_CAG))
 		wpabuf_put_le16(buf, ANQP_CAG);
-	if (get_anqp_elem(hapd, ANQP_VENUE_URL))
+	if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
 		wpabuf_put_le16(buf, ANQP_VENUE_URL);
 	if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
 		wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
@@ -328,6 +328,29 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
 }
 
 
+static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
+		return;
+
+	if (hapd->conf->venue_url) {
+		u8 *len;
+		unsigned int i;
+
+		len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
+		for (i = 0; i < hapd->conf->venue_url_count; i++) {
+			struct hostapd_venue_url *url;
+
+			url = &hapd->conf->venue_url[i];
+			wpabuf_put_u8(buf, 1 + url->url_len);
+			wpabuf_put_u8(buf, url->venue_number);
+			wpabuf_put_data(buf, url->url, url->url_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
 				       struct wpabuf *buf)
 {
@@ -946,6 +969,10 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
 			continue;
 		}
 #endif /* CONFIG_FILS */
+		if (extra_req[i] == ANQP_VENUE_URL) {
+			anqp_add_venue_url(hapd, buf);
+			continue;
+		}
 		anqp_add_elem(hapd, buf, extra_req[i]);
 	}
 
@@ -1082,7 +1109,10 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
 				   "ANQP: FILS Realm Information (local)");
 		} else
 #endif /* CONFIG_FILS */
-		if (!get_anqp_elem(hapd, info_id)) {
+		if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: Venue URL (local)");
+		} else if (!get_anqp_elem(hapd, info_id)) {
 			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
 				   info_id);
 			break;

+ 8 - 2
src/ap/wpa_auth.c

@@ -4737,7 +4737,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 	pos = ieee80211w_kde_add(sm, pos);
 	if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
 		poc_log(sm->addr, "Msg 3/4: including IGTK with %s RSC\n", maxrsc ? "max" : "zero");
-		opos += 2 + RSN_SELECTOR_LEN + 2; /* skip KDE header and keyid */
+		/* skip KDE header and keyid */
+		opos += 2 + RSN_SELECTOR_LEN + 2;
 		os_memset(opos, maxrsc ? 0x88 : 0, 6); /* clear PN */
 	}
 #endif /* CONFIG_IEEE80211W */
@@ -4845,8 +4846,13 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
 		pos = ieee80211w_kde_add(sm, pos);
 		if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
 			poc_log(sm->addr, "Group message 1: including IGTK with %s RSC\n", maxrsc ? "max" : "zero");
-			opos += 2 + RSN_SELECTOR_LEN + 2; /* skip KDE header and keyid */
+			/* skip KDE header and keyid */
+			opos += 2 + RSN_SELECTOR_LEN + 2;
 			os_memset(opos, maxrsc ? 0x88 : 0, 6); /* clear PN */
+		if (pos - opos >=
+		    2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
+
+			os_memset(opos, 0, 6); /* clear PN */
 		}
 #endif /* CONFIG_IEEE80211W */
 		kde_len = pos - kde;

+ 17 - 1
src/common/qca-vendor.h

@@ -2881,6 +2881,8 @@ enum qca_wlan_vendor_tdls_trigger_mode {
  *	limit feature.
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
  *	limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0: Select the SAR power
+ *	limits version 2.0 configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
  *
  * This enumerates the valid set of values that may be supplied for
  * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
@@ -2896,6 +2898,7 @@ enum qca_vendor_attr_sar_limits_selections {
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 = 7,
 };
 
 /**
@@ -2942,7 +2945,12 @@ enum qca_vendor_attr_sar_limits_spec_modulations {
  *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
  *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
  *	contains as a payload the attribute
- *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT.
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT,
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX.
+ *	Either %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT or
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX is
+ *	needed based upon the value of
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE.
  *
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
  *	indicate for which band this specification applies. Valid
@@ -2967,6 +2975,13 @@ enum qca_vendor_attr_sar_limits_spec_modulations {
  * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
  *	value to specify the actual power limit value in units of 0.5
  *	dBm (i.e., a value of 11 represents 5.5 dBm).
+ *	This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX: Required (u32)
+ *	value to indicate SAR V2 indices (0 - 11) to select SAR V2 profiles.
+ *	This is required, when %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT is
+ *	%QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0.
  *
  * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS
  * and %QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS.
@@ -2980,6 +2995,7 @@ enum qca_vendor_attr_sar_limits {
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX = 8,
 
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =

+ 1 - 0
src/common/wpa_ctrl.h

@@ -62,6 +62,7 @@ extern "C" {
 /** EAP authentication failed due to no response received */
 #define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
 #define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
+#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
 /** Network block temporarily disabled (e.g., due to authentication failure) */
 #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
 /** Temporarily disabled network block re-enabled */

+ 9 - 0
src/drivers/driver.h

@@ -4585,6 +4585,15 @@ enum wpa_event_type {
 	 * change event.
 	 */
 	EVENT_STATION_OPMODE_CHANGED,
+
+	/**
+	 * EVENT_INTERFACE_MAC_CHANGED - Notify that interface MAC changed
+	 *
+	 * This event is emitted when the MAC changes while the interface is
+	 * enabled. When an interface was disabled and becomes enabled, it
+	 * must be always assumed that the MAC possibly changed.
+	 */
+	EVENT_INTERFACE_MAC_CHANGED,
 };
 
 

+ 1 - 0
src/drivers/driver_common.c

@@ -85,6 +85,7 @@ const char * event_to_string(enum wpa_event_type event)
 	E2S(EXTERNAL_AUTH);
 	E2S(PORT_AUTHORIZED);
 	E2S(STATION_OPMODE_CHANGED);
+	E2S(INTERFACE_MAC_CHANGED);
 	}
 
 	return "UNKNOWN";

+ 7 - 4
src/drivers/driver_nl80211.c

@@ -952,7 +952,7 @@ nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len,
 
 
 static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
-				int ifindex)
+				int ifindex, int notify)
 {
 	struct i802_bss *bss;
 	u8 addr[ETH_ALEN];
@@ -971,6 +971,9 @@ static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
 			   ifindex, bss->ifname,
 			   MAC2STR(bss->addr), MAC2STR(addr));
 		os_memcpy(bss->addr, addr, ETH_ALEN);
+		if (notify)
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_MAC_CHANGED, NULL);
 	}
 }
 
@@ -1042,11 +1045,11 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 		namebuf[0] = '\0';
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
 		    linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
-			/* Re-read MAC address as it may have changed */
-			nl80211_refresh_mac(drv, ifi->ifi_index);
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
 			drv->ignore_if_down_event = 0;
+			/* Re-read MAC address as it may have changed */
+			nl80211_refresh_mac(drv, ifi->ifi_index, 1);
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
@@ -1092,7 +1095,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 				   "removed", drv->first_bss->ifname);
 		} else {
 			/* Re-read MAC address as it may have changed */
-			nl80211_refresh_mac(drv, ifi->ifi_index);
+			nl80211_refresh_mac(drv, ifi->ifi_index, 0);
 
 			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
 			drv->if_disabled = 0;

+ 4 - 0
src/drivers/driver_nl80211_capa.c

@@ -411,6 +411,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
 	if (ext_feature_isset(ext_features, len,
 			      NL80211_EXT_FEATURE_MFP_OPTIONAL))
 		capa->flags |= WPA_DRIVER_FLAGS_MFP_OPTIONAL;
+
+	if (ext_feature_isset(ext_features, len,
+			      NL80211_EXT_FEATURE_DFS_OFFLOAD))
+		capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
 }
 
 

+ 3 - 0
src/drivers/driver_nl80211_event.c

@@ -1592,6 +1592,9 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
 		wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
 				     &data);
 		break;
+	case NL80211_RADAR_CAC_STARTED:
+		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
 			   "received", event_type);

+ 45 - 1
src/drivers/nl80211_copy.h

@@ -542,7 +542,8 @@
  *	IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
  *	%NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
- *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+ *	%NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and
  *	%NL80211_ATTR_WIPHY_FREQ_HINT.
  *	If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are
  *	restrictions on BSS selection, i.e., they effectively prevent roaming
@@ -990,6 +991,17 @@
  *	&NL80211_CMD_CONNECT or &NL80211_CMD_ROAM. If the 4 way handshake failed
  *	&NL80211_CMD_DISCONNECT should be indicated instead.
  *
+ * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
+ *	and RX notification.  This command is used both as a request to transmit
+ *	a control port frame and as a notification that a control port frame
+ *	has been received. %NL80211_ATTR_FRAME is used to specify the
+ *	frame contents.  The frame is the raw EAPoL data, without ethernet or
+ *	802.11 headers.
+ *	When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ *	%NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added
+ *	indicating the protocol type of the received frame; whether the frame
+ *	was received unencrypted and the MAC address of the peer respectively.
+ *
  * @NL80211_CMD_RELOAD_REGDB: Request that the regdb firmware file is reloaded.
  *
  * @NL80211_CMD_EXTERNAL_AUTH: This interface is exclusively defined for host
@@ -1228,6 +1240,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_STA_OPMODE_CHANGED,
 
+	NL80211_CMD_CONTROL_PORT_FRAME,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1475,6 +1489,15 @@ enum nl80211_commands {
  * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
  *	%NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
  *	ethertype frames used for key negotiation must not be encrypted.
+ * @NL80211_ATTR_CONTROL_PORT_OVER_NL80211: A flag indicating whether control
+ *	port frames (e.g. of type given in %NL80211_ATTR_CONTROL_PORT_ETHERTYPE)
+ *	will be sent directly to the network interface or sent via the NL80211
+ *	socket.  If this attribute is missing, then legacy behavior of sending
+ *	control port frames directly to the network interface is used.  If the
+ *	flag is included, then control port frames are sent over NL80211 instead
+ *	using %CMD_CONTROL_PORT_FRAME.  If control port routing over NL80211 is
+ *	to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
+ *	flag.
  *
  * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
  *	We recommend using nested, driver-specific attributes within this.
@@ -1962,6 +1985,12 @@ enum nl80211_commands {
  *	multicast group.
  *	If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
  *	station will deauthenticate when the socket is closed.
+ *	If set during %NL80211_CMD_JOIN_IBSS the IBSS will be automatically
+ *	torn down when the socket is closed.
+ *	If set during %NL80211_CMD_JOIN_MESH the mesh setup will be
+ *	automatically torn down when the socket is closed.
+ *	If set during %NL80211_CMD_START_AP the AP will be automatically
+ *	disabled when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
@@ -2628,6 +2657,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_NSS,
 	NL80211_ATTR_ACK_SIGNAL,
 
+	NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -4999,6 +5030,14 @@ enum nl80211_feature_flags {
  * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
  * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
  * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
+ * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions.
+ *	Device or driver will do all DFS-related actions by itself,
+ *	informing user-space about CAC progress, radar detection event,
+ *	channel change triggered by radar detection event.
+ *	No need to start CAC from user-space, no need to react to
+ *	"radar detected" event.
+ * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
+ *	receiving control port frames over nl80211 instead of the netdevice.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5029,6 +5068,8 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
 	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
 	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
+	NL80211_EXT_FEATURE_DFS_OFFLOAD,
+	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -5204,6 +5245,8 @@ enum nl80211_smps_mode {
  *	non-operating channel is expired and no longer valid. New CAC must
  *	be done on this channel before starting the operation. This is not
  *	applicable for ETSI dfs domain where pre-CAC is valid for ever.
+ * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
+ *	should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
  */
 enum nl80211_radar_event {
 	NL80211_RADAR_DETECTED,
@@ -5211,6 +5254,7 @@ enum nl80211_radar_event {
 	NL80211_RADAR_CAC_ABORTED,
 	NL80211_RADAR_NOP_FINISHED,
 	NL80211_RADAR_PRE_CAC_EXPIRED,
+	NL80211_RADAR_CAC_STARTED,
 };
 
 /**

+ 17 - 0
src/eap_peer/eap.c

@@ -95,6 +95,14 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
 }
 
 
+static void eap_report_error(struct eap_sm *sm, int error_code)
+{
+	wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
+	if (sm->eapol_cb->notify_eap_error)
+		sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
+}
+
+
 static void eap_sm_free_key(struct eap_sm *sm)
 {
 	if (sm->eapKeyData) {
@@ -2018,6 +2026,15 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
 	case EAP_CODE_FAILURE:
 		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
 		eap_notify_status(sm, "completion", "failure");
+
+		/* Get the error code from method */
+		if (sm->m && sm->m->get_error_code) {
+			int error_code;
+
+			error_code = sm->m->get_error_code(sm->eap_method_priv);
+			if (error_code != NO_EAP_METHOD_ERROR)
+				eap_report_error(sm, error_code);
+		}
 		sm->rxFailure = TRUE;
 		break;
 	case EAP_CODE_INITIATE:

+ 7 - 0
src/eap_peer/eap.h

@@ -246,6 +246,13 @@ struct eapol_callbacks {
 	void (*notify_status)(void *ctx, const char *status,
 			      const char *parameter);
 
+	/**
+	 * notify_eap_error - Report EAP method error code
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @error_code: Error code from the used EAP method
+	 */
+	void (*notify_eap_error)(void *ctx, int error_code);
+
 #ifdef CONFIG_EAP_PROXY
 	/**
 	 * eap_proxy_cb - Callback signifying any updates from eap_proxy

+ 24 - 0
src/eap_peer/eap_aka.c

@@ -56,6 +56,7 @@ struct eap_aka_data {
 	int kdf_negotiation;
 	u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
 	size_t last_kdf_count;
+	int error_code;
 };
 
 
@@ -99,6 +100,9 @@ static void * eap_aka_init(struct eap_sm *sm)
 
 	data->eap_method = EAP_TYPE_AKA;
 
+	/* Zero is a valid error code, so we need to initialize */
+	data->error_code = NO_EAP_METHOD_ERROR;
+
 	eap_aka_state(data, CONTINUE);
 	data->prev_id = -1;
 
@@ -1180,6 +1184,7 @@ static struct wpabuf * eap_aka_process_notification(
 
 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
 	if (attr->notification >= 0 && attr->notification < 32768) {
+		data->error_code = attr->notification;
 		eap_aka_state(data, FAILURE);
 	} else if (attr->notification == EAP_SIM_SUCCESS &&
 		   data->state == RESULT_SUCCESS)
@@ -1524,6 +1529,23 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static int eap_aka_get_error_code(void *priv)
+{
+	struct eap_aka_data *data = priv;
+	int current_data_error;
+
+	if (!data)
+		return NO_EAP_METHOD_ERROR;
+
+	current_data_error = data->error_code;
+
+	/* Now reset for next transaction */
+	data->error_code = NO_EAP_METHOD_ERROR;
+
+	return current_data_error;
+}
+
+
 int eap_peer_aka_register(void)
 {
 	struct eap_method *eap;
@@ -1544,6 +1566,7 @@ int eap_peer_aka_register(void)
 	eap->init_for_reauth = eap_aka_init_for_reauth;
 	eap->get_identity = eap_aka_get_identity;
 	eap->get_emsk = eap_aka_get_emsk;
+	eap->get_error_code = eap_aka_get_error_code;
 
 	return eap_peer_method_register(eap);
 }
@@ -1571,6 +1594,7 @@ int eap_peer_aka_prime_register(void)
 	eap->init_for_reauth = eap_aka_init_for_reauth;
 	eap->get_identity = eap_aka_get_identity;
 	eap->get_emsk = eap_aka_get_emsk;
+	eap->get_error_code = eap_aka_get_error_code;
 
 	return eap_peer_method_register(eap);
 }

+ 13 - 0
src/eap_peer/eap_i.h

@@ -14,6 +14,8 @@
 #include "eap_peer/eap.h"
 #include "eap_common/eap_common.h"
 
+#define NO_EAP_METHOD_ERROR (-1)
+
 /* RFC 4137 - EAP Peer state machine */
 
 typedef enum {
@@ -205,6 +207,17 @@ struct eap_method {
 	 */
 	const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
 
+	/**
+	 * get_error_code - Get the latest EAP method error code
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * Returns: An int for the EAP method specific error code if exists or
+	 * NO_EAP_METHOD_ERROR otherwise.
+	 *
+	 * This method is an optional handler that only EAP methods that need to
+	 * report their error code need to implement.
+	 */
+	int (*get_error_code)(void *priv);
+
 	/**
 	 * free - Free EAP method data
 	 * @method: Pointer to the method data registered with

+ 23 - 0
src/eap_peer/eap_sim.c

@@ -47,6 +47,7 @@ struct eap_sim_data {
 	} state;
 	int result_ind, use_result_ind;
 	int use_pseudonym;
+	int error_code;
 };
 
 
@@ -94,6 +95,9 @@ static void * eap_sim_init(struct eap_sm *sm)
 		return NULL;
 	}
 
+	/* Zero is a valid error code, so we need to initialize */
+	data->error_code = NO_EAP_METHOD_ERROR;
+
 	data->min_num_chal = 2;
 	if (config && config->phase1) {
 		char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
@@ -920,6 +924,7 @@ static struct wpabuf * eap_sim_process_notification(
 
 	eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
 	if (attr->notification >= 0 && attr->notification < 32768) {
+		data->error_code = attr->notification;
 		eap_sim_state(data, FAILURE);
 	} else if (attr->notification == EAP_SIM_SUCCESS &&
 		   data->state == RESULT_SUCCESS)
@@ -1244,6 +1249,23 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static int eap_sim_get_error_code(void *priv)
+{
+	struct eap_sim_data *data = priv;
+	int current_data_error;
+
+	if (!data)
+		return NO_EAP_METHOD_ERROR;
+
+	current_data_error = data->error_code;
+
+	/* Now reset for next transaction */
+	data->error_code = NO_EAP_METHOD_ERROR;
+
+	return current_data_error;
+}
+
+
 int eap_peer_sim_register(void)
 {
 	struct eap_method *eap;
@@ -1264,6 +1286,7 @@ int eap_peer_sim_register(void)
 	eap->init_for_reauth = eap_sim_init_for_reauth;
 	eap->get_identity = eap_sim_get_identity;
 	eap->get_emsk = eap_sim_get_emsk;
+	eap->get_error_code = eap_sim_get_error_code;
 
 	return eap_peer_method_register(eap);
 }

+ 10 - 0
src/eapol_supp/eapol_supp_sm.c

@@ -2015,6 +2015,15 @@ static void eapol_sm_notify_status(void *ctx, const char *status,
 }
 
 
+static void eapol_sm_notify_eap_error(void *ctx, int error_code)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->eap_error_cb)
+		sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
+}
+
+
 #ifdef CONFIG_EAP_PROXY
 
 static void eapol_sm_eap_proxy_cb(void *ctx)
@@ -2062,6 +2071,7 @@ static const struct eapol_callbacks eapol_cb =
 	eapol_sm_eap_param_needed,
 	eapol_sm_notify_cert,
 	eapol_sm_notify_status,
+	eapol_sm_notify_eap_error,
 #ifdef CONFIG_EAP_PROXY
 	eapol_sm_eap_proxy_cb,
 	eapol_sm_eap_proxy_notify_sim_status,

+ 7 - 0
src/eapol_supp/eapol_supp_sm.h

@@ -271,6 +271,13 @@ struct eapol_ctx {
 	void (*status_cb)(void *ctx, const char *status,
 			  const char *parameter);
 
+	/**
+	 * eap_error_cb - Notification of EAP method error
+	 * @ctx: Callback context (ctx)
+	 * @error_code: EAP method error code
+	 */
+	void (*eap_error_cb)(void *ctx, int error_code);
+
 #ifdef CONFIG_EAP_PROXY
 	/**
 	 * eap_proxy_cb - Callback signifying any updates from eap_proxy

+ 4 - 0
src/radius/radius.h

@@ -102,6 +102,10 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
        RADIUS_ATTR_LOCATION_CAPABLE = 131,
        RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
+       RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_NAME = 164,
+       RADIUS_ATTR_GSS_ACCEPTOR_HOST_NAME = 165,
+       RADIUS_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFICS = 166,
+       RADIUS_ATTR_GSS_ACCEPTOR_REALM_NAME = 167,
        RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
        RADIUS_ATTR_WLAN_HESSID = 181,
        RADIUS_ATTR_WLAN_REASON_CODE = 185,

+ 46 - 0
tests/hwsim/test_ap_ciphers.py

@@ -822,6 +822,29 @@ def test_ap_wpa2_plaintext_m1_m3(dev, apdev):
         raise Exception("RESEND_M3 failed")
     time.sleep(0.1)
 
+def test_ap_wpa2_plaintext_m1_m3_pmf(dev, apdev):
+    """Plaintext M1/M3 during PTK rekey (PMF)"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+
+    dev[0].connect("test-wpa2-psk", psk="12345678", ieee80211w="2",
+                   scan_freq="2412")
+
+    time.sleep(0.1)
+    addr = dev[0].own_addr()
+    if "OK" not in hapd.request("RESEND_M1 " + addr + " plaintext"):
+        raise Exception("RESEND_M1 failed")
+    time.sleep(0.1)
+    if "OK" not in hapd.request("RESEND_M3 " + addr + " plaintext"):
+        raise Exception("RESEND_M3 failed")
+    time.sleep(0.1)
+
 def test_ap_wpa2_plaintext_m3(dev, apdev):
     """Plaintext M3 during PTK rekey"""
     params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
@@ -863,3 +886,26 @@ def test_ap_wpa2_plaintext_group_m1(dev, apdev):
     if "OK" not in hapd.request("RESEND_GROUP_M1 " + addr):
         raise Exception("RESEND_GROUP_M1 failed")
     time.sleep(0.1)
+
+def test_ap_wpa2_plaintext_group_m1_pmf(dev, apdev):
+    """Plaintext group M1 (PMF)"""
+    params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
+    params["ieee80211w"] = "2"
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    Wlantest.setup(hapd)
+    wt = Wlantest()
+    wt.flush()
+    wt.add_passphrase("12345678")
+
+    dev[0].connect("test-wpa2-psk", psk="12345678", ieee80211w="2",
+                   scan_freq="2412")
+
+    time.sleep(0.1)
+    addr = dev[0].own_addr()
+    if "OK" not in hapd.request("RESEND_GROUP_M1 " + addr + " plaintext"):
+        raise Exception("RESEND_GROUP_M1 failed")
+    time.sleep(0.2)
+    if "OK" not in hapd.request("RESEND_GROUP_M1 " + addr):
+        raise Exception("RESEND_GROUP_M1 failed")
+    time.sleep(0.1)

+ 59 - 0
tests/hwsim/test_ap_eap.py

@@ -12,6 +12,7 @@ import subprocess
 import logging
 logger = logging.getLogger()
 import os
+import signal
 import socket
 import SocketServer
 import struct
@@ -5891,6 +5892,11 @@ def test_ap_wpa2_eap_sim_db(dev, apdev, params):
                         eap="SIM", identity="1232010000000000",
                         password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581",
                         scan_freq="2412", wait_connect=False)
+    ev = dev[0].wait_event(["EAP-ERROR-CODE"], timeout=10)
+    if ev is None:
+        raise Exception("EAP method specific error code not reported")
+    if int(ev.split()[1]) != 16384:
+        raise Exception("Unexpected EAP method specific error code: " + ev)
     ev = dev[0].wait_event(["CTRL-EVENT-EAP-FAILURE"], timeout=10)
     if ev is None:
         raise Exception("EAP-Failure not reported")
@@ -6365,3 +6371,56 @@ def test_ap_wpa2_eap_wildcard_ssid(dev, apdev):
                    identity="gpsk user",
                    password="abcdefghijklmnop0123456789abcdef",
                    scan_freq="2412")
+
+def test_ap_wpa2_eap_psk_mac_addr_change(dev, apdev):
+    """WPA2-Enterprise connection using EAP-PSK after MAC address change"""
+    params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+    hapd = hostapd.add_ap(apdev[0], params)
+
+    cmd = subprocess.Popen(['ps', '-eo', 'pid,command'], stdout=subprocess.PIPE)
+    res = cmd.stdout.read()
+    cmd.stdout.close()
+    pid = 0
+    for p in res.splitlines():
+        if "wpa_supplicant" not in p:
+            continue
+        if dev[0].ifname not in p:
+            continue
+        pid = int(p.strip().split(' ')[0])
+    if pid == 0:
+        logger.info("Could not find wpa_supplicant PID")
+    else:
+        logger.info("wpa_supplicant PID %d" % pid)
+
+    addr = dev[0].get_status_field("address")
+    subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'down'])
+    subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'address',
+                     '02:11:22:33:44:55'])
+    subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'up'])
+    addr1 = dev[0].get_status_field("address")
+    if addr1 != '02:11:22:33:44:55':
+        raise Exception("Failed to change MAC address")
+
+    # Scan using the externally set MAC address, stop the wpa_supplicant
+    # process to avoid it from processing the ifdown event before the interface
+    # is already UP, change the MAC address back, allow the wpa_supplicant
+    # process to continue. This will result in the ifdown + ifup sequence of
+    # RTM_NEWLINK events to be processed while the interface is already UP.
+    try:
+        dev[0].scan_for_bss(apdev[0]['bssid'], freq=2412)
+        os.kill(pid, signal.SIGSTOP)
+        time.sleep(0.1)
+    finally:
+        subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'down'])
+        subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'address',
+                         addr])
+        subprocess.call(['ip', 'link', 'set', 'dev', dev[0].ifname, 'up'])
+        time.sleep(0.1)
+        os.kill(pid, signal.SIGCONT)
+
+    eap_connect(dev[0], hapd, "PSK", "psk.user@example.com",
+                password_hex="0123456789abcdef0123456789abcdef")
+
+    addr2 = dev[0].get_status_field("address")
+    if addr != addr2:
+        raise Exception("Failed to restore MAC address")

+ 56 - 2
tests/hwsim/test_gas.py

@@ -1608,8 +1608,8 @@ def test_gas_anqp_venue_url(dev, apdev):
 
     url1 = "http://example.com/venue"
     url2 = "https://example.org/venue-info/"
-    duple1 = struct.pack('BB', 1 + len(url1), 0)
-    duple2 = struct.pack('BB', 1 + len(url2), 1)
+    duple1 = struct.pack('BB', 1 + len(url1), 1) + url1
+    duple2 = struct.pack('BB', 1 + len(url2), 2) + url2
     venue_url = binascii.hexlify(duple1 + duple2)
 
     params = { "ssid": "gas/anqp",
@@ -1646,6 +1646,60 @@ def test_gas_anqp_venue_url(dev, apdev):
     if not bss['anqp_capability_list'].startswith(binascii.hexlify(ids)):
         raise Exception("Unexpected Capability List ANQP-element value: " + bss['anqp_capability_list'])
 
+def test_gas_anqp_venue_url2(dev, apdev):
+    """GAS/ANQP and Venue URL (hostapd venue_url)"""
+    venue_group = 1
+    venue_type = 13
+    venue_info = struct.pack('BB', venue_group, venue_type)
+    lang1 = "eng"
+    name1= "Example venue"
+    lang2 = "fin"
+    name2 = "Esimerkkipaikka"
+    venue1 = struct.pack('B', len(lang1 + name1)) + lang1 + name1
+    venue2 = struct.pack('B', len(lang2 + name2)) + lang2 + name2
+    venue_name = binascii.hexlify(venue_info + venue1 + venue2)
+
+    url1 = "http://example.com/venue"
+    url2 = "https://example.org/venue-info/"
+    duple1 = struct.pack('BB', 1 + len(url1), 1) + url1
+    duple2 = struct.pack('BB', 1 + len(url2), 2) + url2
+    venue_url = binascii.hexlify(duple1 + duple2)
+
+    params = { "ssid": "gas/anqp",
+               "interworking": "1",
+               "venue_group": str(venue_group),
+               "venue_type": str(venue_type),
+               "venue_name": [ lang1 + ":" + name1, lang2 + ":" + name2 ],
+               "venue_url": [ "1:" + url1, "2:" + url2 ] }
+    hapd = hostapd.add_ap(apdev[0], params)
+    bssid = apdev[0]['bssid']
+
+    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
+    if "OK" not in dev[0].request("ANQP_GET " + bssid + " 257,258,277"):
+        raise Exception("ANQP_GET command failed")
+
+    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
+    if ev is None:
+        raise Exception("GAS query timed out")
+
+    bss = dev[0].get_bss(bssid)
+
+    if 'anqp_venue_name' not in bss:
+        raise Exception("Venue Name ANQP-element not seen")
+    if bss['anqp_venue_name'] != venue_name:
+        raise Exception("Unexpected Venue Name ANQP-element value: " + bss['anqp_venue_name'])
+    if 'anqp[277]' not in bss:
+        raise Exception("Venue URL ANQP-element not seen")
+    if bss['anqp[277]'] != venue_url:
+        print venue_url
+        raise Exception("Unexpected Venue URL ANQP-element value: " + bss['anqp[277]'])
+
+    if 'anqp_capability_list' not in bss:
+        raise Exception("Capability List ANQP-element not seen")
+    ids = struct.pack('<HHH', 257, 258, 277)
+    if not bss['anqp_capability_list'].startswith(binascii.hexlify(ids)):
+        raise Exception("Unexpected Capability List ANQP-element value: " + bss['anqp_capability_list'])
+
 def test_gas_anqp_capab_list(dev, apdev):
     """GAS/ANQP and Capability List ANQP-element"""
     params = { "ssid": "gas/anqp",

+ 47 - 0
tests/hwsim/test_sigma_dut.py

@@ -1842,6 +1842,53 @@ def run_sigma_dut_dpp_proto_stop_at_initiator(dev, frame, result, fail):
     dev[0].dump_monitor()
     dev[1].dump_monitor()
 
+def test_sigma_dut_dpp_proto_stop_at_initiator_enrollee(dev, apdev):
+    """sigma_dut DPP protocol testing - Stop at TX on Initiator/Enrollee"""
+    check_dpp_capab(dev[0])
+    check_dpp_capab(dev[1])
+    tests = [ ("AuthenticationConfirm",
+               "BootstrapResult,OK,AuthResult,Errorsent,LastFrameReceived,AuthenticationResponse",
+               None) ]
+    for frame, result, fail in tests:
+        dev[0].request("FLUSH")
+        dev[1].request("FLUSH")
+        sigma = start_sigma_dut(dev[0].ifname, debug=True)
+        try:
+            run_sigma_dut_dpp_proto_stop_at_initiator_enrollee(dev, frame,
+                                                               result, fail)
+        finally:
+            stop_sigma_dut(sigma)
+
+def run_sigma_dut_dpp_proto_stop_at_initiator_enrollee(dev, frame, result,
+                                                       fail):
+    addr = dev[1].own_addr().replace(':', '')
+    cmd = "DPP_BOOTSTRAP_GEN type=qrcode chan=81/6 mac=" + addr
+    res = dev[1].request(cmd)
+    if "FAIL" in res:
+        raise Exception("Failed to generate bootstrapping info")
+    id0 = int(res)
+    uri0 = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id0)
+
+    cmd = "DPP_LISTEN 2437 role=configurator"
+    if "OK" not in dev[1].request(cmd):
+        raise Exception("Failed to start listen operation")
+
+    res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,SetPeerBootstrap,DPPBootstrappingdata,%s,DPPBS,QR" % uri0.encode('hex'))
+    if "status,COMPLETE" not in res:
+        raise Exception("dev_exec_action did not succeed: " + res)
+
+    res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Initiator,DPPAuthDirection,Single,DPPProvisioningRole,Enrollee,DPPBS,QR,DPPTimeout,6,DPPStep,Timeout,DPPFrameType,%s" % (frame), timeout=10)
+    if result not in res:
+        raise Exception("Unexpected result: " + res)
+    if fail:
+        ev = dev[1].wait_event(["DPP-FAIL"], timeout=5)
+        if ev is None or fail not in ev:
+            raise Exception("Failure not reported correctly: " + str(ev))
+
+    dev[1].request("DPP_STOP_LISTEN")
+    dev[0].dump_monitor()
+    dev[1].dump_monitor()
+
 def test_sigma_dut_dpp_proto_stop_at_responder(dev, apdev):
     """sigma_dut DPP protocol testing - Stop at RX on Responder"""
     check_dpp_capab(dev[0])

+ 4 - 1
wpa_supplicant/dbus/dbus_new_handlers.c

@@ -980,7 +980,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
 	const struct wpa_dbus_property_desc *property_desc,
 	DBusMessageIter *iter, DBusError *error, void *user_data)
 {
-	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+	const char *capabilities[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
 	size_t num_items = 0;
 
 #ifdef CONFIG_AP
@@ -998,6 +998,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
 #ifdef CONFIG_IEEE80211W
 	capabilities[num_items++] = "pmf";
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MESH
+	capabilities[num_items++] = "mesh";
+#endif /* CONFIG_MESH */
 
 	return wpas_dbus_simple_array_property_getter(iter,
 						      DBUS_TYPE_STRING,

+ 11 - 2
wpa_supplicant/defconfig

@@ -73,6 +73,12 @@ CONFIG_DRIVER_NL80211=y
 # Driver interface for wired Ethernet drivers
 CONFIG_DRIVER_WIRED=y
 
+# Driver interface for MACsec capable Qualcomm Atheros drivers
+#CONFIG_DRIVER_MACSEC_QCA=y
+
+# Driver interface for Linux MACsec drivers
+#CONFIG_DRIVER_MACSEC_LINUX=y
+
 # Driver interface for the Broadcom RoboSwitch family
 #CONFIG_DRIVER_ROBOSWITCH=y
 
@@ -83,8 +89,8 @@ CONFIG_DRIVER_WIRED=y
 #LIBS += -lsocket -ldlpi -lnsl
 #LIBS_c += -lsocket
 
-# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
-# included)
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or
+# MACsec is included)
 CONFIG_IEEE8021X_EAPOL=y
 
 # EAP-MD5
@@ -166,6 +172,9 @@ CONFIG_EAP_LEAP=y
 # EAP-EKE
 #CONFIG_EAP_EKE=y
 
+# MACsec
+#CONFIG_MACSEC=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y

+ 3 - 0
wpa_supplicant/events.c

@@ -4374,6 +4374,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			data->signal_change.current_noise,
 			data->signal_change.current_txrate);
 		break;
+	case EVENT_INTERFACE_MAC_CHANGED:
+		wpa_supplicant_update_mac_addr(wpa_s);
+		break;
 	case EVENT_INTERFACE_ENABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {

+ 6 - 0
wpa_supplicant/notify.c

@@ -816,6 +816,12 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
 }
 
 
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
+{
+	wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_EAP_ERROR_CODE "%d", error_code);
+}
+
+
 void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
 					   struct wpa_ssid *ssid)
 {

+ 1 - 0
wpa_supplicant/notify.h

@@ -134,6 +134,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s,
 		      const u8 *ie, size_t ie_len, u32 ssi_signal);
 void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
 			    const char *parameter);
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code);
 void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
 					   struct wpa_ssid *ssid);
 void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,

+ 23 - 12
wpa_supplicant/wpa_supplicant.conf

@@ -1765,15 +1765,26 @@ network={
 }
 
 
-# Example MACsec configuration
-#network={
-#	key_mgmt=IEEE8021X
-#	eap=TTLS
-#	phase2="auth=PAP"
-#	anonymous_identity="anonymous@example.com"
-#	identity="user@example.com"
-#	password="secretr"
-#	ca_cert="/etc/cert/ca.pem"
-#	eapol_flags=0
-#	macsec_policy=1
-#}
+# Example configuration using EAP-TTLS for authentication and key
+# generation for MACsec
+network={
+	key_mgmt=IEEE8021X
+	eap=TTLS
+	phase2="auth=PAP"
+	anonymous_identity="anonymous@example.com"
+	identity="user@example.com"
+	password="secretr"
+	ca_cert="/etc/cert/ca.pem"
+	eapol_flags=0
+	macsec_policy=1
+}
+
+# Example configuration for MACsec with preshared key
+network={
+	key_mgmt=NONE
+	eapol_flags=0
+	macsec_policy=1
+	mka_cak=0123456789ABCDEF0123456789ABCDEF
+	mka_ckn=6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435
+	mka_priority=128
+}

+ 9 - 0
wpa_supplicant/wpas_glue.c

@@ -1038,6 +1038,14 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status,
 }
 
 
+static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_eap_error(wpa_s, error_code);
+}
+
+
 static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -1115,6 +1123,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
 	ctx->cert_cb = wpa_supplicant_cert_cb;
 	ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
 	ctx->status_cb = wpa_supplicant_status_cb;
+	ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
 	ctx->set_anon_id = wpa_supplicant_set_anon_id;
 	ctx->cb_ctx = wpa_s;
 	wpa_s->eapol = eapol_sm_init(ctx);