Re-write libdhcpcd to talk to dhcpcd directly and not use DBus.
authorRoy Marples <roy@marples.name>
Thu, 3 Jul 2014 19:03:40 +0000 (19:03 +0000)
committerRoy Marples <roy@marples.name>
Thu, 3 Jul 2014 19:03:40 +0000 (19:03 +0000)
Re-write dhcpcd-gtk around the new libdhcpcd API.

17 files changed:
Makefile
configure
mk/lib.mk
src/dhcpcd-gtk/dhcpcd-gtk.h
src/dhcpcd-gtk/main.c
src/dhcpcd-gtk/menu.c
src/dhcpcd-gtk/prefs.c
src/dhcpcd-gtk/wpa.c
src/libdhcpcd/Makefile
src/libdhcpcd/config.c
src/libdhcpcd/dhcpcd.c [new file with mode: 0644]
src/libdhcpcd/dhcpcd.h [new file with mode: 0644]
src/libdhcpcd/dispatch.c [deleted file]
src/libdhcpcd/libdhcpcd.h [deleted file]
src/libdhcpcd/main.c [deleted file]
src/libdhcpcd/misc.c [deleted file]
src/libdhcpcd/wpa.c

index e1682bbd3b92b2ebb9c8b35a8d9b52062505d5f2..a5bec9425695409c713389b3cd9f08377460796d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 PROG=          dhcpcd-ui
-VERSION=       0.6.0
+VERSION=       0.7.0
 
 .PHONY:                icons
 
index 4a75fe537eaf11403a424209b6e432839cb2c0ee..cd598facdf4b0ac6f682ccd23fcf9b18a1aa3767 100755 (executable)
--- a/configure
+++ b/configure
@@ -170,8 +170,18 @@ if ! type "$CC" >/dev/null 2>&1; then
 fi
 
 echo "Using compiler .. $CC"
-if ! type "$CC" >/dev/null 2>&1; then
-       echo "$CC is not an executable"
+cat <<EOF >_test.c
+int main(void) {
+       return 0;
+}
+EOF
+_CC=false
+if $CC _test.c -o _test >/dev/null 2>&1; then
+       [ -x _test ] && _CC=true
+fi
+rm -f _test.c _test
+if ! $_CC; then
+       echo "$CC does not create executables"
        exit 1
 fi
 [ "$CC" != cc ] && echo "CC=   $CC" >>$CONFIG_MK
@@ -218,6 +228,9 @@ EOF
        mirbsd*|openbsd*);; # OpenBSD has many redundant decs in system headers
        *)              echo "CFLAGS+=  -Wredundant-decls" >>$CONFIG_MK;;
        esac
+else
+       # Disable assertations
+       echo "CFLAGS+=  -DNDEBUG" >>$CONFIG_MK
 fi
 
 # Add CPPFLAGS and CFLAGS to CC for testing features
@@ -275,14 +288,6 @@ echo "LIB_DHCPCD=  $x" >>$CONFIG_MK
 # what we actually need.
 echo "LDADD+=  -Wl,--as-needed" >>$CONFIG_MK
 
-# Get DBus CFLAGS
-DBUS_CFLAGS=$(pkg-config --cflags dbus-1) || exit 1
-DBUS_LIBS=$(pkg-config --libs dbus-1) || exit 1
-echo "DBus CFLAGS=$DBUS_CFLAGS"
-echo "DBus LIBS=$DBUS_LIBS"
-echo "DBUS_CFLAGS=     $DBUS_CFLAGS" >>$CONFIG_MK
-echo "DBUS_LIBS=       $DBUS_LIBS" >>$CONFIG_MK
-
 UI=
 if [ "$WITH_GTK" = yes -o -z "$WITH_GTK" ]; then
        if pkg-config --cflags gtk+-2.0 >/dev/null 2>&1; then
index 81a859856a4ed4056bca73bcb70c83c7bff06d04..544ee071ef52bee76aae5911beae6bf600696d70 100644 (file)
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -1,7 +1,5 @@
 # rules to build a library
 
-include ${TOPDIR}/iconfig.mk
-
 SHLIB=                 lib${LIB}.so.${SHLIB_MAJOR}
 SHLIB_LINK=            lib${LIB}.so
 LIBNAME=               lib${LIB}.a
index 6025595ec25852bfcb93eb41855eac4f86a06ad4..3ab2980ee84f724c76d64250032ccf014ad5264e 100644 (file)
@@ -27,8 +27,6 @@
 #ifndef DHCPCD_GTK_H
 #define DHCPCD_GTK_H
 
-#include <arpa/inet.h>
-
 #include <stdbool.h>
 
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <libintl.h>
 
-#include "libdhcpcd.h"
+#include "dhcpcd.h"
 
 #define PACKAGE "dhcpcd-gtk"
 
-/* Work out if we have a private address or not
- * 10/8
- * 172.16/12
- * 192.168/16
- */
-#ifndef IN_PRIVATE
-#  define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) ||        \
-           ((addr & 0xfff00000)    == 0xac100000) ||                         \
-           ((addr & IN_CLASSB_NET) == 0xc0a80000))
-#endif
-#ifndef IN_LINKLOCAL
-#  define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == 0xa9fe0000)
-#endif
-
 #define UNCONST(a)              ((void *)(unsigned long)(const void *)(a))
 
 #ifdef __GNUC__
@@ -63,7 +47,6 @@
 #endif
 
 typedef struct wi_scan {
-       DHCPCD_CONNECTION *connection;
        DHCPCD_IF *interface;
        DHCPCD_WI_SCAN *scans;
        struct wi_scan *next;
@@ -80,7 +63,7 @@ void notify_close(void);
 void dhcpcd_prefs_show(DHCPCD_CONNECTION *con);
 void dhcpcd_prefs_abort(void);
 
-bool wpa_configure(DHCPCD_CONNECTION *, DHCPCD_IF *, DHCPCD_WI_SCAN *);
+bool wpa_configure(DHCPCD_WPA *, DHCPCD_WI_SCAN *);
 
 #if GTK_MAJOR_VERSION == 2
 GtkWidget *gtk_box_new(GtkOrientation, gint);
index a2d1dc66b0ba40ec8c98ce513add9a3bb60c72aa..b16f721395a67539412ddb6cb345d99f0c6fb361 100644 (file)
@@ -24,8 +24,8 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <locale.h>
-#include <poll.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -38,6 +38,7 @@ static NotifyNotification *nn;
 #endif
 
 #include "config.h"
+#include "dhcpcd.h"
 #include "dhcpcd-gtk.h"
 
 static GtkStatusIcon *status_icon;
@@ -47,7 +48,8 @@ static bool online;
 static bool carrier;
 
 struct watch {
-       struct pollfd pollfd;
+       gpointer ref;
+       int fd;
        guint eventid;
        GIOChannel *gio;
        struct watch *next;
@@ -56,6 +58,9 @@ static struct watch *watches;
 
 WI_SCAN *wi_scans;
 
+static gboolean dhcpcd_try_open(gpointer data);
+static gboolean dhcpcd_wpa_try_open(gpointer data);
+
 WI_SCAN *
 wi_scan_find(DHCPCD_WI_SCAN *scan)
 {
@@ -129,10 +134,13 @@ update_online(DHCPCD_CONNECTION *con, bool showif)
        msgs = NULL;
        ifs = dhcpcd_interfaces(con);
        for (i = ifs; i; i = i->next) {
-               if (i->up)
-                       ison = iscarrier = true;
-               if (!iscarrier && g_strcmp0(i->reason, "CARRIER") == 0)
-                       iscarrier = true;
+               if (g_strcmp0(i->type, "link") == 0) {
+                       if (i->up)
+                               iscarrier = true;
+               } else {
+                       if (i->up)
+                               ison = true;
+               }
                msg = dhcpcd_if_message(i);
                if (msg) {
                        if (showif)
@@ -226,38 +234,9 @@ notify(const char *title, const char *msg, const char *icon)
 #endif
 
 static void
-event_cb(DHCPCD_CONNECTION *con, DHCPCD_IF *i, _unused void *data)
-{
-       char *msg;
-       const char *icon;
-
-       g_message("interface event: %s: %s", i->ifname, i->reason);
-       update_online(con, false);
-
-       /* We should ignore renew and stop so we don't annoy the user */
-       if (g_strcmp0(i->reason, "RENEW") == 0 ||
-           g_strcmp0(i->reason, "STOP") == 0)
-               return;
-
-       msg = dhcpcd_if_message(i);
-       if (msg) {
-               g_message("%s", msg);
-               if (i->up)
-                       icon = "network-transmit-receive";
-               //else
-               //      icon = "network-transmit";
-               if (!i->up)
-                       icon = "network-offline";
-               notify(_("Network event"), msg, icon);
-               g_free(msg);
-       }
-}
-
-static void
-status_cb(DHCPCD_CONNECTION *con, const char *status, _unused void *data)
+dhcpcd_status_cb(DHCPCD_CONNECTION *con, const char *status, _unused void *data)
 {
        static char *last = NULL;
-       char *version;
        const char *msg;
        bool refresh;
        WI_SCAN *w;
@@ -283,11 +262,9 @@ status_cb(DHCPCD_CONNECTION *con, const char *status, _unused void *data)
                        wi_scans = w;
                }
        } else {
-               if ((last == NULL || g_strcmp0(last, "down") == 0) &&
-                   dhcpcd_command(con, "GetDhcpcdVersion", NULL, &version))
-               {
-                       g_message(_("Connected to %s-%s"), "dhcpcd", version);
-                       g_free(version);
+               if ((last == NULL || g_strcmp0(last, "down") == 0)) {
+                       g_message(_("Connected to %s-%s"), "dhcpcd",
+                           dhcpcd_version(con));
                        refresh = true;
                } else
                        refresh = false;
@@ -296,26 +273,249 @@ status_cb(DHCPCD_CONNECTION *con, const char *status, _unused void *data)
        last = g_strdup(status);
 }
 
+static struct watch *
+dhcpcd_findwatch(int fd, gpointer data, struct watch **last)
+{
+       struct watch *w;
+
+       if (last)
+               *last = NULL;
+       for (w = watches; w; w = w->next) {
+               if (w->fd == fd || w->ref == data)
+                       return w;
+               if (last)
+                       *last = w;
+       }
+       return NULL;
+}
+
+static void
+dhcpcd_unwatch(int fd, gpointer data)
+{
+       struct watch *w, *l;
+
+       if ((w = dhcpcd_findwatch(fd, data, &l))) {
+               if (l)
+                       l->next = w->next;
+               else
+                       watches = w->next;
+               g_source_remove(w->eventid);
+               g_io_channel_unref(w->gio);
+               g_free(w);
+       }
+}
+
+static gboolean
+dhcpcd_watch(int fd,
+    gboolean (*cb)(GIOChannel *, GIOCondition, gpointer),
+    gpointer data)
+{
+       struct watch *w, *l;
+       GIOChannel *gio;
+       GIOCondition flags;
+       guint eventid;
+
+       /* Sanity */
+       if ((w = dhcpcd_findwatch(fd, data, &l))) {
+               if (w->fd == fd)
+                       return TRUE;
+               if (l)
+                       l->next = w->next;
+               else
+                       watches = w->next;
+               g_source_remove(w->eventid);
+               g_io_channel_unref(w->gio);
+               g_free(w);
+       }
+
+       gio = g_io_channel_unix_new(fd);
+       if (gio == NULL) {
+               g_warning(_("Error creating new GIO Channel\n"));
+               return FALSE;
+       }
+       flags = G_IO_IN | G_IO_ERR | G_IO_HUP;
+       if ((eventid = g_io_add_watch(gio, flags, cb, data)) == 0) {
+               g_warning(_("Error creating watch\n"));
+               g_io_channel_unref(gio);
+               return FALSE;
+       }
+
+       w = g_try_malloc(sizeof(*w));
+       if (w == NULL) {
+               g_warning(_("g_try_malloc\n"));
+               g_source_remove(eventid);
+               g_io_channel_unref(gio);
+               return FALSE;
+       }
+
+       w->ref = data;
+       w->fd = fd;
+       w->eventid = eventid;
+       w->gio = gio;
+       w->next = watches;
+       watches = w;
+
+       return TRUE;
+}
+
+static gboolean
+dhcpcd_cb(_unused GIOChannel *gio, _unused GIOCondition c, gpointer data)
+{
+       DHCPCD_CONNECTION *con;
+
+       con = (DHCPCD_CONNECTION *)data;
+       if (dhcpcd_get_fd(con) == -1) {
+               g_warning(_("dhcpcd connection lost"));
+               dhcpcd_unwatch(-1, con);
+               g_timeout_add(DHCPCD_RETRYOPEN, dhcpcd_try_open, con);
+               return FALSE;
+       }
+
+       dhcpcd_dispatch(con);
+       return TRUE;
+}
+
+static gboolean
+dhcpcd_try_open(gpointer data)
+{
+       DHCPCD_CONNECTION *con;
+       int fd;
+       static int last_error;
+
+       con = (DHCPCD_CONNECTION *)data;
+       fd = dhcpcd_open(con);
+       if (fd == -1) {
+               if (errno != last_error)
+                       g_critical("dhcpcd_open: %s", strerror(errno));
+               last_error = errno;
+               return TRUE;
+       }
+
+       if (!dhcpcd_watch(fd, dhcpcd_cb, con)) {
+               dhcpcd_close(con);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void
+dhcpcd_if_cb(DHCPCD_IF *i, _unused void *data)
+{
+       DHCPCD_CONNECTION *con;
+       char *msg;
+       const char *icon;
+
+       /* Update the tooltip with connection information */
+       con = dhcpcd_if_connection(i);
+       update_online(con, false);
+
+       /* We should ignore renew and stop so we don't annoy the user */
+       if (g_strcmp0(i->reason, "RENEW") == 0 ||
+           g_strcmp0(i->reason, "STOP") == 0 ||
+           g_strcmp0(i->reason, "STOPPED") == 0)
+               return;
+
+       msg = dhcpcd_if_message(i);
+       if (msg) {
+               g_message("%s", msg);
+               if (i->up)
+                       icon = "network-transmit-receive";
+               //else
+               //      icon = "network-transmit";
+               if (!i->up)
+                       icon = "network-offline";
+               notify(_("Network event"), msg, icon);
+               g_free(msg);
+       }
+}
+
+static gboolean
+dhcpcd_wpa_cb(_unused GIOChannel *gio, _unused GIOCondition c,
+    gpointer data)
+{
+       DHCPCD_WPA *wpa;
+       DHCPCD_IF *i;
+
+       wpa = (DHCPCD_WPA *)data;
+       if (dhcpcd_wpa_get_fd(wpa) == -1) {
+               dhcpcd_unwatch(-1, wpa);
+
+               /* If the interface hasn't left, try re-opening */
+               i = dhcpcd_wpa_if(wpa);
+               if (i == NULL ||
+                   g_strcmp0(i->reason, "DEPARTED") == 0 ||
+                   g_strcmp0(i->reason, "STOPPED") == 0)
+                       return TRUE;
+               g_warning(_("dhcpcd WPA connection lost: %s"), i->ifname);
+               g_timeout_add(DHCPCD_RETRYOPEN, dhcpcd_wpa_try_open, wpa);
+               return FALSE;
+       }
+
+       dhcpcd_wpa_dispatch(wpa);
+       return TRUE;
+}
+
+static gboolean
+dhcpcd_wpa_try_open(gpointer data)
+{
+       DHCPCD_WPA *wpa;
+       int fd;
+       static int last_error;
+
+       wpa = (DHCPCD_WPA *)data;
+       fd = dhcpcd_wpa_open(wpa);
+       if (fd == -1) {
+               if (errno != last_error)
+                       g_critical("dhcpcd_wpa_open: %s", strerror(errno));
+               last_error = errno;
+               return TRUE;
+       }
+
+       if (!dhcpcd_watch(fd, dhcpcd_wpa_cb, wpa)) {
+               dhcpcd_wpa_close(wpa);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 static void
-scan_cb(DHCPCD_CONNECTION *con, DHCPCD_IF *i, _unused void *data)
+dhcpcd_wpa_scan_cb(DHCPCD_WPA *wpa, _unused void *data)
 {
+       DHCPCD_IF *i;
        WI_SCAN *w;
        DHCPCD_WI_SCAN *scans, *s1, *s2;
        char *txt, *t;
+       int lerrno, fd;
        const char *msg;
 
-       g_message(_("%s: Received scan results"), i->ifname);
-       scans = dhcpcd_wi_scans(con, i);
-       if (scans == NULL && dhcpcd_error(con) != NULL) {
-               g_warning("%s: %s", i->ifname, dhcpcd_error(con));
-               dhcpcd_error_clear(con);
+       /* This could be a new WPA so watch it */
+       fd = dhcpcd_wpa_get_fd(wpa);
+       if (fd == -1) {
+               g_critical("No fd for WPA %p", wpa);
+               dhcpcd_unwatch(-1, wpa);
+               return;
        }
+       dhcpcd_watch(fd, dhcpcd_wpa_cb, wpa);
+
+       i = dhcpcd_wpa_if(wpa);
+       if (i == NULL) {
+               g_critical("No interface for WPA %p", wpa);
+               return;
+       }
+       g_message(_("%s: Received scan results"), i->ifname);
+       lerrno = errno;
+       errno = 0;
+       scans = dhcpcd_wi_scans(i);
+       if (scans == NULL && errno)
+               g_warning("%s: %s", i->ifname, strerror(errno));
+       errno = lerrno;
        for (w = wi_scans; w; w = w->next)
-               if (w->connection == con && w->interface == i)
+               if (w->interface == i)
                        break;
        if (w == NULL) {
                w = g_malloc(sizeof(*w));
-               w->connection = con;
                w->interface = i;
                w->next = wi_scans;
                wi_scans = w;
@@ -347,81 +547,9 @@ scan_cb(DHCPCD_CONNECTION *con, DHCPCD_IF *i, _unused void *data)
        w->scans = scans;
 }
 
-static gboolean
-gio_callback(GIOChannel *gio, _unused GIOCondition c, _unused gpointer d)
-{
-       int fd;
-
-       fd = g_io_channel_unix_get_fd(gio);
-       dhcpcd_dispatch(fd);
-       return true;
-}
-
-static void
-delete_watch_cb(_unused DHCPCD_CONNECTION *con, const struct pollfd *fd,
-    _unused void *data)
-{
-       struct watch *w, *l;
-
-       l = NULL;
-       for (w = watches; w; w = w->next) {
-               if (w->pollfd.fd == fd->fd) {
-                       if (l == NULL)
-                               watches = w->next;
-                       else
-                               l->next = w->next;
-                       g_source_remove(w->eventid);
-                       g_io_channel_unref(w->gio);
-                       g_free(w);
-                       break;
-               }
-       }
-}
-
-static void
-add_watch_cb(DHCPCD_CONNECTION *con, const struct pollfd *fd,
-    _unused void *data)
-{
-       struct watch *w;
-       GIOChannel *gio;
-       GIOCondition flags;
-       guint eventid;
-
-       /* Remove any existing watch */
-       delete_watch_cb(con, fd, data);
-
-       gio = g_io_channel_unix_new(fd->fd);
-       if (gio == NULL) {
-               g_warning(_("Error creating new GIO Channel\n"));
-               return;
-       }
-       flags = 0;
-       if (fd->events & POLLIN)
-               flags |= G_IO_IN;
-       if (fd->events & POLLOUT)
-               flags |= G_IO_OUT;
-       if (fd->events & POLLERR)
-               flags |= G_IO_ERR;
-       if (fd->events & POLLHUP)
-               flags |= G_IO_HUP;
-       if ((eventid = g_io_add_watch(gio, flags, gio_callback, con)) == 0) {
-               g_io_channel_unref(gio);
-               g_warning(_("Error creating watch\n"));
-               return;
-       }
-       w = g_malloc(sizeof(*w));
-       memcpy(&w->pollfd, fd, sizeof(w->pollfd));
-       w->eventid = eventid;
-       w->gio = gio;
-       w->next = watches;
-       watches = w;
-}
-
 int
 main(int argc, char *argv[])
 {
-       char *error = NULL;
-       char *version = NULL;
        DHCPCD_CONNECTION *con;
 
        setlocale(LC_ALL, "");
@@ -438,39 +566,28 @@ main(int argc, char *argv[])
        gtk_status_icon_set_tooltip_text(status_icon,
            _("Connecting to dhcpcd ..."));
        gtk_status_icon_set_visible(status_icon, true);
-
+       online = false;
 #ifdef NOTIFY
        notify_init(PACKAGE);
 #endif
 
        g_message(_("Connecting ..."));
-       con = dhcpcd_open(&error);
+       con = dhcpcd_new();
        if (con ==  NULL) {
-               g_critical("libdhcpcd: %s", error);
-               exit(EXIT_FAILURE);
-       }
-
-       gtk_status_icon_set_tooltip_text(status_icon,
-           _("Triggering dhcpcd ..."));
-       online = false;
-
-       if (!dhcpcd_command(con, "GetVersion", NULL, &version)) {
-               g_critical("libdhcpcd: GetVersion: %s", dhcpcd_error(con));
-               exit(EXIT_FAILURE);
-       }
-       g_message(_("Connected to %s-%s"), "dhcpcd-dbus", version);
-       g_free(version);
-
-       dhcpcd_set_watch_functions(con, add_watch_cb, delete_watch_cb, NULL);
-       dhcpcd_set_signal_functions(con, event_cb, status_cb, scan_cb, NULL);
-       if (dhcpcd_error(con)) {
-               g_critical("libdhcpcd: %s", dhcpcd_error(con));
+               g_critical("libdhcpcd: %s", strerror(errno));
                exit(EXIT_FAILURE);
        }
+       dhcpcd_set_status_callback(con, dhcpcd_status_cb, NULL);
+       dhcpcd_set_if_callback(con, dhcpcd_if_cb, NULL);
+       dhcpcd_wpa_set_scan_callback(con, dhcpcd_wpa_scan_cb, NULL);
+       //dhcpcd_wpa_set_status_callback(con, dhcpcd_wpa_status_cb, NULL);
+       if (dhcpcd_try_open(con))
+               g_timeout_add(DHCPCD_RETRYOPEN, dhcpcd_try_open, con);
 
        menu_init(status_icon, con);
 
        gtk_main();
        dhcpcd_close(con);
+       dhcpcd_free(con);
        return 0;
 }
index 3dc0cf032c69fc4b520529c142c1d784be31290d..dbf39756eb48b2d170304451988c9363ab36430e 100644 (file)
@@ -80,8 +80,18 @@ ssid_hook(_unused GtkMenuItem *item, gpointer data)
 
        scan = (DHCPCD_WI_SCAN *)data;
        wi = wi_scan_find(scan);
-       if (wi)
-               wpa_configure(wi->connection, wi->interface, scan);
+       if (wi) {
+               DHCPCD_CONNECTION *con;
+
+               con = dhcpcd_if_connection(wi->interface);
+               if (con) {
+                       DHCPCD_WPA *wpa;
+
+                       wpa = dhcpcd_wpa_find(con, wi->interface->ifname);
+                       if (wpa)
+                               wpa_configure(wpa, scan);
+               }
+       }
 }
 
 static void
index 642d5ffa151bc41c4fbeaebedb68968b3646904c..9427772e8ba0e76789ccbcbfc8b93bd7be5083e4 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <sys/types.h>
+#include <arpa/inet.h>
 #include <net/if.h>
 
 #include <errno.h>
 
 static GtkWidget *dialog, *blocks, *names, *controls, *clear, *rebind;
 static GtkWidget *autoconf, *address, *router, *dns_servers, *dns_search;
-static DHCPCD_CONFIG *config;
+static DHCPCD_OPTION *config;
 static char *block, *name;
 static DHCPCD_IF *iface;
 
 static void
-show_config(DHCPCD_CONFIG *conf)
+config_err_dialog(DHCPCD_CONNECTION *con, bool writing, const char *txt)
+{
+       GtkWidget *edialog;
+       char *t;
+
+       t = g_strconcat(_(writing ? "Error saving" : "Error reading"), " ",
+           dhcpcd_cffile(con), "\n\n", txt, NULL);
+       edialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
+           GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", t);
+       gtk_window_set_title(GTK_WINDOW(edialog), _("Config error"));
+       gtk_dialog_run(GTK_DIALOG(edialog));
+       gtk_widget_destroy(edialog);
+       g_free(t);
+}
+
+static void
+show_config(DHCPCD_OPTION *conf)
 {
        const char *val;
        bool autocnf;
@@ -81,25 +98,31 @@ combo_active_text(GtkWidget *widget)
 }
 
 static bool
-set_option(DHCPCD_CONFIG **conf, bool s, const char *opt, const char *val,
+set_option(DHCPCD_OPTION **conf, bool s, const char *opt, const char *val,
        bool *ret)
 {
-       bool r;
 
-       if (s)
-               r = dhcpcd_config_set_static(conf, opt, val);
-       else
-               r = dhcpcd_config_set(conf, opt, val);
-       if (r)
-               return true;
-       g_error("libdhcpcd: %s", strerror(errno));
+       if (s) {
+               if (!dhcpcd_config_set_static(conf, opt, val))
+                       g_critical("dhcpcd_config_set_static: %s",
+                           strerror(errno));
+               else
+                       return true;
+       } else {
+               if (!dhcpcd_config_set(conf, opt, val))
+                       g_critical("dhcpcd_config_set: %s",
+                           strerror(errno));
+               else
+                       return true;
+       }
+
        if (ret)
                *ret = false;
        return false;
 }
 
 static bool
-make_config(DHCPCD_CONFIG **conf)
+make_config(DHCPCD_OPTION **conf)
 {
        const char *val, ns[] = "";
        bool a, ret;
@@ -134,6 +157,23 @@ make_config(DHCPCD_CONFIG **conf)
        return ret;
 }
 
+static bool
+write_config(DHCPCD_CONNECTION *con, DHCPCD_OPTION **conf)
+{
+
+       if (make_config(conf) &&
+           !dhcpcd_config_write(con, block, name, *conf))
+       {
+               const char *s;
+
+               s = strerror(errno);
+               g_warning("dhcpcd_config_write: %s", s);
+               config_err_dialog(con, true, s);
+               return false;
+       }
+       return true;
+}
+
 static GdkPixbuf *
 load_icon(const char *iname)
 {
@@ -175,7 +215,7 @@ list_interfaces(DHCPCD_CONNECTION *con)
        list = NULL;
        for (i = dhcpcd_interfaces(con); i; i = i->next)
                if (strcmp(i->type, "ipv4") == 0)
-                       list = g_slist_append(list, i->ifname);
+                       list = g_slist_append(list, UNCONST(i->ifname));
        return list;
 }
 
@@ -214,8 +254,7 @@ blocks_on_change(GtkWidget *widget, gpointer data)
 
        con = (DHCPCD_CONNECTION *)data;
        if (name) {
-               if (make_config(&config))
-                       dhcpcd_config_save(con, block, name, config);
+               write_config(con, &config);
                dhcpcd_config_free(config);
                config = NULL;
                show_config(config);
@@ -226,7 +265,7 @@ blocks_on_change(GtkWidget *widget, gpointer data)
        block = combo_active_text(widget);
        store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
        gtk_list_store_clear(store);
-       list = dhcpcd_config_blocks_get(con, block);
+       list = dhcpcd_config_blocks(con, block);
 
        if (g_strcmp0(block, "interface") == 0)
                new_names = list_interfaces(con);
@@ -236,12 +275,15 @@ blocks_on_change(GtkWidget *widget, gpointer data)
        n = 0;
        for (l = new_names; l; l = l->next) {
                nn = (const char *)l->data;
-               for (lp = list; *lp; lp++)
-                       if (g_strcmp0(nn, *lp) == 0)
-                               break;
-               if (*lp)
-                       iname = "document-save";
-               else
+               if (list) {
+                       for (lp = list; *lp; lp++)
+                               if (g_strcmp0(nn, *lp) == 0)
+                                       break;
+                       if (*lp)
+                               iname = "document-save";
+                       else
+                               iname = "document-new";
+               } else
                        iname = "document-new";
                pb = load_icon(iname);
                gtk_list_store_append(store, &iter);
@@ -250,7 +292,7 @@ blocks_on_change(GtkWidget *widget, gpointer data)
                n++;
        }
 
-       for (lp = list; *lp; lp++) {
+       for (lp = list; lp && *lp; lp++) {
                for (l = new_names; l; l = l->next)
                        if (g_strcmp0((const char *)l->data, *lp) == 0)
                                break;
@@ -275,8 +317,7 @@ names_on_change(_unused GtkWidget *widget, gpointer data)
 
        con = (DHCPCD_CONNECTION *)data;
        if (name) {
-               if (make_config(&config))
-                       dhcpcd_config_save(con, block, name, config);
+               write_config(con, &config);
                g_free(name);
        }
        name = combo_active_text(names);
@@ -292,9 +333,15 @@ names_on_change(_unused GtkWidget *widget, gpointer data)
        gtk_widget_set_sensitive(address,
            iface && (iface->flags & IFF_POINTOPOINT) == 0);
        if (block && name) {
-               config = dhcpcd_config_load(con, block, name);
-               if (config == NULL && dhcpcd_error(con))
-                       g_error("libdhcpcd: %s", dhcpcd_error(con));
+               errno = 0;
+               config = dhcpcd_config_read(con, block, name);
+               if (config == NULL && errno) {
+                       const char *s;
+
+                       s = strerror(errno);
+                       g_warning("dhcpcd_config_read: %s", s);
+                       config_err_dialog(con, false, s);
+               }
        } else
                config = NULL;
        show_config(config);
@@ -371,10 +418,11 @@ on_clear(_unused GtkWidget *o, gpointer data)
        con = (DHCPCD_CONNECTION *)data;
        dhcpcd_config_free(config);
        config = NULL;
-       if (dhcpcd_config_save(con, block, name, config)) {
+       if (dhcpcd_config_write(con, block, name, config)) {
                set_name_active_icon("document-new");
                show_config(config);
-       }
+       } else
+               g_critical("dhcpcd_config_write: %s", strerror(errno));
 }
 
 static void
@@ -384,21 +432,25 @@ on_rebind(_unused GObject *widget, gpointer data)
        DHCPCD_IF *i;
 
        con = (DHCPCD_CONNECTION *)data;
-       if (make_config(&config) &&
-           dhcpcd_config_save(con, block, name, config)) {
+       if (write_config(con, &config)) {
                set_name_active_icon(config == NULL ?
                    "document-new" : "document-save");
                show_config(config);
-               if (g_strcmp0(block, "interface") == 0)
-                       dhcpcd_rebind(con, iface);
-               else {
+               if (g_strcmp0(block, "interface") == 0) {
+                       if (dhcpcd_rebind(con, iface->ifname) == -1)
+                               g_critical("dhcpcd_rebind %s: %s",
+                                   iface->ifname, strerror(errno));
+               } else {
                        for (i = dhcpcd_interfaces(con); i; i = i->next) {
-                               if (g_strcmp0(i->ssid, name) == 0)
-                                       dhcpcd_rebind(con, i);
+                               if (g_strcmp0(i->ssid, name) == 0) {
+                                       if (dhcpcd_rebind(con, i->ifname) == -1)
+                                               g_critical(
+                                                   "dhcpcd_rebind %s: %s",
+                                                   i->ifname,
+                                                   strerror(errno));
+                               }
                        }
                }
-               if (dhcpcd_error(con))
-                       g_warning("libdhcpcd: %s", dhcpcd_error(con));
        }
 }
 
@@ -407,9 +459,7 @@ on_destroy(_unused GObject *o, gpointer data)
 {
 
        if (name != NULL) {
-               if (make_config(&config))
-                       dhcpcd_config_save((DHCPCD_CONNECTION *)data,
-                           block, name, config);
+               write_config((DHCPCD_CONNECTION *)data, &config);
                g_free(block);
                g_free(name);
                block = name = NULL;
index 6459709fc3c800fe29a8c02205ded7248f96517b..2965326125d737baa6fb1c402353caa45efe29d3 100644 (file)
@@ -24,6 +24,8 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
+
 #include "dhcpcd-gtk.h"
 
 static void
@@ -39,32 +41,36 @@ wpa_dialog(const char *title, const char *txt)
 }
 
 static bool
-configure_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
+configure_network(DHCPCD_WPA *wpa,
     int id, const char *mgmt, const char *var, const char *val, bool quote)
 {
        char *str;
        static bool warned = false;
 
-       if (!dhcpcd_wpa_set_network(con, i, id, "key_mgmt", mgmt))
+       if (!dhcpcd_wpa_network_set(wpa, id, "key_mgmt", mgmt)) {
+               g_warning("libdhcpcd: %s", strerror(errno));
+               wpa_dialog(_("Error"),
+                   _("Failed to set key management"));
                return false;
+       }
        if (quote)
                str = g_strconcat("\"", val, "\"", NULL);
        else
                str = NULL;
-       if (!dhcpcd_wpa_set_network(con, i, id, var, quote ? str : val)) {
-               g_warning("libdhcpcd: %s", dhcpcd_error(con));
-               dhcpcd_error_clear(con);
+       if (!dhcpcd_wpa_network_set(wpa, id, var, quote ? str : val)) {
+               g_warning("libdhcpcd: %s", strerror(errno));
                g_free(str);
                wpa_dialog(_("Error setting password"),
                    _("Failed to set password, probably too short."));
                return false;
        }
        g_free(str);
-       if (!dhcpcd_wpa_command(con, i, "EnableNetwork", id))
+       if (!dhcpcd_wpa_network_enable(wpa, id)) {
+               wpa_dialog(_("Error enabling network"), strerror(errno));
                return false;
-       if (!dhcpcd_wpa_command(con, i, "SaveConfig", -1)) {
-               g_warning("libdhcpcd: %s", dhcpcd_error(con));
-               dhcpcd_error_clear(con);
+       }
+       if (!dhcpcd_wpa_config_write(wpa)) {
+               g_warning("libdhcpcd: %s", strerror(errno));
                if (!warned) {
                        warned = true;
                        wpa_dialog(_("Error saving configuration"),
@@ -72,19 +78,7 @@ configure_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
                }
                return false;
        }
-/*
-  if (!dbus_g_proxy_call(dbus, "Disconnect", &error,
-  G_TYPE_STRING, ifname,
-  G_TYPE_INVALID,
-  G_TYPE_INVALID))
-  {
-  g_warning("Disconnect: %s", error->message);
-  g_error_free(error);
-  }
-*/
-       if (!dhcpcd_wpa_command(con, i, "Reassociate", -1))
-               return false;
-       return true;
+       return dhcpcd_wpa_reassociate(wpa);
 }
 
 static void
@@ -94,7 +88,7 @@ onEnter(_unused GtkWidget *widget, gpointer *data)
 }
 
 bool
-wpa_configure(DHCPCD_CONNECTION *con, DHCPCD_IF *i, DHCPCD_WI_SCAN *s)
+wpa_configure(DHCPCD_WPA *wpa, DHCPCD_WI_SCAN *s)
 {
        GtkWidget *dialog, *label, *psk, *vbox, *hbox;
        const char *var, *mgt;
@@ -131,7 +125,7 @@ again:
        id = -1;
        retval = false;
        if (result == GTK_RESPONSE_ACCEPT) {
-               id = dhcpcd_wpa_find_network_new(con, i, s->ssid);
+               id = dhcpcd_wpa_network_find_new(wpa, s->ssid);
                if (g_strcmp0(s->flags, "[WEP]") == 0) {
                        mgt = "NONE";
                        var = "wep_key0";
@@ -140,13 +134,11 @@ again:
                        var = "psk";
                }
                if (id != -1) {
-                       retval = configure_network(con, i, id, mgt, var,
+                       configure_network(wpa, id, mgt, var,
                            gtk_entry_get_text(GTK_ENTRY(psk)), true);
                }
-               if (!retval && dhcpcd_error(con)) {
-                       wpa_dialog(_("Error"), dhcpcd_error(con));
+               if (!retval)
                        goto again;
-               }
        }
        gtk_widget_destroy(dialog);
        return retval;
index 977482479b63b650f9ddda306d518bc172f90f8e..162377a8d4f177b7775bc3982e2d55b9417f0613 100644 (file)
@@ -1,14 +1,12 @@
 LIB=           dhcpcd
 SHLIB_MAJOR=   1
-SRCS=          main.c config.c dispatch.c misc.c wpa.c
-INCS=          libdhcpcd.h
+SRCS=          dhcpcd.c config.c wpa.c
+INCS=          dhcpcd.h
 
 TOPDIR=                ../..
 include ${TOPDIR}/iconfig.mk
 
-CPPFLAGS+=     -I${TOPDIR} ${DBUS_CFLAGS}
-CFLAGS+=       ${DBUS_CFLAGS}
-LDADD+=                ${DBUS_LIBS}
+CPPFLAGS+=     -I${TOPDIR}
 
 # Don't install
 LIBINSTALL=    ${LIB_DHCPCD_INSTALL}
index dcd4bed59cb35eec5c8155d8971e13bb9bbc3d76..d17fd0d462cc809b8546a33552ca38570de824d5 100644 (file)
  * SUCH DAMAGE.
  */
 
+#include <assert.h>
 #include <errno.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <dbus/dbus.h>
-
 #define IN_LIBDHCPCD
-#include "libdhcpcd.h"
 
-static DHCPCD_CONFIG *
-dhcpcd_config_new(const char *opt, const char *val)
+#include "dhcpcd.h"
+
+static DHCPCD_OPTION *
+dhcpcd_option_new(const char *opt, const char *val)
 {
-       DHCPCD_CONFIG *c;
+       DHCPCD_OPTION *o;
 
-       c = malloc(sizeof(*c));
-       if (c == NULL)
+       o = malloc(sizeof(*o));
+       if (o == NULL)
                return NULL;
-       c->option = strdup(opt);
-       if (c->option == NULL) {
-               free(c);
+       o->option = strdup(opt);
+       if (o->option == NULL) {
+               free(o);
                return NULL;
        }
-       c->value = strdup(val);
-       if (c->value == NULL) {
-               free(c->option);
-               free(c);
+       o->value = strdup(val);
+       if (o->value == NULL) {
+               free(o->option);
+               free(o);
                return NULL;
        }
-       c->next = NULL;
-       return c;
-}
-
-void
-dhcpcd_config_free(DHCPCD_CONFIG *config)
-{
-       DHCPCD_CONFIG *c;
-
-       while (config) {
-               c = config->next;
-               free(config->option);
-               free(config->value);
-               free(config);
-               config = c;
-       }
+       o->next = NULL;
+       return o;
 }
 
-char **
-dhcpcd_config_blocks_get(DHCPCD_CONNECTION *con, const char *block)
+static void
+dhcpcd_option_free(DHCPCD_OPTION *o)
 {
-       DBusMessage *msg, *reply;
-       DBusMessageIter args;
-       DBusError error;
-       char **blocks;
-       int n_blocks;
 
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, "GetConfigBlocks");
-       if (msg == NULL) {
-               dhcpcd_error_set(con, NULL, errno);
-               return NULL;
-       }
-       dbus_message_iter_init_append(msg, &args);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       if (reply == NULL)
-               return NULL;
-       dbus_error_init(&error);
-       blocks = NULL;
-       n_blocks = 0;
-       if (!dbus_message_get_args(reply, &error, DBUS_TYPE_ARRAY,
-               DBUS_TYPE_STRING, &blocks, &n_blocks,
-               DBUS_TYPE_INVALID))
-       {
-               dhcpcd_error_set(con, error.message, 0);
-               dbus_error_free(&error);
-       }
-       dbus_message_unref(reply);
-       return blocks;
+       free(o->option);
+       free(o->value);
+       free(o);
 }
 
-DHCPCD_CONFIG *
-dhcpcd_config_load(DHCPCD_CONNECTION *con, const char *block, const char *name)
+void
+dhcpcd_config_free(DHCPCD_OPTION *c)
 {
-       DHCPCD_CONFIG *config, *c, *l;
-       DBusMessage *msg, *reply;
-       DBusMessageIter args, array, item;
-       const char ns[] = "", *option, *value;
-       int errors;
-
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, "GetConfig");
-       if (msg == NULL) {
-               dhcpcd_error_set(con, NULL, errno);
-               return NULL;
-       }
-       dbus_message_iter_init_append(msg, &args);
-       if (block == NULL)
-               block = ns;
-       if (name == NULL)
-               name = ns;
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &name);
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       if (reply == NULL)
-               return NULL;
-       if (!dbus_message_iter_init(reply, &args) ||
-           dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
-       {
-               dbus_message_unref(reply);
-               dhcpcd_error_set(con, NULL, EINVAL);
-               return NULL;
-       }
-       config = l = NULL;
-       errors = con->errors;
-       dbus_message_iter_recurse(&args, &array);
-       for (;
-            dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
-            dbus_message_iter_next(&array))
-       {
-               dbus_message_iter_recurse(&array, &item);
-               if (!dhcpcd_iter_get(con, &item, DBUS_TYPE_STRING, &option) ||
-                   !dhcpcd_iter_get(con, &item, DBUS_TYPE_STRING, &value))
-                       break;
-               c = dhcpcd_config_new(option, value);
-               if (c == NULL) {
-                       dhcpcd_error_set(con, NULL, errno);
-                       break;
-               }
-               if (l == NULL)
-                       config = c;
-               else
-                       l->next = c;
-               l = c;
-       }
-       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-               if (con->errors == errors)
-                       dhcpcd_error_set(con, NULL, EINVAL);
-               dhcpcd_config_free(config);
-               config = NULL;
-       }
-       dbus_message_unref(reply);
-       return config;
-}
+       DHCPCD_OPTION *n;
 
-bool
-dhcpcd_config_save(DHCPCD_CONNECTION *con, const char *block, const char *name,
-    DHCPCD_CONFIG *config)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter args, array, item;
-       DHCPCD_CONFIG *c;
-       const char ns[] = "", *p;
-       bool retval;
-
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, "SetConfig");
-       if (msg == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return false;
-       }
-       dbus_message_iter_init_append(msg, &args);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &block);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &name);
-       dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
-           DBUS_STRUCT_BEGIN_CHAR_AS_STRING
-           DBUS_TYPE_STRING_AS_STRING
-           DBUS_TYPE_STRING_AS_STRING
-           DBUS_STRUCT_END_CHAR_AS_STRING,
-           &array);
-       for (c = config; c; c = c->next) {
-               dbus_message_iter_open_container(&array,
-                   DBUS_TYPE_STRUCT, NULL, &item);
-               dbus_message_iter_append_basic(&item,
-                   DBUS_TYPE_STRING, &c->option);
-               if (c->value == NULL)
-                       p = ns;
-               else
-                       p = c->value;
-               dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &p);
-               dbus_message_iter_close_container(&array, &item);
+       while (c) {
+               n = c->next;
+               dhcpcd_option_free(c);
+               c = n;
        }
-       dbus_message_iter_close_container(&args, &array);
-
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       if (reply == NULL)
-               retval = false;
-       else {
-               dbus_message_unref(reply);
-               retval = true;
-       }
-       return retval;
 }
 
-static DHCPCD_CONFIG *
-dhcpcd_config_get1(DHCPCD_CONFIG *config, const char *opt, DHCPCD_CONFIG **lst)
+static DHCPCD_OPTION *
+dhcpcd_config_get1(DHCPCD_OPTION *config, const char *opt, DHCPCD_OPTION **lst)
 {
-       DHCPCD_CONFIG *c;
+       DHCPCD_OPTION *o;
 
-       for (c = config; c; c = c->next) {
-               if (strcmp(c->option, opt) == 0)
-                       return c;
+       for (o = config; o; o = o->next) {
+               if (strcmp(o->option, opt) == 0)
+                       return o;
                if (lst)
-                       *lst = c;
+                       *lst = o;
        }
        errno = ESRCH;
        return NULL;
 }
 
 const char *
-dhcpcd_config_get(DHCPCD_CONFIG *config, const char *opt)
+dhcpcd_config_get(DHCPCD_OPTION *config, const char *opt)
 {
-       DHCPCD_CONFIG *c;
+       DHCPCD_OPTION *o;
 
-       c = dhcpcd_config_get1(config, opt, NULL);
-       if (c == NULL)
+       assert(opt);
+       o = dhcpcd_config_get1(config, opt, NULL);
+       if (o == NULL)
                return NULL;
-       return c->value;
+       return o->value;
 }
 
-static DHCPCD_CONFIG *
-dhcpcd_config_get_static1(DHCPCD_CONFIG *config, const char *opt,
-    DHCPCD_CONFIG **lst)
+static DHCPCD_OPTION *
+dhcpcd_config_get_static1(DHCPCD_OPTION *config, const char *opt,
+    DHCPCD_OPTION **lst)
 {
-       DHCPCD_CONFIG *c;
+       DHCPCD_OPTION *o;
        size_t len;
 
-       c = config;
+       o = config;
        len = strlen(opt);
-       while ((c = dhcpcd_config_get1(c, "static", lst)) != NULL) {
-               if (strncmp(c->value, opt, len) == 0)
-                       return c;
+       while ((o = dhcpcd_config_get1(o, "static", lst)) != NULL) {
+               if (strncmp(o->value, opt, len) == 0)
+                       return o;
                if (lst)
-                       *lst = c;
-               c = c->next;
+                       *lst = o;
+               o = o->next;
        }
        return NULL;
 }
 
 const char *
-dhcpcd_config_get_static(DHCPCD_CONFIG *config, const char *opt)
+dhcpcd_config_get_static(DHCPCD_OPTION *config, const char *opt)
 {
-       DHCPCD_CONFIG *c;
+       DHCPCD_OPTION *o;
 
-       c = dhcpcd_config_get_static1(config, opt, NULL);
-       if (c == NULL)
+       assert(opt);
+       o = dhcpcd_config_get_static1(config, opt, NULL);
+       if (o == NULL)
                return NULL;
-       return c->value + strlen(opt);
+       return o->value + strlen(opt);
 }
 
 static bool
-dhcpcd_config_set1(DHCPCD_CONFIG **config, const char *opt, const char *val,
+dhcpcd_config_set1(DHCPCD_OPTION **config, const char *opt, const char *val,
     bool s)
 {
-       DHCPCD_CONFIG *c, *l;
+       DHCPCD_OPTION *o, *l;
        char *t;
        size_t len;
 
        l = NULL;
        if (s)
-               c = dhcpcd_config_get_static1(*config, opt, &l);
+               o = dhcpcd_config_get_static1(*config, opt, &l);
        else
-               c = dhcpcd_config_get1(*config, opt, &l);
+               o = dhcpcd_config_get1(*config, opt, &l);
        if (val == NULL) {
-               if (c == NULL)
+               if (o == NULL)
                        return true;
-               if (c == *config)
-                       *config = c->next;
+               if (o == *config)
+                       *config = o->next;
                else if (l != NULL)
-                       l->next = c->next;
-               free(c->option);
-               free(c->value);
-               free(c);
+                       l->next = o->next;
+               free(o->option);
+               free(o->value);
+               free(o);
                return true;
        }
        if (s) {
@@ -314,33 +172,251 @@ dhcpcd_config_set1(DHCPCD_CONFIG **config, const char *opt, const char *val,
                if (t == NULL)
                        return false;
        }
-       if (c == NULL) {
+       if (o == NULL) {
                if (s)
-                       c = dhcpcd_config_new("static", t);
+                       o = dhcpcd_option_new("static", t);
                else
-                       c = dhcpcd_config_new(opt, val);
-               if (c == NULL)
+                       o = dhcpcd_option_new(opt, val);
+               if (o == NULL)
                        return false;
                if (l == NULL)
-                       *config = c;
+                       *config = o;
                else
-                       l->next = c;
+                       l->next = o;
                return true;
        }
-       free(c->value);
-       c->value = t;
+       free(o->value);
+       o->value = t;
        return true;
 }
 
 bool
-dhcpcd_config_set(DHCPCD_CONFIG **config, const char *opt, const char *val)
+dhcpcd_config_set(DHCPCD_OPTION **config, const char *opt, const char *val)
 {
+
+       assert(config);
+       assert(opt);
        return dhcpcd_config_set1(config, opt, val, false);
 }
 
 bool
-dhcpcd_config_set_static(DHCPCD_CONFIG **config,
+dhcpcd_config_set_static(DHCPCD_OPTION **config,
     const char *opt, const char *val)
 {
+
+       assert(config);
+       assert(opt);
        return dhcpcd_config_set1(config, opt, val, true);
 }
+
+#define ACT_READ  (1 << 0)
+#define ACT_WRITE (1 << 1)
+#define ACT_LIST  (1 << 2)
+
+static DHCPCD_OPTION *
+config(DHCPCD_CONNECTION *con, int action, const char *block, const char *name,
+    const DHCPCD_OPTION *no, char ***list)
+{
+       FILE *fp;
+       DHCPCD_OPTION *options, *o;
+       const DHCPCD_OPTION *co;
+       char *line, *option, *p;
+       char **buf, **nbuf;
+       int skip, free_opts;
+       size_t len, buf_size, buf_len, i;
+
+       fp = fopen(con->cffile, "r");
+       if (fp == NULL)
+               return NULL;
+       options = o = NULL;
+       skip = block && !(action & ACT_LIST) ? 1 : 0;
+       buf = NULL;
+       buf_len = buf_size = 0;
+       free_opts = 1;
+       while (getline(&con->buf, &con->buflen, fp) != -1) {
+               line = con->buf;
+               /* Trim leading trailing newline and whitespace */
+               while (*line == ' ' || *line == '\n' || *line == '\t')
+                       line++;
+               /* Trim trailing newline and whitespace */
+               if (line && *line) {
+                       p = line + strlen(line) - 1;
+                       while (p != line &&
+                           (*p == ' ' || *p == '\n' || *p == '\t') &&
+                           *(p - 1) != '\\')
+                               *p-- = '\0';
+               }
+               option = strsep(&line, " \t");
+               /* Trim trailing whitespace */
+               if (line && *line) {
+                       p = line + strlen(line) - 1;
+                       while (p != line &&
+                           (*p == ' ' || *p == '\n' || *p == '\t') &&
+                           *(p - 1) != '\\')
+                               *p-- = '\0';
+               }
+               if (action & ACT_LIST) {
+                       if (strcmp(option, block) == 0)
+                               skip = 0;
+                       else
+                               skip = 1;
+               } else {
+                       /* Start of a block, skip if not ours */
+                       if (strcmp(option, "interface") == 0 ||
+                           strcmp(option, "ssid") == 0)
+                       {
+                               if (block && name && line &&
+                                   strcmp(option, block) == 0 &&
+                                   strcmp(line, name) == 0)
+                                       skip = 0;
+                               else
+                                       skip = 1;
+                               if (!(action & ACT_WRITE))
+                                       continue;
+                       }
+               }
+               if ((action & ACT_WRITE && skip) ||
+                   (action & ACT_LIST && !skip))
+               {
+                       if (buf_len + 2 > buf_size) {
+                               buf_size += 32;
+                               nbuf = realloc(buf, sizeof(char *) * buf_size);
+                               if (nbuf == NULL)
+                                       goto exit;
+                               buf = nbuf;
+                       }
+                       if (action & ACT_WRITE && line && *line != '\0') {
+                               len = strlen(option) + strlen(line) + 2;
+                               buf[buf_len] = malloc(len);
+                               if (buf[buf_len] == NULL)
+                                       goto exit;
+                               snprintf(buf[buf_len], len,
+                                   "%s %s", option, line);
+                       } else {
+                               if (action & ACT_LIST)
+                                       buf[buf_len] = strdup(line);
+                               else
+                                       buf[buf_len] = strdup(option);
+                               if (buf[buf_len] == NULL)
+                                       goto exit;
+                       }
+                       buf_len++;
+               }
+               if (skip || action & ACT_LIST)
+                       continue;
+               if (*option == '\0' || *option == '#' || *option == ';')
+                       continue;
+               if (o == NULL)
+                       options = o = malloc(sizeof(*options));
+               else {
+                       o->next = malloc(sizeof(*o));
+                       o = o->next;
+               }
+               if (o == NULL)
+                       goto exit;
+               o->next = NULL;
+               o->option = strdup(option);
+               if (o->option == NULL) {
+                       o->value = NULL;
+                       goto exit;
+               }
+               if (line == NULL || *line == '\0')
+                       o->value = NULL;
+               else {
+                       o->value = strdup(line);
+                       if (o->value == NULL)
+                               goto exit;
+               }
+       }
+
+       if (action & ACT_WRITE) {
+               fp = freopen(con->cffile, "w", fp);
+               if (fp == NULL)
+                       goto exit;
+               if (block) {
+                       skip = 0;
+                       for (i = 0; i < buf_len; i++) {
+                               fputs(buf[i], fp);
+                               fputc('\n', fp);
+                               skip = buf[i][0] == '\0' ? 1 : 0;
+                       }
+               } else
+                       skip = 1;
+               if (no && block) {
+                       if (!skip)
+                               fputc('\n', fp);
+                       fprintf(fp, "%s %s\n", block, name);
+               }
+               skip = 0;
+               for (co = no; co; co = co->next) {
+                       if (co->value)
+                               fprintf(fp, "%s %s\n", co->option, co->value);
+                       else
+                               fprintf(fp, "%s\n", co->option);
+                       skip = 1;
+               }
+               if (block == NULL) {
+                       if (!skip)
+                               fputc('\n', fp);
+                       for (i = 0; i < buf_len; i++) {
+                               fputs(buf[i], fp);
+                               fputc('\n', fp);
+                       }
+               }
+       } else
+               free_opts = 0;
+
+exit:
+       if (fp != NULL)
+               fclose(fp);
+       if (action & ACT_LIST) {
+               if (buf)
+                       buf[buf_len] = NULL;
+               *list = buf;
+       } else {
+               for (i = 0; i < buf_len; i++)
+                       free(buf[i]);
+               free(buf);
+       }
+       if (free_opts) {
+               dhcpcd_config_free(options);
+               options = NULL;
+       }
+       return options;
+}
+
+DHCPCD_OPTION *
+dhcpcd_config_read(DHCPCD_CONNECTION *con, const char *block, const char *name)
+{
+
+       assert(con);
+       return config(con, ACT_READ, block, name, NULL, NULL);
+}
+
+bool
+dhcpcd_config_write(DHCPCD_CONNECTION *con,
+    const char *block, const char *name,
+    const DHCPCD_OPTION *opts)
+{
+       int serrno;
+
+       assert(con);
+       serrno = errno;
+       errno = 0;
+       config(con, ACT_WRITE, block, name, opts, NULL);
+       if (errno)
+               return false;
+       errno = serrno;
+       return true;
+}
+
+char **
+dhcpcd_config_blocks(DHCPCD_CONNECTION *con, const char *block)
+{
+       char **blocks;
+
+       assert(con);
+       blocks = NULL;
+       config(con, ACT_LIST, block, NULL, NULL, &blocks);
+       return blocks;
+}
diff --git a/src/libdhcpcd/dhcpcd.c b/src/libdhcpcd/dhcpcd.c
new file mode 100644 (file)
index 0000000..3876d0f
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ * libdhcpcd
+ * Copyright 2009-2014 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// For strverscmp(3)
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define IN_LIBDHCPCD
+
+#include "config.h"
+#include "dhcpcd.h"
+
+#define _ gettext
+
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+       (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+static const char * const dhcpcd_types[] =
+    { "link", "ipv4", "ra", "dhcp6", NULL };
+
+static ssize_t
+dhcpcd_command_fd(DHCPCD_CONNECTION *con,
+    int fd, const char *cmd, char **buffer)
+{
+       size_t len;
+       ssize_t bytes;
+       char buf[1024], *p;
+       char *nbuf;
+
+       /* Each command is \n terminated.
+        * Each argument is NULL seperated.
+        * We may need to send a space one day, so the API
+        * in this function may need to be improved */
+       len = strlen(cmd) + 1;
+       if (con->terminate_commands)
+               len++;
+       if (len > sizeof(buf)) {
+               errno = ENOBUFS;
+               return -1;
+       }
+       strlcpy(buf, cmd, sizeof(buf));
+       p = buf;
+       while ((p = strchr(p, ' ')) != NULL)
+               *p++ = '\0';
+       if (con->terminate_commands) {
+               buf[len - 2] = '\n';
+               buf[len - 1] = '\0';
+       } else
+               buf[len - 1] = '\0';
+       if (write(fd, buf, len) == -1)
+               return -1;
+       if (buffer == NULL)
+               return 0;
+
+       bytes = read(fd, buf, sizeof(size_t));
+       if (bytes == 0 || bytes == -1)
+               return bytes;
+       memcpy(&len, buf, sizeof(size_t));
+       nbuf = realloc(*buffer, len + 1);
+       if (nbuf == NULL)
+               return -1;
+       *buffer = nbuf;
+       bytes = read(fd, *buffer, len);
+       if (bytes != -1 && (size_t)bytes < len)
+               *buffer[bytes] = '\0';
+       return bytes;
+}
+
+ssize_t
+dhcpcd_command(DHCPCD_CONNECTION *con, const char *cmd, char **buffer)
+{
+
+       return dhcpcd_command_fd(con, con->command_fd, cmd, buffer);
+}
+
+bool
+dhcpcd_realloc(DHCPCD_CONNECTION *con, size_t len)
+{
+
+       if (con->buflen < len) {
+               char *nbuf;
+
+               nbuf = realloc(con->buf, len);
+               if (nbuf == NULL)
+                       return false;
+               con->buf = nbuf;
+               con->buflen = len;
+       }
+       return true;
+}
+
+ssize_t
+dhcpcd_command_arg(DHCPCD_CONNECTION *con, const char *cmd, const char *arg,
+    char **buffer)
+{
+       size_t cmdlen, len;
+
+       cmdlen = strlen(cmd);
+       len = cmdlen + strlen(arg) + 2;
+       if (!dhcpcd_realloc(con, len))
+               return -1;
+       strlcpy(con->buf, cmd, con->buflen);
+       con->buf[cmdlen] = ' ';
+       strlcpy(con->buf + cmdlen + 1, arg, con->buflen - 1 - cmdlen);
+
+       return dhcpcd_command_fd(con, con->command_fd, con->buf, buffer);
+}
+
+
+static int
+dhcpcd_connect(void)
+{
+       int fd;
+       socklen_t len;
+       struct sockaddr_un sun;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (fd == -1)
+               return -1;
+
+       memset(&sun, 0, sizeof(sun));
+       sun.sun_family = AF_UNIX;
+       strlcpy(sun.sun_path, DHCPCD_SOCKET, sizeof(sun.sun_path));
+       len = (socklen_t)SUN_LEN(&sun);
+       if (connect(fd, (struct sockaddr *)&sun, len) == 0)
+               return fd;
+       close(fd);
+       return -1;
+}
+
+static const char *
+get_value(const char *data, size_t len, const char *var)
+{
+       const char *end, *p;
+       size_t vlen;
+
+       assert(var);
+       end = data + len;
+       vlen = strlen(var);
+       p = NULL;
+       while (data + vlen + 1 < end) {
+               if (strncmp(data, var, vlen) == 0) {
+                       p = data + vlen;
+                       break;
+               }
+               data += strlen(data) + 1;
+       }
+       if (p != NULL && *p != '\0')
+               return p;
+       return NULL;
+}
+
+const char *
+dhcpcd_get_value(const DHCPCD_IF *i, const char *var)
+{
+
+       assert(i);
+       return get_value(i->data, i->data_len, var);
+}
+
+const char *
+dhcpcd_get_prefix_value(const DHCPCD_IF *i, const char *prefix, const char *var)
+{
+       char pvar[128], *p;
+       size_t plen, l;
+
+       p = pvar;
+       plen = sizeof(pvar);
+       l = strlcpy(p, prefix, plen);
+       if (l >= sizeof(pvar)) {
+               errno = ENOBUFS;
+               return NULL;
+       }
+       p += l;
+       plen -= l;
+       if (strlcpy(p, var, plen) >= plen) {
+               errno = ENOBUFS;
+               return NULL;
+       }
+       return dhcpcd_get_value(i, pvar);
+}
+
+static bool strtobool(const char *var)
+{
+
+       if (var == NULL)
+               return false;
+
+        return (*var == '0' || *var == '\0' ||
+           strcmp(var, "false") == 0 ||
+           strcmp(var, "no") == 0) ? false : true;
+}
+
+static const char *
+get_status(DHCPCD_CONNECTION *con)
+{
+       DHCPCD_IF *i;
+       const char *status;
+
+       assert(con);
+       if (con->command_fd == -1 || con->listen_fd == -1)
+               return "down";
+
+       status = "disconnected";
+       for (i = con->interfaces; i; i = i->next) {
+               if (i->up) {
+                       if (strcmp(i->type, "link")) {
+                               status = "connected";
+                               break;
+                       } else
+                               status = "connecting";
+               }
+       }
+       return status;
+}
+
+static void
+update_status(DHCPCD_CONNECTION *con)
+{
+       const char *nstatus;
+
+       assert(con);
+       nstatus = get_status(con);
+       if (con->status == NULL || strcmp(nstatus, con->status)) {
+               con->status = nstatus;
+               if (con->status_cb)
+                       con->status_cb(con, con->status, con->status_context);
+       }
+}
+
+DHCPCD_IF *
+dhcpcd_interfaces(DHCPCD_CONNECTION *con)
+{
+
+       assert(con);
+       return con->interfaces;
+}
+
+DHCPCD_IF *
+dhcpcd_get_if(DHCPCD_CONNECTION *con, const char *ifname, const char *type)
+{
+       DHCPCD_IF *i;
+
+       assert(con);
+       for (i = con->interfaces; i; i = i->next)
+               if (strcmp(i->ifname, ifname) == 0 &&
+                   strcmp(i->type, type) == 0)
+                       return i;
+       return NULL;
+}
+
+static DHCPCD_IF *
+dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
+{
+       const char *ifname, *reason, *type, *order, *flags;
+       char *orderdup, *o, *p;
+       DHCPCD_IF *e, *i, *l, *n, *nl;
+       int ti;
+
+       ifname = get_value(data, len, "interface=");
+       if (ifname == NULL || *ifname == '\0') {
+               errno = ESRCH;
+               return NULL;
+       }
+       reason = get_value(data, len, "reason=");
+       if (reason == NULL || *reason == '\0') {
+               errno = ESRCH;
+               return NULL;
+       }
+       if (strcmp(reason, "RECONFIGURE") == 0) {
+               errno = ENOTSUP;
+               return NULL;
+       }
+       order = get_value(data, len, "interface_order=");
+       if (order == NULL || *order == '\0') {
+               errno = ESRCH;
+               return NULL;
+       }
+
+       if (strcmp(reason, "PREINIT") == 0 ||
+           strcmp(reason, "UNKNOWN") == 0 ||
+           strcmp(reason, "CARRIER") == 0 ||
+           strcmp(reason, "NOCARRIER") == 0 ||
+           strcmp(reason, "DEPARTED") == 0 ||
+           strcmp(reason, "STOPPED") == 0)
+               type = "link";
+       else if (strcmp(reason, "ROUTERADVERT") == 0)
+               type = "ra";
+       else if (reason[strlen(reason) - 1] == '6')
+               type = "dhcp6";
+       else
+               type = "ipv4";
+
+       i = NULL;
+       /* Remove all instances on carrier drop */
+        if (strcmp(reason, "NOCARRIER") == 0 ||
+            strcmp(reason, "DEPARTED") == 0 ||
+            strcmp(reason, "STOPPED") == 0)
+        {
+                l = NULL;
+                for (e = con->interfaces; e; e = n) {
+                        n = e->next;
+                        if (strcmp(e->ifname, ifname) == 0) {
+                                if (strcmp(e->type, type) == 0)
+                                        l = i = e;
+                                else {
+                                        if (l)
+                                                l->next = e->next;
+                                        else
+                                                con->interfaces = e->next;
+                                        free(e);
+                                }
+                        } else
+                                l = e;
+                }
+        } else if (strcmp(type, "link")) {
+               /* If link is down, ignore it */
+               e = dhcpcd_get_if(con, ifname, "link");
+               if (e && strcmp(e->reason, "NOCARRIER") == 0)
+                       return NULL;
+       }
+
+       orderdup = strdup(order);
+       if (orderdup == NULL)
+               return NULL;
+
+       /* Find our pointer */
+        if (i == NULL) {
+                l = NULL;
+                for (e = con->interfaces; e; e = e->next) {
+                        if (strcmp(e->ifname, ifname) == 0 &&
+                            strcmp(e->type, type) == 0)
+                        {
+                                i = e;
+                                break;
+                        }
+                        l = e;
+                }
+        }
+       if (i == NULL) {
+               i = malloc(sizeof(*i));
+               if (i == NULL) {
+                       free(orderdup);
+                       return NULL;
+               }
+               if (l)
+                       l->next = i;
+               else
+                       con->interfaces = i;
+               i->next = NULL;
+       } else
+               free(i->data);
+
+       /* Now fill out our interface structure */
+       i->con = con;
+       i->data = data;
+       i->data_len = len;
+       i->ifname = ifname;
+       i->type = type;
+       i->reason = reason;
+       flags = dhcpcd_get_value(i, "ifflags=");
+       if (flags)
+               i->flags = (unsigned int)strtoul(flags, NULL, 0);
+       else
+               i->flags = 0;
+       if (strcmp(reason, "CARRIER") == 0)
+               i->up = true;
+       else
+               i->up = strtobool(dhcpcd_get_value(i, "if_up="));
+       i->wireless = strtobool(dhcpcd_get_value(i, "ifwireless="));
+       i->ssid = dhcpcd_get_value(i, i->up ? "new_ssid=" : "old_ssid=");
+
+       /* Sort! */
+       n = nl = NULL;
+       p = orderdup;
+        while ((o = strsep(&p, " ")) != NULL) {
+                for (ti = 0; dhcpcd_types[ti]; ti++) {
+                        l = NULL;
+                        for (e = con->interfaces; e; e = e->next) {
+                                if (strcmp(e->ifname, o) == 0 &&
+                                    strcmp(e->type, dhcpcd_types[ti]) == 0)
+                                        break;
+                                l = e;
+                        }
+                        if (e == NULL)
+                                continue;
+                        if (l)
+                                l->next = e->next;
+                        else
+                                con->interfaces = e->next;
+                        e->next = NULL;
+                        if (nl == NULL)
+                                n = nl = e;
+                        else {
+                                nl->next = e;
+                                nl = e;
+                        }
+                }
+        }
+       free(orderdup);
+        /* Free any stragglers */
+        while (con->interfaces) {
+                e = con->interfaces->next;
+               free(con->interfaces->data);
+                free(con->interfaces);
+                con->interfaces = e;
+        }
+        con->interfaces = n;
+
+       return i;
+}
+
+static DHCPCD_IF *
+dhcpcd_read_if(DHCPCD_CONNECTION *con, int fd)
+{
+       char sbuf[sizeof(size_t)], *rbuf;
+       size_t len;
+       ssize_t bytes;
+       DHCPCD_IF *i;
+
+       bytes = read(fd, sbuf, sizeof(sbuf));
+       if (bytes == 0 || bytes == -1) {
+               dhcpcd_close(con);
+               return NULL;
+       }
+       memcpy(&len, sbuf, sizeof(len));
+       rbuf = malloc(len + 1);
+       if (rbuf == NULL)
+               return NULL;
+       bytes = read(fd, rbuf, len);
+       if (bytes == 0 || bytes == -1) {
+               free(rbuf);
+               dhcpcd_close(con);
+               return NULL;
+       }
+       if ((size_t)bytes != len) {
+               free(rbuf);
+               errno = EINVAL;
+               return NULL;
+       }
+       rbuf[bytes] = '\0';
+
+       i = dhcpcd_new_if(con, rbuf, len);
+       if (i == NULL)
+               free(rbuf);
+       return i;
+}
+
+static void
+dhcpcd_dispatchif(DHCPCD_IF *i)
+{
+
+       assert(i);
+       if (i->con->if_cb)
+               i->con->if_cb(i, i->con->if_context);
+       dhcpcd_wpa_if_event(i);
+}
+
+void
+dhcpcd_dispatch(DHCPCD_CONNECTION *con)
+{
+       DHCPCD_IF *i;
+
+       assert(con);
+       i = dhcpcd_read_if(con, con->listen_fd);
+       if (i)
+               dhcpcd_dispatchif(i);
+
+       /* Have to call update_status last as it could
+        * cause the interface to be destroyed. */
+       update_status(con);
+}
+
+DHCPCD_CONNECTION *
+dhcpcd_new(void)
+{
+       DHCPCD_CONNECTION *con;
+
+       con = calloc(1, sizeof(*con));
+       con->command_fd = con->listen_fd = -1;
+       return con;
+}
+
+#ifndef __GLIBC__
+/* Good enough for our needs */
+static int
+strverscmp(const char *s1, const char *s2)
+{
+       int s1maj, s1min, s1part;
+       int s2maj, s2min, s2part;
+       int r;
+
+       s1min = s1part = 0;
+       if (sscanf(s1, "%d.%d.%d", &s1maj, &s1min, &s1part) < 1)
+               return -1;
+       s2min = s2part = 0;
+       if (sscanf(s2, "%d.%d.%d", &s2maj, &s2min, &s2part) < 1)
+               return -1;
+       r = s1maj - s2maj;
+       if (r != 0)
+               return r;
+       r = s1min - s2min;
+       if (r != 0)
+               return r;
+       return s1part - s2part;
+}
+#endif
+
+int
+dhcpcd_open(DHCPCD_CONNECTION *con)
+{
+       char cmd[128];
+       ssize_t bytes;
+       size_t nifs, n;
+       DHCPCD_IF *i;
+
+       assert(con);
+       if (con->listen_fd != -1)
+               return con->listen_fd;
+       con->command_fd = dhcpcd_connect();
+       if (con->command_fd == -1) {
+               update_status(con);
+               return -1;
+       }
+
+       con->terminate_commands = false;
+       if (dhcpcd_command(con, "--version", &con->version) <= 0)
+               return -1;
+       con->terminate_commands =
+           strverscmp(con->version, "6.4.1") >= 0 ? true : false;
+
+       if (dhcpcd_command(con, "--getconfigfile", &con->cffile) <= 0)
+               return -1;
+
+       con->listen_fd = dhcpcd_connect();
+       if (con->listen_fd == -1) {
+               close(con->command_fd);
+               con->command_fd = -1;
+               update_status(con);
+               return -1;
+       }
+       dhcpcd_command_fd(con, con->listen_fd, "--listen", NULL);
+
+       dhcpcd_command_fd(con, con->command_fd, "--getinterfaces", NULL);
+       bytes = read(con->command_fd, cmd, sizeof(nifs));
+       if (bytes != sizeof(nifs)) {
+               close(con->command_fd);
+               con->command_fd = -1;
+               close(con->listen_fd);
+               con->listen_fd = -1;
+       } else {
+               memcpy(&nifs, cmd, sizeof(nifs));
+               /* We don't dispatch each interface here as that
+                * causes too much notification spam when the GUI starts */
+               for (n = 0; n < nifs; n++) {
+                       i = dhcpcd_read_if(con, con->command_fd);
+                       if (i)
+                               dhcpcd_wpa_if_event(i);
+               }
+       }
+       update_status(con);
+
+       return con->listen_fd;
+}
+
+int
+dhcpcd_get_fd(DHCPCD_CONNECTION *con)
+{
+
+       assert(con);
+       return con->listen_fd;
+}
+
+const char *
+dhcpcd_status(DHCPCD_CONNECTION *con)
+{
+
+       assert(con);
+       return con->status;
+}
+
+const char *
+dhcpcd_version(DHCPCD_CONNECTION *con)
+{
+
+       assert(con);
+       return con->version;
+}
+
+const char *
+dhcpcd_cffile(DHCPCD_CONNECTION *con)
+{
+
+       assert(con);
+       return con->cffile;
+}
+
+void
+dhcpcd_set_if_callback(DHCPCD_CONNECTION *con,
+    void (*cb)(DHCPCD_IF *, void *), void *ctx)
+{
+
+       assert(con);
+       con->if_cb = cb;
+       con->if_context = ctx;
+}
+
+void
+dhcpcd_set_status_callback(DHCPCD_CONNECTION *con,
+    void (*cb)(DHCPCD_CONNECTION *, const char *, void *), void *ctx)
+{
+
+       assert(con);
+       con->status_cb = cb;
+       con->status_context = ctx;
+}
+
+void
+dhcpcd_close(DHCPCD_CONNECTION *con)
+{
+       DHCPCD_WPA *wpa;
+
+       assert(con);
+
+       /* Shut down WPA listeners as they aren't much good without dhcpcd.
+        * They'll be restarted anyway when dhcpcd comes back up. */
+       for (wpa = con->wpa; wpa; wpa = wpa->next)
+               dhcpcd_wpa_close(con->wpa);
+
+       if (con->command_fd != -1) {
+               shutdown(con->command_fd, SHUT_RDWR);
+               con->command_fd = -1;
+       }
+       if (con->listen_fd != -1) {
+               shutdown(con->listen_fd, SHUT_RDWR);
+               con->listen_fd = -1;
+       }
+
+       if (con->cffile) {
+               free(con->cffile);
+               con->cffile = NULL;
+       }
+       if (con->version) {
+               free(con->version);
+               con->version = NULL;
+       }
+       if (con->buf) {
+               free(con->buf);
+               con->buf = NULL;
+               con->buflen = 0;
+       }
+}
+
+DHCPCD_CONNECTION *
+dhcpcd_if_connection(DHCPCD_IF *i)
+{
+
+       assert(i);
+       return i->con;
+}
+
+char *
+dhcpcd_if_message(const DHCPCD_IF *i)
+{
+       const char *ip, *iplen, *pfx;
+       char *msg, *p;
+       const char *reason = NULL;
+       size_t len;
+       bool showssid;
+
+       assert(i);
+       /* Don't report non SLAAC configurations */
+       if (strcmp(i->type, "ra") == 0 && i->up &&
+           dhcpcd_get_value(i, "ra1_prefix=") == NULL)
+               return NULL;
+
+       showssid = false;
+       if (strcmp(i->reason, "EXPIRE") == 0)
+               reason = _("Expired");
+       else if (strcmp(i->reason, "CARRIER") == 0) {
+               if (i->wireless) {
+                       showssid = true;
+                       reason = _("Associated with");
+               } else
+                       reason = _("Cable plugged in");
+       } else if (strcmp(i->reason, "NOCARRIER") == 0) {
+               if (i->wireless) {
+                       if (i->ssid) {
+                               reason = _("Disassociated from");
+                               showssid = true;
+                       } else
+                               reason = _("Not associated");
+               } else
+                       reason = _("Cable unplugged");
+       } else if (strcmp(i->reason, "UNKNOWN") == 0)
+               reason = _("Unknown link state");
+       else if (strcmp(i->reason, "FAIL") == 0)
+               reason = _("Automatic configuration not possible");
+       else if (strcmp(i->reason, "3RDPARTY") == 0)
+               reason = _("Waiting for 3rd Party configuration");
+
+       if (reason == NULL) {
+               if (i->up)
+                       reason = _("Configured");
+               else if (strcmp(i->type, "ra") == 0)
+                       reason = "Expired RA";
+               else
+                       reason = i->reason;
+       }
+
+       pfx = i->up ? "new_" : "old_";
+       if ((ip = dhcpcd_get_prefix_value(i, pfx, "ip_address=")))
+               iplen = dhcpcd_get_prefix_value(i, pfx, "subnet_cidr=");
+       else if ((ip = dhcpcd_get_value(i, "ra1_prefix=")))
+               iplen = NULL;
+       else if ((ip = dhcpcd_get_prefix_value(i, pfx,
+           "dhcp6_ia_na1_ia_addr1=")))
+               iplen = "128";
+       else {
+               ip = NULL;
+               iplen = NULL;
+       }
+
+       len = strlen(i->ifname) + strlen(reason) + 3;
+       if (showssid && i->ssid)
+               len += strlen(i->ssid) + 1;
+       if (ip)
+               len += strlen(ip) + 1;
+       if (iplen)
+               len += strlen(iplen) + 1;
+       msg = p = malloc(len);
+       if (msg == NULL)
+               return NULL;
+       p += snprintf(msg, len, "%s: %s", i->ifname, reason);
+       if (showssid)
+               p += snprintf(p, len - (size_t)(p - msg), " %s", i->ssid);
+       if (iplen)
+               p += snprintf(p, len - (size_t)(p - msg), " %s/%s", ip, iplen);
+       else if (ip)
+               p += snprintf(p, len - (size_t)(p - msg), " %s", ip);
+       return msg;
+}
+
+void
+dhcpcd_free(DHCPCD_CONNECTION *con)
+{
+       DHCPCD_IF *nif;
+       DHCPCD_WPA *nwpa;
+
+       assert(con);
+       while (con->interfaces) {
+               nif = con->interfaces->next;
+               free(con->interfaces->data);
+               free(con->interfaces);
+               con->interfaces = nif;
+       }
+       while (con->wpa) {
+               nwpa = con->wpa->next;
+               dhcpcd_wpa_close(con->wpa);
+               free(con->wpa);
+               con->wpa = nwpa;
+       }
+       free(con);
+}
diff --git a/src/libdhcpcd/dhcpcd.h b/src/libdhcpcd/dhcpcd.h
new file mode 100644 (file)
index 0000000..639918a
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * libdhcpcd
+ * Copyright 2009-2014 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCD_H
+#define DHCPCD_H
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdbool.h>
+
+#ifndef DHCPCD_SOCKET
+#define DHCPCD_SOCKET          "/var/run/dhcpcd.sock"
+#endif
+
+#ifndef WPA_CTRL_DIR
+#define WPA_CTRL_DIR           "/var/run/wpa_supplicant"
+#endif
+
+#define DHCPCD_RETRYOPEN       1       /* seconds */
+#define DHCPCD_WI_HIST_MAX     10      /* Recall 10 scans for averages */
+
+#define IF_SSIDSIZE            33
+#define IF_BSSIDSIZE           64
+#define FLAGSIZE               64
+#define TYPESIZE               8
+#define REASONSIZE             16
+
+typedef struct dhcpcd_wi_avs {
+       int value;
+       int average;
+} DHCPCD_WI_AV;
+
+typedef struct dhcpcd_wi_scan {
+       struct dhcpcd_wi_scan *next;
+       char bssid[IF_BSSIDSIZE];
+       int frequency;
+       DHCPCD_WI_AV quality;
+       DHCPCD_WI_AV noise;
+       DHCPCD_WI_AV level;
+       char ssid[IF_SSIDSIZE];
+       char flags[FLAGSIZE];
+} DHCPCD_WI_SCAN;
+
+#ifdef IN_LIBDHCPCD
+typedef struct dhcpcd_if {
+       struct dhcpcd_if *next;
+       const char *ifname;
+       const char *type;
+       const char *reason;
+
+       unsigned int flags;
+       bool up;
+       bool wireless;
+       const char *ssid;
+
+       char *data;
+       size_t data_len;
+
+       struct dhcpcd_connection *con;
+} DHCPCD_IF;
+#else
+typedef struct dhcpcd_if {
+       struct dhcpcd_if *next;
+       const char *ifname;
+       const char *type;
+       const char *reason;
+
+       int flags;
+       bool up;
+       bool wireless;
+       const char *ssid;
+} DHCPCD_IF;
+#endif
+
+typedef struct dhcpcd_config {
+       struct dhcpcd_config *next;
+       char *option;
+       char *value;
+} DHCPCD_OPTION;
+
+#ifdef IN_LIBDHCPCD
+typedef struct dhcpcd_wi_hist {
+       struct dhcpcd_wi_hist *next;
+       char ifname[IF_NAMESIZE];
+       char bssid[IF_BSSIDSIZE];
+       int quality;
+       int noise;
+       int level;
+} DHCPCD_WI_HIST;
+
+typedef struct dhcpcd_wpa {
+       struct dhcpcd_wpa *next;
+       char ifname[IF_NAMESIZE];
+       int command_fd;
+       char *command_path;
+       int listen_fd;
+       char *listen_path;
+       int attached;
+       struct dhcpcd_connection *con;
+} DHCPCD_WPA;
+
+typedef struct dhcpcd_connection {
+       struct dhcpcd_connection *next;
+       int command_fd;
+       int listen_fd;
+
+       DHCPCD_IF *interfaces;
+       DHCPCD_WPA *wpa;
+       DHCPCD_WI_HIST *wi_history;
+
+       void (*if_cb)(DHCPCD_IF *, void *);
+       void *if_context;
+       void (*status_cb)(struct dhcpcd_connection *, const char *, void *);
+       void *status_context;
+       void (*wi_scanresults_cb)(DHCPCD_WPA *, void *);
+       void *wi_scanresults_context;
+       void (*wpa_status_cb)(DHCPCD_WPA *, const char *, void *);
+       void *wpa_status_context;
+
+       char *buf;
+       size_t buflen;
+
+       char *version;
+       bool terminate_commands;
+       char *error;
+       int err;
+       int errors;
+       const char *status;
+
+       char *cffile;
+} DHCPCD_CONNECTION;
+
+#else
+typedef void *DHCPCD_CONFIG;
+typedef void *DHCPCD_WPA;
+typedef void *DHCPCD_CONNECTION;
+#endif
+
+DHCPCD_CONNECTION * dhcpcd_new(void);
+const char * dhcpcd_version(DHCPCD_CONNECTION *);
+const char * dhcpcd_status(DHCPCD_CONNECTION *);
+const char * dhcpcd_cffile(DHCPCD_CONNECTION *);
+bool dhcpcd_realloc(DHCPCD_CONNECTION *, size_t);
+int dhcpcd_open(DHCPCD_CONNECTION *);
+void dhcpcd_close(DHCPCD_CONNECTION *);
+void dhcpcd_free(DHCPCD_CONNECTION *);
+void dhcpcd_set_if_callback(DHCPCD_CONNECTION *,
+    void (*)(DHCPCD_IF *, void *), void *);
+void dhcpcd_set_status_callback(DHCPCD_CONNECTION *,
+    void (*)(DHCPCD_CONNECTION *, const char *, void *), void *);
+int dhcpcd_get_fd(DHCPCD_CONNECTION *);
+void dhcpcd_dispatch(DHCPCD_CONNECTION *);
+DHCPCD_IF * dhcpcd_interfaces(DHCPCD_CONNECTION *);
+DHCPCD_IF * dhcpcd_get_if(DHCPCD_CONNECTION *, const char *, const char *);
+DHCPCD_CONNECTION * dhcpcd_if_connection(DHCPCD_IF *);
+const char *dhcpcd_get_value(const DHCPCD_IF *, const char *);
+const char *dhcpcd_get_prefix_value(const DHCPCD_IF *, const char *,
+    const char *);
+char * dhcpcd_if_message(const DHCPCD_IF *i);
+
+ssize_t dhcpcd_command(DHCPCD_CONNECTION *, const char *, char **);
+ssize_t dhcpcd_command_arg(DHCPCD_CONNECTION *, const char *, const char *,
+    char **);
+#define dhcpcd_rebind(c, i)    dhcpcd_command_arg((c), "-n", (i), NULL)
+#define dhcpcd_release(c, i)   dhcpcd_command_arg((c), "-k", (i), NULL)
+
+DHCPCD_WPA *dhcpcd_wpa_find(DHCPCD_CONNECTION *, const char *);
+DHCPCD_WPA *dhcpcd_wpa_new(DHCPCD_CONNECTION *, const char *);
+DHCPCD_CONNECTION *dhcpcd_wpa_connection(DHCPCD_WPA *);
+int dhcpcd_wpa_open(DHCPCD_WPA *);
+void dhcpcd_wpa_close(DHCPCD_WPA *);
+void dhcpcd_wpa_dispatch(DHCPCD_WPA *);
+int dhcpcd_wpa_get_fd(DHCPCD_WPA *);
+DHCPCD_IF *dhcpcd_wpa_if(DHCPCD_WPA *);
+void dhcpcd_wpa_if_event(DHCPCD_IF *);
+void dhcpcd_wpa_set_scan_callback(DHCPCD_CONNECTION *,
+    void (*)(DHCPCD_WPA *, void *), void *);
+void dhcpcd_wpa_set_status_callback(DHCPCD_CONNECTION *,
+    void (*)(DHCPCD_WPA *, const char *, void *), void *);
+DHCPCD_WI_SCAN * dhcpcd_wi_scans(DHCPCD_IF *);
+void dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *);
+void dhcpcd_wi_history_clear(DHCPCD_CONNECTION *);
+bool dhcpcd_wpa_set_network(DHCPCD_WPA *, int, const char *, const char *);
+int dhcpcd_wpa_find_network_new(DHCPCD_WPA *, const char *);
+bool dhcpcd_wpa_command(DHCPCD_WPA *, const char *);
+bool dhcpcd_wpa_command_arg(DHCPCD_WPA *, const char *, const char *);
+
+bool dhcpcd_wpa_scan(DHCPCD_WPA *);
+bool dhcpcd_wpa_reassociate(DHCPCD_WPA *);
+bool dhcpcd_wpa_disconnect(DHCPCD_WPA *);
+bool dhcpcd_wpa_config_write(DHCPCD_WPA *);
+int dhcpcd_wpa_network_find_new(DHCPCD_WPA *, const char *);
+bool dhcpcd_wpa_network_disable(DHCPCD_WPA *, int);
+bool dhcpcd_wpa_network_enable(DHCPCD_WPA *, int);
+bool dhcpcd_wpa_network_remove(DHCPCD_WPA *, int);
+char * dhcpcd_wpa_network_get(DHCPCD_WPA *, int, const char *);
+bool dhcpcd_wpa_network_set(DHCPCD_WPA *, int, const char *, const char *);
+
+char ** dhcpcd_config_blocks(DHCPCD_CONNECTION *, const char *);
+DHCPCD_OPTION *dhcpcd_config_read(DHCPCD_CONNECTION *,
+    const char *, const char *);
+void dhcpcd_config_free(DHCPCD_OPTION *);
+const char * dhcpcd_config_get(DHCPCD_OPTION *, const char *);
+const char * dhcpcd_config_get_static(DHCPCD_OPTION *, const char *);
+bool dhcpcd_config_set(DHCPCD_OPTION **, const char *, const char *);
+bool dhcpcd_config_set_static(DHCPCD_OPTION **, const char *, const char *);
+bool dhcpcd_config_write(DHCPCD_CONNECTION *,
+    const char *, const char *, const DHCPCD_OPTION *);
+
+#endif
diff --git a/src/libdhcpcd/dispatch.c b/src/libdhcpcd/dispatch.c
deleted file mode 100644 (file)
index dbe4b7f..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * libdhcpcd
- * Copyright 2009-2014 Roy Marples <roy@marples.name>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#define IN_LIBDHCPCD
-#include "libdhcpcd.h"
-
-static const char * const dhcpcd_types[] =
-    { "link", "ipv4", "ra", "dhcp6", NULL };
-
-static const char *
-dhcpcd_message_get_string(DHCPCD_MESSAGE *msg)
-{
-       DBusMessageIter args;
-       char *str;
-
-       if (dbus_message_iter_init(msg, &args) &&
-           dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING)
-       {
-               dbus_message_iter_get_basic(&args, &str);
-               return str;
-       }
-       return NULL;
-}
-
-static void
-dhcpcd_handle_event(DHCPCD_CONNECTION *con, DHCPCD_MESSAGE *msg)
-{
-       DBusMessageIter args;
-       DHCPCD_IF *i, *e, *l, *n, *nl;
-       char *order, *o, *p;
-       int ti;
-
-       if (!dbus_message_iter_init(msg, &args))
-               return;
-       order = NULL;
-       i = dhcpcd_if_new(con, &args, &order);
-       if (i == NULL)
-               return;
-       p = order;
-       n = nl = NULL;
-
-       /* Remove all instances on carrier drop */
-       if (strcmp(i->reason, "NOCARRIER") == 0 ||
-           strcmp(i->reason, "DEPARTED") == 0 ||
-           strcmp(i->reason, "STOPPED") == 0)
-       {
-               l = NULL;
-               for (e = con->interfaces; e; e = n) {
-                       n = e->next;
-                       if (strcmp(e->ifname, i->ifname) == 0) {
-                               if (strcmp(e->type, i->type) == 0)
-                                       l = nl = e;
-                               else {
-                                       if (l)
-                                               l->next = e->next;
-                                       else
-                                               con->interfaces = e->next;
-                                       free(e);
-                               }
-                       } else
-                               l = e;
-               }
-       }
-
-       /* Find our pointer */
-       if (nl == NULL) {
-               l = NULL;
-               for (e = con->interfaces; e; e = e->next) {
-                       if (strcmp(e->ifname, i->ifname) == 0 &&
-                           strcmp(e->type, i->type) == 0)
-                       {
-                               nl = e;
-                               break;
-                       }
-                       l = e;
-               }
-       }
-       if (nl) {
-               /* Preserve the pointer for wireless history */
-               n = nl->next;
-               memcpy(nl, i, sizeof(*i));
-               nl->next = n;
-               free(i);
-               i = nl;
-       } else {
-               /* Append it then */
-               if (l)
-                       l->next = i;
-               else
-                       con->interfaces = i;
-               i->next = NULL;
-       }
-
-       /* Sort! */
-       n = nl = NULL;
-       while ((o = strsep(&p, " ")) != NULL) {
-               for (ti = 0; dhcpcd_types[ti]; ti++) {
-                       l = NULL;
-                       for (e = con->interfaces; e; e = e->next) {
-                               if (strcmp(e->ifname, o) == 0 &&
-                                   strcmp(e->type, dhcpcd_types[ti]) == 0)
-                                       break;
-                               l = e;
-                       }
-                       if (e == NULL)
-                               continue;
-                       if (l)
-                               l->next = e->next;
-                       else
-                               con->interfaces = e->next;
-                       e->next = NULL;
-                       if (nl == NULL)
-                               n = nl = e;
-                       else {
-                               nl->next = e;
-                               nl = e;
-                       }
-               }
-       }
-       /* Free any stragglers */
-       while (con->interfaces) {
-               e = con->interfaces->next;
-               free(con->interfaces);
-               con->interfaces = e;
-       }
-       con->interfaces = n;
-
-       if (con->event)
-               con->event(con, i, con->signal_data);
-}
-
-bool
-dhcpcd_dispatch_message(DHCPCD_CONNECTION *con, DHCPCD_MESSAGE *msg)
-{
-       bool handled;
-       const char *str;
-       DHCPCD_IF *ifp;
-
-       if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-               return false;
-
-       handled = true;
-       dbus_connection_ref(con->bus);
-       dbus_message_ref(msg);
-       if (dbus_message_is_signal(msg, DHCPCD_SERVICE, "StatusChanged")) {
-               con->status = strdup(dhcpcd_message_get_string(msg));
-               if (strcmp(con->status, "down") == 0) {
-                       dhcpcd_if_free(con->interfaces);
-                       con->interfaces = NULL;
-               }
-               if (con->status_changed)
-                       con->status_changed(con, con->status,
-                           con->signal_data);
-       }
-       else if (dbus_message_is_signal(msg, DHCPCD_SERVICE, "ScanResults"))
-       {
-               if (con->wi_scanresults) {
-                       str = dhcpcd_message_get_string(msg);
-                       ifp = dhcpcd_if_find(con, str, "link");
-                       if (ifp)
-                               con->wi_scanresults(con, ifp, con->signal_data);
-               }
-       } else if (dbus_message_is_signal(msg, DHCPCD_SERVICE, "Event"))
-               dhcpcd_handle_event(con, msg);
-       else
-               handled = false;
-       dbus_message_unref(msg);
-       dbus_connection_unref(con->bus);
-       return handled;
-}
diff --git a/src/libdhcpcd/libdhcpcd.h b/src/libdhcpcd/libdhcpcd.h
deleted file mode 100644 (file)
index 0d31bec..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * libdhcpcd
- * Copyright 2009-2014 Roy Marples <roy@marples.name>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef LIBDHCPCD_H
-#define LIBDHCPCD_H
-
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <poll.h>
-#include <stdbool.h>
-
-#define IF_SSIDSIZE 33
-#define IF_BSSIDSIZE 64
-#define FLAGSIZE 64
-#define TYPESIZE 8
-#define REASONSIZE 16
-
-typedef struct dhcpcd_wi_avs {
-       int value;
-       int average;
-} DHCPCD_WI_AV;
-
-typedef struct dhcpcd_wi_scan {
-       struct dhcpcd_wi_scan *next;
-       char bssid[IF_BSSIDSIZE];
-       int frequency;
-       DHCPCD_WI_AV quality;
-       DHCPCD_WI_AV noise;
-       DHCPCD_WI_AV level;
-       char ssid[IF_SSIDSIZE];
-       char flags[FLAGSIZE];
-} DHCPCD_WI_SCAN;
-
-typedef struct dhcpcd_if {
-       struct dhcpcd_if *next;
-       char ifname[IF_NAMESIZE];
-       char type[TYPESIZE];
-       unsigned int flags;
-       bool wireless;
-       char ssid[IF_SSIDSIZE];
-       bool up;
-       char reason[REASONSIZE];
-       struct in_addr ip;
-       struct in6_addr prefix;
-       int prefix_len;
-       unsigned char cidr;
-       struct in6_addr ip6;
-} DHCPCD_IF;
-
-/* Although we use DBus, we don't have to rely on it for our API */
-#ifdef IN_LIBDHCPCD
-#include <dbus/dbus.h>
-typedef DBusMessage DHCPCD_MESSAGE;
-typedef DBusMessageIter DHCPCD_MESSAGEITER;
-
-typedef struct dhcpcd_wi_hist {
-       struct dhcpcd_wi_hist *next;
-       char ifname[IF_NAMESIZE];
-       char bssid[IF_BSSIDSIZE];
-       int quality;
-       int noise;
-       int level;
-} DHCPCD_WI_HIST;
-
-typedef struct dhcpcd_connection {
-       struct dhcpcd_connection *next;
-       DBusConnection *bus;
-       char *error;
-       int err;
-       int errors;
-       char *status;
-       void (*add_watch)(struct dhcpcd_connection *, const struct pollfd *,
-           void *);
-       void (*delete_watch)(struct dhcpcd_connection *, const struct pollfd *,
-           void *);
-       void *watch_data;
-       void (*event)(struct dhcpcd_connection *, DHCPCD_IF *, void *);
-       void (*status_changed)(struct dhcpcd_connection *, const char *,
-           void *);
-       void (*wi_scanresults)(struct dhcpcd_connection *, DHCPCD_IF *,
-           void *);
-       void *signal_data;
-       DHCPCD_IF *interfaces;
-       DHCPCD_WI_HIST *wi_history;
-} DHCPCD_CONNECTION;
-
-typedef struct dhcpcd_watch {
-       struct dhcpcd_watch *next;
-       DHCPCD_CONNECTION *connection;
-       DBusWatch *watch;
-       struct pollfd pollfd;
-} DHCPCD_WATCH;
-extern DHCPCD_WATCH *dhcpcd_watching;
-
-#define DHCPCD_SERVICE "name.marples.roy.dhcpcd"
-#define DHCPCD_PATH    "/name/marples/roy/dhcpcd"
-
-bool dhcpcd_iter_get(DHCPCD_CONNECTION *, DHCPCD_MESSAGEITER *, int, void *);
-DHCPCD_MESSAGE * dhcpcd_send_reply(DHCPCD_CONNECTION *, DHCPCD_MESSAGE *);
-DHCPCD_MESSAGE * dhcpcd_message_reply(DHCPCD_CONNECTION *,
-    const char *, const char *);
-void dhcpcd_error_set(DHCPCD_CONNECTION *, const char *, int);
-DHCPCD_IF * dhcpcd_if_new(DHCPCD_CONNECTION *, DBusMessageIter *, char **);
-void dhcpcd_if_free(DHCPCD_IF *);
-void dhcpcd_dispatch_signal(DHCPCD_CONNECTION *, const char *, void *);
-bool dhcpcd_dispatch_message(DHCPCD_CONNECTION *, DHCPCD_MESSAGE *);
-#else
-typedef void * DHCPCD_CONNECTION;
-#endif
-
-DHCPCD_CONNECTION * dhcpcd_open(char **);
-bool dhcpcd_close(DHCPCD_CONNECTION *);
-const char * dhcpcd_error(DHCPCD_CONNECTION *);
-void dhcpcd_error_clear(DHCPCD_CONNECTION *);
-void dhcpcd_set_watch_functions(DHCPCD_CONNECTION *,
-    void (*)(DHCPCD_CONNECTION *, const struct pollfd *, void *),
-    void (*)(DHCPCD_CONNECTION *, const struct pollfd *, void *),
-    void *);
-void dhcpcd_set_signal_functions(DHCPCD_CONNECTION *,
-    void (*)(DHCPCD_CONNECTION *, DHCPCD_IF *, void *),
-    void (*)(DHCPCD_CONNECTION *, const char *, void *),
-    void (*)(DHCPCD_CONNECTION *, DHCPCD_IF *, void *),
-    void *);
-const char * dhcpcd_status(DHCPCD_CONNECTION *);
-bool dhcpcd_command(DHCPCD_CONNECTION *, const char *, const char *, char **);
-void dhcpcd_dispatch(int);
-DHCPCD_IF * dhcpcd_interfaces(DHCPCD_CONNECTION *);
-DHCPCD_IF * dhcpcd_if_find(DHCPCD_CONNECTION *, const char *, const char *);
-DHCPCD_CONNECTION * dhcpcd_if_connection(DHCPCD_IF *);
-
-char * dhcpcd_if_message(const DHCPCD_IF *);
-
-DHCPCD_WI_SCAN * dhcpcd_wi_scans(DHCPCD_CONNECTION *, DHCPCD_IF *);
-void dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *);
-void dhcpcd_wi_history_clear(DHCPCD_CONNECTION *);
-bool dhcpcd_wpa_command(DHCPCD_CONNECTION *, DHCPCD_IF *, const char *, int);
-bool dhcpcd_wpa_set_network(DHCPCD_CONNECTION *, DHCPCD_IF *,
-    int, const char *, const char *);
-int dhcpcd_wpa_find_network_new(DHCPCD_CONNECTION *, DHCPCD_IF *,
-    const char *);
-
-#define dhcpcd_rebind(c, i)                                                  \
-       dhcpcd_command(c, "Rebind", i ? (i)->ifname : NULL, NULL)
-#define dhcpcd_release(c, i)                                                 \
-       dhcpcd_command(c, "Release", i ? (i)->ifname : NULL, NULL)
-
-/* Our configuration is probably going to change ... */
-#ifdef IN_LIBDHCPCD
-typedef struct dhcpcd_config {
-       char *option;
-       char *value;
-       struct dhcpcd_config *next;
-} DHCPCD_CONFIG;
-#else
-typedef void *DHCPCD_CONFIG;
-#endif
-
-char ** dhcpcd_config_blocks_get(DHCPCD_CONNECTION *, const char *);
-DHCPCD_CONFIG * dhcpcd_config_load(DHCPCD_CONNECTION *,
-    const char *, const char *);
-void dhcpcd_config_free(DHCPCD_CONFIG *);
-const char * dhcpcd_config_get(DHCPCD_CONFIG *, const char *);
-const char * dhcpcd_config_get_static(DHCPCD_CONFIG *, const char *);
-bool dhcpcd_config_set(DHCPCD_CONFIG **, const char *, const char *);
-bool dhcpcd_config_set_static(DHCPCD_CONFIG **, const char *, const char *);
-bool dhcpcd_config_save(DHCPCD_CONNECTION *,
-    const char *, const char *, DHCPCD_CONFIG *);
-
-#endif
diff --git a/src/libdhcpcd/main.c b/src/libdhcpcd/main.c
deleted file mode 100644 (file)
index d63844f..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * libdhcpcd
- * Copyright 2009-2014 Roy Marples <roy@marples.name>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <dbus/dbus.h>
-
-#define IN_LIBDHCPCD
-#include "libdhcpcd.h"
-#include "config.h"
-
-#define DHCPCD_TIMEOUT_MS 500
-
-#ifndef _unused
-#  ifdef __GNUC__
-#    define _unused __attribute__((__unused__))
-#  else
-#    define _unused
-#  endif
-#endif
-
-DHCPCD_CONNECTION *dhcpcd_connections;
-DHCPCD_WATCH *dhcpcd_watching;
-
-static dbus_bool_t
-dhcpcd_add_watch(DBusWatch *watch, void *data)
-{
-       DHCPCD_WATCH *w;
-       int fd;
-       unsigned int flags;
-
-       fd = dbus_watch_get_unix_fd(watch);
-       for (w = dhcpcd_watching; w; w = w->next) {
-               if (w->pollfd.fd == fd)
-                       break;
-       }
-       if (w == NULL) {
-               w = malloc(sizeof(*w));
-               if (w == NULL)
-                       return false;
-               w->next = dhcpcd_watching;
-               dhcpcd_watching = w;
-       }
-
-       w->connection = (DHCPCD_CONNECTION *)data;
-       w->watch = watch;
-       w->pollfd.fd = fd;
-       flags = dbus_watch_get_flags(watch);
-       w->pollfd.events = POLLHUP | POLLERR;
-       if (flags & DBUS_WATCH_READABLE)
-               w->pollfd.events |= POLLIN;
-       if (flags & DBUS_WATCH_WRITABLE)
-               w->pollfd.events |= POLLOUT;
-       if (w->connection->add_watch)
-               w->connection->add_watch(w->connection, &w->pollfd,
-                       w->connection->watch_data);
-       return true;
-}
-
-static void
-dhcpcd_delete_watch(DBusWatch *watch, void *data)
-{
-       DHCPCD_WATCH *w, *l;
-       int fd;
-
-       fd = dbus_watch_get_unix_fd(watch);
-       l = data = NULL;
-       for (w = dhcpcd_watching; w; w = w->next) {
-               if (w->pollfd.fd == fd) {
-                       if (w->connection->delete_watch)
-                               w->connection->delete_watch(w->connection,
-                                   &w->pollfd, w->connection->watch_data);
-                       if (l == NULL)
-                               dhcpcd_watching = w->next;
-                       else
-                               l->next = w->next;
-                       free(w);
-                       w = l;
-               }
-       }
-}
-
-static DBusHandlerResult
-dhcpcd_message(_unused DBusConnection *bus, DBusMessage *msg, void *data)
-{
-
-       if (dhcpcd_dispatch_message((DHCPCD_CONNECTION *)data, msg))
-               return DBUS_HANDLER_RESULT_HANDLED;
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-void
-dhcpcd_if_free(DHCPCD_IF *ifs)
-{
-       DHCPCD_IF *i;
-
-       while (ifs != NULL) {
-               i = ifs->next;
-               free(ifs);
-               ifs = i;
-       }
-}
-
-DHCPCD_CONNECTION *
-dhcpcd_open(char **error)
-{
-       DBusError err;
-       DHCPCD_CONNECTION *con;
-       DBusConnection *bus;
-       int tries;
-
-       dbus_error_init(&err);
-       bus = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
-       if (dbus_error_is_set(&err)) {
-               if (error)
-                       *error = strdup(err.message);
-               dbus_error_free(&err);
-               return NULL;
-       }
-       if (bus == NULL)
-               return NULL;
-       con = calloc(1, sizeof(*con));
-       if (con == NULL)
-               goto bad;
-       con->bus = bus;
-       if (!dbus_connection_set_watch_functions(bus,
-               dhcpcd_add_watch, dhcpcd_delete_watch, NULL, con, NULL))
-               goto bad;
-       dbus_bus_add_match(bus,
-           "type='signal',interface='" DHCPCD_SERVICE "'", &err);
-       dbus_connection_flush(bus);
-       if (dbus_error_is_set(&err)) {
-               if (error)
-                       *error = strdup(err.message);
-               dbus_error_free(&err);
-               goto bad;
-       }
-       if (!dbus_connection_add_filter(bus, dhcpcd_message, con, NULL))
-               goto bad;
-
-       /* Give dhcpcd-dbus a little time to automatically start */
-       tries = 5;
-       while (--tries > 0) {
-               if (dhcpcd_command(con, "GetVersion", NULL, NULL)) {
-                       dhcpcd_error_clear(con);
-                       break;
-               }
-       }
-
-       con->next = dhcpcd_connections;
-       dhcpcd_connections = con;
-
-       return con;
-
-bad:
-       free(con);
-       dbus_connection_unref(bus);
-       return NULL;
-}
-
-bool
-dhcpcd_close(DHCPCD_CONNECTION *con)
-{
-       DHCPCD_CONNECTION *c, *l;
-
-       l = NULL;
-       for (c = dhcpcd_connections; c; c = c->next) {
-               if (c == con) {
-                       if (l == NULL)
-                               dhcpcd_connections = con->next;
-                       else
-                               l->next = con->next;
-                       dbus_connection_unref(con->bus);
-                       dhcpcd_if_free(con->interfaces);
-                       dhcpcd_wi_history_clear(con);
-                       free(con->status);
-                       free(con->error);
-                       free(con);
-                       return true;
-               }
-               l = c;
-       }
-       dhcpcd_error_set(con, NULL, ESRCH);
-       return false;
-}
-
-DHCPCD_CONNECTION *
-dhcpcd_if_connection(DHCPCD_IF *interface)
-{
-       DHCPCD_CONNECTION *c;
-       DHCPCD_IF *i;
-
-       for (c = dhcpcd_connections; c; c = c->next) {
-               for (i = c->interfaces; i; i = i->next)
-                       if (i == interface)
-                               return c;
-       }
-       return NULL;
-}
-
-void
-dhcpcd_error_clear(DHCPCD_CONNECTION *con)
-{
-
-       free(con->error);
-       con->error = NULL;
-       con->err = 0;
-}
-
-void
-dhcpcd_error_set(DHCPCD_CONNECTION *con, const char *error, int err)
-{
-
-       dhcpcd_error_clear(con);
-       if (error != NULL) {
-               con->error = strdup(error);
-               if (err == 0)
-                       err = EPROTO;
-       } else if (err != 0)
-               con->error = strdup(strerror(err));
-       con->err = err;
-       con->errors++;
-}
-
-const char *
-dhcpcd_error(DHCPCD_CONNECTION *con)
-{
-
-       return con->error;
-}
-
-bool
-dhcpcd_iter_get(DHCPCD_CONNECTION *con, DBusMessageIter *iter,
-    int type, void *arg)
-{
-
-       if (dbus_message_iter_get_arg_type(iter) == type) {
-               dbus_message_iter_get_basic(iter, arg);
-               dbus_message_iter_next(iter);
-               return true;
-       }
-       dhcpcd_error_set(con, 0, EINVAL);
-       return false;
-}
-
-static bool
-dhcpcd_message_error(DHCPCD_CONNECTION *con, DHCPCD_MESSAGE *msg)
-{
-       DBusMessageIter args;
-       char *s;
-
-       if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_ERROR)
-               return false;
-       if (dbus_message_iter_init(msg, &args) &&
-           dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING)
-       {
-               dbus_message_iter_get_basic(&args, &s);
-               dhcpcd_error_set(con, s, 0);
-       }
-       return true;
-}
-
-DHCPCD_MESSAGE *
-dhcpcd_send_reply(DHCPCD_CONNECTION *con, DHCPCD_MESSAGE *msg)
-{
-       DBusMessage *reply;
-       DBusPendingCall *pending;
-
-       pending = NULL;
-       if (!dbus_connection_send_with_reply(con->bus, msg, &pending,
-               DHCPCD_TIMEOUT_MS) ||
-           pending == NULL)
-               return NULL;
-       dbus_connection_flush(con->bus);
-
-       /* Block until we receive a reply */
-       dbus_pending_call_block(pending);
-       reply = dbus_pending_call_steal_reply(pending);
-       dbus_pending_call_unref(pending);
-       if (dhcpcd_message_error(con, reply)) {
-               dbus_message_unref(reply);
-               return NULL;
-       }
-       return reply;
-}
-
-DHCPCD_MESSAGE *
-dhcpcd_message_reply(DHCPCD_CONNECTION *con, const char *cmd, const char *arg)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter args;
-
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, cmd);
-       if (msg == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return NULL;
-       }
-       dbus_message_iter_init_append(msg, &args);
-       if (arg != NULL &&
-           !dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &arg))
-       {
-               dbus_message_unref(msg);
-               dhcpcd_error_set(con, 0, EINVAL);
-               return NULL;
-       }
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       return reply;
-}
-
-bool
-dhcpcd_command(DHCPCD_CONNECTION *con, const char *cmd, const char *arg,
-       char **reply)
-{
-       DBusMessage *msg;
-       DBusMessageIter args;
-       char *s;
-
-       msg = dhcpcd_message_reply(con, cmd, arg);
-       if (msg == NULL)
-               return false;
-       if (dhcpcd_message_error(con, msg)) {
-               dbus_message_unref(msg);
-               return false;
-       }
-       if (reply != NULL &&
-           dbus_message_iter_init(msg, &args) &&
-           dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING)
-       {
-               dbus_message_iter_get_basic(&args, &s);
-               *reply = strdup(s);
-       }
-       dbus_message_unref(msg);
-       return true;
-}
-
-void
-dhcpcd_dispatch(int fd)
-{
-       DHCPCD_WATCH *w;
-       struct pollfd fds;
-       unsigned int flags;
-
-       flags = 0;
-       fds.fd = fd;
-       fds.events = (POLLIN | POLLHUP | POLLOUT | POLLERR);
-       if (poll(&fds, 1, 0) == 1) {
-               if (fds.revents & POLLIN)
-                       flags |= DBUS_WATCH_READABLE;
-               if (fds.revents & POLLOUT)
-                       flags |= DBUS_WATCH_WRITABLE;
-               if (fds.revents & POLLHUP)
-                       flags |= DBUS_WATCH_HANGUP;
-               if (fds.revents & POLLERR)
-                       flags |= DBUS_WATCH_ERROR;
-       }
-       for (w = dhcpcd_watching; w; w = w->next) {
-               if (w->pollfd.fd == fd) {
-                       if (flags != 0)
-                               dbus_watch_handle(w->watch, flags);
-                       dbus_connection_ref(w->connection->bus);
-                       while (dbus_connection_dispatch(w->connection->bus) ==
-                           DBUS_DISPATCH_DATA_REMAINS)
-                               ;
-                       dbus_connection_unref(w->connection->bus);
-               }
-       }
-}
-
-DHCPCD_IF *
-dhcpcd_if_new(DHCPCD_CONNECTION *con, DBusMessageIter *array, char **order)
-{
-       DBusMessageIter dict, entry, var, a;
-       DHCPCD_IF *i;
-       char *s, *p;
-       uint32_t u32;
-       int b, errors;
-       size_t l;
-
-       if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) {
-               errno = EINVAL;
-               return NULL;
-       }
-       dbus_message_iter_recurse(array, &dict);
-       i = calloc(1, sizeof(*i));
-       if (i == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return NULL;
-       }
-       errors = con->errors;
-       for (;
-            dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
-            dbus_message_iter_next(&dict))
-       {
-               dbus_message_iter_recurse(&dict, &entry);
-               if (!dhcpcd_iter_get(con, &entry, DBUS_TYPE_STRING, &s))
-                       break;
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
-                       break;
-               dbus_message_iter_recurse(&entry, &var);
-               if (strcmp(s, "Interface") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(i->ifname, s, sizeof(i->ifname));
-               } else if (strcmp(s, "Type") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(i->type, s, sizeof(i->type));
-               } else if (strcmp(s, "Flags") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_UINT32, &u32))
-                               break;
-                       i->flags = u32;
-               } else if (strcmp(s, "Up") == 0) {
-                       /* b is an int as DBus booleans want more space than
-                        * a C99 boolean */
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_BOOLEAN, &b))
-                               break;
-                       i->up = b;
-               } else if (strcmp(s, "Reason") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-
-                       strlcpy(i->reason, s, sizeof(i->reason));
-                       l = strlen(i->reason);
-                       if (l != 0 && i->reason[l - 1] == '6')
-                               i->reason[l - 1] = '\0';
-               } else if (strcmp(s, "Wireless") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_BOOLEAN, &b))
-                               break;
-                       i->wireless = b;
-               } else if (strcmp(s, "SSID") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(i->ssid, s, sizeof(i->ssid));
-               } else if (strcmp(s, "IPAddress") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_UINT32, &u32))
-                               break;
-                       i->ip.s_addr = u32;
-               } else if (strcmp(s, "SubnetCIDR") == 0)
-                       dbus_message_iter_get_basic(&var, &i->cidr);
-               else if (strcmp(s, "RA_Prefix") == 0) {
-                       /* Don't crash with older dhcpcd versions */
-                       if (dbus_message_iter_get_arg_type(&dict) ==
-                           DBUS_TYPE_STRING)
-                       {
-                               if (!dhcpcd_iter_get(con, &a,
-                                   DBUS_TYPE_STRING, &s))
-                                       break;
-                               inet_pton(AF_INET6, s, &i->prefix.s6_addr);
-                               continue;
-                       }
-
-                       if (dbus_message_iter_get_arg_type(&dict) !=
-                           DBUS_TYPE_DICT_ENTRY)
-                               break;
-                       dbus_message_iter_recurse(&var, &a);
-                       if (!dhcpcd_iter_get(con, &a, DBUS_TYPE_STRING, &s))
-                               break;
-                       /* Future versions may include pltime and vltime */
-                       p = strchr(s, ',');
-                       if (p)
-                               *p = '\0';
-                       p = strchr(s, '/');
-                       if (p) {
-                               *p++ = '\0';
-                               i->prefix_len = atoi(p);
-                       } else
-                               i->prefix_len = 0;
-                       inet_pton(AF_INET6, s, &i->prefix.s6_addr);
-               } else if (strcmp(s, "RA_PrefixLen") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_BYTE, &b))
-                               break;
-                       i->prefix_len = b;
-               } else if (strcmp(s, "D6_IPAddress") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       inet_pton(AF_INET6, s, &i->ip6.s6_addr);
-               } else if (order != NULL && strcmp(s, "InterfaceOrder") == 0)
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, order))
-                               break;
-       }
-
-       if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
-               free(i);
-               if (con->errors == errors)
-                       dhcpcd_error_set(con, NULL, EINVAL);
-               return NULL;
-       }
-       return i;
-}
-
-DHCPCD_IF *
-dhcpcd_interfaces(DHCPCD_CONNECTION *con)
-{
-       DBusMessage *msg;
-       DBusMessageIter args, dict, entry;
-       DHCPCD_IF *i, *l;
-       int errors;
-       char *stopif;
-
-       if (con->interfaces != NULL)
-               return con->interfaces;
-       l = NULL;
-       msg = dhcpcd_message_reply(con, "GetInterfaces", NULL);
-       if (msg == NULL)
-               return NULL;
-       if (!dbus_message_iter_init(msg, &args) ||
-           dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
-       {
-               dbus_message_unref(msg);
-               dhcpcd_error_set(con, 0, EINVAL);
-               return NULL;
-       }
-
-       l = NULL;
-       errors = con->errors;
-       dbus_message_iter_recurse(&args, &dict);
-       stopif = NULL;
-       for (;
-            dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
-            dbus_message_iter_next(&dict))
-       {
-               dbus_message_iter_recurse(&dict, &entry);
-               dbus_message_iter_next(&entry);
-               i = dhcpcd_if_new(con, &entry, NULL);
-               if (i == NULL)
-                       break;
-               if (stopif && strcmp(stopif, i->ifname) == 0) {
-                       free(i);
-                       continue;
-               }
-               if (strcmp(i->reason, "NOCARRIER") == 0 ||
-                   strcmp(i->reason, "DEPARTED") == 0 ||
-                   strcmp(i->reason, "STOPPED") == 0)
-                       stopif = i->ifname;
-               if (l == NULL)
-                       con->interfaces = i;
-               else
-                       l->next = i;
-               l = i;
-       }
-       dbus_message_unref(msg);
-       if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
-               if (con->errors == errors)
-                       dhcpcd_error_set(con, 0, EINVAL);
-               dhcpcd_if_free(con->interfaces);
-               con->interfaces = NULL;
-       }
-       return con->interfaces;
-}
-
-DHCPCD_IF *
-dhcpcd_if_find(DHCPCD_CONNECTION *con, const char *ifname, const char *type)
-{
-       DHCPCD_IF *i;
-
-       if (con->interfaces == NULL)
-               dhcpcd_interfaces(con);
-       for (i = con->interfaces; i; i = i ->next)
-               if (strcmp(i->ifname, ifname) == 0 &&
-                   strcmp(i->type, type) == 0)
-                       return i;
-       return NULL;
-}
-
-const char *
-dhcpcd_status(DHCPCD_CONNECTION *con)
-{
-       if (con->status == NULL)
-               dhcpcd_command(con, "GetStatus", NULL, &con->status);
-       return con->status;
-}
-
-void
-dhcpcd_set_watch_functions(DHCPCD_CONNECTION *con,
-    void (*add_watch)(DHCPCD_CONNECTION *, const struct pollfd *, void *),
-    void (*delete_watch)(DHCPCD_CONNECTION *, const struct pollfd *, void *),
-    void *data)
-{
-       DHCPCD_WATCH *w;
-
-       con->add_watch = add_watch;
-       con->delete_watch = delete_watch;
-       con->watch_data = data;
-       if (con->add_watch) {
-               for (w = dhcpcd_watching; w; w = w->next)
-                       if (w->connection == con)
-                               con->add_watch(con, &w->pollfd, data);
-       }
-}
-
-void
-dhcpcd_set_signal_functions(DHCPCD_CONNECTION *con,
-    void (*event)(DHCPCD_CONNECTION *, DHCPCD_IF *, void *),
-    void (*status_changed)(DHCPCD_CONNECTION *, const char *, void *),
-    void (*wi_scanresults)(DHCPCD_CONNECTION *, DHCPCD_IF *, void *),
-    void *data)
-{
-       DHCPCD_IF *i;
-
-       con->event = event;
-       con->status_changed = status_changed;
-       con->wi_scanresults = wi_scanresults;
-       con->signal_data = data;
-       if (con->status_changed) {
-               if (con->status == NULL)
-                       dhcpcd_status(con);
-               con->status_changed(con, con->status, data);
-       }
-       if (con->wi_scanresults) {
-               for (i = dhcpcd_interfaces(con); i; i = i->next)
-                       if (i->wireless && strcmp(i->type, "link") == 0)
-                               con->wi_scanresults(con, i, data);
-       }
-}
diff --git a/src/libdhcpcd/misc.c b/src/libdhcpcd/misc.c
deleted file mode 100644 (file)
index 2ea94e5..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * libdhcpcd
- * Copyright 2009-2014 Roy Marples <roy@marples.name>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <arpa/inet.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libintl.h>
-
-#define IN_LIBDHCPCD
-#include "libdhcpcd.h"
-
-#define _ gettext
-
-char *
-dhcpcd_if_message(const DHCPCD_IF *i)
-{
-       char *msg, *p;
-       const char *reason = NULL;
-       size_t len;
-       bool showip, showssid;
-       char buf[INET6_ADDRSTRLEN];
-
-       /* Don't report non SLAAC configurations */
-       if (strcmp(i->type, "ra") == 0 &&
-           IN6_IS_ADDR_UNSPECIFIED(&i->prefix) &&
-           i->up)
-               return NULL;
-
-       showip = true;
-       showssid = false;
-       if (strcmp(i->reason, "EXPIRE") == 0)
-               reason = _("Expired");
-       else if (strcmp(i->reason, "CARRIER") == 0) {
-               if (i->wireless) {
-                       reason = _("Associated with");
-                       if (*i->ssid != '\0')
-                               showssid = true;
-               } else
-                       reason = _("Cable plugged in");
-               showip = false;
-       } else if (strcmp(i->reason, "NOCARRIER") == 0) {
-               if (i->wireless) {
-                       if (*i->ssid != '\0' || i->ip.s_addr != 0) {
-                               reason = _("Disassociated from");
-                               showssid = true;
-                       } else
-                               reason = _("Not associated");
-               } else
-                       reason = _("Cable unplugged");
-               showip = false;
-       } else if (strcmp(i->reason, "UNKNOWN") == 0)
-               reason = _("Unknown link state");
-       else if (strcmp(i->reason, "FAIL") == 0)
-               reason = _("Automatic configuration not possible");
-       else if (strcmp(i->reason, "3RDPARTY") == 0)
-               reason = _("Waiting for 3rd Party configuration");
-
-       if (reason == NULL) {
-               if (i->up)
-                       reason = _("Configured");
-               else if (strcmp(i->type, "ra") == 0)
-                       reason = "Expired RA";
-               else
-                       reason = i->reason;
-       }
-
-       len = strlen(i->ifname) + 3;
-       len += strlen(reason) + 1;
-       if (i->ip.s_addr != 0) {
-               len += 16; /* 000. * 4 */
-               if (i->cidr != 0)
-                       len += 3; /* /32 */
-       } else if (!IN6_IS_ADDR_UNSPECIFIED(&i->ip6)) {
-               len += INET6_ADDRSTRLEN;
-       } else if (!IN6_IS_ADDR_UNSPECIFIED(&i->prefix)) {
-               len += INET6_ADDRSTRLEN;
-               if (i->prefix_len != 0)
-                       len += 4;
-       }
-       if (showssid)
-               len += strlen(i->ssid) + 1;
-       msg = p = malloc(len);
-       if (msg == NULL)
-               return NULL;
-       p += snprintf(msg, len, "%s: %s", i->ifname, reason);
-       if (showssid)
-               p += snprintf(p, len - (size_t)(p - msg), " %s", i->ssid);
-       if (i->ip.s_addr != 0 && showip) {
-               p += snprintf(p, len - (size_t)(p - msg), " %s",
-                   inet_ntoa(i->ip));
-               if (i->cidr != 0)
-                       snprintf(p, len - (size_t)(p - msg), "/%d", i->cidr);
-       } else if (!IN6_IS_ADDR_UNSPECIFIED(&i->ip6) && showip) {
-               p += snprintf(p, len - (size_t)(p - msg), " %s",
-                   inet_ntop(AF_INET6, &i->ip6, buf, INET6_ADDRSTRLEN));
-       } else if (!IN6_IS_ADDR_UNSPECIFIED(&i->prefix) && showip) {
-               p += snprintf(p, len - (size_t)(p - msg), " %s",
-                   inet_ntop(AF_INET6, &i->prefix, buf, INET6_ADDRSTRLEN));
-               if (i->prefix_len != 0)
-                       snprintf(p, len - (size_t)(p - msg),
-                           "/%d", i->prefix_len);
-       }
-       return msg;
-}
index 68c56db7073d31345d492933936ac71d0e8e7312..89e46c523cdfd77f572c16d7072f1bd2d70ba370 100644 (file)
  * SUCH DAMAGE.
  */
 
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <assert.h>
 #include <errno.h>
+#include <limits.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #define IN_LIBDHCPCD
-#include "libdhcpcd.h"
 #include "config.h"
+#include "dhcpcd.h"
 
-#define HIST_MAX 10 /* Max history per ssid/bssid */
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+       (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
 
-void
-dhcpcd_wi_history_clear(DHCPCD_CONNECTION *con)
+static int
+wpa_open(const char *ifname, char **path)
 {
-       DHCPCD_WI_HIST *h;
+       static int counter;
+       int fd;
+       socklen_t len;
+       struct sockaddr_un sun;
 
-       while (con->wi_history) {
-               h = con->wi_history->next;
-               free(con->wi_history);
-               con->wi_history = h;
+       if ((fd = socket(AF_UNIX,
+           SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1)
+               return -1;
+       memset(&sun, 0, sizeof(sun));
+       sun.sun_family = AF_UNIX;
+       snprintf(sun.sun_path, sizeof(sun.sun_path),
+           "/tmp/libdhcpcd-wpa-%d.%d", getpid(), counter++);
+       *path = strdup(sun.sun_path);
+       len = (socklen_t)SUN_LEN(&sun);
+       if (bind(fd, (struct sockaddr *)&sun, len) == -1) {
+               close(fd);
+               unlink(*path);
+               free(*path);
+               *path = NULL;
+               return -1;
+       }
+       snprintf(sun.sun_path, sizeof(sun.sun_path),
+           WPA_CTRL_DIR "/%s", ifname);
+       len = (socklen_t)SUN_LEN(&sun);
+       if (connect(fd, (struct sockaddr *)&sun, len) == -1) {
+               close(fd);
+               unlink(*path);
+               free(*path);
+               *path = NULL;
+               return -1;
        }
+
+       return fd;
+}
+
+static ssize_t
+wpa_cmd(int fd, const char *cmd, char *buffer, size_t len)
+{
+       int retval;
+       ssize_t bytes;
+       struct pollfd pfd;
+
+       if (buffer)
+               *buffer = '\0';
+       bytes = write(fd, cmd, strlen(cmd));
+       if (bytes == -1 || bytes == 0)
+               return -1;
+       if (buffer == NULL || len == 0)
+               return 0;
+       pfd.fd = fd;
+       pfd.events = POLLIN | POLLHUP;
+       pfd.revents = 0;
+       retval = poll(&pfd, 1, 2000);
+       if (retval == -1)
+               return -1;
+       if (retval == 0 || !(pfd.revents & (POLLIN | POLLHUP)))
+               return -1;
+
+       bytes = read(fd, buffer, len == 1 ? 1 : len - 1);
+       if (bytes != -1)
+               buffer[bytes] = '\0';
+       return bytes;
+}
+
+bool
+dhcpcd_wpa_command(DHCPCD_WPA *wpa, const char *cmd)
+{
+       char buf[10];
+       ssize_t bytes;
+
+       bytes = wpa_cmd(wpa->command_fd, cmd, buf, sizeof(buf));
+       return (bytes == -1 || bytes == 0 ||
+           strcmp(buf, "OK\n")) ? false : true;
+}
+
+bool
+dhcpcd_wpa_command_arg(DHCPCD_WPA *wpa, const char *cmd, const char *arg)
+{
+       size_t cmdlen, nlen;
+
+       cmdlen = strlen(cmd);
+       nlen = cmdlen + strlen(arg) + 2;
+       if (!dhcpcd_realloc(wpa->con, nlen))
+               return -1;
+       strlcpy(wpa->con->buf, cmd, wpa->con->buflen);
+       wpa->con->buf[cmdlen] = ' ';
+       strlcpy(wpa->con->buf + cmdlen + 1, arg, wpa->con->buflen - 1 - cmdlen);
+       return dhcpcd_wpa_command(wpa, wpa->con->buf);
+}
+
+static bool
+dhcpcd_attach_detach(DHCPCD_WPA *wpa, int attach)
+{
+       char buf[10];
+       ssize_t bytes;
+
+       if (wpa->attached == attach)
+               return true;
+
+       bytes = wpa_cmd(wpa->listen_fd, attach > 0 ? "ATTACH" : "DETACH",
+           buf, sizeof(buf));
+       if (bytes == -1 || bytes == 0 || strcmp(buf, "OK\n"))
+               return false;
+
+       wpa->attached = attach;
+       return true;
+}
+
+bool
+dhcpcd_wpa_scan(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_wpa_command(wpa, "SCAN");
 }
 
 void
@@ -59,114 +176,96 @@ dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *wis)
        }
 }
 
+static void
+dhcpcd_strtoi(int *val, const char *s)
+{
+       long l;
+
+       l = strtol(s, NULL, 0);
+       if (l >= INT_MIN && l <= INT_MAX)
+               *val = (int)l;
+       else
+               errno = ERANGE;
+}
+
 static DHCPCD_WI_SCAN *
-dhcpcd_scanresult_new(DHCPCD_CONNECTION *con, DBusMessageIter *array)
+dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
 {
-       DBusMessageIter dict, entry, var;
-       DHCPCD_WI_SCAN *wis;
-       char *s;
-       int32_t i32;
-       int errors;
+       size_t i;
+       ssize_t bytes;
+       DHCPCD_WI_SCAN *wis, *w, *l;
+       char *s, *p, buf[32];
 
-       wis = calloc(1, sizeof(*wis));
-       if (wis == NULL) {
-               dhcpcd_error_set(con, NULL, errno);
+       if (!dhcpcd_realloc(wpa->con, 2048))
                return NULL;
-       }
-       errors = con->errors;
-       dbus_message_iter_recurse(array, &dict);
-       for (;
-            dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
-            dbus_message_iter_next(&dict))
-       {
-               dbus_message_iter_recurse(&dict, &entry);
-               if (!dhcpcd_iter_get(con, &entry, DBUS_TYPE_STRING, &s))
-                   break;
-               if (dbus_message_iter_get_arg_type(&entry) !=
-                   DBUS_TYPE_VARIANT)
+       wis = NULL;
+       for (i = 0; i < 1000; i++) {
+               snprintf(buf, sizeof(buf), "BSS %zu", i);
+               bytes = wpa_cmd(wpa->command_fd, buf,
+                   wpa->con->buf, wpa->con->buflen);
+               if (bytes == 0 || bytes == -1 ||
+                   strncmp(wpa->con->buf, "FAIL", 4) == 0)
+                       break;
+               p = wpa->con->buf;
+               w = calloc(1, sizeof(*w));
+               if (w == NULL)
                        break;
-               dbus_message_iter_recurse(&entry, &var);
-               if (strcmp(s, "BSSID") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(wis->bssid, s, sizeof(wis->bssid));
-               } else if (strcmp(s, "Frequency") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
-                               break;
-                       wis->frequency = i32;
-               } else if (strcmp(s, "Quality") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
-                               break;
-                       wis->quality.value = i32;
-               } else if (strcmp(s, "Noise") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
-                               break;
-                       wis->noise.value = i32;
-               } else if (strcmp(s, "Level") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
-                               break;
-                       wis->level.value = i32;
-               } else if (strcmp(s, "Flags") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(wis->flags, s, sizeof(wis->flags));
-               } else if (strcmp(s, "SSID") == 0) {
-                       if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
-                               break;
-                       strlcpy(wis->ssid, s, sizeof(wis->ssid));
+               if (wis == NULL)
+                       wis = w;
+               else
+                       l->next = w;
+               l = w;
+               while ((s = strsep(&p, "\n"))) {
+                       if (*s == '\0')
+                               continue;
+                       if (strncmp(s, "bssid=", 6) == 0)
+                               strlcpy(w->bssid, s + 6, sizeof(w->bssid));
+                       else if (strncmp(s, "freq=", 5) == 0)
+                               dhcpcd_strtoi(&w->frequency, s + 5);
+//                     else if (strncmp(s, "beacon_int=", 11) == 0)
+//                             ;
+                       else if (strncmp(s, "qual=", 5) == 0)
+                               dhcpcd_strtoi(&w->quality.value, s + 5);
+                       else if (strncmp(s, "noise=", 6) == 0)
+                               dhcpcd_strtoi(&w->noise.value, s + 6);
+                       else if (strncmp(s, "level=", 6) == 0)
+                               dhcpcd_strtoi(&w->level.value, s + 6);
+                       else if (strncmp(s, "flags=", 6) == 0)
+                               strlcpy(w->flags, s + 6, sizeof(w->flags));
+                       else if (strncmp(s, "ssid=", 5) == 0)
+                               strlcpy(w->ssid, s + 5, sizeof(w->ssid));
                }
        }
-       if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
-               if (con->errors == errors)
-                       dhcpcd_error_set(con, NULL, EINVAL);
-               free(wis);
-               return NULL;
-       }
        return wis;
 }
 
 DHCPCD_WI_SCAN *
-dhcpcd_wi_scans(DHCPCD_CONNECTION *con, DHCPCD_IF *i)
+dhcpcd_wi_scans(DHCPCD_IF *i)
 {
-       DBusMessage *msg;
-       DBusMessageIter args, array;
-       DHCPCD_WI_SCAN *wis, *scans, *l;
+       DHCPCD_WPA *wpa;
+       DHCPCD_WI_SCAN *wis, *w;
+       int nh;
        DHCPCD_WI_HIST *h, *hl;
-       int errors, nh;
 
-       msg = dhcpcd_message_reply(con, "ScanResults", i->ifname);
-       if (msg == NULL)
-               return NULL;
-       if (!dbus_message_iter_init(msg, &args) ||
-           dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
-       {
-               dhcpcd_error_set(con, NULL, EINVAL);
+       wpa = dhcpcd_wpa_find(i->con, i->ifname);
+       if (wpa == NULL)
                return NULL;
-       }
-
-       scans = l = NULL;
-       errors = con->errors;
-       dbus_message_iter_recurse(&args, &array);
-       for(;
-           dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY;
-           dbus_message_iter_next(&array))
-       {
-               wis = dhcpcd_scanresult_new(con, &array);
-               if (wis == NULL)
-                       break;
+       wis = dhcpcd_wpa_scans_read(wpa);
+       for (w = wis; w; w = w->next) {
                nh = 1;
                hl = NULL;
-               wis->quality.average = wis->quality.value;
-               wis->noise.average = wis->noise.value;
-               wis->level.average = wis->level.value;
-               for (h = con->wi_history; h; h = h->next) {
+               w->quality.average = w->quality.value;
+               w->noise.average = w->noise.value;
+               w->level.average = w->level.value;
+
+               for (h = wpa->con->wi_history; h; h = h->next) {
                        if (strcmp(h->ifname, i->ifname) == 0 &&
                            strcmp(h->bssid, wis->bssid) == 0)
                        {
-                               wis->quality.average += h->quality;
-                               wis->noise.average += h->noise;
-                               wis->level.average += h->level;
-                               if (++nh == HIST_MAX) {
+                               w->quality.average += h->quality;
+                               w->noise.average += h->noise;
+                               w->level.average += h->level;
+                               if (++nh == DHCPCD_WI_HIST_MAX) {
                                        hl->next = h->next;
                                        free(h);
                                        break;
@@ -174,196 +273,364 @@ dhcpcd_wi_scans(DHCPCD_CONNECTION *con, DHCPCD_IF *i)
                        }
                        hl = h;
                }
+
                if (nh != 1) {
-                       wis->quality.average /= nh;
-                       wis->noise.average /= nh;
-                       wis->level.average /= nh;
+                       w->quality.average /= nh;
+                       w->noise.average /= nh;
+                       w->level.average /= nh;
                }
                h = malloc(sizeof(*h));
                if (h) {
                        strlcpy(h->ifname, i->ifname, sizeof(h->ifname));
-                       strlcpy(h->bssid, wis->bssid, sizeof(h->bssid));
-                       h->quality = wis->quality.value;
-                       h->noise = wis->noise.value;
-                       h->level = wis->level.value;
-                       h->next = con->wi_history;
-                       con->wi_history = h;
-               }
-               if (l == NULL)
-                       scans = l = wis;
-               else {
-                       l->next = wis;
-                       l = l->next;
+                       strlcpy(h->bssid, w->bssid, sizeof(h->bssid));
+                       h->quality = w->quality.value;
+                       h->noise = w->noise.value;
+                       h->level = w->level.value;
+                       h->next = wpa->con->wi_history;
+                       wpa->con->wi_history = h;
                }
        }
-       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-               if (con->errors == errors)
-                       dhcpcd_error_set(con, NULL, EINVAL);
-               dhcpcd_wi_scans_free(scans);
-               scans = NULL;
+
+       return wis;
+}
+
+bool
+dhcpcd_wpa_reassociate(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_wpa_command(wpa, "REASSOCIATE");
+}
+
+bool
+dhcpcd_wpa_disconnect(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_wpa_command(wpa, "DISCONNECT");
+}
+
+bool
+dhcpcd_wpa_config_write(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_wpa_command(wpa, "SAVE_CONFIG");
+}
+
+static bool
+dhcpcd_wpa_network(DHCPCD_WPA *wpa, const char *cmd, int id)
+{
+       size_t len;
+
+       len = strlen(cmd) + 32;
+       if (!dhcpcd_realloc(wpa->con, len))
+               return false;
+       snprintf(wpa->con->buf, wpa->con->buflen, "%s %d", cmd, id);
+       return dhcpcd_wpa_command(wpa, wpa->con->buf);
+}
+
+bool
+dhcpcd_wpa_network_disable(DHCPCD_WPA *wpa, int id)
+{
+
+       return dhcpcd_wpa_network(wpa, "DISABLE_NETWORK", id);
+}
+
+bool
+dhcpcd_wpa_network_enable(DHCPCD_WPA *wpa, int id)
+{
+
+       return dhcpcd_wpa_network(wpa, "ENABLE_NETWORK", id);
+}
+
+bool
+dhcpcd_wpa_network_remove(DHCPCD_WPA *wpa, int id)
+{
+
+       return dhcpcd_wpa_network(wpa, "REMOVE_NETWORK", id);
+}
+
+char *
+dhcpcd_wpa_network_get(DHCPCD_WPA *wpa, int id, const char *param)
+{
+       ssize_t bytes;
+
+       if (!dhcpcd_realloc(wpa->con, 2048))
+               return NULL;
+       snprintf(wpa->con->buf, wpa->con->buflen, "GET_NETWORK %d %s",
+           id, param);
+       bytes = wpa_cmd(wpa->command_fd, wpa->con->buf,
+           wpa->con->buf, wpa->con->buflen);
+       if (bytes == 0 || bytes == -1)
+               return NULL;
+       if (strcmp(wpa->con->buf, "FAIL\n") == 0) {
+               errno = EINVAL;
+               return NULL;
        }
-       dbus_message_unref(msg);
-       return scans;
+       return wpa->con->buf;
+}
+
+bool
+dhcpcd_wpa_network_set(DHCPCD_WPA *wpa, int id,
+    const char *param, const char *value)
+{
+       size_t len;
+
+       len = strlen("SET_NETWORK") + 32 + strlen(param) + strlen(value) + 3;
+       if (!dhcpcd_realloc(wpa->con, len))
+               return false;
+       snprintf(wpa->con->buf, wpa->con->buflen, "SET_NETWORK %d %s %s",
+           id, param, value);
+       return dhcpcd_wpa_command(wpa, wpa->con->buf);
 }
 
 static int
-dhcpcd_wpa_find_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i, const char *ssid)
+dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
 {
-       DBusMessage *msg;
-       DBusMessageIter args, array, entry;
-       int32_t id;
-       char *s;
-       int errors;
+       ssize_t bytes;
+       char *s, *t, *ssid, *bssid, *flags;
+       long l;
 
-       msg = dhcpcd_message_reply(con, "ListNetworks", i->ifname);
-       if (msg == NULL)
+       dhcpcd_realloc(wpa->con, 2048);
+       bytes = wpa_cmd(wpa->command_fd, "LIST_NETWORKS",
+           wpa->con->buf, wpa->con->buflen);
+       if (bytes == 0 || bytes == -1)
                return -1;
-       if (!dbus_message_iter_init(msg, &args)) {
-               dhcpcd_error_set(con, NULL, EINVAL);
-               return -1;
-       }
 
-       errors = con->errors;
-       for(;
-           dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_ARRAY;
-           dbus_message_iter_next(&args))
-       {
-               dbus_message_iter_recurse(&args, &array);
-               for(;
-                   dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
-                   dbus_message_iter_next(&array))
-               {
-                       dbus_message_iter_recurse(&array, &entry);
-                       if (!dhcpcd_iter_get(con, &entry,
-                               DBUS_TYPE_INT32, &id) ||
-                           !dhcpcd_iter_get(con, &entry,
-                               DBUS_TYPE_STRING, &s))
-                               break;
-                       if (strcmp(s, ssid) == 0) {
-                               dbus_message_unref(msg);
-                               return (int)id;
-                       }
+       s = strchr(wpa->con->buf, '\n');
+       if (s == NULL)
+               return -1;
+       while ((t = strsep(&s, "\b"))) {
+               if (*t == '\0')
+                       continue;
+               ssid = strchr(t, '\t');
+               if (ssid == NULL)
+                       break;
+               *ssid++ = '\0';
+               bssid = strchr(ssid, '\t');
+               if (bssid == NULL)
+                       break;
+               *bssid++ = '\0';
+               flags = strchr(bssid, '\t');
+               if (flags == NULL)
+                       break;
+               *flags++ = '\0';
+               l = strtol(t, NULL, 0);
+               if (l < 0 || l > INT_MAX) {
+                       errno = ERANGE;
+                       break;
                }
+               if (strcmp(ssid, fssid) == 0)
+                       return (int)l;
        }
-       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID &&
-           con->errors == errors)
-               dhcpcd_error_set(con, NULL, EINVAL);
-       dbus_message_unref(msg);
+       errno = ENOENT;
        return -1;
 }
 
 static int
-dhcpcd_wpa_add_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i)
+dhcpcd_wpa_network_new(DHCPCD_WPA *wpa)
 {
-       DBusMessage *msg;
-       DBusMessageIter args;
-       int32_t id;
-       int ret;
+       ssize_t bytes;
+       long l;
 
-       msg = dhcpcd_message_reply(con, "AddNetwork", i->ifname);
-       if (msg == NULL)
+       dhcpcd_realloc(wpa->con, 32);
+       bytes = wpa_cmd(wpa->command_fd, "ADD_NETWORK",
+           wpa->con->buf, sizeof(wpa->con->buf));
+       if (bytes == 0 || bytes == -1)
+               return -1;
+       l = strtol(wpa->con->buf, NULL, 0);
+       if (l < 0 || l > INT_MAX) {
+               errno = ERANGE;
                return -1;
-       ret = -1;
-       if (dbus_message_iter_init(msg, &args)) {
-               if (dhcpcd_iter_get(con, &args, DBUS_TYPE_INT32, &id))
-                       ret = id;
-       } else
-               dhcpcd_error_set(con, NULL, EINVAL);
-       dbus_message_unref(msg);
-       return ret;
+       }
+       return (int)l;
 }
 
-bool
-dhcpcd_wpa_set_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i, int id,
-    const char *opt, const char *val)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter args;
-       bool retval;
-       char *ifname;
-
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, "SetNetwork");
-       if (msg == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return false;
-       }
-       dbus_message_iter_init_append(msg, &args);
-       ifname = i->ifname;
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &ifname);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &id);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &opt);
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &val);
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       if (reply == NULL)
-               retval = false;
-       else {
-               dbus_message_unref(reply);
-               retval = true;
+int
+dhcpcd_wpa_network_find_new(DHCPCD_WPA *wpa, const char *ssid)
+{
+       int id;
+
+       id = dhcpcd_wpa_network_find(wpa, ssid);
+       if (id == -1)
+               id = dhcpcd_wpa_network_new(wpa);
+       return id;
+}
+
+void
+dhcpcd_wpa_close(DHCPCD_WPA *wpa)
+{
+
+       if (wpa->command_fd == -1)
+               return;
+
+       dhcpcd_attach_detach(wpa, -1);
+       shutdown(wpa->command_fd, SHUT_RDWR);
+       wpa->command_fd = -1;
+       shutdown(wpa->listen_fd, SHUT_RDWR);
+       wpa->listen_fd = -1;
+       unlink(wpa->command_path);
+       free(wpa->command_path);
+       wpa->command_path = NULL;
+       unlink(wpa->listen_path);
+       free(wpa->listen_path);
+       wpa->listen_path = NULL;
+
+       if (wpa->con->wpa_status_cb)
+               wpa->con->wpa_status_cb(wpa, "down",
+                   wpa->con->wpa_status_context);
+
+}
+
+DHCPCD_WPA *
+dhcpcd_wpa_find(DHCPCD_CONNECTION *con, const char *ifname)
+{
+       DHCPCD_WPA *wpa;
+
+       for (wpa = con->wpa; wpa; wpa = wpa->next) {
+               if (strcmp(wpa->ifname, ifname) == 0)
+                       return wpa;
        }
-       return retval;
+       return NULL;
+}
+
+DHCPCD_WPA *
+dhcpcd_wpa_new(DHCPCD_CONNECTION *con, const char *ifname)
+{
+       DHCPCD_WPA *wpa;
+
+       wpa = dhcpcd_wpa_find(con, ifname);
+       if (wpa)
+               return wpa;
+
+       wpa = malloc(sizeof(*wpa));
+       if (wpa == NULL)
+               return NULL;
+
+       wpa->con = con;
+       strlcpy(wpa->ifname, ifname, sizeof(wpa->ifname));
+       wpa->command_fd = wpa->listen_fd = -1;
+       wpa->command_path = wpa->listen_path = NULL;
+       wpa->next = con->wpa;
+       con->wpa = wpa;
+       return wpa;
+}
+
+DHCPCD_CONNECTION *
+dhcpcd_wpa_connection(DHCPCD_WPA *wpa)
+{
+
+       return wpa->con;
+}
+
+DHCPCD_IF *
+dhcpcd_wpa_if(DHCPCD_WPA *wpa)
+{
+
+       return dhcpcd_get_if(wpa->con, wpa->ifname, "link");
 }
 
 int
-dhcpcd_wpa_find_network_new(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
-    const char *ssid)
+dhcpcd_wpa_open(DHCPCD_WPA *wpa)
 {
-       int errors, id;
-       char *q;
-       size_t len;
-       bool retval;
+       int cmd_fd, list_fd = -1;
+       char *cmd_path = NULL, *list_path = NULL;
 
-       len = strlen(ssid) + 3;
-       q = malloc(len);
-       if (q == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return -1;
-       }
-       errors = con->errors;
-       id = dhcpcd_wpa_find_network(con, i, ssid);
-       if (id != -1 || con->errors != errors) {
-               free(q);
-               return id;
-       }
-       id = dhcpcd_wpa_add_network(con, i);
-       if (id == -1) {
-               free(q);
+       if (wpa->listen_fd != -1)
+               return wpa->listen_fd;
+
+       cmd_fd = wpa_open(wpa->ifname, &cmd_path);
+       if (cmd_fd == -1)
+               goto fail;
+
+       list_fd = wpa_open(wpa->ifname, &list_path);
+       if (list_fd == -1)
+               goto fail;
+
+       wpa->attached = 0;
+       wpa->command_fd = cmd_fd;
+       wpa->command_path = cmd_path;
+       wpa->listen_fd = list_fd;
+       wpa->listen_path = list_path;
+       if (!dhcpcd_attach_detach(wpa, 1)) {
+               dhcpcd_wpa_close(wpa);
                return -1;
        }
-       snprintf(q, len, "\"%s\"", ssid);
-       retval = dhcpcd_wpa_set_network(con, i, id, "ssid", q);
-       free(q);
-       return retval;
+
+       if (wpa->con->wi_scanresults_cb)
+               wpa->con->wi_scanresults_cb(wpa,
+                   wpa->con->wi_scanresults_context);
+
+       return wpa->listen_fd;
+
+fail:
+       if (cmd_fd != -1)
+               close(cmd_fd);
+       if (list_fd != -1)
+               close(list_fd);
+       if (cmd_path)
+               unlink(cmd_path);
+       free(cmd_path);
+       if (list_path)
+               free(list_path);
+       return -1;
 }
 
-bool
-dhcpcd_wpa_command(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
-    const char *cmd, int id)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter args;
-       char *ifname;
-       bool retval;
-
-       msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
-           DHCPCD_SERVICE, cmd);
-       if (msg == NULL) {
-               dhcpcd_error_set(con, 0, errno);
-               return false;
+int
+dhcpcd_wpa_get_fd(DHCPCD_WPA *wpa)
+{
+
+       return wpa->listen_fd;
+}
+
+void
+dhcpcd_wpa_set_scan_callback(DHCPCD_CONNECTION *con,
+    void (*cb)(DHCPCD_WPA *, void *), void *context)
+{
+
+       con->wi_scanresults_cb = cb;
+       con->wi_scanresults_context = context;
+}
+
+void
+dhcpcd_wpa_dispatch(DHCPCD_WPA *wpa)
+{
+       char buffer[256], *p;
+       size_t bytes;
+
+       bytes = (size_t)read(wpa->listen_fd, buffer, sizeof(buffer));
+       if ((ssize_t)bytes == -1 || bytes == 0) {
+               dhcpcd_wpa_close(wpa);
+               return;
        }
-       dbus_message_iter_init_append(msg, &args);
-       ifname = i->ifname;
-       dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &ifname);
-       if (id != -1)
-               dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &id);
-       reply = dhcpcd_send_reply(con, msg);
-       dbus_message_unref(msg);
-       if (reply == NULL)
-               retval = false;
-       else {
-               dbus_message_unref(reply);
-               retval = true;
+
+       buffer[bytes] = '\0';
+       bytes = strlen(buffer);
+       if (buffer[bytes - 1] == ' ')
+               buffer[--bytes] = '\0';
+       for (p = buffer + 1; *p != '\0'; p++)
+               if (*p == '>') {
+                       p++;
+                       break;
+               }
+       if (strcmp(p, "CTRL-EVENT-SCAN-RESULTS") == 0 &&
+           wpa->con->wi_scanresults_cb)
+               wpa->con->wi_scanresults_cb(wpa,
+                   wpa->con->wi_scanresults_context);
+       return;
+}
+
+void
+dhcpcd_wpa_if_event(DHCPCD_IF *i)
+{
+       DHCPCD_WPA *wpa;
+
+       if (i->wireless) {
+               if (strcmp(i->reason, "STOPPING") == 0) {
+                       wpa = dhcpcd_wpa_find(i->con, i->ifname);
+                       if (wpa)
+                               dhcpcd_wpa_close(wpa);
+               } else if (i->up) {
+                       wpa = dhcpcd_wpa_new(i->con, i->ifname);
+                       dhcpcd_wpa_open(wpa);
+               }
        }
-       return retval;
 }