WPA_Supplicant slave mode patch



Hi,

Had some spare time (didn't feel like reading) and "finished" up
wpa_supplicant  changes. Added a slave mode where config can be
changed dynamically through socket.

I've added a "network" command to socket interface. Takes 1 argument,
a string of network options (same options as in config file) separated
by ; and ended by ;;. Example:
"network ssid="something";proto=WPA;key_mgmt=WPA-PSK;pairwise=TKIP;group=TKIP;psk="verysecretpassphrase";;"

Also added a way to chance ap_scan(See config file) behavior: "set AP_MODE # "
where # is mode number.

If we don't want any other wireless scanning, ap_scan must be 0. In
this mode wpa_supplicant won't do any WPA association and must be done
by NM. See association function in each of the wpa_supplicant drivers.

Slave mode is activated by wpa_supplicant option -S

Only testet with WPA-PSK connection at my parents. I'll test WPA
EAP-TLS when I'm back home.

Todo:
non hardcoded ctrl socket file path
-- 
Tim Warberg
Email: twarberg at gmail.com
diff -ruN wpa_supplicant-0.3.8/config.c wpa_supplicant-0.3.8_slave/config.c
--- wpa_supplicant-0.3.8/config.c	2005-02-05 05:19:10.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/config.c	2005-06-11 13:23:07.000000000 +0200
@@ -820,6 +820,145 @@
 	return 0;
 }
 
+struct wpa_ssid * wpa_ssid_from_iface(char * cmd) {
+	struct wpa_ssid *ssid;
+	int errors = 0, i, end = 0, chr;
+	char *pos, *pos2;
+
+	ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
+	if (ssid == NULL)
+		return NULL;
+	memset(ssid, 0, sizeof(*ssid));
+	ssid->id = 0;
+
+	ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
+	ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
+	ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
+		WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
+	ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
+	ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+		EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
+	ssid->eap_workaround = (unsigned int) -1;
+
+	pos = malloc(strlen(cmd));
+
+	while (TRUE) {	
+		if (strcmp(cmd, ";") == 0) {
+			end = 1;
+			break;
+		}
+
+		chr = 0;
+		memset(pos, 0, strlen(cmd));
+		
+		while((strlen(cmd) > 0) && (strncmp(cmd, ";", 1) != 0)) {
+			pos[chr] = *cmd;
+			chr++;
+			cmd++;
+		}
+		*cmd++ = '\0';
+		
+		pos2 = strchr(pos, '=');
+		if (pos2 == NULL) {
+			wpa_printf(MSG_ERROR, "Char %d: Invalid SSID line "
+				   "'%s'.", *cmd, pos);
+			errors++;
+			continue;
+		}
+
+		*pos2++ = '\0';
+		if (*pos2 == '"') {
+			if (strchr(pos2 + 1, '"') == NULL) {
+				wpa_printf(MSG_ERROR, "Char %d: invalid "
+					   "quotation '%s'.", *cmd, pos2);
+				errors++;
+				continue;
+			}
+		}
+
+		for (i = 0; i < NUM_SSID_FIELDS; i++) {
+			struct parse_data *field = &ssid_fields[i];
+			if (strcmp(pos, field->name) != 0)
+				continue;
+
+			field->ssid = ssid;
+			if (field->parser(field, *cmd, pos2)) {
+				wpa_printf(MSG_ERROR, "Char %d: failed to "
+					   "parse %s '%s'.", *cmd, pos, pos2);
+				errors++;
+			}
+			break;
+		}
+		if (i == NUM_SSID_FIELDS) {
+			wpa_printf(MSG_ERROR, "Unknown network field "
+				   "'%s'.", pos);
+			errors++;
+		}
+	}
+
+	if (!end) {
+		wpa_printf(MSG_ERROR, "Network block was not "
+			   "terminated properly.");
+		errors++;
+	}
+
+	if (ssid->passphrase) {
+		if (ssid->psk_set) {
+			wpa_printf(MSG_ERROR, "Both PSK and "
+				   "passphrase configured.");
+			errors++;
+		}
+		pbkdf2_sha1(ssid->passphrase,
+			    (char *) ssid->ssid, ssid->ssid_len, 4096,
+			    ssid->psk, PMK_LEN);
+		wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+				ssid->psk, PMK_LEN);
+		ssid->psk_set = 1;
+	}
+
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
+		wpa_printf(MSG_ERROR, "Char %d: WPA-PSK accepted for key "
+			   "management, but no PSK configured.", *cmd);
+		errors++;
+	}
+
+	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
+		/* Group cipher cannot be stronger than the pairwise cipher. */
+		wpa_printf(MSG_DEBUG, "Char %d: removed CCMP from group cipher"
+			   " list since it was not allowed for pairwise "
+			   "cipher", *cmd);
+		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+	}
+
+	if (errors) {
+		free(ssid);
+		ssid = NULL;
+		return NULL;
+	}
+
+	return ssid;
+}
+
+struct wpa_config * wpa_config_slave(void)
+{
+	struct wpa_config *config;
+	config = malloc(sizeof(*config));
+	if (config == NULL)
+		return NULL;
+	memset(config, 0, sizeof(*config));
+	config->eapol_version = 1;
+	config->ap_scan = 0;
+	config->fast_reauth = 1;
+	free(config->ctrl_interface);
+	config->ctrl_interface = "/var/run/wpa_supplicant";
+	wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
+			   config->ctrl_interface);
+	config->ctrl_interface_gid = 0;
+	config->ctrl_interface_gid_set = 1;
+	
+	return config;
+}
 
 struct wpa_config * wpa_config_read(const char *config_file)
 {
diff -ruN wpa_supplicant-0.3.8/config.h wpa_supplicant-0.3.8_slave/config.h
--- wpa_supplicant-0.3.8/config.h	2005-01-06 06:10:30.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/config.h	2005-06-10 17:43:24.000000000 +0200
@@ -26,7 +26,8 @@
 	int fast_reauth;
 };
 
-
+struct wpa_config * wpa_config_slave(void);
+struct wpa_ssid * wpa_ssid_from_iface(char * buf);
 struct wpa_config * wpa_config_read(const char *config_file);
 void wpa_config_free(struct wpa_config *ssid);
 
diff -ruN wpa_supplicant-0.3.8/ctrl_iface.c wpa_supplicant-0.3.8_slave/ctrl_iface.c
--- wpa_supplicant-0.3.8/ctrl_iface.c	2005-01-29 19:17:48.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/ctrl_iface.c	2005-06-11 13:45:35.000000000 +0200
@@ -78,7 +78,6 @@
 	}
 }
 
-
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 					 char *cmd)
 {
@@ -102,11 +101,32 @@
 	} else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) {
 		eapol_sm_configure(wpa_s->eapol,
 				   -1, -1, -1, atoi(value));
-	} else
+	} else if (strcasecmp(cmd, "AP_MODE") == 0) {
+		if (atoi(value) >= 0 && atoi(value) <= 2)
+			wpa_s->conf->ap_scan = atoi(value);
+		else
+			return -1;
+	} else 
 		return -1;
 	return 0;
 }
 
+static int wpa_supplicant_ctrl_iface_network(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	struct wpa_ssid *ssid;
+	
+	if(!wpa_s->slave)
+		return 1;
+	if((ssid = wpa_ssid_from_iface(cmd)) == NULL)
+		return 1;
+	wpa_s->current_ssid = NULL;
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	rsn_preauth_deinit(wpa_s);
+	wpa_s->conf->ssid = ssid;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+	return 0;
+}
 
 static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
 					     char *addr)
@@ -391,6 +411,9 @@
 	} else if (strncmp(buf, "STATUS", 6) == 0) {
 		reply_len = wpa_supplicant_ctrl_iface_status(
 			wpa_s, buf + 6, reply, reply_size);
+	} else if (strncmp(buf, "NETWORK ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_network(wpa_s, buf + 8))
+			reply_len = -1;
 	} else if (strcmp(buf, "PMKSA") == 0) {
 		reply_len = pmksa_cache_list(wpa_s, reply, reply_size);
 	} else if (strncmp(buf, "SET ", 4) == 0) {
diff -ruN wpa_supplicant-0.3.8/wpa_cli.c wpa_supplicant-0.3.8_slave/wpa_cli.c
--- wpa_supplicant-0.3.8/wpa_cli.c	2005-02-05 07:51:25.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/wpa_cli.c	2005-06-11 13:57:47.000000000 +0200
@@ -98,6 +98,7 @@
 "  logoff = IEEE 802.1X EAPOL state machine logoff\n"
 "  logon = IEEE 802.1X EAPOL state machine logon\n"
 "  set = set variables (shows list of variables when run without arguments)\n"
+"  network = add network config (semicolon between each and double semicolon at end)\n"
 "  pmksa = show PMKSA cache\n"
 "  reassociate = force reassociation\n"
 "  reconfigure = force wpa_supplicant to re-read its configuration file\n"
@@ -263,7 +264,8 @@
 	       "  EAPOL::startPeriod (EAPOL state machine start period, in "
 	       "seconds)\n"
 	       "  EAPOL::maxStart (EAPOL state machine maximum start "
-	       "attempts)\n");
+	       "attempts)\n"
+	       "  AP_MODE (ap_scan mode: 0-2)\n");
 }
 
 
@@ -290,6 +292,28 @@
 	return wpa_ctrl_command(ctrl, cmd);
 }
 
