Cumulative patch from commit d4f1a347ceca31fd9cf14070fd000235d5f4e9c1

d4f1a34 Allow AP mode configuration with VHT enabled on 2.4 GHz
bb337dd DFS: Do not use cf1 to override freq for 20 MHz channels
0dfd2c6 Document AP mode startup functions
fee947b hostapd: Use correct wpa_printf verbosity level for message
2fe210c hostapd: Fix multi-BSS configuration file parsing regression
e4ba031 hostapd: Use start_ctrl_iface() from hostapd_add_iface()
bf7f09b Fix AP mode QoS Map configuration to be per-BSS
dc036d9 DFS: Convert hostapd_data use to hostapd_iface
2db938e hostapd: Fill in phyname automatically
5ae6449 hostapd: Add ctrl_iface STATUS command
afadaff Optimize 40 MHz HT co-ex scan on AP
7d6d737 hostapd: Add AP-ENABLED/DISABLED ctrl_iface events
e1c5faf hostapd: Track interface state
f0793bf hostapd: Wait for channel list update after country code change
ae134e1 hostapd: Add ctrl_iface events for ACS
ad08e14 hostapd: Move ctrl_iface initialization to happen earlier
c20cb02 hostapd: Remove hostapd_interface_init2()
4a5deb9 hostapd: Simplify interface initialization
186c905 DFS: Add control interface events for various DFS events
ddf5517 hostapd: Add control interface test commands for radar detection
884f1a3 nl80211: Verify radar event attributes exist before using them
71cdf6b hostapd: Fix ENABLE failure to not remove interface
18ca733 SAE: Fix group selection
65015b2 Replace unnecessary UTF-8 characters with ASCII versions
61323e7 Convert perror/printf calls to wpa_printf
3f134b4 hostapd: Accept RELOG from global control interface
b253e6f hostapd: Use wpa_printf() for hostapd_logger() to stdout
c092d83 P2P: Clear pending group formation data on group removal
9100b66 P2P: Debug print reason for specific SSID for scan
2aec4f3 Allow add-BSS operation to re-use existing netdev
5592065 hostapd: Allow a single BSS to be removed from an interface
2e2fff3 hostapd: Allow a single BSS to be added to an interface
a1fb569 hostapd: Make hostapd_interface_init_bss() available externally
66936c6 hostapd: Make hostapd_init() available externally
390e489 hostapd: Allow the first BSS in a multi-BSS setup to be removed
834ee56 nl80211: Make wpa_driver_nl80211_data::first_bss pointer
748c0ac nl80211: Fix monitor interface reference counting
08e55eb nl80211: Add a debug print for DEL_BEACON
33b0b33 hostapd: Fix error path in hostapd_add_iface()
770ecdf ACS: Do not get stuck while failing to do a subsequent scan
813d4ba DFS: Add support for multi-BSS
954e71d DFS: Reset cac_started properly
6a398dd DFS: Sanitize channel availability checks
32595da DFS: Fix HT40/VHT calculation
0648c3b hostapd: Add -T Linux tracing option
392e68e Set GTK rekey offload information after initial group key handshake
bbc706a nl80211: Add debug prints for NL80211_CMD_SET_STATION
731ca63 Update regulatory change to all virtual interface for the phy
6f2db2f hostapd: Validate configuration parameters on RELOAD command
eff0fd1 hostapd: Move generic configuration functions into src/ap
5afaa06 hostapd: Allow per-BSS (vif) configuration files
ebd79f0 hostapd: Make hostapd_config::bss array of pointers
a781e21 hostapd: Force PSK to be derived again on BSS reload
9f104b0 hostapd: Reuse hostapd_clear_old() for RELOAD command

