diff mbox

[v4,08/29] hostap: add UDP support for ctrl iface

Message ID 1456479524-14185-9-git-send-email-janusz.dziedzic@tieto.com
State Superseded
Headers show

Commit Message

Janusz.Dziedzic@tieto.com Feb. 26, 2016, 9:38 a.m. UTC
Add UDP support for ctrl interface.

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 cli usage:
hostapd_cli -i localhost:8877

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
---
 hostapd/Makefile      |  23 +++-
 hostapd/ctrl_iface.c  | 294 ++++++++++++++++++++++++++++++++++++++++++++++++--
 hostapd/hostapd_cli.c |   5 +
 src/ap/hostapd.c      |   1 +
 4 files changed, 311 insertions(+), 12 deletions(-)
diff mbox

Patch

diff --git a/hostapd/Makefile b/hostapd/Makefile
index d96b007..e2406e4 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -206,12 +206,33 @@  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
+CFLAGS += -DCONFIG_CTRL_IFACE
 
 ifdef CONFIG_IAPP
 CFLAGS += -DCONFIG_IAPP
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 4d90155..89aad34 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -19,6 +19,10 @@ 
 #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"
@@ -52,6 +56,15 @@ 
 
 #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
 
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
@@ -2329,8 +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);
@@ -2343,10 +2357,50 @@  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) {
+		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+			   "drop request");
+		os_free(reply);
+		return;
+	}
+
+	if (hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+			   "request - drop request");
+		os_free(reply);
+		return;
+	}
+
+	if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+			   "drop request");
+		os_free(reply);
+		return;
+	}
+
+	pos = buf + 7 + 2 * COOKIE_LEN;
+	while (*pos == ' ')
+		pos++;
+#endif
+	if (os_strcmp(pos, "PING") == 0)
+		level = MSG_EXCESSIVE;
+
+	reply_len = hostapd_ctrl_iface_receive_process(hapd, pos,
 						       reply, reply_size,
 						       &from, fromlen);
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+done:
+#endif
 	if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
 		   fromlen) < 0) {
 		wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2355,7 +2409,7 @@  static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 	os_free(reply);
 }
 
-
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
 {
 	char *buf;
@@ -2375,7 +2429,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,
 				      enum wpa_msg_type type,
@@ -2387,7 +2441,99 @@  static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
 	hostapd_ctrl_iface_send(hapd, level, type, txt, len);
 }
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+	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
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+	hints.ai_family = AF_INET6;
+#else
+	hints.ai_family = AF_INET;
+#endif
+	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;
+}
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (hapd->ctrl_sock >= 0) {
+		eloop_unregister_read_sock(hapd->ctrl_sock);
+		close(hapd->ctrl_sock);
+		hapd->ctrl_sock = -1;
+	}
+
+	dl_list_for_each_safe(dst, prev, &hapd->ctrl_dst, struct wpa_ctrl_dst, list)
+		os_free(dst);
 
+#ifdef CONFIG_TESTING_OPTIONS
+	l2_packet_deinit(hapd->l2_test);
+	hapd->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+#else
 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
 {
 	struct sockaddr_un addr;
@@ -2579,7 +2725,7 @@  void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
 	hapd->l2_test = NULL;
 #endif /* CONFIG_TESTING_OPTIONS */
 }
-
+#endif /* CONFIG_CTRL_UDP */
 
 static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
 				  char *buf)
@@ -2841,15 +2987,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
 
-	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",
@@ -2872,6 +3021,41 @@  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) {
+		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+			   "drop request");
+		os_free(reply);
+		return;
+	}
+
+	if (hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+			   "request - drop request");
+		os_free(reply);
+		return;
+	}
+
+	if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+			   "drop request");
+		os_free(reply);
+		return;
+	}
+
+	buf = buf + 7 + 2 * COOKIE_LEN;
+	while (*buf == ' ')
+		buf++;
+#endif
+
 	if (os_strncmp(buf, "IFNAME=", 7) == 0) {
 		char *pos = os_strchr(buf + 7, ' ');
 
@@ -2952,7 +3136,7 @@  send_reply:
 	os_free(reply);
 }
 
-
+#ifndef CONFIG_CTRL_IFACE_UDP
 static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
 {
 	char *buf;
@@ -2972,8 +3156,96 @@  static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
 	buf[len - 1] = '\0';
 	return buf;
 }
+#endif
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+	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
+
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+	hints.ai_family = AF_INET6;
+#else
+	hints.ai_family = AF_INET;
+#endif
+	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;
+}
 
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (interface->global_ctrl_sock > 0) {
+		eloop_unregister_read_sock(interface->global_ctrl_sock);
+		close(interface->global_ctrl_sock);
+		interface->global_ctrl_sock = -1;
+	}
 
+	os_free(interface->global_iface_path);
+	interface->global_iface_path = NULL;
+
+	dl_list_for_each_safe(dst, prev, &interface->global_ctrl_dst, struct wpa_ctrl_dst, list)
+		os_free(dst);
+}
+#else
 int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
 {
 	struct sockaddr_un addr;
@@ -3120,7 +3392,7 @@  void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
 	dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst, struct wpa_ctrl_dst, list)
 		os_free(dst);
 }
-
+#endif
 
 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
 				    enum wpa_msg_type type,
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 1787ab3..f8519ac 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -142,6 +142,11 @@  static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
 	if (ifname == NULL)
 		return NULL;
 
+#ifdef CONFIG_CTRL_IFACE_UDP
+	ctrl_conn = wpa_ctrl_open(ifname);
+	return ctrl_conn;
+#endif
+
 	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
 	cfile = malloc(flen);
 	if (cfile == NULL)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index dd2dc17..426456b 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1854,6 +1854,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;
 }