From f5753aae233fa64b5d4784ade2cc170f7da539a4 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 22 Nov 2018 20:53:09 +0100 Subject: [PATCH] hostapd: add support for WPS pushbutton station similar to hostapd, also add a ubus interface for wpa_supplicant which will allow handling WPS push-button just as it works for hostapd. In order to have wpa_supplicant running without any network configuration (so you can use it to retrieve credentials via WPS), configure wifi-iface in /etc/config/wireless: config wifi-iface 'default_radio0' option device 'radio0' option network 'wwan' option mode 'sta' option encryption 'wps' This section will automatically be edited if credentials have successfully been acquired via WPS. Size difference (mips_24kc): roughly +4kb for the 'full' variants of wpa_supplicant and wpad which do support WPS. Signed-off-by: Daniel Golle --- package/network/services/hostapd/Makefile | 15 +- .../network/services/hostapd/files/hostapd.sh | 9 +- .../hostapd/files/wpa_supplicant-basic.config | 5 + .../hostapd/files/wpa_supplicant-full.config | 5 + .../hostapd/files/wpa_supplicant-mini.config | 5 + .../hostapd/files/wpa_supplicant-p2p.config | 5 + .../services/hostapd/files/wps-hotplug.sh | 55 +++- .../hostapd/patches/600-ubus_support.patch | 82 ++++++ .../hostapd/src/wpa_supplicant/ubus.c | 249 ++++++++++++++++++ .../hostapd/src/wpa_supplicant/ubus.h | 53 ++++ 10 files changed, 468 insertions(+), 15 deletions(-) create mode 100644 package/network/services/hostapd/src/wpa_supplicant/ubus.c create mode 100644 package/network/services/hostapd/src/wpa_supplicant/ubus.h diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 45c394640d4..a1480bf963b 100644 --- a/package/network/services/hostapd/Makefile +++ b/package/network/services/hostapd/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hostapd -PKG_RELEASE:=6 +PKG_RELEASE:=7 PKG_SOURCE_URL:=http://w1.fi/hostap.git PKG_SOURCE_PROTO:=git @@ -296,7 +296,7 @@ define Package/wpa-supplicant/Default CATEGORY:=Network TITLE:=WPA Supplicant URL:=http://hostap.epitest.fi/wpa_supplicant/ - DEPENDS:=$(DRV_DEPENDS) + DEPENDS:=$(DRV_DEPENDS) +hostapd-common +libubus PROVIDES:=wpa-supplicant CONFLICTS:=$(SUPPLICANT_PROVIDERS) SUPPLICANT_PROVIDERS+=$(1) @@ -444,10 +444,7 @@ TARGET_CPPFLAGS := \ $(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY)) TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto -TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -ifeq ($(findstring supplicant,$(BUILD_VARIANT)),) - TARGET_LDFLAGS += -lubox -lubus -endif +TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus ifdef CONFIG_PACKAGE_kmod-cfg80211 TARGET_LDFLAGS += -lm -lnl-tiny @@ -534,8 +531,9 @@ define Install/supplicant endef define Package/hostapd-common/install - $(INSTALL_DIR) $(1)/lib/netifd + $(INSTALL_DIR) $(1)/lib/netifd $(1)/etc/rc.button $(INSTALL_DATA) ./files/hostapd.sh $(1)/lib/netifd/hostapd.sh + $(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps endef define Package/hostapd/install @@ -549,9 +547,8 @@ Package/hostapd-wolfssl/install = $(Package/hostapd/install) ifneq ($(LOCAL_TYPE),supplicant) define Package/hostapd-utils/install - $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/rc.button + $(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd/hostapd_cli $(1)/usr/sbin/ - $(INSTALL_BIN) ./files/wps-hotplug.sh $(1)/etc/rc.button/wps endef endif diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 7f3157cd273..7335e75fd5f 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -762,6 +762,9 @@ wpa_supplicant_add_network() { hostapd_append_wep_key network_data append network_data "wep_tx_keyidx=$wep_keyidx" "$N$T" ;; + wps) + key_mgmt='WPS' + ;; psk|sae|psk-sae) local passphrase @@ -869,7 +872,10 @@ wpa_supplicant_add_network() { append network_data "mcast_rate=$mc_rate" "$N$T" } - cat >> "$_config" <> "$_config" + else + cat >> "$_config" <parent; + #endif /* CONFIG_MESH */ + ++ wpas_ubus_free_bss(wpa_s); ++ + /* Remove interface from the global list of interfaces */ + prev = global->ifaces; + if (prev == wpa_s) { +--- a/wpa_supplicant/wpa_supplicant_i.h ++++ b/wpa_supplicant/wpa_supplicant_i.h +@@ -17,6 +17,7 @@ + #include "wps/wps_defs.h" + #include "config_ssid.h" + #include "wmm_ac.h" ++#include "ubus.h" + + extern const char *const wpa_supplicant_version; + extern const char *const wpa_supplicant_license; +@@ -500,6 +501,7 @@ struct wpa_supplicant { + unsigned char own_addr[ETH_ALEN]; + unsigned char perm_addr[ETH_ALEN]; + char ifname[100]; ++ struct wpas_ubus_bss ubus; + #ifdef CONFIG_MATCH_IFACE + int matched; + #endif /* CONFIG_MATCH_IFACE */ +--- a/wpa_supplicant/wps_supplicant.c ++++ b/wpa_supplicant/wps_supplicant.c +@@ -33,6 +33,7 @@ + #include "p2p/p2p.h" + #include "p2p_supplicant.h" + #include "wps_supplicant.h" ++#include "ubus.h" + + + #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG +@@ -388,6 +389,8 @@ static int wpa_supplicant_wps_cred(void + wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", + cred->cred_attr, cred->cred_attr_len); + ++ wpas_ubus_notify(wpa_s, cred); ++ + if (wpa_s->conf->wps_cred_processing == 1) + return 0; + diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.c b/package/network/services/hostapd/src/wpa_supplicant/ubus.c new file mode 100644 index 00000000000..d4ed8e222ae --- /dev/null +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.c @@ -0,0 +1,249 @@ +/* + * wpa_supplicant / ubus support + * Copyright (c) 2018, Daniel Golle + * Copyright (c) 2013, Felix Fietkau + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/wpabuf.h" +#include "common/ieee802_11_defs.h" +#include "wpa_supplicant_i.h" +#include "wps_supplicant.h" +#include "ubus.h" + +static struct ubus_context *ctx; +static struct blob_buf b; +static int ctx_ref; + +static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj) +{ + return container_of(obj, struct wpa_supplicant, ubus.obj); +} + +static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct ubus_context *ctx = eloop_ctx; + ubus_handle_event(ctx); +} + +static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx) +{ + if (ubus_reconnect(ctx, NULL)) { + eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL); + return; + } + + eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); +} + +static void wpas_ubus_connection_lost(struct ubus_context *ctx) +{ + eloop_unregister_read_sock(ctx->sock.fd); + eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL); +} + +static bool wpas_ubus_init(void) +{ + if (ctx) + return true; + + ctx = ubus_connect(NULL); + if (!ctx) + return false; + + ctx->connection_lost = wpas_ubus_connection_lost; + eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); + return true; +} + +static void wpas_ubus_ref_inc(void) +{ + ctx_ref++; +} + +static void wpas_ubus_ref_dec(void) +{ + ctx_ref--; + if (!ctx) + return; + + if (ctx_ref) + return; + + eloop_unregister_read_sock(ctx->sock.fd); + ubus_free(ctx); + ctx = NULL; +} + +static int +wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); + + blob_buf_init(&b, 0); + blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes)); + blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes)); + ubus_send_reply(ctx, req, b.head); + + return 0; +} + +#ifdef CONFIG_WPS +static int +wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + int rc; + struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); + + rc = wpas_wps_start_pbc(wpa_s, NULL, 0); + + if (rc != 0) + return UBUS_STATUS_NOT_SUPPORTED; + + return 0; +} + +static int +wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + int rc; + struct wpa_supplicant *wpa_s = get_wpas_from_object(obj); + + rc = wpas_wps_cancel(wpa_s); + + if (rc != 0) + return UBUS_STATUS_NOT_SUPPORTED; + + return 0; +} +#endif + +static const struct ubus_method bss_methods[] = { +#ifdef CONFIG_WPS + UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start), + UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel), +#endif + UBUS_METHOD_NOARG("get_features", wpas_bss_get_features), +}; + +static struct ubus_object_type bss_object_type = + UBUS_OBJECT_TYPE("wpas_bss", bss_methods); + +void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s) +{ + struct ubus_object *obj = &wpa_s->ubus.obj; + char *name; + int ret; + + if (!wpas_ubus_init()) + return; + + if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0) + return; + + obj->name = name; + obj->type = &bss_object_type; + obj->methods = bss_object_type.methods; + obj->n_methods = bss_object_type.n_methods; + ret = ubus_add_object(ctx, obj); + wpas_ubus_ref_inc(); +} + +void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s) +{ + struct ubus_object *obj = &wpa_s->ubus.obj; + char *name = (char *) obj->name; + + if (!ctx) + return; + + if (obj->id) { + ubus_remove_object(ctx, obj); + wpas_ubus_ref_dec(); + } + + free(name); +} + +#ifdef CONFIG_WPS +void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred) +{ + u16 auth_type; + char *ifname, *encryption, *ssid, *key; + size_t ifname_len; + + if (!cred) + return; + + auth_type = cred->auth_type; + + if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) + auth_type = WPS_AUTH_WPA2PSK; + + if (auth_type != WPS_AUTH_OPEN && + auth_type != WPS_AUTH_WPAPSK && + auth_type != WPS_AUTH_WPA2PSK) { + wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for " + "unsupported authentication type 0x%x", + auth_type); + return; + } + + if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) { + if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) { + wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with " + "invalid Network Key length %lu", + (unsigned long) cred->key_len); + return; + } + } + + blob_buf_init(&b, 0); + + ifname_len = strlen(wpa_s->ifname); + ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1); + memcpy(ifname, wpa_s->ifname, ifname_len + 1); + ifname[ifname_len] = '\0'; + blobmsg_add_string_buffer(&b); + + switch (auth_type) { + case WPS_AUTH_WPA2PSK: + encryption = "psk2"; + break; + case WPS_AUTH_WPAPSK: + encryption = "psk"; + break; + default: + encryption = "none"; + break; + } + + blobmsg_add_string(&b, "encryption", encryption); + + ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1); + memcpy(ssid, cred->ssid, cred->ssid_len); + ssid[cred->ssid_len] = '\0'; + blobmsg_add_string_buffer(&b); + + if (cred->key_len > 0) { + key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1); + memcpy(key, cred->key, cred->key_len); + key[cred->key_len] = '\0'; + blobmsg_add_string_buffer(&b); + } + +// ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1); + ubus_send_event(ctx, "wps_credentials", b.head); +} +#endif /* CONFIG_WPS */ diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.h b/package/network/services/hostapd/src/wpa_supplicant/ubus.h new file mode 100644 index 00000000000..c37e743e738 --- /dev/null +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.h @@ -0,0 +1,53 @@ +/* + * wpa_supplicant / ubus support + * Copyright (c) 2018, Daniel Golle + * Copyright (c) 2013, Felix Fietkau + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#ifndef __WPAS_UBUS_H +#define __WPAS_UBUS_H + +struct wpa_supplicant; +#include "wps_supplicant.h" + +#ifdef UBUS_SUPPORT +#include + +struct wpas_ubus_bss { + struct ubus_object obj; +}; + +void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s); +void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s); + +#ifdef CONFIG_WPS +void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); +#endif + +#else +struct wpas_ubus_bss {}; + +static inline void wpas_ubus_add_iface(struct wpa_supplicant *wpa_s) +{ +} + +static inline void wpas_ubus_free_iface(struct wpa_supplicant *wpa_s) +{ +} + +static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s) +{ +} + +static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s) +{ +} + +static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred) +{ +} +#endif + +#endif