Change-Id: I7fbb26cbd4a2960af66a4373c0e6bbe5390a4940
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/main.c b/hostapd/main.c
index 6a67347..bc61db1 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -114,7 +114,7 @@
 
 	if ((conf_stdout & module) && level >= conf_stdout_level) {
 		wpa_debug_print_timestamp();
-		printf("%s\n", format);
+		wpa_printf(MSG_INFO, "%s", format);
 	}
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -148,65 +148,8 @@
 
 
 /**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
  */
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
-	struct hostapd_iface *hapd_iface = NULL;
-	struct hostapd_config *conf = NULL;
-	struct hostapd_data *hapd;
-	size_t i;
-
-	hapd_iface = os_zalloc(sizeof(*hapd_iface));
-	if (hapd_iface == NULL)
-		goto fail;
-
-	hapd_iface->config_fname = os_strdup(config_file);
-	if (hapd_iface->config_fname == NULL)
-		goto fail;
-
-	conf = hostapd_config_read(hapd_iface->config_fname);
-	if (conf == NULL)
-		goto fail;
-	hapd_iface->conf = conf;
-
-	hapd_iface->num_bss = conf->num_bss;
-	hapd_iface->bss = os_calloc(conf->num_bss,
-				    sizeof(struct hostapd_data *));
-	if (hapd_iface->bss == NULL)
-		goto fail;
-
-	for (i = 0; i < conf->num_bss; i++) {
-		hapd = hapd_iface->bss[i] =
-			hostapd_alloc_bss_data(hapd_iface, conf,
-					       &conf->bss[i]);
-		if (hapd == NULL)
-			goto fail;
-		hapd->msg_ctx = hapd;
-	}
-
-	return hapd_iface;
-
-fail:
-	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
-		   config_file);
-	if (conf)
-		hostapd_config_free(conf);
-	if (hapd_iface) {
-		os_free(hapd_iface->config_fname);
-		os_free(hapd_iface->bss);
-		os_free(hapd_iface);
-	}
-	return NULL;
-}
-
-
 static int hostapd_driver_init(struct hostapd_iface *iface)
 {
 	struct wpa_init_params params;
@@ -282,19 +225,17 @@
 		iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
 	}
 
-#ifdef CONFIG_INTERWORKING
-	if (hapd->driver->set_qos_map && conf->qos_map_set_len &&
-	    hapd->driver->set_qos_map(hapd->drv_priv, conf->qos_map_set,
-				      conf->qos_map_set_len)) {
-		wpa_printf(MSG_ERROR, "Failed to initialize QoS Map.");
-		return -1;
-	}
-#endif /* CONFIG_INTERWORKING */
-
 	return 0;
 }
 
 
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
 static struct hostapd_iface *
 hostapd_interface_init(struct hapd_interfaces *interfaces,
 		       const char *config_fname, int debug)
@@ -303,7 +244,7 @@
 	int k;
 
 	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
-	iface = hostapd_init(config_fname);
+	iface = hostapd_init(interfaces, config_fname);
 	if (!iface)
 		return NULL;
 	iface->interfaces = interfaces;
@@ -313,7 +254,7 @@
 			iface->bss[0]->conf->logger_stdout_level--;
 	}
 
-	if (iface->conf->bss[0].iface[0] == '\0' &&
+	if (iface->conf->bss[0]->iface[0] == '\0' &&
 	    !hostapd_drv_none(iface->bss[0])) {
 		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
 			   config_fname);
@@ -321,12 +262,6 @@
 		return NULL;
 	}
 
-	if (hostapd_driver_init(iface) ||
-	    hostapd_setup_interface(iface)) {
-		hostapd_interface_deinit_free(iface);
-		return NULL;
-	}
-
 	return iface;
 }
 
@@ -516,6 +451,10 @@
 #ifdef CONFIG_DEBUG_FILE
 		"   -f   log output to debug file instead of stdout\n"
 #endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		"   -T = record to Linux tracing in addition to logging\n"
+		"        (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		"   -t   include timestamps in some debug messages\n"
 		"   -v   show hostapd version\n");
 
