[PATCH 3/3 v7] Add WPA PSK support to netcfg.
I think I have addressed most of Jeremy's comments. A few still left to sort out though. Will work
at trying to make a common function for the wpa commands. With this last version, all usuability
issues that I have seen are fixed and its basically usuable as far as I can tell. I'll make some
test images if anyone is interested in doing some testing.
I have also dropped the WPA support from netcfg-static, which makes the patch a bit smaller. Please
comment if you see something you think is not right.
Cheers
Glenn
Add WPA support to netcfg. With this patch we add the option of installing over a WPA-PSK network.
A wpasupplicant udeb is required, and if not available, fall back to previous behaviour.
---
packages/netcfg/Makefile | 2 +-
packages/netcfg/debian/netcfg-common.templates | 44 +++
packages/netcfg/debian/netcfg-dhcp.templates | 2 +-
packages/netcfg/dhcp.c | 66 +++-
packages/netcfg/netcfg.c | 58 +++-
packages/netcfg/netcfg.h | 16 +-
packages/netcfg/wireless.c | 2 +-
packages/netcfg/wpa.c | 473 ++++++++++++++++++++++++
packages/netcfg/wpa_ctrl.c | 256 +++++++++++++
packages/netcfg/wpa_ctrl.h | 187 ++++++++++
10 files changed, 1086 insertions(+), 20 deletions(-)
create mode 100644 packages/netcfg/wpa.c
create mode 100644 packages/netcfg/wpa_ctrl.c
create mode 100644 packages/netcfg/wpa_ctrl.h
diff --git a/packages/netcfg/Makefile b/packages/netcfg/Makefile
index 4753350..977aeb3 100644
--- a/packages/netcfg/Makefile
+++ b/packages/netcfg/Makefile
@@ -18,7 +18,7 @@ endif
all: $(TARGETS)
netcfg-static: netcfg-static.o static.o
-netcfg: netcfg.o dhcp.o static.o ethtool-lite.o
+netcfg: netcfg.o dhcp.o static.o ethtool-lite.o wpa.o wpa_ctrl.o
$(TARGETS): $(COMMON_OBJS)
$(CC) -o $@ $^ $(LDOPTS)
diff --git a/packages/netcfg/debian/netcfg-common.templates b/packages/netcfg/debian/netcfg-common.templates
index 973411e..815c410 100644
--- a/packages/netcfg/debian/netcfg-common.templates
+++ b/packages/netcfg/debian/netcfg-common.templates
@@ -56,6 +56,15 @@ _Description: Wireless ESSID for ${iface}:
of the wireless network you would like ${iface} to use. To skip wireless
configuration and continue, leave this field blank.
+Template: netcfg/wireless_security_type
+Type: select
+Choices-C: wep/open, wpa
+__Choices: WEP/Open Network, WPA PSK
+# :sl2:
+_Description: Wireless Network Type for ${iface}:
+ Choose WEP/Open if the network is open or secured with WEP.
+ Choose WPA if the network is a WPA PSK protected network.
+
Template: netcfg/wireless_wep
Type: string
# :sl1:
@@ -80,6 +89,19 @@ _Description: Invalid WEP key
the next screen carefully on how to enter your WEP key correctly, and try
again.
+Template: netcfg/invalid_pass
+Type: error
+# :sl2:
+_Description: Invalid passphrase
+ The WPA PSK passphrase was either too long (more than 64 characters)
+ or too short (less than 8 characters).
+
+Template: netcfg/wireless_wpa
+Type: string
+# :sl1:
+_Description: WPA passphrase for wireless device ${iface}:
+ Enter a passphrase for WPA PSK authentication.
+
Template: netcfg/invalid_essid
Type: error
# :sl2:
@@ -87,6 +109,28 @@ _Description: Invalid ESSID
The ESSID "${essid}" is invalid. ESSIDs may only be up to 32 characters,
but may contain all kinds of characters.
+Template: netcfg/wpa_progress
+Type: text
+# :sl1:
+_Description: Attempting to exchange keys with the access point...
+
+Template: netcfg/wpa_progress_note
+Type: text
+# :sl1:
+_Description: This may take some time.
+
+Template: netcfg/wpa_success_note
+Type: text
+# :sl1:
+_Description: WPA connection succeeded
+
+Template: netcfg/wpa_supplicant_failed
+Type: note
+# :sl1:
+_Description: Failure of key exchange and association
+ The exchange of keys and association with the access point failed.
+ Please check the WPA parameters you provided.
+
Template: netcfg/get_hostname
Type: string
Default: debian
diff --git a/packages/netcfg/debian/netcfg-dhcp.templates b/packages/netcfg/debian/netcfg-dhcp.templates
index 571a7e9..86ab6c4 100644
--- a/packages/netcfg/debian/netcfg-dhcp.templates
+++ b/packages/netcfg/debian/netcfg-dhcp.templates
@@ -77,7 +77,7 @@ Template: netcfg/dhcp_timeout
Type: text
Description: for internal use; can be preseeded
Timeout for trying DHCP
-Default: 15
+Default: 25
Template: netcfg/dhcp_ntp_servers
Type: text
diff --git a/packages/netcfg/dhcp.c b/packages/netcfg/dhcp.c
index a98981f..c6de79d 100644
--- a/packages/netcfg/dhcp.c
+++ b/packages/netcfg/dhcp.c
@@ -50,13 +50,18 @@ static void netcfg_write_dhcp (char *iface, char *dhostname)
fprintf(fp, "\thostname %s\n", dhostname);
}
if (is_wireless_iface(iface)) {
- fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
- fprintf(fp, "\twireless-mode %s\n",
- (mode == MANAGED) ? "managed" : "ad-hoc");
- fprintf(fp, "\twireless-essid %s\n",
- (essid && *essid) ? essid : "any");
- if (wepkey != NULL)
- fprintf(fp, "\twireless-key1 %s\n", wepkey);
+ if (wpa_supplicant_status == WPA_QUEUED) {
+ fprintf(fp, "\twpa-ssid %s\n", essid);
+ fprintf(fp, "\twpa-psk %s\n", passphrase);
+ } else {
+ fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
+ fprintf(fp, "\twireless-mode %s\n",
+ (mode == MANAGED) ? "managed" : "ad-hoc");
+ fprintf(fp, "\twireless-essid %s\n",
+ (essid && *essid) ? essid : "any");
+ if (wepkey != NULL)
+ fprintf(fp, "\twireless-key1 %s\n", wepkey);
+ }
}
fclose(fp);
}
@@ -306,20 +311,59 @@ int ask_dhcp_options (struct debconfclient *client)
int ask_wifi_configuration (struct debconfclient *client)
{
- enum { ABORT, DONE, ESSID, WEP } wifistate = ESSID;
+ enum { ABORT, ESSID, SECURITY_TYPE, WEP, WPA, START, DONE } wifistate = ESSID;
+
+ extern enum wpa_t wpa_supplicant_status;
+ if (wpa_supplicant_status != WPA_UNAVAIL)
+ kill_wpa_supplicant();
+
for (;;) {
switch (wifistate) {
case ESSID:
- wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
- ABORT : WEP;
+ if (wpa_supplicant_status == WPA_UNAVAIL)
+ wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
+ ABORT : WEP;
+ else
+ wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
+ ABORT : SECURITY_TYPE;
break;
+
+ case SECURITY_TYPE:
+ {
+ int ret;
+ ret = wireless_security_type(client, interface);
+ if (ret == GO_BACK)
+ wifistate = ESSID;
+ else if (ret == REPLY_WPA)
+ wifistate = WPA;
+ else
+ wifistate = WEP;
+ break;
+ }
+
case WEP:
- wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
+ if (wpa_supplicant_status == WPA_UNAVAIL)
+ wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
+ ESSID : DONE;
+ else
+ wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
+ SECURITY_TYPE : DONE;
+ break;
+
+ case WPA:
+ wifistate = (netcfg_set_passphrase(client, interface) == GO_BACK) ?
+ SECURITY_TYPE : START;
+ break;
+
+ case START:
+ wifistate = (wpa_supplicant_start(client, interface, essid, passphrase) == GO_BACK) ?
ESSID : DONE;
break;
+
case ABORT:
return REPLY_ASK_OPTIONS;
break;
+
case DONE:
return REPLY_CHECK_DHCP;
break;
diff --git a/packages/netcfg/netcfg.c b/packages/netcfg/netcfg.c
index 3c638aa..f1e7f17 100644
--- a/packages/netcfg/netcfg.c
+++ b/packages/netcfg/netcfg.c
@@ -33,6 +33,7 @@
#endif
#include "netcfg.h"
+enum wpa_t wpa_supplicant_status;
static method_t netcfg_method = DHCP;
response_t netcfg_get_method(struct debconfclient *client)
@@ -69,11 +70,15 @@ int main(int argc, char *argv[])
GET_STATIC,
WCONFIG,
WCONFIG_ESSID,
+ WCONFIG_SECURITY_TYPE,
WCONFIG_WEP,
+ WCONFIG_WPA,
+ START_WPA,
QUIT } state = GET_INTERFACE;
static struct debconfclient *client;
static int requested_wireless_tools = 0;
+ extern enum wpa_t wpa_supplicant_status;
char **ifaces;
char *defiface = NULL, *defwireless = NULL;
response_t res;
@@ -103,6 +108,12 @@ int main(int argc, char *argv[])
case BACKUP:
return 10;
case GET_INTERFACE:
+ /* If we have returned from outside of netcfg and want to
+ * reconfigure networking, check to see if wpasupplicant is
+ * running, and kill it if it is. If left running when
+ * the interfaces are taken up and down, it appears to
+ * leave it in an inconsistant state */
+ kill_wpa_supplicant();
/* Choose a default from ethtool-lite */
if (get_all_ifs(1, &ifaces) > 1) {
while (*ifaces) {
@@ -251,19 +262,60 @@ int main(int argc, char *argv[])
case WCONFIG_ESSID:
if (netcfg_wireless_set_essid(client, interface, NULL) == GO_BACK)
state = BACKUP;
- else
- state = WCONFIG_WEP;
+ else {
+ init_wpa_supplicant_support();
+ if (wpa_supplicant_status == WPA_UNAVAIL)
+ state = WCONFIG_WEP;
+ else
+ state = WCONFIG_SECURITY_TYPE;
+ }
break;
+ case WCONFIG_SECURITY_TYPE:
+ {
+ int ret;
+ ret = wireless_security_type(client, interface);
+ if (ret == GO_BACK)
+ state = WCONFIG_ESSID;
+ else if (ret == REPLY_WPA)
+ state = WCONFIG_WPA;
+ else
+ state = WCONFIG_WEP;
+ break;
+ }
+
case WCONFIG_WEP:
if (netcfg_wireless_set_wep(client, interface) == GO_BACK)
- state = WCONFIG_ESSID;
+ if (wpa_supplicant_status == WPA_UNAVAIL)
+ state = WCONFIG_ESSID;
+ else
+ state = WCONFIG_SECURITY_TYPE;
else
state = GET_METHOD;
break;
+ case WCONFIG_WPA:
+ if (wpa_supplicant_status == WPA_OK) {
+ di_exec_shell_log("apt-install wpasupplicant");
+ wpa_supplicant_status = WPA_QUEUED;
+ }
+
+ if (netcfg_set_passphrase(client, interface) == GO_BACK)
+ state = WCONFIG_SECURITY_TYPE;
+ else
+ state = START_WPA;
+ break;
+
+ case START_WPA:
+ if (wpa_supplicant_start(client, interface, essid, passphrase) == GO_BACK)
+ state = WCONFIG_ESSID;
+ else
+ state = GET_METHOD;
+ break;
+
case QUIT:
return 0;
}
}
}
+
diff --git a/packages/netcfg/netcfg.h b/packages/netcfg/netcfg.h
index a7bc8a9..0d6c2bf 100644
--- a/packages/netcfg/netcfg.h
+++ b/packages/netcfg/netcfg.h
@@ -10,11 +10,16 @@
#define DHCLIENT3_CONF "/etc/dhcp3/dhclient.conf"
#define DOMAIN_FILE "/tmp/domain_name"
#define NTP_SERVER_FILE "/tmp/dhcp-ntp-servers"
+#define WPASUPP_CTRL "/var/run/wpa_supplicant"
+#define WPAPID "/var/run/wpa_supplicant.pid"
#define DEVNAMES "/etc/network/devnames"
#define DEVHOTPLUG "/etc/network/devhotplug"
#define STAB "/var/run/stab"
+#define WPA_MIN 8 /* minimum passphrase length */
+#define WPA_MAX 64 /* maximum passphrase length */
+
#define _GNU_SOURCE
#include <sys/types.h>
@@ -41,9 +46,10 @@
"ff02::2 ip6-allrouters\n" \
"ff02::3 ip6-allhosts\n"
-typedef enum { NOT_ASKED = 30, GO_BACK } response_t;
+typedef enum { NOT_ASKED = 30, GO_BACK, REPLY_WEP, REPLY_WPA } response_t;
typedef enum { DHCP, STATIC, DUNNO } method_t;
typedef enum { ADHOC = 1, MANAGED = 2 } wifimode_t;
+extern enum wpa_t { WPA_OK, WPA_QUEUED, WPA_UNAVAIL } wpa_supplicant_status;
extern int netcfg_progress_displayed;
extern int wfd, skfd;
@@ -64,7 +70,7 @@ extern struct in_addr gateway;
extern struct in_addr pointopoint;
/* wireless */
-extern char *essid, *wepkey;
+extern char *essid, *wepkey, *passphrase;
extern wifimode_t mode;
/* common functions */
@@ -108,10 +114,14 @@ extern void netcfg_write_common (struct in_addr ipaddress, char *hostname,
void netcfg_nameservers_to_array(char *nameservers, struct in_addr array[]);
extern int is_wireless_iface (const char* iface);
-
extern int netcfg_wireless_set_essid (struct debconfclient *client, char* iface, char* priority);
extern int netcfg_wireless_set_wep (struct debconfclient *client, char* iface);
+extern int wireless_security_type (struct debconfclient *client, char* iface);
+extern int netcfg_set_passphrase (struct debconfclient *client, char* iface);
+extern int init_wpa_supplicant_support (void);
+extern int kill_wpa_supplicant (void);
+extern int wpa_supplicant_start (struct debconfclient *client, char *iface, char *ssid, char *passphrase);
extern int iface_is_hotpluggable(const char *iface);
extern short find_in_stab (const char *iface);
extern void deconfigure_network(void);
diff --git a/packages/netcfg/wireless.c b/packages/netcfg/wireless.c
index ed07b8a..40432d1 100644
--- a/packages/netcfg/wireless.c
+++ b/packages/netcfg/wireless.c
@@ -53,7 +53,7 @@ int netcfg_wireless_set_essid (struct debconfclient * client, char *iface, char*
wconf.has_mode = 1;
wconf.mode = mode;
- debconf_input(client, priority ? priority : "low", "netcfg/wireless_essid");
+ debconf_input(client, priority ? priority : "high", "netcfg/wireless_essid");
if (debconf_go(client) == 30)
return GO_BACK;
diff --git a/packages/netcfg/wpa.c b/packages/netcfg/wpa.c
new file mode 100644
index 0000000..96e4edf
--- /dev/null
+++ b/packages/netcfg/wpa.c
@@ -0,0 +1,473 @@
+/*
+* WPA module for netcfg
+*
+* Copyright (C) 2008 Glenn Saberton <gsaberton@foomagic.org>
+*
+* Licensed under the terms of the GNU General Public License version 2
+*
+*/
+
+#include "netcfg.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <debian-installer.h>
+#include "wpa_ctrl.h"
+#include <iwlib.h>
+
+pid_t wpa_supplicant_pid = -1;
+enum wpa_t wpa_supplicant_status;
+struct wpa_ctrl *ctrl;
+char *passphrase = NULL;
+static int wpa_is_running = 0;
+
+int init_wpa_supplicant_support(void)
+{
+ if (access("/sbin/wpa_supplicant", F_OK) == 0)
+ wpa_supplicant_status = WPA_OK;
+ else {
+ wpa_supplicant_status = WPA_UNAVAIL;
+ di_info("Wpasupplicant not found on the system. Disabling WPA options");
+ }
+ return 0;
+}
+
+int kill_wpa_supplicant(void)
+{
+ pid_t wpa_pid;
+ FILE *fp;
+
+ fp = (fopen(WPAPID, "r"));
+ if (fp == NULL) {
+ di_warning("Couldn't read Wpasupplicant pid file, not trying to kill.");
+ return 0;
+ }
+ else {
+ fscanf(fp, "%d", &wpa_pid);
+ fclose(fp);
+ }
+ if ((kill(wpa_pid, SIGTERM)) == 0)
+ return 0;
+ else {
+ kill(wpa_pid, SIGKILL);
+ unlink(WPAPID);
+ return 0;
+ }
+}
+
+int wireless_security_type (struct debconfclient *client, char *iface)
+{
+ int ret = 0 ;
+ debconf_subst(client, "netcfg/wireless_security_type", "iface", iface);
+ debconf_input(client, "high", "netcfg/wireless_security_type");
+ ret = debconf_go(client);
+
+ if (ret == 30)
+ return GO_BACK;
+
+ debconf_get(client, "netcfg/wireless_security_type");
+
+ if (!strcmp(client->value, "wep/open"))
+ return REPLY_WEP;
+ else
+ return REPLY_WPA;
+
+}
+
+int netcfg_set_passphrase (struct debconfclient *client, char *iface)
+{
+ int ret;
+
+ debconf_subst(client, "netcfg/wireless_wpa", "iface", iface);
+ debconf_input(client, "high", "netcfg/wireless_wpa");
+ ret = debconf_go(client);
+
+ if (ret == 30)
+ return GO_BACK;
+
+ if (passphrase != NULL)
+ free(passphrase);
+
+ debconf_get(client, "netcfg/wireless_wpa");
+ passphrase = strdup(client->value);
+
+ while (strlen(passphrase) < WPA_MIN || strlen(passphrase) > WPA_MAX) {
+ debconf_subst(client, "netcfg/invalid_pass", "passphrase", passphrase);
+ debconf_input(client, "critical", "netcfg/invalid_pass");
+ debconf_go(client);
+ free(passphrase);
+
+ debconf_input(client, "high", "netcfg/wireless_wpa");
+ ret = debconf_go(client);
+
+ if (ret == 30)
+ return GO_BACK;
+
+ debconf_get(client, "netcfg/wireless_wpa");
+ passphrase = strdup(client->value);
+ }
+ return 0;
+}
+
+static int start_wpa_daemon(struct debconfclient *client)
+{
+ wpa_supplicant_pid = fork();
+
+ if (wpa_supplicant_pid == 0) {
+ fclose(client->out);
+ if (execlp("wpa_supplicant", "wpa_supplicant", "-i", interface, "-C",
+ WPASUPP_CTRL, "-P", WPAPID, "-B", NULL) == -1) {
+ di_error("could not exec wpasupplicant: %s", strerror(errno));
+ return 1;
+ }
+ else
+ return 0;
+ }
+ else {
+ waitpid(wpa_supplicant_pid, NULL, 0);
+ return 0;
+ }
+}
+
+void wpa_daemon_running(void)
+{
+ FILE *fp = fopen(WPAPID, "r");
+ if (fp) {
+ wpa_is_running = 1;
+ fclose(fp);
+ }
+}
+
+static int wpa_connect(char *iface)
+{
+ char *cfile;
+ int flen, res;
+
+ flen = (strlen(WPASUPP_CTRL) + strlen(iface) + 2);
+
+ cfile = malloc(flen);
+ if (cfile == NULL) {
+ di_info("Can't allocate memory for WPA control iface.");
+ return -1;
+ }
+
+ res = snprintf(cfile, flen, "%s/%s", WPASUPP_CTRL, iface);
+ if ((res < 0) || (res >= flen)) {
+ free(cfile);
+ return -1;
+ }
+ ctrl = wpa_ctrl_open(cfile);
+ free(cfile);
+
+ if (ctrl == NULL) {
+ di_info("Couldn't connect to wpasupplicant");
+ return -1;
+ }
+ else
+ return 0;
+}
+
+static int wpa_add_network(void)
+{
+ size_t len;
+ char buf[256];
+ int ret;
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, "ADD_NETWORK", 12, buf, &len, NULL);
+ if (ret < 0)
+ return 1;
+
+ return 0;
+}
+
+static int wpa_set_ssid (char *ssid)
+{
+ int ret, res;
+ size_t len;
+ char cmd[256];
+ char buf[256];
+
+ res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "ssid", ssid);
+ if (res < 0)
+ return 1;
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
+ if (ret != 0) {
+ di_info("Failed to set the ssid with wpasupplicant");
+ return 1;
+ }
+ return 0;
+}
+
+static int wpa_set_psk(char *passphrase)
+{
+ int ret, res;
+ size_t len;
+ char buf[256];
+ char cmd[256];
+
+ res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s \"%s\"", "psk", passphrase);
+ if (res < 0)
+ return 1;
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
+ if (ret != 0)
+ return 1;
+
+ return 0;
+}
+
+static int wpa_set_scan_ssid(void)
+{
+ int ret, res;
+ size_t len;
+ char cmd[256];
+ char buf[256];
+
+ res = snprintf(cmd, sizeof(cmd), "SET_NETWORK 0 %s 1", "scan_ssid");
+ if (res < 0)
+ return 1;
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
+ if (ret != 0)
+ return 1;
+
+ return 0;
+}
+
+static int wpa_enable_network(void)
+{
+ int ret, res;
+ size_t len;
+ char buf[256];
+ char cmd[256];
+
+ res = snprintf(cmd, sizeof(cmd), "SELECT_NETWORK 0");
+ if (res < 0)
+ return 1;
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, cmd, sizeof(cmd), buf, &len, NULL);
+ if (ret != 0)
+ return 1;
+
+ return 0;
+}
+
+static int wpa_status(void)
+{
+ int ret;
+ size_t len;
+ char buf[2048];
+ const char *success = "wpa_state=COMPLETED";
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, "STATUS", 7, buf, &len, NULL);
+
+ if (ret == 0) {
+ buf[len] = '\0';
+ di_info("buf = %s", buf);
+ }
+ else
+ return 1;
+
+ if (strstr(buf, success) == NULL)
+ return 1;
+ else {
+ di_info("success");
+ return 0;
+ }
+}
+
+static int wpa_ping(void)
+{
+ int ret;
+ size_t len;
+ char buf[256];
+
+ len = sizeof(buf) -1;
+ ret = wpa_ctrl_request(ctrl, "PING", 5, buf, &len, NULL);
+ if (ret < 0) {
+ di_info("Ctrl iface did not respond to PING");
+ return 1;
+ }
+ return 0;
+}
+
+int poll_wpa_supplicant(struct debconfclient *client)
+{
+ int wpa_timeout = 60;
+ int seconds_slept = 0;
+ int state = 1;
+
+ debconf_capb(client, "backup progresscancel");
+ debconf_progress_start(client, 0, wpa_timeout, "netcfg/wpa_progress");
+
+ for (seconds_slept = 0; seconds_slept <= wpa_timeout; seconds_slept++) {
+
+ if (debconf_progress_info(client, "netcfg/wpa_progress_note") == 30)
+ goto stop;
+
+ if (debconf_progress_step(client, 1) == 30)
+ goto stop;
+
+ sleep(1);
+
+ if ((seconds_slept <= wpa_timeout) && (seconds_slept % 5) == 0) {
+ if (!wpa_status()) {
+ debconf_progress_set(client, wpa_timeout);
+ debconf_progress_info(client, "netcfg/wpa_success_note");
+ state = 0;
+ sleep(2);
+ goto stop;
+ }
+ }
+ if (seconds_slept == wpa_timeout) {
+ debconf_progress_stop(client);
+ debconf_capb(client, "backup");
+ debconf_capb(client, "");
+ debconf_input(client, "critical", "netcfg/wpa_supplicant_failed");
+ debconf_go(client);
+ debconf_capb(client, "backup");
+ return 1;
+ }
+ }
+ stop:
+ debconf_progress_stop(client);
+ debconf_capb(client, "backup");
+ if (!state)
+ return 0;
+ else
+ return 1;
+
+}
+
+int wpa_supplicant_start(struct debconfclient *client, char *iface, char *ssid, char *passphrase)
+{
+ int retry = 0;
+
+ enum { CHECK_DAEMON,
+ START_DAEMON,
+ CONNECT,
+ PING,
+ ADD_NETWORK,
+ SET_ESSID,
+ SET_PSK,
+ SET_SCAN_SSID,
+ ENABLE_NETWORK,
+ POLL,
+ ABORT,
+ SUCCESS } state = CHECK_DAEMON;
+
+ for (;;) {
+ switch(state) {
+
+ case CHECK_DAEMON:
+ wpa_daemon_running();
+ if (wpa_is_running)
+ state = CONNECT;
+ else
+ state = START_DAEMON;
+ break;
+
+ case START_DAEMON:
+ if (!start_wpa_daemon(client))
+ state = CONNECT;
+ else
+ state = ABORT;
+ break;
+
+ case CONNECT:
+ if (wpa_connect(iface) == 0)
+ state = PING;
+ else
+ state = ABORT;
+ break;
+
+ case PING:
+ /* if the daemon doesn't respond, try and ping
+ * it and increment retry. If we have done
+ * this 4 times, something must be wrong
+ * so bail out. */
+ retry++;
+ if (retry > 4)
+ state = ABORT;
+ else if (wpa_ping()) {
+ kill_wpa_supplicant();
+ state = START_DAEMON;
+ break;
+ }
+ else
+ state = ADD_NETWORK;
+ break;
+
+ case ADD_NETWORK:
+ if (wpa_is_running) {
+ state = SET_ESSID;
+ break;
+ }
+ if (wpa_add_network())
+ state = PING;
+ else
+ state = SET_ESSID;
+ break;
+
+ case SET_ESSID:
+ if (wpa_set_ssid(ssid))
+ state = PING;
+ else
+ state = SET_PSK;
+ break;
+
+ case SET_PSK:
+ if (wpa_set_psk(passphrase))
+ state = PING;
+ else
+ state = SET_SCAN_SSID;
+ break;
+
+ case SET_SCAN_SSID:
+ if (wpa_set_scan_ssid())
+ state = PING;
+ else
+ state = ENABLE_NETWORK;
+ break;
+
+ case ENABLE_NETWORK:
+ if (wpa_enable_network())
+ state = PING;
+ else
+ state = POLL;
+ break;
+
+ case POLL:
+ if (poll_wpa_supplicant(client))
+ state = ABORT;
+ else
+ state = SUCCESS;
+ break;
+
+ case ABORT:
+ if (ctrl == NULL)
+ return GO_BACK;
+ else {
+ wpa_ctrl_close(ctrl);
+ ctrl = NULL;
+ return GO_BACK;
+ }
+
+ case SUCCESS:
+ if (ctrl == NULL)
+ return 0;
+ else {
+ wpa_ctrl_close(ctrl);
+ ctrl = NULL;
+ return 0;
+ }
+ }
+ }
+}
diff --git a/packages/netcfg/wpa_ctrl.c b/packages/netcfg/wpa_ctrl.c
new file mode 100644
index 0000000..6e01a9e
--- /dev/null
+++ b/packages/netcfg/wpa_ctrl.c
@@ -0,0 +1,256 @@
+/*
+ * Modifed version of src/common/wpa_ctrl.c from wpa_supplicant, discarding
+ * all code paths except for CONFIG_CTRL_IFACE_UNIX. Define strlcpy inline,
+ * it is not provided by GNU libc.
+ * Copyright (c) 2008, Kel Modderman <kel@otaku42.de>
+ *
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include "wpa_ctrl.h"
+
+/**
+ * strlcpy - Copy a string with size bound and NUL-termination
+ * @dest: Destination
+ * @src: Source
+ * @siz: Size of the target buffer
+ * Returns: Total length of the target string (length of src) (not including
+ * NUL-termination)
+ *
+ * This function matches in behavior with the strlcpy(3) function in OpenBSD.
+ */
+size_t strlcpy(char *dest, const char *src, size_t siz)
+{
+ const char *s = src;
+ size_t left = siz;
+
+ if (left) {
+ /* Copy string up to the maximum size of the dest buffer */
+ while (--left != 0) {
+ if ((*dest++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ if (left == 0) {
+ /* Not enough room for the string; force NUL-termination */
+ if (siz != 0)
+ *dest = '\0';
+ while (*s++)
+ ; /* determine total src string length */
+ }
+
+ return s - src - 1;
+}
+
+
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
+struct wpa_ctrl {
+ int s;
+ struct sockaddr_un local;
+ struct sockaddr_un dest;
+};
+
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+ struct wpa_ctrl *ctrl;
+ static int counter = 0;
+ int ret;
+ size_t res;
+
+ ctrl = malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ memset(ctrl, 0, sizeof(*ctrl));
+
+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (ctrl->s < 0) {
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->local.sun_family = AF_UNIX;
+ ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+ "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
+ if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+ sizeof(ctrl->local)) < 0) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+
+ ctrl->dest.sun_family = AF_UNIX;
+ res = strlcpy(ctrl->dest.sun_path, ctrl_path,
+ sizeof(ctrl->dest.sun_path));
+ if (res >= sizeof(ctrl->dest.sun_path)) {
+ close(ctrl->s);
+ free(ctrl);
+ return NULL;
+ }
+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+ sizeof(ctrl->dest)) < 0) {
+ close(ctrl->s);
+ unlink(ctrl->local.sun_path);
+ free(ctrl);
+ return NULL;
+ }
+
+ return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+ unlink(ctrl->local.sun_path);
+ close(ctrl->s);
+ free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len))
+{
+ struct timeval tv;
+ int res;
+ fd_set rfds;
+ const char *_cmd;
+ char *cmd_buf = NULL;
+ size_t _cmd_len;
+
+ {
+ _cmd = cmd;
+ _cmd_len = cmd_len;
+ }
+
+ if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+ free(cmd_buf);
+ return -1;
+ }
+ free(cmd_buf);
+
+ for (;;) {
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ if (FD_ISSET(ctrl->s, &rfds)) {
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ if (res > 0 && reply[0] == '<') {
+ /* This is an unsolicited message from
+ * wpa_supplicant, not the reply to the
+ * request. Use msg_cb to report this to the
+ * caller. */
+ if (msg_cb) {
+ /* Make sure the message is nul
+ * terminated. */
+ if ((size_t) res == *reply_len)
+ res = (*reply_len) - 1;
+ reply[res] = '\0';
+ msg_cb(reply, res);
+ }
+ continue;
+ }
+ *reply_len = res;
+ break;
+ } else {
+ return -2;
+ }
+ }
+ return 0;
+}
+
+
+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
+{
+ char buf[10];
+ int ret;
+ size_t len = 10;
+
+ ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+ buf, &len, NULL);
+ if (ret < 0)
+ return ret;
+ if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
+ return 0;
+ return -1;
+}
+
+
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
+{
+ return wpa_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
+{
+ return wpa_ctrl_attach_helper(ctrl, 0);
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+ int res;
+
+ res = recv(ctrl->s, reply, *reply_len, 0);
+ if (res < 0)
+ return res;
+ *reply_len = res;
+ return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+ struct timeval tv;
+ fd_set rfds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(ctrl->s, &rfds);
+ select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+ return ctrl->s;
+}
diff --git a/packages/netcfg/wpa_ctrl.h b/packages/netcfg/wpa_ctrl.h
new file mode 100644
index 0000000..e4cd490
--- /dev/null
+++ b/packages/netcfg/wpa_ctrl.h
@@ -0,0 +1,187 @@
+/*
+ * Unmodifed version of src/common/wpa_ctrl.h from wpa_supplicant.
+ *
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef WPA_CTRL_H
+#define WPA_CTRL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** New scan results available */
+#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
+void wpa_ctrl_close(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
+
+
+/**
+ * wpa_ctrl_pending - Check whether there are pending event messages
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WPA_CTRL_H */
--
1.5.6
Reply to: