Accumulative patch from commit 17b8995cf5813d7c027cd7a6884700e791d72392

17b8995 Interworking: Try to use same BSS entry for storing GAS results
3db5439 Optimize Extended Capabilities element to be of minimal length
8cd6b7b hostapd/wpa_s: Use driver's extended capabilities
acb5464 Add ctrl_iface command FLUSH for clearing wpa_supplicant state
97236ce WPS: Skip rescanning after provisioning if AP was configured
4342326 Add ignore_old_scan_res configuration parameter
9599ccc WPS: Clear after_wps on new WPS connection
702621e WPS: Use latest updated BSS entry if multiple BSSID matches found
ab547b5 WPS: Add more helpful debug for invalid WPS_REG command parsing
a679c0f WPS: Allow hostapd process to control independent WPS interfaces
ccdff94 WPS AP: Add support for reconfiguration with in-memory config
8970bae nl80211: Use nla_nest_start/end instead of nla_put_nested
558d69e P2P: Omit P2P Group Info in case of no connected peers
65a32cd AP: Fix infinite loop in WPA state machine when out of random bytes
a5f61b2 Fix OLBC non-HT AP detection to check channel
69554d7 ap_list: Remove unused functions
08c99ca ap_list: Remove unused iteration list pointers
6b16917 ap_list: Remove unused fields
66f1f75 P2P: Fix provision discovery response handling in some cases
2f9b66d Extend ROAM command to handle multiple SSIDs per BSS

Change-Id: I46002b1d3bbf6e376c2ae09bcb2c824c54805bbd
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index e017972..69b34fe 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -45,6 +45,7 @@
 struct wps_for_each_data {
 	int (*func)(struct hostapd_data *h, void *ctx);
 	void *ctx;
+	struct hostapd_data *calling_hapd;
 };
 
 
@@ -57,7 +58,14 @@
 		return 0;
 	for (j = 0; j < iface->num_bss; j++) {
 		struct hostapd_data *hapd = iface->bss[j];
-		int ret = data->func(hapd, data->ctx);
+		int ret;
+
+		if (hapd != data->calling_hapd &&
+		    (hapd->conf->wps_independent ||
+		     data->calling_hapd->conf->wps_independent))
+			continue;
+
+		ret = data->func(hapd, data->ctx);
 		if (ret)
 			return ret;
 	}
@@ -74,6 +82,7 @@
 	struct wps_for_each_data data;
 	data.func = func;
 	data.ctx = ctx;
+	data.calling_hapd = hapd;
 	if (iface->interfaces == NULL ||
 	    iface->interfaces->for_each_interface == NULL)
 		return wps_for_each(iface, &data);
@@ -277,6 +286,114 @@
 }
 
 
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+				       const struct wps_credential *cred)
+{
+	struct hostapd_bss_config *bss = hapd->conf;
+
+	wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+	bss->wps_state = 2;
+	if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+		os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+		bss->ssid.ssid_len = cred->ssid_len;
+		bss->ssid.ssid_set = 1;
+	}
+
+	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+		bss->wpa = 3;
+	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+		bss->wpa = 2;
+	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+		bss->wpa = 1;
+	else
+		bss->wpa = 0;
+
+	if (bss->wpa) {
+		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+		bss->wpa_pairwise = 0;
+		if (cred->encr_type & WPS_ENCR_AES)
+			bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+		if (cred->encr_type & WPS_ENCR_TKIP)
+			bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+		bss->rsn_pairwise = bss->wpa_pairwise;
+		bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+							    bss->wpa_pairwise,
+							    bss->rsn_pairwise);
+
+		if (cred->key_len >= 8 && cred->key_len < 64) {
+			os_free(bss->ssid.wpa_passphrase);
+			bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+			if (bss->ssid.wpa_passphrase)
+				os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+					  cred->key_len);
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk = NULL;
+		} else if (cred->key_len == 64) {
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk =
+				os_zalloc(sizeof(struct hostapd_wpa_psk));
+			if (bss->ssid.wpa_psk &&
+			    hexstr2bin((const char *) cred->key,
+				       bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+				bss->ssid.wpa_psk->group = 1;
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = NULL;
+			}
+		}
+		bss->auth_algs = 1;
+	} else {
+		if ((cred->auth_type & WPS_AUTH_OPEN) &&
+		    (cred->auth_type & WPS_AUTH_SHARED))
+			bss->auth_algs = 3;
+		else if (cred->auth_type & WPS_AUTH_SHARED)
+			bss->auth_algs = 2;
+		else
+			bss->auth_algs = 1;
+		if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
+		    cred->key_idx <= 4) {
+			struct hostapd_wep_keys *wep = &bss->ssid.wep;
+			int idx = cred->key_idx;
+			if (idx)
+				idx--;
+			wep->idx = idx;
+			if (cred->key_len == 10 || cred->key_len == 26) {
+				os_free(wep->key[idx]);
+				wep->key[idx] = os_malloc(cred->key_len / 2);
+				if (wep->key[idx] == NULL ||
+				    hexstr2bin((const char *) cred->key,
+					       wep->key[idx],
+					       cred->key_len / 2))
+					return -1;
+				wep->len[idx] = cred->key_len / 2;
+			} else {
+				os_free(wep->key[idx]);
+				wep->key[idx] = os_malloc(cred->key_len);
+				if (wep->key[idx] == NULL)
+					return -1;
+				os_memcpy(wep->key[idx], cred->key,
+					  cred->key_len);
+				wep->len[idx] = cred->key_len;
+			}
+			wep->keys_set = 1;
+		}
+	}
+
+	/* Schedule configuration reload after short period of time to allow
+	 * EAP-WSC to be finished.
+	 */
+	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+			       NULL);
+
+	return 0;
+}
+
+
 static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
 	const struct wps_credential *cred = ctx;
@@ -344,7 +461,7 @@
 	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
 
 	if (hapd->iface->config_fname == NULL)
-		return 0;
+		return hapd_wps_reconfig_in_memory(hapd, cred);
 	len = os_strlen(hapd->iface->config_fname) + 5;
 	tmp_fname = os_malloc(len);
 	if (tmp_fname == NULL)
@@ -706,7 +823,8 @@
 		return 0;
 	for (j = 0; j < iface->num_bss; j++) {
 		struct hostapd_data *hapd = iface->bss[j];
-		if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+		if (hapd->wps && !hapd->conf->wps_independent &&
+		    !is_nil_uuid(hapd->wps->uuid)) {
 			*uuid = hapd->wps->uuid;
 			return 1;
 		}
@@ -799,7 +917,7 @@
 	if (is_nil_uuid(hapd->conf->uuid)) {
 		const u8 *uuid;
 		uuid = get_own_uuid(hapd->iface);
-		if (uuid) {
+		if (uuid && !conf->wps_independent) {
 			os_memcpy(wps->uuid, uuid, UUID_LEN);
 			wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
 				    "interface", wps->uuid, UUID_LEN);