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/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6fb1cae..a6478b6 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1184,30 +1184,67 @@
 }
 
 
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
+{
+	*pos = 0x00;
+
+	switch (idx) {
+	case 0: /* Bits 0-7 */
+		break;
+	case 1: /* Bits 8-15 */
+		break;
+	case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+		*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+		*pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+		break;
+	case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+		*pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		if (wpa_s->conf->interworking)
+			*pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+		break;
+	case 4: /* Bits 32-39 */
+		break;
+	case 5: /* Bits 40-47 */
+		break;
+	case 6: /* Bits 48-55 */
+		break;
+	}
+}
+
+
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
 {
-	u32 ext_capab = 0;
 	u8 *pos = buf;
+	u8 len = 4, i;
 
-#ifdef CONFIG_INTERWORKING
-	if (wpa_s->conf->interworking)
-		ext_capab |= BIT(31); /* Interworking */
-#endif /* CONFIG_INTERWORKING */
-
-#ifdef CONFIG_WNM
-	ext_capab |= BIT(17); /* WNM-Sleep Mode */
-	ext_capab |= BIT(19); /* BSS Transition */
-#endif /* CONFIG_WNM */
-
-	if (!ext_capab)
-		return 0;
+	if (len < wpa_s->extended_capa_len)
+		len = wpa_s->extended_capa_len;
 
 	*pos++ = WLAN_EID_EXT_CAPAB;
-	*pos++ = 4;
-	WPA_PUT_LE32(pos, ext_capab);
-	pos += 4;
+	*pos++ = len;
+	for (i = 0; i < len; i++, pos++) {
+		wpas_ext_capab_byte(wpa_s, pos, i);
 
-	return pos - buf;
+		if (i < wpa_s->extended_capa_len) {
+			*pos &= ~wpa_s->extended_capa_mask[i];
+			*pos |= wpa_s->extended_capa[i];
+		}
+	}
+
+	while (len > 0 && buf[1 + len] == 0) {
+		len--;
+		buf[1] = len;
+	}
+	if (len == 0)
+		return 0;
+
+	return 2 + len;
 }
 
 
@@ -2925,6 +2962,9 @@
 		wpa_s->max_match_sets = capa.max_match_sets;
 		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
 		wpa_s->max_stations = capa.max_stations;
+		wpa_s->extended_capa = capa.extended_capa;
+		wpa_s->extended_capa_mask = capa.extended_capa_mask;
+		wpa_s->extended_capa_len = capa.extended_capa_len;
 	}
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;