]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wpa_supplicant: Add support for IPv6 with UDP ctrl_iface
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>
Mon, 24 Feb 2014 12:22:16 +0000 (13:22 +0100)
committerJouni Malinen <j@w1.fi>
Tue, 25 Feb 2014 14:43:01 +0000 (16:43 +0200)
Add IPv6 support when using udp/udp-remote control interface using the
following new build configuration options:

CONFIG_CTRL_IFACE=udp6
CONFIG_CTRL_IFACE=udp6-remote

This is useful for testing, while we don't need to assign IPv4 address
(static or using DHCP) and can just use auto configured IPv6 addresses
(link local, which is based on the MAC address). Also add scope id
support for link local case.

For example,
./wpa_cli
./wpa_cli -i ::1,9877
./wpa_cli -i fe80::203:7fff:fe05:69%wlan0,9877

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
src/common/wpa_ctrl.c
wpa_supplicant/Makefile
wpa_supplicant/ctrl_iface_udp.c
wpa_supplicant/defconfig

index f4af94aa1c9e40e7e96cfb5638502c6838bbb1f7..5820a1364f3f721cdbccec49fc0fe7c3ad63cc53 100644 (file)
 #include "private/android_filesystem_config.h"
 #endif /* ANDROID */
 
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+#include <net/if.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+
 #include "wpa_ctrl.h"
 #include "common.h"
 
 struct wpa_ctrl {
 #ifdef CONFIG_CTRL_IFACE_UDP
        int s;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       struct sockaddr_in6 local;
+       struct sockaddr_in6 dest;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        struct sockaddr_in local;
        struct sockaddr_in dest;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        char *cookie;
        char *remote_ifname;
        char *remote_ip;
@@ -279,19 +288,33 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                return NULL;
        os_memset(ctrl, 0, sizeof(*ctrl));
 
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        if (ctrl->s < 0) {
                perror("socket");
                os_free(ctrl);
                return NULL;
        }
 
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       ctrl->local.sin6_family = AF_INET6;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       ctrl->local.sin6_addr = in6addr_any;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+       inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        ctrl->local.sin_family = AF_INET;
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
        ctrl->local.sin_addr.s_addr = INADDR_ANY;
 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
        ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+
        if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
                 sizeof(ctrl->local)) < 0) {
                close(ctrl->s);
@@ -299,14 +322,24 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                return NULL;
        }
 
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       ctrl->dest.sin6_family = AF_INET6;
+       inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
+       ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        ctrl->dest.sin_family = AF_INET;
        ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
        ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
        if (ctrl_path) {
                char *port, *name;
                int port_id;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               char *scope;
+               int scope_id = 0;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
                name = os_strdup(ctrl_path);
                if (name == NULL) {
@@ -314,7 +347,11 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                        os_free(ctrl);
                        return NULL;
                }
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               port = os_strchr(name, ',');
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                port = os_strchr(name, ':');
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
                if (port) {
                        port_id = atoi(&port[1]);
@@ -322,7 +359,16 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                } else
                        port_id = WPA_CTRL_IFACE_PORT;
 
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               scope = os_strchr(name, '%');
+               if (scope) {
+                       scope_id = if_nametoindex(&scope[1]);
+                       scope[0] = '\0';
+               }
+               h = gethostbyname2(name, AF_INET6);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                h = gethostbyname(name);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                ctrl->remote_ip = os_strdup(name);
                os_free(name);
                if (h == NULL) {
@@ -332,16 +378,33 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
                        os_free(ctrl);
                        return NULL;
                }
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               ctrl->dest.sin6_scope_id = scope_id;
+               ctrl->dest.sin6_port = htons(port_id);
+               os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                ctrl->dest.sin_port = htons(port_id);
-               os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
-                         h->h_length);
+               os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        } else
                ctrl->remote_ip = os_strdup("localhost");
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
        if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
                    sizeof(ctrl->dest)) < 0) {
-               perror("connect");
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               char addr[INET6_ADDRSTRLEN];
+               wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
+                          inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
+                                    sizeof(ctrl->dest)),
+                          ntohs(ctrl->dest.sin6_port),
+                          strerror(errno));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+               wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
+                          inet_ntoa(ctrl->dest.sin_addr),
+                          ntohs(ctrl->dest.sin_port),
+                          strerror(errno));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                close(ctrl->s);
                os_free(ctrl->remote_ip);
                os_free(ctrl);
index 7b556e84dd301308d406646e1b69610ba3434de1..b9c8a46886a3916d6522bec0fa1b2c055f3a3789 100644 (file)
@@ -1267,6 +1267,11 @@ endif
 ifeq ($(CONFIG_CTRL_IFACE), udp)
 CFLAGS += -DCONFIG_CTRL_IFACE_UDP
 endif
+ifeq ($(CONFIG_CTRL_IFACE), udp6)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+endif
 ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
 CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
 endif
@@ -1275,6 +1280,12 @@ CONFIG_CTRL_IFACE=udp
 CFLAGS += -DCONFIG_CTRL_IFACE_UDP
 CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
 endif
+ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+endif
 OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
 endif
 
index 8c09ba1338d2c9179dac7a0eec8c678d88b488e1..9d0674de074485abf074cd1cb2c579168f272723 100644 (file)
  */
 struct wpa_ctrl_dst {
        struct wpa_ctrl_dst *next;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       struct sockaddr_in6 addr;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        struct sockaddr_in addr;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        socklen_t addrlen;
        int debug_level;
        int errors;
@@ -51,38 +55,68 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
 
 
 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+                                           struct sockaddr_in6 *from,
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                            struct sockaddr_in *from,
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                            socklen_t fromlen)
 {
        struct wpa_ctrl_dst *dst;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_UDP_IPV6 */
 
        dst = os_zalloc(sizeof(*dst));
        if (dst == NULL)
                return -1;
-       os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
+       os_memcpy(&dst->addr, from, sizeof(*from));
        dst->addrlen = fromlen;
        dst->debug_level = MSG_INFO;
        dst->next = priv->ctrl_dst;
        priv->ctrl_dst = dst;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
+                  inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
+                  ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
                   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        return 0;
 }
 
 
 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+                                           struct sockaddr_in6 *from,
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                            struct sockaddr_in *from,
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                            socklen_t fromlen)
 {
        struct wpa_ctrl_dst *dst, *prev = NULL;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
        dst = priv->ctrl_dst;
        while (dst) {
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+               if (from->sin6_port == dst->addr.sin6_port &&
+                   !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
+                              sizeof(from->sin6_addr))) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
+                                  inet_ntop(AF_INET6, &from->sin6_addr, addr,
+                                            sizeof(*from)),
+                                  ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
                    from->sin_port == dst->addr.sin_port) {
                        wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
                                   "%s:%d", inet_ntoa(from->sin_addr),
                                   ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                        if (prev == NULL)
                                priv->ctrl_dst = dst->next;
                        else
@@ -98,21 +132,38 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
 
 
 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+                                          struct sockaddr_in6 *from,
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                           struct sockaddr_in *from,
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                                           socklen_t fromlen,
                                           char *level)
 {
        struct wpa_ctrl_dst *dst;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
 
        dst = priv->ctrl_dst;
        while (dst) {
+#if CONFIG_CTRL_IFACE_UDP_IPV6
+               if (from->sin6_port == dst->addr.sin6_port &&
+                   !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
+                              sizeof(from->sin6_addr))) {
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
+                                  inet_ntop(AF_INET6, &from->sin6_addr, addr,
+                                            sizeof(*from)),
+                                  ntohs(from->sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
                    from->sin_port == dst->addr.sin_port) {
                        wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
                                   "level %s:%d", inet_ntoa(from->sin_addr),
                                   ntohs(from->sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                        dst->debug_level = atoi(level);
                        return 0;
                }
@@ -150,7 +201,14 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
        struct ctrl_iface_priv *priv = sock_ctx;
        char buf[256], *pos;
        int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       struct sockaddr_in6 from;
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+       char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        socklen_t fromlen = sizeof(from);
        char *reply = NULL;
        size_t reply_len = 0;
@@ -165,6 +223,13 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
        }
 
 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
+       if (os_strcmp(addr, "::1")) {
+               wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
+                          addr);
+       }
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
                /*
                 * The OS networking stack is expected to drop this kind of
@@ -176,6 +241,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
                           "source %s", inet_ntoa(from.sin_addr));
                return;
        }
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
        buf[res] = '\0';
@@ -269,8 +335,14 @@ struct ctrl_iface_priv *
 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 {
        struct ctrl_iface_priv *priv;
-       struct sockaddr_in addr;
        int port = WPA_CTRL_IFACE_PORT;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       struct sockaddr_in6 addr;
+       int domain = PF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       struct sockaddr_in addr;
+       int domain = PF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
@@ -282,21 +354,34 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        if (wpa_s->conf->ctrl_interface == NULL)
                return priv;
 
-       priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+       priv->sock = socket(domain, SOCK_DGRAM, 0);
        if (priv->sock < 0) {
                perror("socket(PF_INET)");
                goto fail;
        }
 
        os_memset(&addr, 0, sizeof(addr));
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       addr.sin6_family = AF_INET6;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       addr.sin6_addr = in6addr_any;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+       inet_pton(AF_INET6, "::1", &addr.sin6_addr);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        addr.sin_family = AF_INET;
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
        addr.sin_addr.s_addr = INADDR_ANY;
 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
        addr.sin_addr.s_addr = htonl((127 << 24) | 1);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 try_again:
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       addr.sin6_port = htons(port);
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        addr.sin_port = htons(port);
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
        if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                port--;
                if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
@@ -362,6 +447,9 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        int idx;
        char *sbuf;
        int llen;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       char addr[INET6_ADDRSTRLEN];
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 
        dst = priv->ctrl_dst;
        if (priv->sock < 0 || dst == NULL)
@@ -381,9 +469,16 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        while (dst) {
                next = dst->next;
                if (level >= dst->debug_level) {
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+                       wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
+                                  inet_ntop(AF_INET6, &dst->addr.sin6_addr,
+                                            addr, sizeof(dst->addr)),
+                                  ntohs(dst->addr.sin6_port));
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                        wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
                                   inet_ntoa(dst->addr.sin_addr),
                                   ntohs(dst->addr.sin_port));
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
                        if (sendto(priv->sock, sbuf, llen + len, 0,
                                   (struct sockaddr *) &dst->addr,
                                   sizeof(dst->addr)) < 0) {
index 6684782c4bec4676fb8083ab19adccabaa273a9c..91eea355059d907d089f9c7b3238e4f9b17c9a60 100644 (file)
@@ -192,8 +192,10 @@ CONFIG_SMARTCARD=y
 # Select control interface backend for external programs, e.g, wpa_cli:
 # unix = UNIX domain sockets (default for Linux/*BSD)
 # udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
 # named_pipe = Windows Named Pipe (default for Windows)
 # udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
 # y = use default (backwards compatibility)
 # If this option is commented out, control interface is not included in the
 # build.