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

[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: