Browse Source

Add interface matching support with -M, guarded by CONFIG_MATCH_IFACE

The new wpa_supplicant command line argument -M can be used to describe
matching rules with a wildcard interface name (e.g., "wlan*").

This is very useful for systems without udev (Linux) or devd (FreeBSD).

Signed-off-by: Roy Marples <roy@marples.name>
Roy Marples 9 years ago
parent
commit
2e997eece5

+ 4 - 0
wpa_supplicant/Makefile

@@ -316,6 +316,10 @@ CFLAGS += -DCONFIG_NO_VLAN
 OBJS += ibss_rsn.o
 OBJS += ibss_rsn.o
 endif
 endif
 
 
+ifdef CONFIG_MATCH_IFACE
+CFLAGS += -DCONFIG_MATCH_IFACE
+endif
+
 ifdef CONFIG_P2P
 ifdef CONFIG_P2P
 OBJS += p2p_supplicant.o
 OBJS += p2p_supplicant.o
 OBJS += p2p_supplicant_sd.o
 OBJS += p2p_supplicant_sd.o

+ 18 - 1
wpa_supplicant/README

@@ -410,7 +410,7 @@ usage:
   wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
   wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
         [-G<group>] \
         [-G<group>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
-        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+        [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
         [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
         [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
 
 
 options:
 options:
@@ -434,6 +434,7 @@ options:
   -u = enable DBus control interface
   -u = enable DBus control interface
   -v = show version
   -v = show version
   -W = wait for a control interface monitor before starting
   -W = wait for a control interface monitor before starting
+  -M = start describing matching interface
   -N = start describing new interface
   -N = start describing new interface
   -m = Configuration file for the P2P Device
   -m = Configuration file for the P2P Device
 
 
@@ -476,6 +477,22 @@ wpa_supplicant \
 	-c wpa2.conf -i wlan1 -D wext
 	-c wpa2.conf -i wlan1 -D wext
 
 
 
 
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+	-M -c wpa_wired.conf -ilan0 -D wired \
+	-M -c wpa1.conf -iwlan* \
+	-M -c wpa2.conf
+
+
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 interface needs to be configured to wpa_supplicant in addition to the
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
 main interface:

+ 3 - 0
wpa_supplicant/defconfig

@@ -467,6 +467,9 @@ CONFIG_PEERKEY=y
 # Hotspot 2.0
 # Hotspot 2.0
 #CONFIG_HS20=y
 #CONFIG_HS20=y
 
 
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
 # Disable roaming in wpa_supplicant
 # Disable roaming in wpa_supplicant
 #CONFIG_NO_ROAMING=y
 #CONFIG_NO_ROAMING=y
 
 

+ 21 - 0
wpa_supplicant/events.c

@@ -2758,6 +2758,13 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
 		}
 		}
 #endif /* CONFIG_P2P */
 #endif /* CONFIG_P2P */
 
 
+#ifdef CONFIG_MATCH_IFACE
+		if (wpa_s->matched) {
+			wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+			break;
+		}
+#endif /* CONFIG_MATCH_IFACE */
+
 #ifdef CONFIG_TERMINATE_ONLASTIF
 #ifdef CONFIG_TERMINATE_ONLASTIF
 		/* check if last interface */
 		/* check if last interface */
 		if (!any_interfaces(wpa_s->global->ifaces))
 		if (!any_interfaces(wpa_s->global->ifaces))
@@ -4030,6 +4037,20 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
 			return;
 			return;
 		}
 		}
 	}
 	}
+#ifdef CONFIG_MATCH_IFACE
+	else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+		struct wpa_interface *wpa_i;
+
+		wpa_i = wpa_supplicant_match_iface(
+			ctx, data->interface_status.ifname);
+		if (!wpa_i)
+			return;
+		wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
+		os_free(wpa_i);
+		if (wpa_s)
+			wpa_s->matched = 1;
+	}
+#endif /* CONFIG_MATCH_IFACE */
 
 
 	if (wpa_s)
 	if (wpa_s)
 		wpa_supplicant_event(wpa_s, event, data);
 		wpa_supplicant_event(wpa_s, event, data);

+ 51 - 1
wpa_supplicant/main.c

@@ -81,6 +81,9 @@ static void usage(void)
 #ifdef CONFIG_P2P
 #ifdef CONFIG_P2P
 	       "  -m = Configuration file for the P2P Device interface\n"
 	       "  -m = Configuration file for the P2P Device interface\n"
 #endif /* CONFIG_P2P */
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+	       "  -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
 	       "  -N = start describing new interface\n"
 	       "  -N = start describing new interface\n"
 	       "  -o = override driver parameter for new interfaces\n"
 	       "  -o = override driver parameter for new interfaces\n"
 	       "  -O = override ctrl_interface parameter for new interfaces\n"
 	       "  -O = override ctrl_interface parameter for new interfaces\n"
@@ -153,6 +156,28 @@ static void wpa_supplicant_fd_workaround(int start)
 }
 }
 
 
 
 
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+	/*
+	 * The assumption is that the first driver is the primary driver and
+	 * will handle the arrival / departure of interfaces.
+	 */
+	if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+		global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+		if (!global->drv_priv[0]) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to initialize driver '%s'",
+				   wpa_drivers[0]->name);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 {
 	int c, i;
 	int c, i;
@@ -176,7 +201,7 @@ int main(int argc, char *argv[])
 
 
 	for (;;) {
 	for (;;) {
 		c = getopt(argc, argv,
 		c = getopt(argc, argv,
-			   "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+			   "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
 		if (c < 0)
 		if (c < 0)
 			break;
 			break;
 		switch (c) {
 		switch (c) {
@@ -282,6 +307,20 @@ int main(int argc, char *argv[])
 		case 'W':
 		case 'W':
 			params.wait_for_monitor++;
 			params.wait_for_monitor++;
 			break;
 			break;
+#ifdef CONFIG_MATCH_IFACE
+		case 'M':
+			params.match_iface_count++;
+			iface = os_realloc_array(params.match_ifaces,
+						 params.match_iface_count,
+						 sizeof(struct wpa_interface));
+			if (!iface)
+				goto out;
+			params.match_ifaces = iface;
+			iface = &params.match_ifaces[params.match_iface_count -
+						     1];
+			os_memset(iface, 0, sizeof(*iface));
+			break;
+#endif /* CONFIG_MATCH_IFACE */
 		case 'N':
 		case 'N':
 			iface_count++;
 			iface_count++;
 			iface = os_realloc_array(ifaces, iface_count,
 			iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@ int main(int argc, char *argv[])
 		     ifaces[i].ctrl_interface == NULL) ||
 		     ifaces[i].ctrl_interface == NULL) ||
 		    ifaces[i].ifname == NULL) {
 		    ifaces[i].ifname == NULL) {
 			if (iface_count == 1 && (params.ctrl_interface ||
 			if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+						 params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
 						 params.dbus_ctrl_interface))
 						 params.dbus_ctrl_interface))
 				break;
 				break;
 			usage();
 			usage();
@@ -341,6 +383,11 @@ int main(int argc, char *argv[])
 		}
 		}
 	}
 	}
 
 
+#ifdef CONFIG_MATCH_IFACE
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
 	if (exitcode == 0)
 	if (exitcode == 0)
 		exitcode = wpa_supplicant_run(global);
 		exitcode = wpa_supplicant_run(global);
 
 
@@ -351,6 +398,9 @@ int main(int argc, char *argv[])
 out:
 out:
 	wpa_supplicant_fd_workaround(0);
 	wpa_supplicant_fd_workaround(0);
 	os_free(ifaces);
 	os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+	os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
 	os_free(params.pid_file);
 	os_free(params.pid_file);
 
 
 	os_program_deinit();
 	os_program_deinit();

+ 92 - 0
wpa_supplicant/wpa_supplicant.c

@@ -11,6 +11,10 @@
  */
  */
 
 
 #include "includes.h"
 #include "includes.h"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
 
 
 #include "common.h"
 #include "common.h"
 #include "crypto/random.h"
 #include "crypto/random.h"
@@ -4911,6 +4915,74 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 }
 }
 
 
 
 
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+						  const char *ifname)
+{
+	int i;
+	struct wpa_interface *iface, *miface;
+
+	for (i = 0; i < global->params.match_iface_count; i++) {
+		miface = &global->params.match_ifaces[i];
+		if (!miface->ifname ||
+		    fnmatch(miface->ifname, ifname, 0) == 0) {
+			iface = os_zalloc(sizeof(*iface));
+			if (!iface)
+				return NULL;
+			*iface = *miface;
+			iface->ifname = ifname;
+			return iface;
+		}
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+	struct if_nameindex *ifi, *ifp;
+	struct wpa_supplicant *wpa_s;
+	struct wpa_interface *iface;
+
+	ifp = if_nameindex();
+	if (!ifp) {
+		wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+		return -1;
+	}
+
+	for (ifi = ifp; ifi->if_name; ifi++) {
+		wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+		if (wpa_s)
+			continue;
+		iface = wpa_supplicant_match_iface(global, ifi->if_name);
+		if (iface) {
+			wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+			os_free(iface);
+			if (wpa_s)
+				wpa_s->matched = 1;
+		}
+	}
+
+	if_freenameindex(ifp);
+	return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
 /**
 /**
  * wpa_supplicant_add_iface - Add a new network interface
  * wpa_supplicant_add_iface - Add a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -5212,6 +5284,18 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 	if (params->override_ctrl_interface)
 	if (params->override_ctrl_interface)
 		global->params.override_ctrl_interface =
 		global->params.override_ctrl_interface =
 			os_strdup(params->override_ctrl_interface);
 			os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+	global->params.match_iface_count = params->match_iface_count;
+	if (params->match_iface_count) {
+		global->params.match_ifaces =
+			os_calloc(params->match_iface_count,
+				  sizeof(struct wpa_interface));
+		os_memcpy(global->params.match_ifaces,
+			  params->match_ifaces,
+			  params->match_iface_count *
+			  sizeof(struct wpa_interface));
+	}
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
 #ifdef CONFIG_P2P
 	if (params->conf_p2p_dev)
 	if (params->conf_p2p_dev)
 		global->params.conf_p2p_dev =
 		global->params.conf_p2p_dev =
@@ -5291,6 +5375,11 @@ int wpa_supplicant_run(struct wpa_global *global)
 	     eloop_sock_requeue()))
 	     eloop_sock_requeue()))
 		return -1;
 		return -1;
 
 
+#ifdef CONFIG_MATCH_IFACE
+	if (wpa_supplicant_match_existing(global))
+		return -1;
+#endif
+
 	if (global->params.wait_for_monitor) {
 	if (global->params.wait_for_monitor) {
 		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
 		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
 			if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
 			if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
@@ -5359,6 +5448,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 	os_free(global->params.ctrl_interface_group);
 	os_free(global->params.ctrl_interface_group);
 	os_free(global->params.override_driver);
 	os_free(global->params.override_driver);
 	os_free(global->params.override_ctrl_interface);
 	os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+	os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
 #ifdef CONFIG_P2P
 	os_free(global->params.conf_p2p_dev);
 	os_free(global->params.conf_p2p_dev);
 #endif /* CONFIG_P2P */
 #endif /* CONFIG_P2P */

+ 16 - 0
wpa_supplicant/wpa_supplicant_i.h

@@ -228,6 +228,17 @@ struct wpa_params {
 	char *conf_p2p_dev;
 	char *conf_p2p_dev;
 #endif /* CONFIG_P2P */
 #endif /* CONFIG_P2P */
 
 
+#ifdef CONFIG_MATCH_IFACE
+	/**
+	 * match_ifaces - Interface descriptions to match
+	 */
+	struct wpa_interface *match_ifaces;
+
+	/**
+	 * match_iface_count - Number of defined matching interfaces
+	 */
+	int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
 };
 };
 
 
 struct p2p_srv_bonjour {
 struct p2p_srv_bonjour {
@@ -458,6 +469,9 @@ struct wpa_supplicant {
 	unsigned char own_addr[ETH_ALEN];
 	unsigned char own_addr[ETH_ALEN];
 	unsigned char perm_addr[ETH_ALEN];
 	unsigned char perm_addr[ETH_ALEN];
 	char ifname[100];
 	char ifname[100];
+#ifdef CONFIG_MATCH_IFACE
+	int matched;
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_CTRL_IFACE_DBUS
 #ifdef CONFIG_CTRL_IFACE_DBUS
 	char *dbus_path;
 	char *dbus_path;
 #endif /* CONFIG_CTRL_IFACE_DBUS */
 #endif /* CONFIG_CTRL_IFACE_DBUS */
@@ -1108,6 +1122,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s);
 
 
 void wpa_show_license(void);
 void wpa_show_license(void);
 
 
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+						  const char *ifname);
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
 						 struct wpa_interface *iface,
 						 struct wpa_interface *iface,
 						 struct wpa_supplicant *parent);
 						 struct wpa_supplicant *parent);