Cumulative patch from commit f4e3860f8a770a0db3816196c77baf894c7ccc1e

f4e3860 Fix AP mode default TXOP Limit values for AC_VI and AC_VO
47bd94a TLS testing: Add new test cases for RSA-DHE primes
f5bbb2f TLS client: Reject RSA-DHE prime if it shorter than 768 bits
817742f TLS testing: Fix test_flags check for ApplData report
1120e45 Allow config blobs to be set through ctrl_iface
c3722e1 ACS: Fix VHT20
49b7443 Fix HT40 co-ex scan for some pri/sec channel switches
5bdac4a Remove unused STA entry information
c9d9ee9 Fix hostapd_add_iface error path to deinit partially initialized BSS
6829da3 Fix external radio_work deinit path
8dd9f9c Allow management group cipher to be configured
67d39cf P2P: Do not create another group interface on NFC Token enable
6aa1cd4 wpa_supplicant: Apply VHT_OVERRIDES to wpas_start_assoc_cb()
db63757 hostapd: Supply default parameters for OBSS scan
6e9375e TDLS: Add get_capability tdls command
67e1a40 hostapd: For VHT 20/40, allow center segment 0 to be zero
d0bf06f GAS server: Remove incomplete remote ANQP processing
fdb4535 WPS: Extend per-station PSK to support ER case as well
9a1a538 wpa_supplicant AP: Allow PMF to be enabled with ieee80211w
ce6b9cd Allow reason code to be specified for DEAUTH/DISASSOC test frame
dda8be7 TDLS: Use QoS info from WMM IE obtained in TDLS frames
daa70bd Fix CONFIG_NO_SCAN_PROCESSING=y build
3a8ec73 P2P: Report dev_found event (if not yet done) from GO Neg Req RX
0f23a5e Mark AP disabled if initialization steps fail

Change-Id: I7e499241552147c734fec9b77351b47ffd6e3a7c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 98c4b65..87ed3e2 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -206,6 +206,45 @@
 }
 
 
+#ifndef CONFIG_NO_CONFIG_BLOBS
+static int wpas_ctrl_set_blob(struct wpa_supplicant *wpa_s, char *pos)
+{
+	char *name = pos;
+	struct wpa_config_blob *blob;
+	size_t len;
+
+	pos = os_strchr(pos, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	len = os_strlen(pos);
+	if (len & 1)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "CTRL: Set blob '%s'", name);
+	blob = os_zalloc(sizeof(*blob));
+	if (blob == NULL)
+		return -1;
+	blob->name = os_strdup(name);
+	blob->data = os_malloc(len / 2);
+	if (blob->name == NULL || blob->data == NULL) {
+		wpa_config_free_blob(blob);
+		return -1;
+	}
+
+	if (hexstr2bin(pos, blob->data, len / 2) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL: Invalid blob hex data");
+		wpa_config_free_blob(blob);
+		return -1;
+	}
+	blob->len = len / 2;
+
+	wpa_config_set_blob(wpa_s->conf, blob);
+
+	return 0;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 					 char *cmd)
 {
@@ -355,6 +394,10 @@
 	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
 		wpa_s->ext_mgmt_frame_handling = !!atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	} else if (os_strcmp(cmd, "blob") == 0) {
+		ret = wpas_ctrl_set_blob(wpa_s, value);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
 	} else {
 		value[-1] = '=';
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -538,6 +581,22 @@
 	return ret;
 }
 
+
+static int ctrl_iface_get_capability_tdls(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	int ret;
+
+	ret = os_snprintf(buf, buflen, "%s\n",
+			  wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT ?
+			  (wpa_s->drv_flags &
+			   WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
+			   "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
+	if (ret < 0 || (size_t) ret > buflen)
+		return -1;
+	return ret;
+}
+
 #endif /* CONFIG_TDLS */
 
 
@@ -3180,6 +3239,11 @@
 	if (os_strcmp(field, "freq") == 0)
 		return ctrl_iface_get_capability_freq(wpa_s, buf, buflen);
 
+#ifdef CONFIG_TDLS
+	if (os_strcmp(field, "tdls") == 0)
+		return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
+#endif /* CONFIG_TDLS */
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
 		   field);
 
@@ -5637,8 +5701,8 @@
 			"Completed external radio work %u (%s)",
 			ework->id, ework->type);
 		eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
-		os_free(ework);
 		radio_work_done(work);
+		os_free(ework);
 		return 3; /* "OK\n" */
 	}