@@ -526,8 +465,9 @@
 static const char * hostapd_msg_ifname_cb(void *ctx)
 {
 	struct hostapd_data *hapd = ctx;
-	if (hapd && hapd->iconf && hapd->iconf->bss)
-		return hapd->iconf->bss->iface;
+	if (hapd && hapd->iconf && hapd->iconf->bss &&
+	    hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+		return hapd->iconf->bss[0]->iface;
 	return NULL;
 }
 
@@ -576,11 +516,16 @@
 {
 	struct hapd_interfaces interfaces;
 	int ret = 1;
-	size_t i;
+	size_t i, j;
 	int c, debug = 0, daemonize = 0;
 	char *pid_file = NULL;
 	const char *log_file = NULL;
 	const char *entropy_file = NULL;
+	char **bss_config = NULL, **tmp_bss;
+	size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	if (os_program_init())
 		return -1;
@@ -597,7 +542,7 @@
 	interfaces.global_ctrl_sock = -1;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
+		c = getopt(argc, argv, "b:Bde:f:hKP:Ttvg:G:");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -628,6 +573,11 @@
 		case 't':
 			wpa_debug_timestamp++;
 			break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		case 'T':
+			enable_trace_dbg = 1;
+			break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 		case 'v':
 			show_version();
 			exit(1);
@@ -640,23 +590,42 @@
 			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
 				return -1;
 			break;
+		case 'b':
+			tmp_bss = os_realloc_array(bss_config,
+						   num_bss_configs + 1,
+						   sizeof(char *));
+			if (tmp_bss == NULL)
+				goto out;
+			bss_config = tmp_bss;
+			bss_config[num_bss_configs++] = optarg;
+			break;
 		default:
 			usage();
 			break;
 		}
 	}
 
-	if (optind == argc && interfaces.global_iface_path == NULL)
+	if (optind == argc && interfaces.global_iface_path == NULL &&
+	    num_bss_configs == 0)
 		usage();
 
 	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
 
 	if (log_file)
 		wpa_debug_open_file(log_file);
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (enable_trace_dbg) {
+		int tret = wpa_debug_open_linux_tracing();
+		if (tret) {
+			wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+			return -1;
+		}
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
 	interfaces.count = argc - optind;
-	if (interfaces.count) {
-		interfaces.iface = os_calloc(interfaces.count,
+	if (interfaces.count || num_bss_configs) {
+		interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
 					     sizeof(struct hostapd_iface *));
 		if (interfaces.iface == NULL) {
 			wpa_printf(MSG_ERROR, "malloc failed");
@@ -669,7 +638,7 @@
 		return -1;
 	}
 
-	/* Initialize interfaces */
+	/* Allocate and parse configuration for full interface files */
 	for (i = 0; i < interfaces.count; i++) {
 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
 							     argv[optind + i],
@@ -680,6 +649,56 @@
 		}
 	}
 
+	/* Allocate and parse configuration for per-BSS files */
+	for (i = 0; i < num_bss_configs; i++) {
+		struct hostapd_iface *iface;
+		char *fname;
+
+		wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+		fname = os_strchr(bss_config[i], ':');
+		if (fname == NULL) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid BSS config identifier '%s'",
+				   bss_config[i]);
+			goto out;
+		}
+		*fname++ = '\0';
+		iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+						   fname, debug);
+		if (iface == NULL)
+			goto out;
+		for (j = 0; j < interfaces.count; j++) {
+			if (interfaces.iface[j] == iface)
+				break;
+		}
+		if (j == interfaces.count) {
+			struct hostapd_iface **tmp;
+			tmp = os_realloc_array(interfaces.iface,
+					       interfaces.count + 1,
+					       sizeof(struct hostapd_iface *));
+			if (tmp == NULL) {
+				hostapd_interface_deinit_free(iface);
+				goto out;
+			}
+			interfaces.iface = tmp;
+			interfaces.iface[interfaces.count++] = iface;
+		}
+	}
+
+	/*
+	 * Enable configured interfaces. Depending on channel configuration,
+	 * this may complete full initialization before returning or use a
+	 * callback mechanism to complete setup in case of operations like HT
+	 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+	 * In such case, the interface will be enabled from eloop context within
+	 * hostapd_global_run().
+	 */
+	for (i = 0; i < interfaces.count; i++) {
+		if (hostapd_driver_init(interfaces.iface[i]) ||
+		    hostapd_setup_interface(interfaces.iface[i]))
+			goto out;
+	}
+
 	hostapd_global_ctrl_iface_init(&interfaces);
 
 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
@@ -701,6 +720,9 @@
 
 	if (log_file)
 		wpa_debug_close_file();
+	wpa_debug_close_linux_tracing();
+
+	os_free(bss_config);
 
 	os_program_deinit();