diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2016-03-10 20:05:50 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-03-10 20:05:50 +0000 |
commit | f9e47b690c718a1837bcc7b0e048ed0d196250af (patch) | |
tree | d15ce782dc7b16684cba9e5d22b834a7d4e7fe25 | |
parent | fed5ddb554a3f3bc71827d2df722b97a57f483f4 (diff) | |
parent | 31a29cc7ed87b62465c7e01f03484f4643d12309 (diff) | |
download | android_external_wpa_supplicant_8-f9e47b690c718a1837bcc7b0e048ed0d196250af.tar.gz android_external_wpa_supplicant_8-f9e47b690c718a1837bcc7b0e048ed0d196250af.tar.bz2 android_external_wpa_supplicant_8-f9e47b690c718a1837bcc7b0e048ed0d196250af.zip |
Cumulative patch from commit f2d6c17aa0f9107a0e8092238b849461447cdd21
am: 31a29cc7ed
* commit '31a29cc7ed87b62465c7e01f03484f4643d12309':
Cumulative patch from commit f2d6c17aa0f9107a0e8092238b849461447cdd21
37 files changed, 963 insertions, 306 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 65ec4fd0..96500b6a 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -187,6 +187,7 @@ endif ifdef CONFIG_NO_CTRL_IFACE L_CFLAGS += -DCONFIG_NO_CTRL_IFACE else +OBJS += src/common/ctrl_iface_common.c OBJS += ctrl_iface.c OBJS += src/ap/ctrl_iface_ap.c endif diff --git a/hostapd/Makefile b/hostapd/Makefile index 62f3b324..e0d25a53 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -206,11 +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 diff --git a/hostapd/config_file.c b/hostapd/config_file.c index a157a74d..6f525d92 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2826,6 +2826,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line); return 1; } + } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) { + conf->use_driver_iface_addr = atoi(pos); #ifdef CONFIG_IEEE80211W } else if (os_strcmp(buf, "ieee80211w") == 0) { bss->ieee80211w = atoi(pos); diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index c0008fdf..33819ab8 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -19,10 +19,15 @@ #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" #include "common/ieee802_11_defs.h" +#include "common/ctrl_iface_common.h" #include "crypto/tls.h" #include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" @@ -51,14 +56,15 @@ #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256 -struct wpa_ctrl_dst { - struct wpa_ctrl_dst *next; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - +#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, @@ -66,81 +72,27 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = hapd->ctrl_dst; - hapd->ctrl_dst = dst; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - return 0; + return ctrl_iface_attach(&hapd->ctrl_dst, from, fromlen); } static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - if (prev == NULL) - hapd->ctrl_dst = dst->next; - else - prev->next = dst->next; - os_free(dst); - return 0; - } - prev = dst; - dst = dst->next; - } - return -1; + return ctrl_iface_detach(&hapd->ctrl_dst, from, fromlen); } static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, char *level) { - struct wpa_ctrl_dst *dst; - - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - - dst = hapd->ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " - "level", (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - dst->debug_level = atoi(level); - return 0; - } - dst = dst->next; - } - - return -1; + return ctrl_iface_level(&hapd->ctrl_dst, from, fromlen, level); } @@ -2122,7 +2074,7 @@ static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd, static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, char *buf, char *reply, int reply_size, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { int reply_len, res; @@ -2375,12 +2327,15 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, struct hostapd_data *hapd = eloop_ctx; char buf[4096]; int res; - struct sockaddr_un from; + 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); @@ -2390,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) { @@ -2404,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", @@ -2417,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; @@ -2436,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, @@ -2451,6 +2441,99 @@ 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 }; + char port_str[40], *tmp; + char *pos; + 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; + + pos = os_strstr(hapd->conf->ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port"); + goto fail; + } + } + + 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 && !pos) + goto try_again; + wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); + goto fail; + } + + freeaddrinfo(saveres); + + os_snprintf(port_str, sizeof(port_str), "udp:%d", port); + tmp = os_strdup(port_str); + if (tmp) { + os_free(hapd->conf->ctrl_interface); + hapd->conf->ctrl_interface = tmp; + } + 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; @@ -2460,6 +2543,8 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) return 0; } + dl_list_init(&hapd->ctrl_dst); + if (hapd->conf->ctrl_interface == NULL) return 0; @@ -2599,6 +2684,7 @@ fail: os_free(fname); } return -1; +#endif /* CONFIG_CTRL_IFACE_UDP */ } @@ -2607,10 +2693,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); @@ -2629,15 +2719,12 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) strerror(errno)); } } +#endif /* !CONFIG_CTRL_IFACE_UDP */ } - dst = hapd->ctrl_dst; - hapd->ctrl_dst = NULL; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + 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); @@ -2669,54 +2756,18 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dst->next = interfaces->global_ctrl_dst; - interfaces->global_ctrl_dst = dst; - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)", - from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - return 0; + return ctrl_iface_attach(&interfaces->global_ctrl_dst, from, fromlen); } static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst, *prev = NULL; - - dst = interfaces->global_ctrl_dst; - while (dst) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - wpa_hexdump(MSG_DEBUG, - "CTRL_IFACE monitor detached (global)", - from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - if (prev == NULL) - interfaces->global_ctrl_dst = dst->next; - else - prev->next = dst->next; - os_free(dst); - return 0; - } - prev = dst; - dst = dst->next; - } - return -1; + return ctrl_iface_detach(&interfaces->global_ctrl_dst, from, fromlen); } @@ -2870,6 +2921,51 @@ error_return: static int +hostapd_global_ctrl_iface_interfaces(struct hapd_interfaces *interfaces, + const char *input, + char *reply, int reply_size) +{ + size_t i, j; + int res; + char *pos, *end; + struct hostapd_iface *iface; + int show_ctrl = 0; + + if (input) + show_ctrl = !!os_strstr(input, "ctrl"); + + pos = reply; + end = reply + reply_size; + + for (i = 0; i < interfaces->count; i++) { + iface = interfaces->iface[i]; + + for (j = 0; j < iface->num_bss; j++) { + struct hostapd_bss_config *conf; + + conf = iface->conf->bss[j]; + if (show_ctrl) + res = os_snprintf(pos, end - pos, + "%s ctrl_iface=%s\n", + conf->iface, + conf->ctrl_interface ? + conf->ctrl_interface : "N/A"); + else + res = os_snprintf(pos, end - pos, "%s\n", + conf->iface); + if (os_snprintf_error(end - pos, res)) { + *pos = '\0'; + return pos - reply; + } + pos += res; + } + } + + return pos - reply; +} + + +static int hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces, char *cmd) { @@ -2918,7 +3014,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces, const char *ifname, char *buf, char *reply, int reply_size, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { struct hostapd_data *hapd; @@ -2942,15 +3038,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_un from; + 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", @@ -2973,6 +3072,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, ' '); @@ -3033,6 +3161,11 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len = os_snprintf(reply, reply_size, "OK\n"); else reply_len = -1; + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { + reply_len = hostapd_global_ctrl_iface_interfaces( + interfaces, buf + 10, reply, sizeof(buffer)); + } else if (os_strcmp(buf, "TERMINATE") == 0) { + eloop_terminate(); } else { wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " "ignored"); @@ -3054,6 +3187,7 @@ send_reply: } +#ifndef CONFIG_CTRL_IFACE_UDP static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) { char *buf; @@ -3073,10 +3207,95 @@ 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 }; + char *pos; + 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; + + pos = os_strstr(interface->global_iface_path, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port"); + goto fail; + } + } + + 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 && !pos) + 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; @@ -3182,18 +3401,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); @@ -3213,18 +3436,15 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) strerror(errno)); } } +#endif /* CONFIG_CTRL_IFACE_UDP */ } os_free(interfaces->global_iface_path); interfaces->global_iface_path = NULL; - dst = interfaces->global_ctrl_dst; - interfaces->global_ctrl_dst = NULL; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + dl_list_for_each_safe(dst, prev, &interfaces->global_ctrl_dst, + struct wpa_ctrl_dst, list) + os_free(dst); } @@ -3233,6 +3453,7 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; + struct dl_list *ctrl_dst; struct msghdr msg; int idx; struct iovec io[2]; @@ -3241,13 +3462,13 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, if (type != WPA_MSG_ONLY_GLOBAL) { s = hapd->ctrl_sock; - dst = hapd->ctrl_dst; + ctrl_dst = &hapd->ctrl_dst; } else { s = hapd->iface->interfaces->global_ctrl_sock; - dst = hapd->iface->interfaces->global_ctrl_dst; + ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst; } - if (s < 0 || dst == NULL) + if (s < 0 || dl_list_empty(ctrl_dst)) return; os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); @@ -3260,12 +3481,10 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, msg.msg_iovlen = 2; idx = 0; - while (dst) { - next = dst->next; + dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { if (level >= dst->debug_level) { - wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor send", + &dst->addr, dst->addrlen); msg.msg_name = &dst->addr; msg.msg_namelen = dst->addrlen; if (sendmsg(s, &msg, 0) < 0) { @@ -3289,7 +3508,6 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, dst->errors = 0; } idx++; - dst = next; } } diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 3d5c5e2c..d943a43d 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1926,6 +1926,10 @@ own_ip_addr=127.0.0.1 # - is not the same as the MAC address of the radio # - is not the same as any other explicitly specified BSSID # +# Alternatively, the 'use_driver_iface_addr' parameter can be used to request +# hostapd to use the driver auto-generated interface address (e.g., to use the +# exact MAC addresses allocated to the device). +# # Not all drivers support multiple BSSes. The exact mechanism for determining # the driver capabilities is driver specific. With the current (i.e., a recent # kernel) drivers using nl80211, this information can be checked with "iw list" diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 1787ab38..fc8a72e3 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -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 */ diff --git a/hostapd/main.c b/hostapd/main.c index 1b9002cf..25dc20b4 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -474,9 +474,8 @@ static void usage(void) static const char * hostapd_msg_ifname_cb(void *ctx) { struct hostapd_data *hapd = ctx; - if (hapd && hapd->iconf && hapd->iconf->bss && - hapd->iconf->num_bss > 0 && hapd->iconf->bss[0]) - return hapd->iconf->bss[0]->iface; + if (hapd && hapd->conf) + return hapd->conf->iface; return NULL; } @@ -484,11 +483,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx) static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, const char *path) { +#ifndef CONFIG_CTRL_IFACE_UDP char *pos; +#endif /* !CONFIG_CTRL_IFACE_UDP */ + os_free(interfaces->global_iface_path); interfaces->global_iface_path = os_strdup(path); if (interfaces->global_iface_path == NULL) return -1; + +#ifndef CONFIG_CTRL_IFACE_UDP pos = os_strrchr(interfaces->global_iface_path, '/'); if (pos == NULL) { wpa_printf(MSG_ERROR, "No '/' in the global control interface " @@ -500,6 +504,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, *pos = '\0'; interfaces->global_iface_name = pos + 1; +#endif /* !CONFIG_CTRL_IFACE_UDP */ return 0; } @@ -593,7 +598,7 @@ int main(int argc, char *argv[]) interfaces.global_iface_path = NULL; interfaces.global_iface_name = NULL; interfaces.global_ctrl_sock = -1; - interfaces.global_ctrl_dst = NULL; + dl_list_init(&interfaces.global_ctrl_dst); for (;;) { c = getopt(argc, argv, "b:Bde:f:hKP:STtu:vg:G:"); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index f19cac6c..2d07c67b 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -665,6 +665,9 @@ struct hostapd_config { u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; + /* Use driver-generated interface addresses when adding multiple BSSs */ + u8 use_driver_iface_addr; + #ifdef CONFIG_FST struct fst_iface_cfg fst_cfg; #endif /* CONFIG_FST */ diff --git a/src/ap/dfs.c b/src/ap/dfs.c index bda23f0a..47adba7e 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -704,7 +704,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) skip_radar); if (!channel) { wpa_printf(MSG_ERROR, "could not get valid channel"); - return -1; + hostapd_set_state(iface, HAPD_IFACE_DFS); + return 0; } iface->freq = channel->freq; @@ -793,7 +794,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) if (!channel) { wpa_printf(MSG_ERROR, "No valid channel available"); - hostapd_setup_interface_complete(iface, err); return err; } @@ -858,8 +858,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) &vht_oper_centr_freq_seg1_idx, skip_radar); if (!channel) { - /* FIXME: Wait for channel(s) to become available */ - hostapd_disable_iface(iface); + wpa_printf(MSG_INFO, + "%s: no DFS channels left, waiting for NOP to finish", + __func__); return err; } @@ -982,6 +983,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, /* TODO add correct implementation here */ set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); + + /* Handle cases where all channels were initially unavailable */ + if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) + hostapd_handle_dfs(iface); + return 0; } diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 303786b4..55ca9e8f 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -512,6 +512,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) if (hostapd_drv_none(hapd)) return 0; + if (iface->conf->use_driver_iface_addr) + return 0; + /* Generate BSSID mask that is large enough to cover the BSSIDs. */ /* Determine the bits necessary to cover the number of BSSIDs. */ @@ -905,12 +908,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hapd->started = 1; if (!first || first == -1) { - if (is_zero_ether_addr(conf->bssid)) { - /* Allocate the next available BSSID. */ - do { - inc_byte_array(hapd->own_addr, ETH_ALEN); - } while (mac_in_conf(hapd->iconf, hapd->own_addr)); - } else { + u8 *addr = hapd->own_addr; + + if (!is_zero_ether_addr(conf->bssid)) { /* Allocate the configured BSSID. */ os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); @@ -922,11 +922,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) "the radio", conf->iface); return -1; } + } else if (hapd->iconf->use_driver_iface_addr) { + addr = NULL; + } else { + /* Allocate the next available BSSID. */ + do { + inc_byte_array(hapd->own_addr, ETH_ALEN); + } while (mac_in_conf(hapd->iconf, hapd->own_addr)); } hapd->interface_added = 1; if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, - conf->iface, hapd->own_addr, hapd, + conf->iface, addr, hapd, &hapd->drv_priv, force_ifname, if_addr, conf->bridge[0] ? conf->bridge : NULL, first == -1)) { @@ -935,6 +942,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hapd->interface_added = 0; return -1; } + + if (!addr) + os_memcpy(hapd->own_addr, if_addr, ETH_ALEN); } if (conf->wmm_enabled < 0) @@ -1859,6 +1869,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; } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index d6d96dbc..60516aec 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -41,7 +41,7 @@ struct hapd_interfaces { size_t count; int global_ctrl_sock; - struct wpa_ctrl_dst *global_ctrl_dst; + struct dl_list global_ctrl_dst; char *global_iface_path; char *global_iface_name; #ifndef CONFIG_NATIVE_WINDOWS @@ -155,7 +155,7 @@ struct hostapd_data { int tkip_countermeasures; int ctrl_sock; - struct wpa_ctrl_dst *ctrl_dst; + struct dl_list ctrl_dst; void *ssl_ctx; void *eap_sim_db_priv; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index b36e68dd..134ae062 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2782,6 +2782,25 @@ static void handle_assoc_cb(struct hostapd_data *hapd, wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); + + if (sta->pending_eapol_rx) { + struct os_reltime now, age; + + os_get_reltime(&now); + os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age); + if (age.sec == 0 && age.usec < 200000) { + wpa_printf(MSG_DEBUG, + "Process pending EAPOL frame that was received from " MACSTR " just before association notification", + MAC2STR(sta->addr)); + ieee802_1x_receive( + hapd, mgmt->da, + wpabuf_head(sta->pending_eapol_rx->buf), + wpabuf_len(sta->pending_eapol_rx->buf)); + } + wpabuf_free(sta->pending_eapol_rx->buf); + os_free(sta->pending_eapol_rx); + sta->pending_eapol_rx = NULL; + } } diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index c774d5cc..42b02995 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -861,6 +861,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) } +static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, + size_t len) +{ + if (sta->pending_eapol_rx) { + wpabuf_free(sta->pending_eapol_rx->buf); + } else { + sta->pending_eapol_rx = + os_malloc(sizeof(*sta->pending_eapol_rx)); + if (!sta->pending_eapol_rx) + return; + } + + sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); + if (!sta->pending_eapol_rx->buf) { + os_free(sta->pending_eapol_rx); + sta->pending_eapol_rx = NULL; + return; + } + + os_get_reltime(&sta->pending_eapol_rx->rx_time); +} + + /** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant * @hapd: hostapd BSS data @@ -891,6 +914,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " "associated/Pre-authenticating STA"); + + if (sta && (sta->flags & WLAN_STA_AUTH)) { + wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR + " for later use", MAC2STR(sta->addr)); + ieee802_1x_save_eapol(sta, buf, len); + } + return; } @@ -1183,6 +1213,12 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); #endif /* CONFIG_HS20 */ + if (sta->pending_eapol_rx) { + wpabuf_free(sta->pending_eapol_rx->buf); + os_free(sta->pending_eapol_rx); + sta->pending_eapol_rx = NULL; + } + if (sm == NULL) return; diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index cd89e998..70a59ccd 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -56,6 +56,11 @@ struct mbo_non_pref_chan_info { u8 channels[]; }; +struct pending_eapol_rx { + struct wpabuf *buf; + struct os_reltime rx_time; +}; + struct sta_info { struct sta_info *next; /* next entry in sta list */ struct sta_info *hnext; /* next entry in hash table list */ @@ -113,6 +118,8 @@ struct sta_info { /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; + struct pending_eapol_rx *pending_eapol_rx; + u64 acct_session_id; struct os_reltime acct_session_start; int acct_session_started; diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c new file mode 100644 index 00000000..acd24100 --- /dev/null +++ b/src/common/ctrl_iface_common.c @@ -0,0 +1,152 @@ +/* + * Common hostapd/wpa_supplicant ctrl iface code. + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2015, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include <netdb.h> +#include <sys/un.h> + +#include "utils/common.h" +#include "ctrl_iface_common.h" + +static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len, + struct sockaddr_storage *b, socklen_t b_len) +{ + struct sockaddr_in *in_a, *in_b; + struct sockaddr_in6 *in6_a, *in6_b; + struct sockaddr_un *u_a, *u_b; + + if (a->ss_family != b->ss_family) + return 1; + + switch (a->ss_family) { + case AF_INET: + in_a = (struct sockaddr_in *) a; + in_b = (struct sockaddr_in *) b; + + if (in_a->sin_port != in_b->sin_port) + return 1; + if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr) + return 1; + break; + case AF_INET6: + in6_a = (struct sockaddr_in6 *) a; + in6_b = (struct sockaddr_in6 *) b; + + if (in6_a->sin6_port != in6_b->sin6_port) + return 1; + if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr, + sizeof(in6_a->sin6_addr)) != 0) + return 1; + break; + case AF_UNIX: + u_a = (struct sockaddr_un *) a; + u_b = (struct sockaddr_un *) b; + + if (a_len != b_len || + os_memcmp(u_a->sun_path, u_b->sun_path, + a_len - offsetof(struct sockaddr_un, sun_path)) + != 0) + return 1; + break; + default: + return 1; + } + + return 0; +} + + +void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock, + socklen_t socklen) +{ + char host[NI_MAXHOST] = { 0 }; + char service[NI_MAXSERV] = { 0 }; + char addr_txt[200]; + + switch (sock->ss_family) { + case AF_INET: + case AF_INET6: + getnameinfo((struct sockaddr *) sock, socklen, + host, sizeof(host), + service, sizeof(service), + NI_NUMERICHOST); + + wpa_printf(level, "%s %s:%s", msg, host, service); + break; + case AF_UNIX: + printf_encode(addr_txt, sizeof(addr_txt), + (u8 *) ((struct sockaddr_un *) sock)->sun_path, + socklen - offsetof(struct sockaddr_un, sun_path)); + wpa_printf(level, "%s %s", msg, addr_txt); + break; + default: + wpa_printf(level, "%s", msg); + break; + } +} + + +int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dst = os_zalloc(sizeof(*dst)); + if (dst == NULL) + return -1; + os_memcpy(&dst->addr, from, fromlen); + dst->addrlen = fromlen; + dst->debug_level = MSG_INFO; + dl_list_add(ctrl_dst, &dst->list); + + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen); + return 0; +} + + +int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen) +{ + struct wpa_ctrl_dst *dst; + + dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { + if (!sockaddr_compare(from, fromlen, + &dst->addr, dst->addrlen)) { + sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached", + from, fromlen); + dl_list_del(&dst->list); + os_free(dst); + return 0; + } + } + + return -1; +} + + +int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen, const char *level) +{ + struct wpa_ctrl_dst *dst; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); + + dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { + if (!sockaddr_compare(from, fromlen, + &dst->addr, dst->addrlen)) { + sockaddr_print(MSG_DEBUG, + "CTRL_IFACE changed monitor level", + from, fromlen); + dst->debug_level = atoi(level); + return 0; + } + } + + return -1; +} diff --git a/src/common/ctrl_iface_common.h b/src/common/ctrl_iface_common.h new file mode 100644 index 00000000..0b6e3e74 --- /dev/null +++ b/src/common/ctrl_iface_common.h @@ -0,0 +1,38 @@ +/* + * Common hostapd/wpa_supplicant ctrl iface code. + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> + * Copyright (c) 2015, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#ifndef CONTROL_IFACE_COMMON_H +#define CONTROL_IFACE_COMMON_H + +#include "utils/list.h" + +/** + * struct wpa_ctrl_dst - Data structure of control interface monitors + * + * This structure is used to store information about registered control + * interface monitors into struct wpa_supplicant. + */ +struct wpa_ctrl_dst { + struct dl_list list; + struct sockaddr_storage addr; + socklen_t addrlen; + int debug_level; + int errors; +}; + +void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock, + socklen_t socklen); + +int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen); +int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen); +int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from, + socklen_t fromlen, const char *level); + +#endif /* CONTROL_IFACE_COMMON_H */ diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index a3ee91d8..f3d185ea 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -162,6 +162,7 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109, /* 110..114 - reserved for QCA */ QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115, + /* 116..118 - reserved for QCA */ }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 570dee66..5fb6652a 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -5912,6 +5912,14 @@ static void *i802_init(struct hostapd_data *hapd, params->ifname, master_ifname); /* start listening for EAPOL on the master interface */ add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex); + + /* check if master itself is under bridge */ + if (linux_br_get(master_ifname, master_ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s", + master_ifname); + br_ifindex = if_nametoindex(master_ifname); + os_strlcpy(bss->brname, master_ifname, IFNAMSIZ); + } } else { master_ifname[0] = '\0'; } diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c index e0c055f0..d6157b17 100644 --- a/src/fst/fst_group.c +++ b/src/fst/fst_group.c @@ -220,7 +220,7 @@ fst_group_get_new_iface_by_mbie_and_band_id(struct fst_group *g, if (peer_addr && fst_iface_is_connected(iface, peer_addr, - TRUE) && + FALSE) && band_id == fst_iface_get_band_id(iface)) { os_memcpy(iface_peer_addr, peer_addr, ETH_ALEN); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index fe0096f1..9f0b3f3d 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -1268,6 +1268,11 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, dev->client_timeout = msg.config_timeout[1]; } + if (msg.wfd_subelems) { + wpabuf_free(dev->info.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); + } + if (!msg.operating_channel && !go) { /* * Note: P2P Client may omit Operating Channel attribute to diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index e6535d41..93a0535f 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -1349,6 +1349,9 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, " with no pending request", MAC2STR(sa)); p2p_parse_free(&msg); return; + } else if (msg.wfd_subelems) { + wpabuf_free(dev->info.wfd_subelems); + dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } if (dev->dialog_token != msg.dialog_token) { diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c index 2ef4c511..a8bc5ba7 100644 --- a/src/p2p/p2p_sd.c +++ b/src/p2p/p2p_sd.c @@ -425,9 +425,16 @@ void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs) { struct wpabuf *resp; + size_t max_len; + + /* + * In the 60 GHz, we have a smaller maximum frame length for management + * frames. + */ + max_len = (freq > 56160) ? 928 : 1400; /* TODO: fix the length limit to match with the maximum frame length */ - if (wpabuf_len(resp_tlvs) > 1400) { + if (wpabuf_len(resp_tlvs) > max_len) { p2p_dbg(p2p, "SD response long enough to require fragmentation"); if (p2p->sd_resp) { /* @@ -614,7 +621,7 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, { struct wpabuf *resp; u8 dialog_token; - size_t frag_len; + size_t frag_len, max_len; int more = 0; wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len); @@ -638,9 +645,14 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, return; } + /* + * In the 60 GHz, we have a smaller maximum frame length for management + * frames. + */ + max_len = (rx_freq > 56160) ? 928 : 1400; frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos; - if (frag_len > 1400) { - frag_len = 1400; + if (frag_len > max_len) { + frag_len = max_len; more = 1; } resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS, diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 8f4cc9cb..4f0319ef 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -1291,6 +1291,7 @@ endif L_CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += src/common/ctrl_iface_common.c endif ifeq ($(CONFIG_CTRL_IFACE), udp) L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 28ae1728..8fa2b5ac 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1335,6 +1335,7 @@ endif CFLAGS += -DCONFIG_CTRL_IFACE ifeq ($(CONFIG_CTRL_IFACE), unix) CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += ../src/common/ctrl_iface_common.o endif ifeq ($(CONFIG_CTRL_IFACE), udp) CFLAGS += -DCONFIG_CTRL_IFACE_UDP diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index b8cf2091..23ac7fa0 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -640,12 +640,17 @@ p2p_set managed <0/1> Disable/enable managed P2P Device operations. This is disabled by default. -p2p_set listen_channel <1/6/11> +p2p_set listen_channel <channel> [<op_class>] Set P2P Listen channel. This is mainly meant for testing purposes and changing the Listen channel during normal operations can result in protocol failures. +When specifying a social channel on the 2.4 GHz band (1/6/11) there is +no need to specify the operating class since it defaults to 81. When +specifying a social channel on the 60 GHz band (2), specify the 60 GHz +operating class (180). + p2p_set ssid_postfix <postfix> Set postfix string to be added to the automatically generated P2P SSID diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index f585b926..4e169871 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -55,6 +55,7 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len); static int * freq_range_to_channel_list(struct wpa_supplicant *wpa_s, char *val); @@ -5918,8 +5919,15 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) } if (os_strcmp(cmd, "listen_channel") == 0) { - return p2p_set_listen_channel(wpa_s->global->p2p, 81, - atoi(param), 1); + char *pos; + u8 channel, op_class; + + channel = atoi(param); + pos = os_strchr(param, ' '); + op_class = pos ? atoi(pos) : 81; + + return p2p_set_listen_channel(wpa_s->global->p2p, op_class, + channel, 1); } if (os_strcmp(cmd, "ssid_postfix") == 0) { @@ -8842,9 +8850,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( wpa_s->global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - wpa_s->global, reply, reply_size); + wpa_s->global, buf + 10, reply, reply_size); } else if (os_strncmp(buf, "BSS ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); @@ -9250,18 +9258,31 @@ static int wpa_supplicant_global_iface_list(struct wpa_global *global, static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, + const char *input, char *buf, int len) { int res; char *pos, *end; struct wpa_supplicant *wpa_s; + int show_ctrl = 0; + + if (input) + show_ctrl = !!os_strstr(input, "ctrl"); wpa_s = global->ifaces; pos = buf; end = buf + len; while (wpa_s) { - res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname); + if (show_ctrl) + res = os_snprintf(pos, end - pos, "%s ctrl_iface=%s\n", + wpa_s->ifname, + wpa_s->conf->ctrl_interface ? + wpa_s->conf->ctrl_interface : "N/A"); + else + res = os_snprintf(pos, end - pos, "%s\n", + wpa_s->ifname); + if (os_snprintf_error(end - pos, res)) { *pos = '\0'; break; @@ -9650,9 +9671,9 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, } else if (os_strcmp(buf, "INTERFACE_LIST") == 0) { reply_len = wpa_supplicant_global_iface_list( global, reply, reply_size); - } else if (os_strcmp(buf, "INTERFACES") == 0) { + } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = wpa_supplicant_global_iface_interfaces( - global, reply, reply_size); + global, buf + 10, reply, reply_size); #ifdef CONFIG_FST } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) { reply_len = wpas_global_ctrl_iface_fst_attach(global, buf + 11, diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 76f69f2b..503052a6 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -48,13 +48,33 @@ struct ctrl_iface_priv { u8 cookie[COOKIE_LEN]; }; +struct ctrl_iface_global_priv { + int sock; + struct wpa_ctrl_dst *ctrl_dst; + u8 cookie[COOKIE_LEN]; +}; + -static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, +static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, + const char *ifname, int sock, + struct wpa_ctrl_dst **head, int level, const char *buf, size_t len); -static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, +static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst) +{ + struct wpa_ctrl_dst *prev; + + while (dst) { + prev = dst; + dst = dst->next; + os_free(prev); + } +} + + +static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head, #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 *from, #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ @@ -73,8 +93,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, os_memcpy(&dst->addr, from, sizeof(*from)); dst->addrlen = fromlen; dst->debug_level = MSG_INFO; - dst->next = priv->ctrl_dst; - priv->ctrl_dst = dst; + dst->next = *head; + *head = 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)), @@ -87,7 +107,7 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, } -static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, +static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head, #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 *from, #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ @@ -100,7 +120,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, char addr[INET6_ADDRSTRLEN]; #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ - dst = priv->ctrl_dst; + dst = *head; while (dst) { #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 if (from->sin6_port == dst->addr.sin6_port && @@ -118,7 +138,7 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, ntohs(from->sin_port)); #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (prev == NULL) - priv->ctrl_dst = dst->next; + *head = dst->next; else prev->next = dst->next; os_free(dst); @@ -282,14 +302,16 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, pos++; if (os_strcmp(pos, "ATTACH") == 0) { - if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) + if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, + &from, fromlen)) reply_len = 1; else { new_attached = 1; reply_len = 2; } } else if (os_strcmp(pos, "DETACH") == 0) { - if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) + if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, + &from, fromlen)) reply_len = 1; else reply_len = 2; @@ -327,9 +349,28 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, const char *txt, size_t len) { struct wpa_supplicant *wpa_s = ctx; - if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) + + if (!wpa_s) + return; + + if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { + struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; + + if (priv->ctrl_dst) { + wpa_supplicant_ctrl_iface_send( + wpa_s, + type != WPA_MSG_PER_INTERFACE ? + NULL : wpa_s->ifname, + priv->sock, &priv->ctrl_dst, level, txt, len); + } + } + + if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface) return; - wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); + + wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, + &wpa_s->ctrl_iface->ctrl_dst, + level, txt, len); } @@ -338,6 +379,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; int port = WPA_CTRL_IFACE_PORT; + char *pos; #ifdef CONFIG_CTRL_IFACE_UDP_IPV6 struct sockaddr_in6 addr; int domain = PF_INET6; @@ -356,6 +398,17 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) if (wpa_s->conf->ctrl_interface == NULL) return priv; + pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s", + wpa_s->conf->ctrl_interface); + goto fail; + } + } + priv->sock = socket(domain, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); @@ -386,7 +439,8 @@ try_again: #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) + if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT && + !pos) goto try_again; wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); goto fail; @@ -412,8 +466,6 @@ fail: void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) { - struct wpa_ctrl_dst *dst, *prev; - if (priv->sock > -1) { eloop_unregister_read_sock(priv->sock); if (priv->ctrl_dst) { @@ -430,22 +482,19 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) priv->sock = -1; } - dst = priv->ctrl_dst; - while (dst) { - prev = dst; - dst = dst->next; - os_free(prev); - } + wpas_ctrl_iface_free_dst(priv->ctrl_dst); os_free(priv); } -static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, +static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, + const char *ifname, int sock, + struct wpa_ctrl_dst **head, int level, const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; - char levelstr[10]; + char levelstr[64]; int idx; char *sbuf; int llen; @@ -453,11 +502,15 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, char addr[INET6_ADDRSTRLEN]; #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ - dst = priv->ctrl_dst; - if (priv->sock < 0 || dst == NULL) + dst = *head; + if (sock < 0 || dst == NULL) return; - os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + if (ifname) + os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>", + ifname, level); + else + os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); llen = os_strlen(levelstr); sbuf = os_malloc(llen + len); @@ -481,7 +534,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 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, + if (sendto(sock, sbuf, llen + len, 0, (struct sockaddr *) &dst->addr, sizeof(dst->addr)) < 0) { wpa_printf(MSG_ERROR, @@ -490,7 +543,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, dst->errors++; if (dst->errors > 10) { wpa_supplicant_ctrl_iface_detach( - priv, &dst->addr, + head, &dst->addr, dst->addrlen); } } else @@ -513,12 +566,6 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) /* Global ctrl_iface */ -struct ctrl_iface_global_priv { - int sock; - u8 cookie[COOKIE_LEN]; -}; - - static char * wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, size_t *reply_len) @@ -548,7 +595,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, int res; struct sockaddr_in from; socklen_t fromlen = sizeof(from); - char *reply; + char *reply = NULL; size_t reply_len; u8 cookie[COOKIE_LEN]; @@ -603,17 +650,34 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, while (*pos == ' ') pos++; - reply = wpa_supplicant_global_ctrl_iface_process(global, pos, - &reply_len); + if (os_strcmp(pos, "ATTACH") == 0) { + if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, + &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else if (os_strcmp(pos, "DETACH") == 0) { + if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, + &from, fromlen)) + reply_len = 1; + else + reply_len = 2; + } else { + reply = wpa_supplicant_global_ctrl_iface_process(global, pos, + &reply_len); + } done: if (reply) { sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); os_free(reply); - } else if (reply_len) { + } else if (reply_len == 1) { sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, fromlen); + } else if (reply_len == 2) { + sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, + fromlen); } } @@ -623,6 +687,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) { struct ctrl_iface_global_priv *priv; struct sockaddr_in addr; + char *pos; int port = WPA_GLOBAL_CTRL_IFACE_PORT; priv = os_zalloc(sizeof(*priv)); @@ -637,6 +702,17 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) wpa_printf(MSG_DEBUG, "Global control interface '%s'", global->params.ctrl_interface); + pos = os_strstr(global->params.ctrl_interface, "udp:"); + if (pos) { + pos += 4; + port = atoi(pos); + if (port <= 0) { + wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s", + global->params.ctrl_interface); + goto fail; + } + } + priv->sock = socket(PF_INET, SOCK_DGRAM, 0); if (priv->sock < 0) { wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno)); @@ -655,7 +731,7 @@ try_again: if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { port++; if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) < - WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT) + WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos) goto try_again; wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno)); goto fail; @@ -668,6 +744,7 @@ try_again: eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv); + wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); return priv; @@ -686,5 +763,7 @@ wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) eloop_unregister_read_sock(priv->sock); close(priv->sock); } + + wpas_ctrl_iface_free_dst(priv->ctrl_dst); os_free(priv); } diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index 7b367513..2fc89a92 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -24,6 +24,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/list.h" +#include "common/ctrl_iface_common.h" #include "eapol_supp/eapol_supp_sm.h" #include "config.h" #include "wpa_supplicant_i.h" @@ -31,22 +32,6 @@ /* Per-interface ctrl_iface */ -/** - * struct wpa_ctrl_dst - Internal data structure of control interface monitors - * - * This structure is used to store information about registered control - * interface monitors into struct wpa_supplicant. This data is private to - * ctrl_iface_unix.c and should not be touched directly from other files. - */ -struct wpa_ctrl_dst { - struct dl_list list; - struct sockaddr_un addr; - socklen_t addrlen; - int debug_level; - int errors; -}; - - struct ctrl_iface_priv { struct wpa_supplicant *wpa_s; int sock; @@ -116,81 +101,29 @@ static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, int global) { - struct wpa_ctrl_dst *dst; - char addr_txt[200]; - - dst = os_zalloc(sizeof(*dst)); - if (dst == NULL) - return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); - dst->addrlen = fromlen; - dst->debug_level = MSG_INFO; - dl_list_add(ctrl_dst, &dst->list); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s", - global ? "global " : "", addr_txt); - return 0; + return ctrl_iface_attach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen) { - struct wpa_ctrl_dst *dst; - - dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, - fromlen - - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", - addr_txt); - dl_list_del(&dst->list); - os_free(dst); - return 0; - } - } - return -1; + return ctrl_iface_detach(ctrl_dst, from, fromlen); } static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, - struct sockaddr_un *from, + struct sockaddr_storage *from, socklen_t fromlen, char *level) { - struct wpa_ctrl_dst *dst; - wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); - dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { - if (fromlen == dst->addrlen && - os_memcmp(from->sun_path, dst->addr.sun_path, - fromlen - offsetof(struct sockaddr_un, sun_path)) - == 0) { - char addr_txt[200]; - dst->debug_level = atoi(level); - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) from->sun_path, fromlen - - offsetof(struct sockaddr_un, sun_path)); - wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", - dst->debug_level, addr_txt); - return 0; - } - } - - return -1; + return ctrl_iface_level(&priv->ctrl_dst, from, fromlen, level); } @@ -201,7 +134,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len = 0; @@ -995,33 +928,31 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { int _errno; - char addr_txt[200]; + char txt[200]; if (level < dst->debug_level) continue; - printf_encode(addr_txt, sizeof(addr_txt), - (u8 *) dst->addr.sun_path, dst->addrlen - - offsetof(struct sockaddr_un, sun_path)); msg.msg_name = (void *) &dst->addr; msg.msg_namelen = dst->addrlen; wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { - wpa_printf(MSG_MSGDUMP, - "CTRL_IFACE monitor sent successfully to %s", - addr_txt); + sockaddr_print(MSG_MSGDUMP, + "CTRL_IFACE monitor sent successfully to", + &dst->addr, dst->addrlen); dst->errors = 0; continue; } _errno = errno; - wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", - addr_txt, errno, strerror(errno)); + os_snprintf(txt, sizeof(txt), "CTRL_IFACE monitor: %d (%s) for", + _errno, strerror(_errno)); + sockaddr_print(MSG_DEBUG, txt, &dst->addr, dst->addrlen); dst->errors++; if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { - wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", - addr_txt); + sockaddr_print(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages:", + &dst->addr, dst->addrlen); wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, dst->addrlen); } @@ -1055,7 +986,7 @@ void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) { char buf[256]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); if (priv->sock == -1) @@ -1118,7 +1049,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_global_priv *priv = sock_ctx; char buf[4096]; int res; - struct sockaddr_un from; + struct sockaddr_storage from; socklen_t fromlen = sizeof(from); char *reply = NULL, *reply_buf = NULL; size_t reply_len; diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index d74630ee..d894f6ae 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -2001,6 +2001,10 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, prop = "DisconnectReason"; flush = TRUE; break; + case WPAS_DBUS_PROP_ASSOC_STATUS_CODE: + prop = "AssocStatusCode"; + flush = TRUE; + break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); @@ -3255,6 +3259,11 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { NULL, NULL }, + { "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i", + wpas_dbus_getter_assoc_status_code, + NULL, + NULL + }, { NULL, NULL, NULL, NULL, NULL, NULL } }; diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 6d240fff..3ac66db1 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -29,6 +29,7 @@ enum wpas_dbus_prop { WPAS_DBUS_PROP_CURRENT_AUTH_MODE, WPAS_DBUS_PROP_BSSS, WPAS_DBUS_PROP_DISCONNECT_REASON, + WPAS_DBUS_PROP_ASSOC_STATUS_CODE, }; enum wpas_dbus_bss_prop { diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 09461c5d..da90ea1c 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -2858,6 +2858,27 @@ dbus_bool_t wpas_dbus_getter_disconnect_reason( /** + * wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "AssocStatusCode" property. + */ +dbus_bool_t wpas_dbus_getter_assoc_status_code( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + dbus_int32_t status_code = wpa_s->assoc_status_code; + + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, + &status_code, error); +} + + +/** * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age * @iter: Pointer to incoming dbus message iter * @error: Location to store error on failure diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 31b92d19..cd299c05 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -138,6 +138,7 @@ DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth); DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason); DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason); +DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code); DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age); DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age); DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b3e730f1..a84ba2dc 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3505,6 +3505,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT "status_code=%u", data->assoc_reject.status_code); + wpa_s->assoc_status_code = data->assoc_reject.status_code; + wpas_notify_assoc_status_code(wpa_s); if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_assoc_reject(wpa_s, data); else { diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 45d06bf3..325883dd 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -128,6 +128,15 @@ void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s) } +void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE); +} + + void wpas_notify_network_changed(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index d9f0f5a9..1b7f04d2 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -23,6 +23,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, enum wpa_states new_state, enum wpa_states old_state); void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s); +void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s); void wpas_notify_network_changed(struct wpa_supplicant *wpa_s); void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s); void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index cf2653de..5ff758f6 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5771,6 +5771,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, unsigned int cand; unsigned int num, i; int ignore_no_freqs = 0; + int unused_channels = wpas_p2p_num_unused_channels(wpa_s) > 0; os_memset(params, 0, sizeof(*params)); params->role_go = 1; @@ -5827,8 +5828,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, } } - if (!ignore_no_freqs && - wpas_p2p_num_unused_channels(wpa_s) <= 0) { + if (!ignore_no_freqs && !unused_channels) { wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%d MHz) as all the channels are in use", freq); @@ -5843,12 +5843,13 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, } /* consider using one of the shared frequencies */ - if (num) { + if (num && + (!wpa_s->conf->p2p_ignore_shared_freq || !unused_channels)) { cand = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num); if (wpas_p2p_supported_freq_go(wpa_s, channels, cand)) { wpa_printf(MSG_DEBUG, "P2P: Use shared freq (%d MHz) for GO", - freq); + cand); params->freq = cand; goto success; } @@ -5859,15 +5860,14 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, freqs[i].freq)) { wpa_printf(MSG_DEBUG, "P2P: Use shared freq (%d MHz) for GO", - freq); + freqs[i].freq); params->freq = freqs[i].freq; goto success; } } } - if (!ignore_no_freqs && - wpas_p2p_num_unused_channels(wpa_s) <= 0) { + if (!ignore_no_freqs && !unused_channels) { wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using"); goto fail; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 1b16d281..269bac0f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -950,6 +950,9 @@ struct wpa_supplicant { /* WLAN_REASON_* reason codes. Negative if locally generated. */ int disconnect_reason; + /* WLAN_STATUS_* status codes from (Re)Association Response frame. */ + u16 assoc_status_code; + struct ext_password_data *ext_pw; struct wpabuf *last_gas_resp, *prev_gas_resp; |