diff options
author | John Crispin <john@phrozen.org> | 2019-10-30 16:57:22 +0100 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2019-11-12 11:52:26 +0100 |
commit | 60fb4c92b6b0d1582d31e02167b90b424185f3a2 (patch) | |
tree | f707a8fe5cc2e1abf21b51d38f9767f1b1d69996 /package/network/services/hostapd/src | |
parent | 155ede4f1fdb192b11f8ae2dbffda5f7ef4903bd (diff) | |
download | upstream-60fb4c92b6b0d1582d31e02167b90b424185f3a2.tar.gz upstream-60fb4c92b6b0d1582d31e02167b90b424185f3a2.tar.bz2 upstream-60fb4c92b6b0d1582d31e02167b90b424185f3a2.zip |
hostapd: add ubus reload
Add ubus interface to hostapd and wpa_supplicant to allow dynamically
reloading wiface configuration without having to restart the hostapd
process.
As a consequence, both hostapd and wpa_supplicant are now started
persistently on boot for each wifi device in the system and then
receive ubus calls adding, modifying or removing interface
configuration.
At a later stage it would be desirable to reduce the services to one
single instance managing all radios.
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Diffstat (limited to 'package/network/services/hostapd/src')
4 files changed, 328 insertions, 4 deletions
diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index 3b768d0e8c..e25c3294ee 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -26,12 +26,16 @@ static struct ubus_context *ctx; static struct blob_buf b; static int ctx_ref; +static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj) +{ + return container_of(obj, struct hapd_interfaces, ubus); +} + static inline struct hostapd_data *get_hapd_from_object(struct ubus_object *obj) { return container_of(obj, struct hostapd_data, ubus.obj); } - struct ubus_banned_client { struct avl_node avl; u8 addr[ETH_ALEN]; @@ -143,6 +147,16 @@ hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time) } static int +hostapd_bss_reload(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); + hostapd_reload_config(hapd->iface); + hostapd_reload_iface(hapd->iface); +} + +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) @@ -380,6 +394,70 @@ hostapd_bss_update_beacon(struct ubus_context *ctx, struct ubus_object *obj, } enum { + CONFIG_IFACE, + CONFIG_FILE, + __CONFIG_MAX +}; + +static const struct blobmsg_policy config_add_policy[__CONFIG_MAX] = { + [CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, + [CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING }, +}; + +static int +hostapd_config_add(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CONFIG_MAX]; + struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj); + char buf[128]; + + blobmsg_parse(config_add_policy, __CONFIG_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[CONFIG_FILE] || !tb[CONFIG_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + snprintf(buf, sizeof(buf), "bss_config=%s:%s", + blobmsg_get_string(tb[CONFIG_IFACE]), + blobmsg_get_string(tb[CONFIG_FILE])); + + if (hostapd_add_iface(interfaces, buf)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +enum { + CONFIG_REM_IFACE, + __CONFIG_REM_MAX +}; + +static const struct blobmsg_policy config_remove_policy[__CONFIG_REM_MAX] = { + [CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, +}; + +static int +hostapd_config_remove(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CONFIG_REM_MAX]; + struct hapd_interfaces *interfaces = get_hapd_interfaces_from_object(obj); + char buf[128]; + + blobmsg_parse(config_remove_policy, __CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[CONFIG_REM_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hostapd_remove_iface(interfaces, blobmsg_get_string(tb[CONFIG_REM_IFACE]))) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +enum { CSA_FREQ, CSA_BCN_COUNT, CSA_CENTER_FREQ1, @@ -949,6 +1027,7 @@ hostapd_wnm_disassoc_imminent(struct ubus_context *ctx, struct ubus_object *obj, #endif static const struct ubus_method bss_methods[] = { + UBUS_METHOD_NOARG("reload", hostapd_bss_reload), 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), @@ -1021,6 +1100,56 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd) free(name); } +static const struct ubus_method daemon_methods[] = { + UBUS_METHOD("config_add", hostapd_config_add, config_add_policy), + UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy), +}; + +static struct ubus_object_type daemon_object_type = + UBUS_OBJECT_TYPE("hostapd", daemon_methods); + +void hostapd_ubus_add(struct hapd_interfaces *interfaces) +{ + struct ubus_object *obj = &interfaces->ubus; + int name_len; + int ret; + + if (!hostapd_ubus_init()) + return; + + name_len = strlen("hostapd") + 1; + if (interfaces->name) + name_len += strlen(interfaces->name) + 1; + obj->name = malloc(name_len); + strcpy(obj->name, "hostapd"); + if (interfaces->name) { + strcat(obj->name, "."); + strcat(obj->name, interfaces->name); + } + + obj->type = &daemon_object_type; + obj->methods = daemon_object_type.methods; + obj->n_methods = daemon_object_type.n_methods; + ret = ubus_add_object(ctx, obj); + hostapd_ubus_ref_inc(); +} + +void hostapd_ubus_free(struct hapd_interfaces *interfaces) +{ + struct ubus_object *obj = &interfaces->ubus; + 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; int resp; diff --git a/package/network/services/hostapd/src/src/ap/ubus.h b/package/network/services/hostapd/src/src/ap/ubus.h index 58ebe0e65b..27acd32659 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.h +++ b/package/network/services/hostapd/src/src/ap/ubus.h @@ -25,6 +25,7 @@ struct hostapd_ubus_request { struct hostapd_iface; struct hostapd_data; +struct hapd_interfaces; #ifdef UBUS_SUPPORT @@ -45,6 +46,9 @@ void hostapd_ubus_free_bss(struct hostapd_data *hapd); int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req); void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac); +void hostapd_ubus_add(struct hapd_interfaces *interfaces); +void hostapd_ubus_free(struct hapd_interfaces *interfaces); + #else struct hostapd_ubus_bss {}; @@ -73,6 +77,14 @@ static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct ho static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac) { } + +static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces) +{ +} + +static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces) +{ +} #endif #endif diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.c b/package/network/services/hostapd/src/wpa_supplicant/ubus.c index 5fdb57be7a..9a98979e9a 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ubus.c +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.c @@ -20,6 +20,11 @@ static struct ubus_context *ctx; static struct blob_buf b; static int ctx_ref; +static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj) +{ + return container_of(obj, struct wpa_global, ubus_global); +} + static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj) { return container_of(obj, struct wpa_supplicant, ubus.obj); @@ -95,6 +100,19 @@ wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +wpas_bss_reload(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); + + if (wpa_supplicant_reload_configuration(wpa_s)) + return UBUS_STATUS_UNKNOWN_ERROR; + else + return 0; +} + #ifdef CONFIG_WPS enum { WPS_START_MULTI_AP, @@ -146,11 +164,12 @@ wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj, #endif static const struct ubus_method bss_methods[] = { + UBUS_METHOD_NOARG("reload", wpas_bss_reload), + UBUS_METHOD_NOARG("get_features", wpas_bss_get_features), #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 = @@ -162,8 +181,6 @@ void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s) char *name; int ret; - if (!wpas_ubus_init()) - return; if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0) return; @@ -192,6 +209,159 @@ void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s) free(name); } +enum { + WPAS_CONFIG_DRIVER, + WPAS_CONFIG_IFACE, + WPAS_CONFIG_BRIDGE, + WPAS_CONFIG_HOSTAPD_CTRL, + WPAS_CONFIG_CTRL, + WPAS_CONFIG_FILE, + __WPAS_CONFIG_MAX +}; + +static const struct blobmsg_policy wpas_config_add_policy[__WPAS_CONFIG_MAX] = { + [WPAS_CONFIG_DRIVER] = { "driver", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_BRIDGE] = { "bridge", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_HOSTAPD_CTRL] = { "hostapd_ctrl", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_CTRL] = { "ctrl", BLOBMSG_TYPE_STRING }, + [WPAS_CONFIG_FILE] = { "config", BLOBMSG_TYPE_STRING }, +}; + +static int +wpas_config_add(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__WPAS_CONFIG_MAX]; + struct wpa_global *global = get_wpa_global_from_object(obj); + struct wpa_interface *iface; + + blobmsg_parse(wpas_config_add_policy, __WPAS_CONFIG_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[WPAS_CONFIG_FILE] || !tb[WPAS_CONFIG_IFACE] || !tb[WPAS_CONFIG_DRIVER]) + return UBUS_STATUS_INVALID_ARGUMENT; + + iface = os_zalloc(sizeof(struct wpa_interface)); + if (iface == NULL) + return UBUS_STATUS_UNKNOWN_ERROR; + + iface->driver = blobmsg_get_string(tb[WPAS_CONFIG_DRIVER]); + iface->ifname = blobmsg_get_string(tb[WPAS_CONFIG_IFACE]); + iface->confname = blobmsg_get_string(tb[WPAS_CONFIG_FILE]); + + if (tb[WPAS_CONFIG_BRIDGE]) + iface->bridge_ifname = blobmsg_get_string(tb[WPAS_CONFIG_BRIDGE]); + + if (tb[WPAS_CONFIG_CTRL]) + iface->ctrl_interface = blobmsg_get_string(tb[WPAS_CONFIG_CTRL]); + + if (tb[WPAS_CONFIG_HOSTAPD_CTRL]) + iface->hostapd_ctrl = blobmsg_get_string(tb[WPAS_CONFIG_HOSTAPD_CTRL]); + + if (!wpa_supplicant_add_iface(global, iface, NULL)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +enum { + WPAS_CONFIG_REM_IFACE, + __WPAS_CONFIG_REM_MAX +}; + +static const struct blobmsg_policy wpas_config_remove_policy[__WPAS_CONFIG_REM_MAX] = { + [WPAS_CONFIG_REM_IFACE] = { "iface", BLOBMSG_TYPE_STRING }, +}; + +static int +wpas_config_remove(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__WPAS_CONFIG_REM_MAX]; + struct wpa_global *global = get_wpa_global_from_object(obj); + struct wpa_supplicant *wpa_s = NULL; + unsigned int found = 0; + + blobmsg_parse(wpas_config_remove_policy, __WPAS_CONFIG_REM_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[WPAS_CONFIG_REM_IFACE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + /* find wpa_s object for to-be-removed interface */ + for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { + if (!strncmp(wpa_s->ifname, + blobmsg_get_string(tb[WPAS_CONFIG_REM_IFACE]), + sizeof(wpa_s->ifname))) + { + found = 1; + break; + } + } + + if (!found) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (wpa_supplicant_remove_iface(global, wpa_s, 0)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return UBUS_STATUS_OK; +} + +static const struct ubus_method wpas_daemon_methods[] = { + UBUS_METHOD("config_add", wpas_config_add, wpas_config_add_policy), + UBUS_METHOD("config_remove", wpas_config_remove, wpas_config_remove_policy), +}; + +static struct ubus_object_type wpas_daemon_object_type = + UBUS_OBJECT_TYPE("wpa_supplicant", wpas_daemon_methods); + +void wpas_ubus_add(struct wpa_global *global) +{ + struct ubus_object *obj = &global->ubus_global; + int name_len; + int ret; + + if (!wpas_ubus_init()) + return; + + name_len = strlen("wpa_supplicant") + 1; + if (global->params.name) + name_len += strlen(global->params.name) + 1; + obj->name = malloc(name_len); + strcpy(obj->name, "wpa_supplicant"); + + if (global->params.name) + { + strcat(obj->name, "."); + strcat(obj->name, global->params.name); + } + + obj->type = &wpas_daemon_object_type; + obj->methods = wpas_daemon_object_type.methods; + obj->n_methods = wpas_daemon_object_type.n_methods; + ret = ubus_add_object(ctx, obj); + wpas_ubus_ref_inc(); +} + +void wpas_ubus_free(struct wpa_global *global) +{ + struct ubus_object *obj = &global->ubus_global; + 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) { diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.h b/package/network/services/hostapd/src/wpa_supplicant/ubus.h index c37e743e73..bf92b98c01 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ubus.h +++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.h @@ -10,6 +10,8 @@ #define __WPAS_UBUS_H struct wpa_supplicant; +struct wpa_global; + #include "wps_supplicant.h" #ifdef UBUS_SUPPORT @@ -22,6 +24,9 @@ struct wpas_ubus_bss { void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s); void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s); +void wpas_ubus_add(struct wpa_global *global); +void wpas_ubus_free(struct wpa_global *global); + #ifdef CONFIG_WPS void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); #endif @@ -48,6 +53,14 @@ 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) { } + +static inline void wpas_ubus_add(struct wpa_global *global) +{ +} + +static inline void wpas_ubus_free(struct wpa_global *global) +{ +} #endif #endif |