+static int wpa_cli_cmd_network(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+
+	if (argc == 0) {
+		printf("Use same network options as in config file. "
+			   "Each separated by semicolon and double semicolon at end.\n");
+		return 0;
+	}
+
+	if (argc != 1) {
+		printf("Invalid NETWORK command: needs one argument\n");
+		return 0;
+	}
+
+	if (snprintf(cmd, sizeof(cmd), "NETWORK %s", argv[0]) >=
+	    sizeof(cmd) - 1) {
+		printf("Too long NETWORK command.\n");
+		return 0;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
 
 static int wpa_cli_cmd_logoff(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -498,6 +522,7 @@
 	{ "otp", wpa_cli_cmd_otp },
 	{ "reconfigure", wpa_cli_cmd_reconfigure },
 	{ "terminate", wpa_cli_cmd_terminate },
+	{ "network", wpa_cli_cmd_network },
 	{ NULL, NULL }
 };
 
diff -ruN wpa_supplicant-0.3.8/wpa_supplicant.c wpa_supplicant-0.3.8_slave/wpa_supplicant.c
--- wpa_supplicant-0.3.8/wpa_supplicant.c	2005-02-05 07:51:25.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/wpa_supplicant.c	2005-06-11 14:50:35.000000000 +0200
@@ -2114,6 +2114,7 @@
 	       "  -h = show this help text\n"
 	       "  -L = show license (GPL and BSD)\n"
 	       "  -q = decrease debugging verbosity (-qq even less)\n"
+	       "  -S = slave mode\n"
 	       "  -v = show version\n"
 	       "  -w = wait for interface to be added, if needed\n"
 	       "  -N = start describing new interface\n");
@@ -2142,7 +2143,6 @@
 	return wpa_s;
 }
 
-
 static int wpa_supplicant_init(struct wpa_supplicant *wpa_s,
 			       const char *confname, const char *driver,
 			       const char *ifname)
@@ -2154,7 +2154,9 @@
 		return -1;
 	}
 
-	if (confname) {
+	if (wpa_s->slave)
+		wpa_s->conf = wpa_config_slave();
+	else if (confname) {
 		wpa_s->confname = rel2abs_path(confname);
 		if (wpa_s->confname == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to get absolute path "
@@ -2171,7 +2173,7 @@
 		}
 	}
 
-	if (wpa_s->conf == NULL || wpa_s->conf->ssid == NULL) {
+	if (wpa_s->conf == NULL || (wpa_s->conf->ssid == NULL && !wpa_s->slave)) {
 		usage();
 		printf("\nNo networks (SSID) configured.\n");
 		return -1;
@@ -2291,7 +2293,7 @@
 	struct wpa_supplicant *head, *wpa_s;
 	int c;
 	const char *confname, *driver, *ifname;
-	int daemonize = 0, wait_for_interface = 0, disable_eapol = 0, exitcode;
+	int daemonize = 0, wait_for_interface = 0, disable_eapol = 0, slave = 0, exitcode;
 
 #ifdef CONFIG_NATIVE_WINDOWS
 	WSADATA wsaData;
@@ -2312,7 +2314,7 @@
 	ifname = confname = driver = NULL;
 
 	for (;;) {
-		c = getopt(argc, argv, "Bc:D:dehi:KLNqtvw");
+		c = getopt(argc, argv, "Bc:D:dehi:KLNqtvwS");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -2359,6 +2361,9 @@
 		case 'w':
 			wait_for_interface++;
 			break;
+		case 'S':
+			slave++;
+			break;
 		case 'N':
 			if (wpa_supplicant_init(wpa_s, confname, driver,
 						ifname))
@@ -2375,7 +2380,10 @@
 			return -1;
 		}
 	}
-
+	
+	if (slave)
+		wpa_s->slave = 1;
+	
 	if (wpa_supplicant_init(wpa_s, confname, driver, ifname))
 		return -1;
 
diff -ruN wpa_supplicant-0.3.8/wpa_supplicant_i.h wpa_supplicant-0.3.8_slave/wpa_supplicant_i.h
--- wpa_supplicant-0.3.8/wpa_supplicant_i.h	2005-01-31 05:25:36.000000000 +0100
+++ wpa_supplicant-0.3.8_slave/wpa_supplicant_i.h	2005-06-10 17:24:29.000000000 +0200
@@ -58,6 +58,7 @@
 	struct l2_packet_data *l2;
 	unsigned char own_addr[ETH_ALEN];
 	char ifname[100];
+	int slave;
 #ifdef CONFIG_XSUPPLICANT_IFACE
 	int dot1x_s; /* socket for connection to Xsupplicant */
 	int ext_pmk_received; /* 1 = PMK was received from Xsupplicant */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]