hostapd: Add UDP support for ctrl_iface
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>
Fri, 4 Mar 2016 09:20:24 +0000 (10:20 +0100)
committerJouni Malinen <j@w1.fi>
Sat, 5 Mar 2016 15:44:37 +0000 (17:44 +0200)
Add UDP support for ctrl_iface:

New config option could be set:
CONFIG_CTRL_IFACE=udp
CONFIG_CTRL_IFACE=udp-remote
CONFIG_CTRL_IFACE=udp6
CONFIG_CTRL_IFACE=udp6-remote

And hostapd_cli usage:
hostapd_cli -i localhost:8877

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
hostapd/Makefile
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/hostapd.c

index d96b007..e0d25a5 100644 (file)
@@ -206,12 +206,35 @@ endif
 ifdef CONFIG_NO_CTRL_IFACE
 CFLAGS += -DCONFIG_NO_CTRL_IFACE
 else
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+else
+ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
+else
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+endif
+endif
+endif
 OBJS += ../src/common/ctrl_iface_common.o
 OBJS += ctrl_iface.o
 OBJS += ../src/ap/ctrl_iface_ap.o
 endif
 
-CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+ifndef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_CTRL_IFACE
+endif
 
 ifdef CONFIG_IAPP
 CFLAGS += -DCONFIG_IAPP
index ae95fd6..237f02c 100644 (file)
 #include <sys/stat.h>
 #include <stddef.h>
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/version.h"
 
 #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define COOKIE_LEN 8
+static unsigned char cookie[COOKIE_LEN];
+static unsigned char gcookie[COOKIE_LEN];
+#define HOSTAPD_CTRL_IFACE_PORT                8877
+#define HOSTAPD_CTRL_IFACE_PORT_LIMIT  50
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT         8878
+#define HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT   50
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
                                    enum wpa_msg_type type,
@@ -2316,10 +2329,13 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        int res;
        struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
-       char *reply;
+       char *reply, *pos = buf;
        const int reply_size = 4096;
        int reply_len;
        int level = MSG_DEBUG;
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
        res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
@@ -2329,9 +2345,6 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                return;
        }
        buf[res] = '\0';
-       if (os_strcmp(buf, "PING") == 0)
-               level = MSG_EXCESSIVE;
-       wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
 
        reply = os_malloc(reply_size);
        if (reply == NULL) {
@@ -2343,10 +2356,46 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                return;
        }
 
-       reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
+#ifdef CONFIG_CTRL_IFACE_UDP
+       if (os_strcmp(buf, "GET_COOKIE") == 0) {
+               os_memcpy(reply, "COOKIE=", 7);
+               wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+                                cookie, COOKIE_LEN);
+               reply_len = 7 + 2 * COOKIE_LEN;
+               goto done;
+       }
+
+       if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+           hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: No cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       pos = buf + 7 + 2 * COOKIE_LEN;
+       while (*pos == ' ')
+               pos++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+       if (os_strcmp(pos, "PING") == 0)
+               level = MSG_EXCESSIVE;
+       wpa_hexdump_ascii(level, "RX ctrl_iface", pos, res);
+
+       reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
                                                       reply, reply_size,
                                                       &from, fromlen);
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+done:
+#endif /* CONFIG_CTRL_IFACE_UDP */
        if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
                   fromlen) < 0) {
                wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2356,6 +2405,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 }
 
 
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
 {
        char *buf;
@@ -2375,6 +2425,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
        buf[len - 1] = '\0';
        return buf;
 }
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 
 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
@@ -2390,6 +2441,81 @@ static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
 
 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
 {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       int port = HOSTAPD_CTRL_IFACE_PORT;
+       char p[32] = { 0 };
+       struct addrinfo hints = { 0 }, *res, *saveres;
+       int n;
+
+       if (hapd->ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
+
+       if (hapd->conf->ctrl_interface == NULL)
+               return 0;
+
+       dl_list_init(&hapd->ctrl_dst);
+       hapd->ctrl_sock = -1;
+       os_get_random(cookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+       os_snprintf(p, sizeof(p), "%d", port);
+       n = getaddrinfo(NULL, p, &hints, &res);
+       if (n) {
+               wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+               goto fail;
+       }
+
+       saveres = res;
+       hapd->ctrl_sock = socket(res->ai_family, res->ai_socktype,
+                                res->ai_protocol);
+       if (hapd->ctrl_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       if (bind(hapd->ctrl_sock, res->ai_addr, res->ai_addrlen) < 0) {
+               port--;
+               if ((HOSTAPD_CTRL_IFACE_PORT - port) <
+                   HOSTAPD_CTRL_IFACE_PORT_LIMIT)
+                       goto try_again;
+               wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       freeaddrinfo(saveres);
+
+       wpa_printf(MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+
+       if (eloop_register_read_sock(hapd->ctrl_sock,
+                                    hostapd_ctrl_iface_receive, hapd, NULL) <
+           0) {
+               hostapd_ctrl_iface_deinit(hapd);
+               return -1;
+       }
+
+       hapd->msg_ctx = hapd;
+       wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+       return 0;
+
+fail:
+       if (hapd->ctrl_sock >= 0)
+               close(hapd->ctrl_sock);
+       return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
        struct sockaddr_un addr;
        int s = -1;
        char *fname = NULL;
@@ -2540,6 +2666,7 @@ fail:
                os_free(fname);
        }
        return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
@@ -2548,10 +2675,14 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
        struct wpa_ctrl_dst *dst, *prev;
 
        if (hapd->ctrl_sock > -1) {
+#ifndef CONFIG_CTRL_IFACE_UDP
                char *fname;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
                eloop_unregister_read_sock(hapd->ctrl_sock);
                close(hapd->ctrl_sock);
                hapd->ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
                fname = hostapd_ctrl_iface_path(hapd);
                if (fname)
                        unlink(fname);
@@ -2570,6 +2701,7 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
                                           strerror(errno));
                        }
                }
+#endif /* !CONFIG_CTRL_IFACE_UDP */
        }
 
        dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst,
@@ -2843,15 +2975,18 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
                                              void *sock_ctx)
 {
        void *interfaces = eloop_ctx;
-       char buf[256];
+       char buffer[256], *buf = buffer;
        int res;
        struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        char *reply;
        int reply_len;
        const int reply_size = 4096;
+#ifdef CONFIG_CTRL_IFACE_UDP
+       unsigned char lcookie[COOKIE_LEN];
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
-       res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+       res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0,
                       (struct sockaddr *) &from, &fromlen);
        if (res < 0) {
                wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
@@ -2874,6 +3009,35 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
        os_memcpy(reply, "OK\n", 3);
        reply_len = 3;
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+       if (os_strcmp(buf, "GET_COOKIE") == 0) {
+               os_memcpy(reply, "COOKIE=", 7);
+               wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+                                gcookie, COOKIE_LEN);
+               reply_len = 7 + 2 * COOKIE_LEN;
+               goto send_reply;
+       }
+
+       if (os_strncmp(buf, "COOKIE=", 7) != 0 ||
+           hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: No cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "CTRL: Invalid cookie in the request - drop request");
+               os_free(reply);
+               return;
+       }
+
+       buf += 7 + 2 * COOKIE_LEN;
+       while (*buf == ' ')
+               buf++;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
        if (os_strncmp(buf, "IFNAME=", 7) == 0) {
                char *pos = os_strchr(buf + 7, ' ');
 
@@ -2955,6 +3119,7 @@ send_reply:
 }
 
 
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
 {
        char *buf;
@@ -2974,10 +3139,84 @@ static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
        buf[len - 1] = '\0';
        return buf;
 }
+#endif /* CONFIG_CTRL_IFACE_UDP */
 
 
 int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
 {
+#ifdef CONFIG_CTRL_IFACE_UDP
+       int port = HOSTAPD_GLOBAL_CTRL_IFACE_PORT;
+       char p[32] = { 0 };
+       struct addrinfo hints = { 0 }, *res, *saveres;
+       int n;
+
+       if (interface->global_ctrl_sock > -1) {
+               wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+               return 0;
+       }
+
+       if (interface->global_iface_path == NULL)
+               return 0;
+
+       dl_list_init(&interface->global_ctrl_dst);
+       interface->global_ctrl_sock = -1;
+       os_get_random(gcookie, COOKIE_LEN);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+       hints.ai_flags = AI_PASSIVE;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+       hints.ai_family = AF_INET6;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_family = AF_INET;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
+       hints.ai_socktype = SOCK_DGRAM;
+
+try_again:
+       os_snprintf(p, sizeof(p), "%d", port);
+       n = getaddrinfo(NULL, p, &hints, &res);
+       if (n) {
+               wpa_printf(MSG_ERROR, "getaddrinfo(): %s", gai_strerror(n));
+               goto fail;
+       }
+
+       saveres = res;
+       interface->global_ctrl_sock = socket(res->ai_family, res->ai_socktype,
+                                            res->ai_protocol);
+       if (interface->global_ctrl_sock < 0) {
+               wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       if (bind(interface->global_ctrl_sock, res->ai_addr, res->ai_addrlen) <
+           0) {
+               port++;
+               if ((port - HOSTAPD_GLOBAL_CTRL_IFACE_PORT) <
+                   HOSTAPD_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+                       goto try_again;
+               wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
+               goto fail;
+       }
+
+       freeaddrinfo(saveres);
+
+       wpa_printf(MSG_DEBUG, "global ctrl_iface_init UDP port: %d", port);
+
+       if (eloop_register_read_sock(interface->global_ctrl_sock,
+                                    hostapd_global_ctrl_iface_receive,
+                                    interface, NULL) < 0) {
+               hostapd_global_ctrl_iface_deinit(interface);
+               return -1;
+       }
+
+       return 0;
+
+fail:
+       if (interface->global_ctrl_sock >= 0)
+               close(interface->global_ctrl_sock);
+       return -1;
+#else /* CONFIG_CTRL_IFACE_UDP */
        struct sockaddr_un addr;
        int s = -1;
        char *fname = NULL;
@@ -3083,18 +3322,22 @@ fail:
                os_free(fname);
        }
        return -1;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
 void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *fname = NULL;
+#endif /* CONFIG_CTRL_IFACE_UDP */
        struct wpa_ctrl_dst *dst, *prev;
 
        if (interfaces->global_ctrl_sock > -1) {
                eloop_unregister_read_sock(interfaces->global_ctrl_sock);
                close(interfaces->global_ctrl_sock);
                interfaces->global_ctrl_sock = -1;
+#ifndef CONFIG_CTRL_IFACE_UDP
                fname = hostapd_global_ctrl_iface_path(interfaces);
                if (fname) {
                        unlink(fname);
@@ -3114,6 +3357,7 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
                                           strerror(errno));
                        }
                }
+#endif /* CONFIG_CTRL_IFACE_UDP */
        }
 
        os_free(interfaces->global_iface_path);
index 1787ab3..fc8a72e 100644 (file)
@@ -16,6 +16,7 @@
 #include "utils/edit.h"
 #include "common/version.h"
 
+#ifndef CONFIG_NO_CTRL_IFACE
 
 static const char *const hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
@@ -136,12 +137,18 @@ static void usage(void)
 
 static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
 {
+#ifndef CONFIG_CTRL_IFACE_UDP
        char *cfile;
        int flen;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
 
        if (ifname == NULL)
                return NULL;
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+       ctrl_conn = wpa_ctrl_open(ifname);
+       return ctrl_conn;
+#else /* CONFIG_CTRL_IFACE_UDP */
        flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
        cfile = malloc(flen);
        if (cfile == NULL)
@@ -158,6 +165,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
        ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
        free(cfile);
        return ctrl_conn;
+#endif /* CONFIG_CTRL_IFACE_UDP */
 }
 
 
@@ -1514,3 +1522,12 @@ int main(int argc, char *argv[])
        hostapd_cli_cleanup();
        return 0;
 }
+
+#else /* CONFIG_NO_CTRL_IFACE */
+
+int main(int argc, char *argv[])
+{
+       return -1;
+}
+
+#endif /* CONFIG_NO_CTRL_IFACE */
index 303786b..9aaa9a6 100644 (file)
@@ -1859,6 +1859,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
        hapd->iface = hapd_iface;
        hapd->driver = hapd->iconf->driver;
        hapd->ctrl_sock = -1;
+       dl_list_init(&hapd->ctrl_dst);
 
        return hapd;
 }