hostapd: initial prototype of an ubus binding
Supports listing, removing and banning clients, and hooking into probe/assoc/auth requests via object subscribe. SVN-Revision: 36081
This commit is contained in:
		| @@ -93,7 +93,7 @@ define Package/hostapd/Default | |||||||
|   CATEGORY:=Network |   CATEGORY:=Network | ||||||
|   TITLE:=IEEE 802.1x Authenticator |   TITLE:=IEEE 802.1x Authenticator | ||||||
|   URL:=http://hostap.epitest.fi/ |   URL:=http://hostap.epitest.fi/ | ||||||
|   DEPENDS:=$(DRV_DEPENDS) |   DEPENDS:=$(DRV_DEPENDS) +libubus | ||||||
| endef | endef | ||||||
|  |  | ||||||
| define Package/hostapd | define Package/hostapd | ||||||
| @@ -138,7 +138,7 @@ endef | |||||||
| define Package/wpad | define Package/wpad | ||||||
| $(call Package/wpad/Default) | $(call Package/wpad/Default) | ||||||
|   TITLE+= (full) |   TITLE+= (full) | ||||||
|   DEPENDS:=$(DRV_DEPENDS) +WPA_SUPPLICANT_OPENSSL:libopenssl |   DEPENDS:=$(DRV_DEPENDS) +WPA_SUPPLICANT_OPENSSL:libopenssl +libubus | ||||||
|   VARIANT:=wpad-full |   VARIANT:=wpad-full | ||||||
| endef | endef | ||||||
|  |  | ||||||
| @@ -150,7 +150,7 @@ endef | |||||||
| define Package/wpad-mini | define Package/wpad-mini | ||||||
| $(call Package/wpad/Default) | $(call Package/wpad/Default) | ||||||
|   TITLE+= (WPA-PSK only) |   TITLE+= (WPA-PSK only) | ||||||
|   DEPENDS:=$(DRV_DEPENDS) |   DEPENDS:=$(DRV_DEPENDS) +libubus | ||||||
|   VARIANT:=wpad-mini |   VARIANT:=wpad-mini | ||||||
| endef | endef | ||||||
|  |  | ||||||
| @@ -225,6 +225,7 @@ TARGET_CPPFLAGS := \ | |||||||
|  |  | ||||||
| TARGET_CFLAGS += -ffunction-sections -fdata-sections | TARGET_CFLAGS += -ffunction-sections -fdata-sections | ||||||
| TARGET_LDFLAGS += -Wl,--gc-sections | TARGET_LDFLAGS += -Wl,--gc-sections | ||||||
|  | TARGET_LDFLAGS += -lubox -lubus | ||||||
|  |  | ||||||
| ifdef CONFIG_PACKAGE_kmod-mac80211 | ifdef CONFIG_PACKAGE_kmod-mac80211 | ||||||
|   TARGET_LDFLAGS += -lm -lnl-tiny |   TARGET_LDFLAGS += -lm -lnl-tiny | ||||||
|   | |||||||
| @@ -162,3 +162,4 @@ CONFIG_NO_DUMP_STATE=y | |||||||
| CONFIG_WPS=y | CONFIG_WPS=y | ||||||
| CONFIG_FULL_DYNAMIC_VLAN=y | CONFIG_FULL_DYNAMIC_VLAN=y | ||||||
|  |  | ||||||
|  | CONFIG_UBUS=y | ||||||
|   | |||||||
| @@ -155,3 +155,5 @@ CONFIG_NO_RADIUS=y | |||||||
| CONFIG_TLS=internal | CONFIG_TLS=internal | ||||||
|  |  | ||||||
| CONFIG_NO_DUMP_STATE=y | CONFIG_NO_DUMP_STATE=y | ||||||
|  |  | ||||||
|  | CONFIG_UBUS=y | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								package/network/services/hostapd/patches/630-bool_fix.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								package/network/services/hostapd/patches/630-bool_fix.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | --- a/src/ap/ieee802_1x.c | ||||||
|  | +++ b/src/ap/ieee802_1x.c | ||||||
|  | @@ -2043,9 +2043,9 @@ void ieee802_1x_notify_pre_auth(struct e | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |   | ||||||
|  | -static const char * bool_txt(Boolean bool) | ||||||
|  | +static const char * bool_txt(Boolean bool_val) | ||||||
|  |  { | ||||||
|  | -	return bool ? "TRUE" : "FALSE"; | ||||||
|  | +	return bool_val ? "TRUE" : "FALSE"; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  #ifdef CONFIG_CTRL_IFACE_MIB | ||||||
							
								
								
									
										673
									
								
								package/network/services/hostapd/patches/700-ubus_support.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										673
									
								
								package/network/services/hostapd/patches/700-ubus_support.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,673 @@ | |||||||
|  | --- a/hostapd/Makefile | ||||||
|  | +++ b/hostapd/Makefile | ||||||
|  | @@ -97,6 +97,11 @@ OBJS += ../src/common/wpa_common.o | ||||||
|  |   | ||||||
|  |  OBJS += ../src/eapol_auth/eapol_auth_sm.o | ||||||
|  |   | ||||||
|  | +ifdef CONFIG_UBUS | ||||||
|  | +CFLAGS += -DUBUS_SUPPORT | ||||||
|  | +OBJS += ../src/ap/ubus.o | ||||||
|  | +LIBS += -lubox -lubus | ||||||
|  | +endif | ||||||
|  |   | ||||||
|  |  ifndef CONFIG_NO_DUMP_STATE | ||||||
|  |  # define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to | ||||||
|  | --- a/src/ap/hostapd.h | ||||||
|  | +++ b/src/ap/hostapd.h | ||||||
|  | @@ -11,6 +11,7 @@ | ||||||
|  |   | ||||||
|  |  #include "common/defs.h" | ||||||
|  |  #include "ap_config.h" | ||||||
|  | +#include "ubus.h" | ||||||
|  |   | ||||||
|  |  struct wpa_driver_ops; | ||||||
|  |  struct wpa_ctrl_dst; | ||||||
|  | @@ -71,6 +72,7 @@ struct hostapd_data { | ||||||
|  |  	struct hostapd_iface *iface; | ||||||
|  |  	struct hostapd_config *iconf; | ||||||
|  |  	struct hostapd_bss_config *conf; | ||||||
|  | +	struct hostapd_ubus_bss ubus; | ||||||
|  |  	int interface_added; /* virtual interface added for this BSS */ | ||||||
|  |   | ||||||
|  |  	u8 own_addr[ETH_ALEN]; | ||||||
|  | @@ -212,6 +214,7 @@ struct hostapd_iface { | ||||||
|  |  	void *owner; | ||||||
|  |  	char *config_fname; | ||||||
|  |  	struct hostapd_config *conf; | ||||||
|  | +	struct hostapd_ubus_iface ubus; | ||||||
|  |   | ||||||
|  |  	size_t num_bss; | ||||||
|  |  	struct hostapd_data **bss; | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/src/ap/ubus.c | ||||||
|  | @@ -0,0 +1,354 @@ | ||||||
|  | +/* | ||||||
|  | + * hostapd / ubus support | ||||||
|  | + * Copyright (c) 2013, Felix Fietkau <nbd@openwrt.org> | ||||||
|  | + * | ||||||
|  | + * 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 "common/ieee802_11_defs.h" | ||||||
|  | +#include "hostapd.h" | ||||||
|  | +#include "sta_info.h" | ||||||
|  | +#include "ubus.h" | ||||||
|  | + | ||||||
|  | +static struct ubus_context *ctx; | ||||||
|  | +static struct blob_buf b; | ||||||
|  | +static int ctx_ref; | ||||||
|  | + | ||||||
|  | +struct ubus_banned_client { | ||||||
|  | +	struct avl_node avl; | ||||||
|  | +	u8 addr[ETH_ALEN]; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void ubus_receive(int sock, void *eloop_ctx, void *sock_ctx) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_context *ctx = eloop_ctx; | ||||||
|  | +	ubus_handle_event(ctx); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static bool hostapd_ubus_init(void) | ||||||
|  | +{ | ||||||
|  | +	if (ctx) | ||||||
|  | +		return true; | ||||||
|  | + | ||||||
|  | +	ctx = ubus_connect(NULL); | ||||||
|  | +	if (!ctx) | ||||||
|  | +		return false; | ||||||
|  | + | ||||||
|  | +	eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL); | ||||||
|  | +	return true; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void hostapd_ubus_ref_inc(void) | ||||||
|  | +{ | ||||||
|  | +	ctx_ref++; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void hostapd_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; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void hostapd_ubus_add_iface(struct hostapd_iface *iface) | ||||||
|  | +{ | ||||||
|  | +	if (!hostapd_ubus_init()) | ||||||
|  | +		return; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void hostapd_ubus_free_iface(struct hostapd_iface *iface) | ||||||
|  | +{ | ||||||
|  | +	if (!ctx) | ||||||
|  | +		return; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +hostapd_bss_del_ban(void *eloop_data, void *user_ctx) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_banned_client *ban = eloop_data; | ||||||
|  | +	struct hostapd_data *hapd = user_ctx; | ||||||
|  | + | ||||||
|  | +	avl_delete(&hapd->ubus.banned, &ban->avl); | ||||||
|  | +	free(ban); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_banned_client *ban; | ||||||
|  | + | ||||||
|  | +	if (time < 0) | ||||||
|  | +		time = 0; | ||||||
|  | + | ||||||
|  | +	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl); | ||||||
|  | +	if (!ban) { | ||||||
|  | +		if (!time) | ||||||
|  | +			return; | ||||||
|  | + | ||||||
|  | +		ban = os_zalloc(sizeof(*ban)); | ||||||
|  | +		memcpy(ban->addr, addr, sizeof(ban->addr)); | ||||||
|  | +		ban->avl.key = ban->addr; | ||||||
|  | +		avl_insert(&hapd->ubus.banned, &ban->avl); | ||||||
|  | +	} else { | ||||||
|  | +		eloop_cancel_timeout(hostapd_bss_del_ban, ban, hapd); | ||||||
|  | +		if (!time) { | ||||||
|  | +			hostapd_bss_del_ban(ban, hapd); | ||||||
|  | +			return; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj, | ||||||
|  | +			struct ubus_request_data *req, const char *method, | ||||||
|  | +			struct blob_attr *msg) | ||||||
|  | +{ | ||||||
|  | +	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); | ||||||
|  | +	struct sta_info *sta; | ||||||
|  | +	void *list, *c; | ||||||
|  | +	char mac_buf[20]; | ||||||
|  | +	static const struct { | ||||||
|  | +		const char *name; | ||||||
|  | +		uint32_t flag; | ||||||
|  | +	} sta_flags[] = { | ||||||
|  | +		{ "auth", WLAN_STA_AUTH }, | ||||||
|  | +		{ "assoc", WLAN_STA_ASSOC }, | ||||||
|  | +		{ "authorized", WLAN_STA_AUTHORIZED }, | ||||||
|  | +		{ "preauth", WLAN_STA_PREAUTH }, | ||||||
|  | +		{ "wds", WLAN_STA_WDS }, | ||||||
|  | +		{ "wmm", WLAN_STA_WMM }, | ||||||
|  | +		{ "ht", WLAN_STA_HT }, | ||||||
|  | +		{ "vht", WLAN_STA_VHT }, | ||||||
|  | +		{ "wps", WLAN_STA_WPS }, | ||||||
|  | +		{ "mfp", WLAN_STA_MFP }, | ||||||
|  | +	}; | ||||||
|  | + | ||||||
|  | +	blob_buf_init(&b, 0); | ||||||
|  | +	list = blobmsg_open_table(&b, "clients"); | ||||||
|  | +	for (sta = hapd->sta_list; sta; sta = sta->next) { | ||||||
|  | +		int i; | ||||||
|  | + | ||||||
|  | +		sprintf(mac_buf, MACSTR, MAC2STR(sta->addr)); | ||||||
|  | +		c = blobmsg_open_table(&b, mac_buf); | ||||||
|  | +		for (i = 0; i < ARRAY_SIZE(sta_flags); i++) | ||||||
|  | +			blobmsg_add_u8(&b, sta_flags[i].name, | ||||||
|  | +				       !!(sta->flags & sta_flags[i].flag)); | ||||||
|  | +		blobmsg_add_u32(&b, "aid", sta->aid); | ||||||
|  | +		blobmsg_close_table(&b, c); | ||||||
|  | +	} | ||||||
|  | +	blobmsg_close_array(&b, list); | ||||||
|  | +	ubus_send_reply(ctx, req, b.head); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +enum { | ||||||
|  | +	DEL_CLIENT_ADDR, | ||||||
|  | +	DEL_CLIENT_REASON, | ||||||
|  | +	DEL_CLIENT_DEAUTH, | ||||||
|  | +	DEL_CLIENT_BAN_TIME, | ||||||
|  | +	__DEL_CLIENT_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static const struct blobmsg_policy del_policy[__DEL_CLIENT_MAX] = { | ||||||
|  | +	[DEL_CLIENT_ADDR] = { "addr", BLOBMSG_TYPE_STRING }, | ||||||
|  | +	[DEL_CLIENT_REASON] = { "reason", BLOBMSG_TYPE_INT32 }, | ||||||
|  | +	[DEL_CLIENT_DEAUTH] = { "deauth", BLOBMSG_TYPE_INT8 }, | ||||||
|  | +	[DEL_CLIENT_BAN_TIME] = { "ban_time", BLOBMSG_TYPE_INT32 }, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +hostapd_bss_del_client(struct ubus_context *ctx, struct ubus_object *obj, | ||||||
|  | +			struct ubus_request_data *req, const char *method, | ||||||
|  | +			struct blob_attr *msg) | ||||||
|  | +{ | ||||||
|  | +	struct blob_attr *tb[__DEL_CLIENT_MAX]; | ||||||
|  | +	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); | ||||||
|  | +	struct sta_info *sta; | ||||||
|  | +	bool deauth = false; | ||||||
|  | +	int reason; | ||||||
|  | +	u8 addr[ETH_ALEN]; | ||||||
|  | + | ||||||
|  | +	blobmsg_parse(del_policy, __DEL_CLIENT_MAX, tb, blob_data(msg), blob_len(msg)); | ||||||
|  | + | ||||||
|  | +	if (!tb[DEL_CLIENT_ADDR]) | ||||||
|  | +		return UBUS_STATUS_INVALID_ARGUMENT; | ||||||
|  | + | ||||||
|  | +	if (hwaddr_aton(blobmsg_data(tb[DEL_CLIENT_ADDR]), addr)) | ||||||
|  | +		return UBUS_STATUS_INVALID_ARGUMENT; | ||||||
|  | + | ||||||
|  | +	if (tb[DEL_CLIENT_REASON]) | ||||||
|  | +		reason = blobmsg_get_u32(tb[DEL_CLIENT_REASON]); | ||||||
|  | + | ||||||
|  | +	if (tb[DEL_CLIENT_DEAUTH]) | ||||||
|  | +		deauth = blobmsg_get_bool(tb[DEL_CLIENT_DEAUTH]); | ||||||
|  | + | ||||||
|  | +	sta = ap_get_sta(hapd, addr); | ||||||
|  | +	if (sta) { | ||||||
|  | +		if (deauth) { | ||||||
|  | +			hostapd_drv_sta_deauth(hapd, addr, reason); | ||||||
|  | +			ap_sta_deauthenticate(hapd, sta, reason); | ||||||
|  | +		} else { | ||||||
|  | +			hostapd_drv_sta_disassoc(hapd, addr, reason); | ||||||
|  | +			ap_sta_disassociate(hapd, sta, reason); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (tb[DEL_CLIENT_BAN_TIME]) | ||||||
|  | +		hostapd_bss_ban_client(hapd, addr, blobmsg_get_u32(tb[DEL_CLIENT_BAN_TIME])); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const u8 *addr) | ||||||
|  | +{ | ||||||
|  | +	char *s; | ||||||
|  | + | ||||||
|  | +	s = blobmsg_alloc_string_buffer(buf, name, 20); | ||||||
|  | +	sprintf(s, MACSTR, MAC2STR(addr)); | ||||||
|  | +	blobmsg_add_string_buffer(buf); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +hostapd_bss_list_bans(struct ubus_context *ctx, struct ubus_object *obj, | ||||||
|  | +		      struct ubus_request_data *req, const char *method, | ||||||
|  | +		      struct blob_attr *msg) | ||||||
|  | +{ | ||||||
|  | +	struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); | ||||||
|  | +	struct ubus_banned_client *ban; | ||||||
|  | +	void *c; | ||||||
|  | + | ||||||
|  | +	blob_buf_init(&b, 0); | ||||||
|  | +	c = blobmsg_open_array(&b, "clients"); | ||||||
|  | +	avl_for_each_element(&hapd->ubus.banned, ban, avl) | ||||||
|  | +		blobmsg_add_macaddr(&b, NULL, ban->addr); | ||||||
|  | +	blobmsg_close_array(&b, c); | ||||||
|  | +	ubus_send_reply(ctx, req, b.head); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct ubus_method bss_methods[] = { | ||||||
|  | +	UBUS_METHOD_NOARG("get_clients", hostapd_bss_get_clients), | ||||||
|  | +	UBUS_METHOD("del_client", hostapd_bss_del_client, del_policy), | ||||||
|  | +	UBUS_METHOD_NOARG("list_bans", hostapd_bss_list_bans), | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct ubus_object_type bss_object_type = | ||||||
|  | +	UBUS_OBJECT_TYPE("hostapd_bss", bss_methods); | ||||||
|  | + | ||||||
|  | +static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr) | ||||||
|  | +{ | ||||||
|  | +	return memcmp(k1, k2, ETH_ALEN); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void hostapd_ubus_add_bss(struct hostapd_data *hapd) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_object *obj = &hapd->ubus.obj; | ||||||
|  | +	char *name; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	if (!hostapd_ubus_init()) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL); | ||||||
|  | +	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); | ||||||
|  | +	hostapd_ubus_ref_inc(); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void hostapd_ubus_free_bss(struct hostapd_data *hapd) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_object *obj = &hapd->ubus.obj; | ||||||
|  | +	char *name = (char *) obj->name; | ||||||
|  | + | ||||||
|  | +	if (!ctx) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	if (obj->id) { | ||||||
|  | +		ubus_remove_object(ctx, obj); | ||||||
|  | +		hostapd_ubus_ref_dec(); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	free(name); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +struct ubus_event_req { | ||||||
|  | +	struct ubus_notify_request nreq; | ||||||
|  | +	bool deny; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +ubus_event_cb(struct ubus_notify_request *req, int idx, int ret) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_event_req *ureq = container_of(req, struct ubus_event_req, nreq); | ||||||
|  | + | ||||||
|  | +	if (ret) | ||||||
|  | +		ureq->deny = true; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req) | ||||||
|  | +{ | ||||||
|  | +	struct ubus_banned_client *ban; | ||||||
|  | +	const char *types[HOSTAPD_UBUS_TYPE_MAX] = { | ||||||
|  | +		[HOSTAPD_UBUS_PROBE_REQ] = "probe", | ||||||
|  | +		[HOSTAPD_UBUS_AUTH_REQ] = "auth", | ||||||
|  | +		[HOSTAPD_UBUS_ASSOC_REQ] = "assoc", | ||||||
|  | +	}; | ||||||
|  | +	const char *type = "mgmt"; | ||||||
|  | +	struct ubus_event_req ureq = {}; | ||||||
|  | +	const u8 *addr; | ||||||
|  | + | ||||||
|  | +	if (req->mgmt_frame) | ||||||
|  | +		addr = req->mgmt_frame->sa; | ||||||
|  | +	else | ||||||
|  | +		addr = req->addr; | ||||||
|  | + | ||||||
|  | +	ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl); | ||||||
|  | +	if (ban) | ||||||
|  | +		return -2; | ||||||
|  | + | ||||||
|  | +	if (!hapd->ubus.obj.has_subscribers) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	if (req->type < ARRAY_SIZE(types)) | ||||||
|  | +		type = types[req->type]; | ||||||
|  | + | ||||||
|  | +	blob_buf_init(&b, 0); | ||||||
|  | +	blobmsg_add_macaddr(&b, "address", addr); | ||||||
|  | +	if (req->mgmt_frame) | ||||||
|  | +		blobmsg_add_macaddr(&b, "target", req->mgmt_frame->da); | ||||||
|  | +	if (req->frame_info) | ||||||
|  | +		blobmsg_add_u32(&b, "signal", req->frame_info->ssi_signal); | ||||||
|  | + | ||||||
|  | +	if (ubus_notify_async(ctx, &hapd->ubus.obj, type, b.head, &ureq.nreq)) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	ureq.nreq.status_cb = ubus_event_cb; | ||||||
|  | +	ubus_complete_request(ctx, &ureq.nreq.req, 100); | ||||||
|  | + | ||||||
|  | +	if (ureq.deny) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/src/ap/ubus.h | ||||||
|  | @@ -0,0 +1,78 @@ | ||||||
|  | +/* | ||||||
|  | + * hostapd / ubus support | ||||||
|  | + * Copyright (c) 2013, Felix Fietkau <nbd@openwrt.org> | ||||||
|  | + * | ||||||
|  | + * This software may be distributed under the terms of the BSD license. | ||||||
|  | + * See README for more details. | ||||||
|  | + */ | ||||||
|  | +#ifndef __HOSTAPD_UBUS_H | ||||||
|  | +#define __HOSTAPD_UBUS_H | ||||||
|  | + | ||||||
|  | +enum hostapd_ubus_event_type { | ||||||
|  | +	HOSTAPD_UBUS_PROBE_REQ, | ||||||
|  | +	HOSTAPD_UBUS_AUTH_REQ, | ||||||
|  | +	HOSTAPD_UBUS_ASSOC_REQ, | ||||||
|  | +	HOSTAPD_UBUS_TYPE_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct hostapd_ubus_request { | ||||||
|  | +	enum hostapd_ubus_event_type type; | ||||||
|  | +	const struct ieee80211_mgmt *mgmt_frame; | ||||||
|  | +	const struct hostapd_frame_info *frame_info; | ||||||
|  | +	const u8 *addr; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#ifdef UBUS_SUPPORT | ||||||
|  | + | ||||||
|  | +#include <libubox/avl.h> | ||||||
|  | +#include <libubus.h> | ||||||
|  | + | ||||||
|  | +struct hostapd_iface; | ||||||
|  | +struct hostapd_data; | ||||||
|  | + | ||||||
|  | +struct hostapd_ubus_iface { | ||||||
|  | +	struct ubus_object obj; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct hostapd_ubus_bss { | ||||||
|  | +	struct ubus_object obj; | ||||||
|  | +	struct avl_tree banned; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +void hostapd_ubus_add_iface(struct hostapd_iface *iface); | ||||||
|  | +void hostapd_ubus_free_iface(struct hostapd_iface *iface); | ||||||
|  | +void hostapd_ubus_add_bss(struct hostapd_data *hapd); | ||||||
|  | +void hostapd_ubus_free_bss(struct hostapd_data *hapd); | ||||||
|  | + | ||||||
|  | +int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req); | ||||||
|  | + | ||||||
|  | +#else | ||||||
|  | + | ||||||
|  | +struct hostapd_ubus_iface {}; | ||||||
|  | + | ||||||
|  | +struct hostapd_ubus_bss {}; | ||||||
|  | + | ||||||
|  | +static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface) | ||||||
|  | +{ | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface) | ||||||
|  | +{ | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd) | ||||||
|  | +{ | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd) | ||||||
|  | +{ | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req) | ||||||
|  | +{ | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +#endif | ||||||
|  | --- a/src/ap/hostapd.c | ||||||
|  | +++ b/src/ap/hostapd.c | ||||||
|  | @@ -254,6 +254,7 @@ static int hostapd_broadcast_wep_set(str | ||||||
|  |   | ||||||
|  |  static void hostapd_free_hapd_data(struct hostapd_data *hapd) | ||||||
|  |  { | ||||||
|  | +	hostapd_ubus_free_bss(hapd); | ||||||
|  |  	iapp_deinit(hapd->iapp); | ||||||
|  |  	hapd->iapp = NULL; | ||||||
|  |  	accounting_deinit(hapd); | ||||||
|  | @@ -818,6 +819,8 @@ static int hostapd_setup_bss(struct host | ||||||
|  |  	if (hapd->driver && hapd->driver->set_operstate) | ||||||
|  |  		hapd->driver->set_operstate(hapd->drv_priv, 1); | ||||||
|  |   | ||||||
|  | +	hostapd_ubus_add_bss(hapd); | ||||||
|  | + | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -900,6 +903,7 @@ int hostapd_setup_interface_complete(str | ||||||
|  |  	if (err) | ||||||
|  |  		goto error; | ||||||
|  |   | ||||||
|  | +	hostapd_ubus_add_iface(iface); | ||||||
|  |  	wpa_printf(MSG_DEBUG, "Completing interface initialization"); | ||||||
|  |  	if (hapd->iconf->channel) { | ||||||
|  |  		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); | ||||||
|  | @@ -990,6 +994,7 @@ int hostapd_setup_interface_complete(str | ||||||
|  |   | ||||||
|  |  error: | ||||||
|  |  	wpa_printf(MSG_ERROR, "Interface initialization failed"); | ||||||
|  | +	hostapd_ubus_free_iface(iface); | ||||||
|  |  	eloop_terminate(); | ||||||
|  |  	return -1; | ||||||
|  |  } | ||||||
|  | @@ -1088,6 +1093,8 @@ void hostapd_interface_deinit_free(struc | ||||||
|  |  	void *drv_priv; | ||||||
|  |  	if (iface == NULL) | ||||||
|  |  		return; | ||||||
|  | + | ||||||
|  | +	hostapd_ubus_free_iface(iface); | ||||||
|  |  	driver = iface->bss[0]->driver; | ||||||
|  |  	drv_priv = iface->bss[0]->drv_priv; | ||||||
|  |  	hostapd_interface_deinit(iface); | ||||||
|  | --- a/src/ap/ieee802_11.c | ||||||
|  | +++ b/src/ap/ieee802_11.c | ||||||
|  | @@ -535,7 +535,8 @@ static void handle_auth_sae(struct hosta | ||||||
|  |   | ||||||
|  |   | ||||||
|  |  static void handle_auth(struct hostapd_data *hapd, | ||||||
|  | -			const struct ieee80211_mgmt *mgmt, size_t len) | ||||||
|  | +			const struct ieee80211_mgmt *mgmt, size_t len, | ||||||
|  | +			struct hostapd_frame_info *fi) | ||||||
|  |  { | ||||||
|  |  	u16 auth_alg, auth_transaction, status_code; | ||||||
|  |  	u16 resp = WLAN_STATUS_SUCCESS; | ||||||
|  | @@ -550,6 +551,11 @@ static void handle_auth(struct hostapd_d | ||||||
|  |  	size_t resp_ies_len = 0; | ||||||
|  |  	char *identity = NULL; | ||||||
|  |  	char *radius_cui = NULL; | ||||||
|  | +	struct hostapd_ubus_request req = { | ||||||
|  | +		.type = HOSTAPD_UBUS_AUTH_REQ, | ||||||
|  | +		.mgmt_frame = mgmt, | ||||||
|  | +		.frame_info = fi, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  |  	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { | ||||||
|  |  		printf("handle_auth - too short payload (len=%lu)\n", | ||||||
|  | @@ -623,6 +629,14 @@ static void handle_auth(struct hostapd_d | ||||||
|  |  		resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
|  |  		goto fail; | ||||||
|  |  	} | ||||||
|  | + | ||||||
|  | +	if (hostapd_ubus_handle_event(hapd, &req)) { | ||||||
|  | +		wpa_printf(MSG_DEBUG, "Station " MACSTR " rejected by ubus handler.\n", | ||||||
|  | +		       MAC2STR(mgmt->sa)); | ||||||
|  | +		resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	if (res == HOSTAPD_ACL_PENDING) { | ||||||
|  |  		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR | ||||||
|  |  			   " waiting for an external authentication", | ||||||
|  | @@ -1211,13 +1225,18 @@ static void send_assoc_resp(struct hosta | ||||||
|  |   | ||||||
|  |  static void handle_assoc(struct hostapd_data *hapd, | ||||||
|  |  			 const struct ieee80211_mgmt *mgmt, size_t len, | ||||||
|  | -			 int reassoc) | ||||||
|  | +			 int reassoc, struct hostapd_frame_info *fi) | ||||||
|  |  { | ||||||
|  |  	u16 capab_info, listen_interval; | ||||||
|  |  	u16 resp = WLAN_STATUS_SUCCESS; | ||||||
|  |  	const u8 *pos; | ||||||
|  |  	int left, i; | ||||||
|  |  	struct sta_info *sta; | ||||||
|  | +	struct hostapd_ubus_request req = { | ||||||
|  | +		.type = HOSTAPD_UBUS_ASSOC_REQ, | ||||||
|  | +		.mgmt_frame = mgmt, | ||||||
|  | +		.frame_info = fi, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  |  	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : | ||||||
|  |  				      sizeof(mgmt->u.assoc_req))) { | ||||||
|  | @@ -1296,6 +1315,13 @@ static void handle_assoc(struct hostapd_ | ||||||
|  |  		goto fail; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (hostapd_ubus_handle_event(hapd, &req)) { | ||||||
|  | +		wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n", | ||||||
|  | +		       MAC2STR(mgmt->sa)); | ||||||
|  | +		resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
|  | +		goto fail; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	sta->capability = capab_info; | ||||||
|  |  	sta->listen_interval = listen_interval; | ||||||
|  |   | ||||||
|  | @@ -1705,7 +1731,7 @@ void ieee802_11_mgmt(struct hostapd_data | ||||||
|  |   | ||||||
|  |   | ||||||
|  |  	if (stype == WLAN_FC_STYPE_PROBE_REQ) { | ||||||
|  | -		handle_probe_req(hapd, mgmt, len, fi->ssi_signal); | ||||||
|  | +		handle_probe_req(hapd, mgmt, len, fi); | ||||||
|  |  		return; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | @@ -1720,15 +1746,15 @@ void ieee802_11_mgmt(struct hostapd_data | ||||||
|  |  	switch (stype) { | ||||||
|  |  	case WLAN_FC_STYPE_AUTH: | ||||||
|  |  		wpa_printf(MSG_DEBUG, "mgmt::auth"); | ||||||
|  | -		handle_auth(hapd, mgmt, len); | ||||||
|  | +		handle_auth(hapd, mgmt, len, fi); | ||||||
|  |  		break; | ||||||
|  |  	case WLAN_FC_STYPE_ASSOC_REQ: | ||||||
|  |  		wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); | ||||||
|  | -		handle_assoc(hapd, mgmt, len, 0); | ||||||
|  | +		handle_assoc(hapd, mgmt, len, 0, fi); | ||||||
|  |  		break; | ||||||
|  |  	case WLAN_FC_STYPE_REASSOC_REQ: | ||||||
|  |  		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); | ||||||
|  | -		handle_assoc(hapd, mgmt, len, 1); | ||||||
|  | +		handle_assoc(hapd, mgmt, len, 1, fi); | ||||||
|  |  		break; | ||||||
|  |  	case WLAN_FC_STYPE_DISASSOC: | ||||||
|  |  		wpa_printf(MSG_DEBUG, "mgmt::disassoc"); | ||||||
|  | --- a/src/ap/beacon.c | ||||||
|  | +++ b/src/ap/beacon.c | ||||||
|  | @@ -352,7 +352,7 @@ static enum ssid_match_result ssid_match | ||||||
|  |   | ||||||
|  |  void handle_probe_req(struct hostapd_data *hapd, | ||||||
|  |  		      const struct ieee80211_mgmt *mgmt, size_t len, | ||||||
|  | -		      int ssi_signal) | ||||||
|  | +		      struct hostapd_frame_info *fi) | ||||||
|  |  { | ||||||
|  |  	u8 *resp; | ||||||
|  |  	struct ieee802_11_elems elems; | ||||||
|  | @@ -360,8 +360,14 @@ void handle_probe_req(struct hostapd_dat | ||||||
|  |  	size_t ie_len; | ||||||
|  |  	struct sta_info *sta = NULL; | ||||||
|  |  	size_t i, resp_len; | ||||||
|  | +	int ssi_signal = fi->ssi_signal; | ||||||
|  |  	int noack; | ||||||
|  |  	enum ssid_match_result res; | ||||||
|  | +	struct hostapd_ubus_request req = { | ||||||
|  | +		.type = HOSTAPD_UBUS_PROBE_REQ, | ||||||
|  | +		.mgmt_frame = mgmt, | ||||||
|  | +		.frame_info = fi, | ||||||
|  | +	}; | ||||||
|  |   | ||||||
|  |  	ie = mgmt->u.probe_req.variable; | ||||||
|  |  	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) | ||||||
|  | @@ -489,6 +495,12 @@ void handle_probe_req(struct hostapd_dat | ||||||
|  |  	} | ||||||
|  |  #endif /* CONFIG_INTERWORKING */ | ||||||
|  |   | ||||||
|  | +	if (hostapd_ubus_handle_event(hapd, &req)) { | ||||||
|  | +		wpa_printf(MSG_DEBUG, "Probe request for " MACSTR " rejected by ubus handler.\n", | ||||||
|  | +		       MAC2STR(mgmt->sa)); | ||||||
|  | +		return; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	/* TODO: verify that supp_rates contains at least one matching rate | ||||||
|  |  	 * with AP configuration */ | ||||||
|  |   | ||||||
|  | --- a/src/ap/beacon.h | ||||||
|  | +++ b/src/ap/beacon.h | ||||||
|  | @@ -20,7 +20,7 @@ struct ieee80211_mgmt; | ||||||
|  |   | ||||||
|  |  void handle_probe_req(struct hostapd_data *hapd, | ||||||
|  |  		      const struct ieee80211_mgmt *mgmt, size_t len, | ||||||
|  | -		      int ssi_signal); | ||||||
|  | +		      struct hostapd_frame_info *fi); | ||||||
|  |  void ieee802_11_set_beacon(struct hostapd_data *hapd); | ||||||
|  |  void ieee802_11_set_beacons(struct hostapd_iface *iface); | ||||||
|  |  void ieee802_11_update_beacons(struct hostapd_iface *iface); | ||||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau