diff options
author | Daniel Golle <daniel@makrotopia.org> | 2018-11-22 20:53:09 +0100 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2018-12-12 09:37:23 +0100 |
commit | f5753aae233fa64b5d4784ade2cc170f7da539a4 (patch) | |
tree | fe53918ad7ed179876f1e015e655569fdf0b19c1 | |
parent | 5beedcddc3ad2c6f92c24ce2655a84524ca26594 (diff) | |
download | upstream-f5753aae233fa64b5d4784ade2cc170f7da539a4.tar.gz upstream-f5753aae233fa64b5d4784ade2cc170f7da539a4.tar.bz2 upstream-f5753aae233fa64b5d4784ade2cc170f7da539a4.zip |
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 <daniel@makrotopia.org>
10 files changed, 467 insertions, 14 deletions
diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 45c394640d..a1480bf963 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 7f3157cd27..7335e75fd5 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" <<EOF + if [ "$key_mgnt" = "WPS" ]; then + echo "wps_cred_processing=1" >> "$_config" + else + cat >> "$_config" <<EOF network={ $scan_ssid ssid="$ssid" @@ -877,6 +883,7 @@ network={ $network_data } EOF + fi return 0 } diff --git a/package/network/services/hostapd/files/wpa_supplicant-basic.config b/package/network/services/hostapd/files/wpa_supplicant-basic.config index 7c33996691..01ef7b6e3f 100644 --- a/package/network/services/hostapd/files/wpa_supplicant-basic.config +++ b/package/network/services/hostapd/files/wpa_supplicant-basic.config @@ -591,3 +591,8 @@ CONFIG_NO_RANDOM_POOL=y # Opportunistic Wireless Encryption (OWE) # Experimental implementation of draft-harkins-owe-07.txt #CONFIG_OWE=y + +# uBus IPC/RPC System +# Services can connect to the bus and provide methods +# that can be called by other services or clients. +CONFIG_UBUS=y diff --git a/package/network/services/hostapd/files/wpa_supplicant-full.config b/package/network/services/hostapd/files/wpa_supplicant-full.config index 55b31a345b..0ec846943f 100644 --- a/package/network/services/hostapd/files/wpa_supplicant-full.config +++ b/package/network/services/hostapd/files/wpa_supplicant-full.config @@ -593,3 +593,8 @@ CONFIG_IBSS_RSN=y # Opportunistic Wireless Encryption (OWE) # Experimental implementation of draft-harkins-owe-07.txt #CONFIG_OWE=y + +# uBus IPC/RPC System +# Services can connect to the bus and provide methods +# that can be called by other services or clients. +CONFIG_UBUS=y diff --git a/package/network/services/hostapd/files/wpa_supplicant-mini.config b/package/network/services/hostapd/files/wpa_supplicant-mini.config index 67c0b323af..2adb94802c 100644 --- a/package/network/services/hostapd/files/wpa_supplicant-mini.config +++ b/package/network/services/hostapd/files/wpa_supplicant-mini.config @@ -593,3 +593,8 @@ CONFIG_NO_RANDOM_POOL=y # Opportunistic Wireless Encryption (OWE) # Experimental implementation of draft-harkins-owe-07.txt #CONFIG_OWE=y + +# uBus IPC/RPC System +# Services can connect to the bus and provide methods +# that can be called by other services or clients. +CONFIG_UBUS=y diff --git a/package/network/services/hostapd/files/wpa_supplicant-p2p.config b/package/network/services/hostapd/files/wpa_supplicant-p2p.config index c1e85f0163..435f45a944 100644 --- a/package/network/services/hostapd/files/wpa_supplicant-p2p.config +++ b/package/network/services/hostapd/files/wpa_supplicant-p2p.config @@ -593,3 +593,8 @@ CONFIG_IBSS_RSN=y # Opportunistic Wireless Encryption (OWE) # Experimental implementation of draft-harkins-owe-07.txt #CONFIG_OWE=y + +# uBus IPC/RPC System +# Services can connect to the bus and provide methods +# that can be called by other services or clients. +CONFIG_UBUS=y diff --git a/package/network/services/hostapd/files/wps-hotplug.sh b/package/network/services/hostapd/files/wps-hotplug.sh index 24af80e55b..ddfd021195 100644 --- a/package/network/services/hostapd/files/wps-hotplug.sh +++ b/package/network/services/hostapd/files/wps-hotplug.sh @@ -1,11 +1,56 @@ #!/bin/sh +wps_catch_credentials() { + local iface ifaces ifc ifname ssid encryption key radio radios + local found=0 + + . /usr/share/libubox/jshn.sh + ubus -S -t 30 listen wps_credentials | while read creds; do + json_init + json_load "$creds" + json_select wps_credentials || continue + json_get_vars ifname ssid key encryption + local ifcname="$ifname" + json_init + json_load "$(ubus -S call network.wireless status)" + json_get_keys radios + for radio in $radios; do + json_select $radio + json_select interfaces + json_get_keys ifaces + for ifc in $ifaces; do + json_select $ifc + json_get_vars ifname + [ "$ifname" = "$ifcname" ] && { + ubus -S call uci set "{\"config\":\"wireless\", \"type\":\"wifi-iface\", \ + \"match\": { \"device\": \"$radio\", \"encryption\": \"wps\" }, \ + \"values\": { \"encryption\": \"$encryption\", \ + \"ssid\": \"$ssid\", \ + \"key\": \"$key\" } }" + ubus -S call uci commit '{"config": "wireless"}' + ubus -S call uci apply + } + json_select .. + done + json_select .. + json_select .. + done + done +} + if [ "$ACTION" = "pressed" -a "$BUTTON" = "wps" ]; then - cd /var/run/hostapd - for socket in *; do - [ -S "$socket" ] || continue - hostapd_cli -i "$socket" wps_pbc + wps_done=0 + ubusobjs="$( ubus -S list hostapd.* )" + for ubusobj in $ubusobjs; do + ubus -S call $ubusobj wps_start && wps_done=1 + done + [ $wps_done = 0 ] || return 0 + wps_done=0 + ubusobjs="$( ubus -S list wpa_supplicant.* )" + for ubusobj in $ubusobjs; do + ubus -S call $ubusobj wps_start && wps_done=1 done + [ $wps_done = 0 ] || wps_catch_credentials & fi return 0 diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index b1e7c78c22..e22c8d91fc 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -341,3 +341,85 @@ } +--- a/wpa_supplicant/Makefile ++++ b/wpa_supplicant/Makefile +@@ -189,6 +189,12 @@ ifdef CONFIG_EAPOL_TEST + CFLAGS += -Werror -DEAPOL_TEST + endif + ++ifdef CONFIG_UBUS ++CFLAGS += -DUBUS_SUPPORT ++OBJS += ubus.o ++LIBS += -lubox -lubus ++endif ++ + ifdef CONFIG_CODE_COVERAGE + CFLAGS += -O0 -fprofile-arcs -ftest-coverage + LIBS += -lgcov +@@ -915,6 +921,9 @@ endif + ifdef CONFIG_IEEE80211AX + OBJS += ../src/ap/ieee802_11_he.o + endif ++ifdef CONFIG_UBUS ++OBJS += ../src/ap/ubus.o ++endif + endif + ifdef CONFIG_WNM_AP + CFLAGS += -DCONFIG_WNM_AP +--- a/wpa_supplicant/wpa_supplicant.c ++++ b/wpa_supplicant/wpa_supplicant.c +@@ -5998,6 +5998,8 @@ struct wpa_supplicant * wpa_supplicant_a + } + #endif /* CONFIG_P2P */ + ++ wpas_ubus_add_bss(wpa_s); ++ + return wpa_s; + } + +@@ -6024,6 +6026,8 @@ int wpa_supplicant_remove_iface(struct w + struct wpa_supplicant *parent = wpa_s->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 0000000000..d4ed8e222a --- /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 <daniel@makrotopia.org> + * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name> + * + * 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 0000000000..c37e743e73 --- /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 <daniel@makrotopia.org> + * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name> + * + * 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 <libubus.h> + +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 |