aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/hostapd/src/wpa_supplicant
diff options
context:
space:
mode:
Diffstat (limited to 'package/network/services/hostapd/src/wpa_supplicant')
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ubus.c162
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ubus.h11
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ucode.c281
-rw-r--r--package/network/services/hostapd/src/wpa_supplicant/ucode.h49
4 files changed, 336 insertions, 167 deletions
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ubus.c b/package/network/services/hostapd/src/wpa_supplicant/ubus.c
index 16a68c5073..1c477f0c0c 100644
--- a/package/network/services/hostapd/src/wpa_supplicant/ubus.c
+++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.c
@@ -30,12 +30,6 @@ static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *ob
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)) {
@@ -43,12 +37,12 @@ static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
return;
}
- eloop_register_read_sock(ctx->sock.fd, ubus_receive, ctx, NULL);
+ ubus_add_uloop(ctx);
}
static void wpas_ubus_connection_lost(struct ubus_context *ctx)
{
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
}
@@ -57,12 +51,14 @@ static bool wpas_ubus_init(void)
if (ctx)
return true;
+ eloop_add_uloop();
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);
+ ubus_add_uloop(ctx);
+
return true;
}
@@ -80,7 +76,7 @@ static void wpas_ubus_ref_dec(void)
if (ctx_ref)
return;
- eloop_unregister_read_sock(ctx->sock.fd);
+ uloop_fd_delete(&ctx->sock);
ubus_free(ctx);
ctx = NULL;
}
@@ -211,152 +207,6 @@ 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;
-
- blob_buf_init(&b, 0);
- blobmsg_add_u32(&b, "pid", getpid());
- ubus_send_reply(ctx, req, b.head);
-
- 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 ret;
-
- if (!wpas_ubus_init())
- return;
-
- obj->name = strdup("wpa_supplicant");
-
- 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 bf92b98c01..f6681cb26d 100644
--- a/package/network/services/hostapd/src/wpa_supplicant/ubus.h
+++ b/package/network/services/hostapd/src/wpa_supplicant/ubus.h
@@ -24,9 +24,6 @@ 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
@@ -34,14 +31,6 @@ void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential
#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)
{
}
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.c b/package/network/services/hostapd/src/wpa_supplicant/ucode.c
new file mode 100644
index 0000000000..55d22584ff
--- /dev/null
+++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.c
@@ -0,0 +1,281 @@
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/ucode.h"
+#include "drivers/driver.h"
+#include "ap/hostapd.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "bss.h"
+#include "ucode.h"
+
+static struct wpa_global *wpa_global;
+static uc_resource_type_t *global_type, *iface_type;
+static uc_value_t *global, *iface_registry;
+static uc_vm_t *vm;
+
+static uc_value_t *
+wpas_ucode_iface_get_uval(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_s->ucode.idx)
+ return wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+
+ val = uc_resource_new(iface_type, wpa_s);
+ wpa_s->ucode.idx = wpa_ucode_registry_add(iface_registry, val);
+
+ return val;
+}
+
+static void
+wpas_ucode_update_interfaces(void)
+{
+ uc_value_t *ifs = ucv_object_new(vm);
+ struct wpa_supplicant *wpa_s;
+ int i;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ ucv_object_add(ifs, wpa_s->ifname, ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+
+ ucv_object_add(ucv_prototype_get(global), "interfaces", ucv_get(ifs));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ if (wpa_ucode_call_prepare("iface_add"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(wpas_ucode_iface_get_uval(wpa_s)));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_remove(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ wpa_s->ucode.idx = 0;
+ if (wpa_ucode_call_prepare("iface_remove"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ ucv_put(wpa_ucode_call(2));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_update_state(struct wpa_supplicant *wpa_s)
+{
+ const char *state;
+ uc_value_t *val;
+
+ val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ if (wpa_ucode_call_prepare("state"))
+ return;
+
+ state = wpa_supplicant_state_txt(wpa_s->wpa_state);
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_get(ucv_string_new(state)));
+ ucv_put(wpa_ucode_call(3));
+ ucv_gc(vm);
+}
+
+void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data)
+{
+ const char *state;
+ uc_value_t *val;
+
+ if (event != EVENT_CH_SWITCH_STARTED)
+ return;
+
+ val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx);
+ if (!val)
+ return;
+
+ if (wpa_ucode_call_prepare("event"))
+ return;
+
+ uc_value_push(ucv_get(ucv_string_new(wpa_s->ifname)));
+ uc_value_push(ucv_get(val));
+ uc_value_push(ucv_get(ucv_string_new(event_to_string(event))));
+ val = ucv_object_new(vm);
+ uc_value_push(ucv_get(val));
+
+ if (event == EVENT_CH_SWITCH_STARTED) {
+ ucv_object_add(val, "csa_count", ucv_int64_new(data->ch_switch.count));
+ ucv_object_add(val, "frequency", ucv_int64_new(data->ch_switch.freq));
+ ucv_object_add(val, "sec_chan_offset", ucv_int64_new(data->ch_switch.ch_offset));
+ ucv_object_add(val, "center_freq1", ucv_int64_new(data->ch_switch.cf1));
+ ucv_object_add(val, "center_freq2", ucv_int64_new(data->ch_switch.cf2));
+ }
+
+ ucv_put(wpa_ucode_call(4));
+ ucv_gc(vm);
+}
+
+static const char *obj_stringval(uc_value_t *obj, const char *name)
+{
+ uc_value_t *val = ucv_object_get(obj, name, NULL);
+
+ return ucv_string_get(val);
+}
+
+static uc_value_t *
+uc_wpas_add_iface(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *info = uc_fn_arg(0);
+ uc_value_t *ifname = ucv_object_get(info, "iface", NULL);
+ uc_value_t *bridge = ucv_object_get(info, "bridge", NULL);
+ uc_value_t *config = ucv_object_get(info, "config", NULL);
+ uc_value_t *ctrl = ucv_object_get(info, "ctrl", NULL);
+ struct wpa_interface iface;
+ int ret = -1;
+
+ if (ucv_type(info) != UC_OBJECT)
+ goto out;
+
+ iface = (struct wpa_interface){
+ .driver = "nl80211",
+ .ifname = ucv_string_get(ifname),
+ .bridge_ifname = ucv_string_get(bridge),
+ .confname = ucv_string_get(config),
+ .ctrl_interface = ucv_string_get(ctrl),
+ };
+
+ if (!iface.ifname || !iface.confname)
+ goto out;
+
+ ret = wpa_supplicant_add_iface(wpa_global, &iface, 0) ? 0 : -1;
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_remove_iface(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = NULL;
+ uc_value_t *ifname_arg = uc_fn_arg(0);
+ const char *ifname = ucv_string_get(ifname_arg);
+ int ret = -1;
+
+ if (!ifname)
+ goto out;
+
+ for (wpa_s = wpa_global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ if (!strcmp(wpa_s->ifname, ifname))
+ break;
+
+ if (!wpa_s)
+ goto out;
+
+ ret = wpa_supplicant_remove_iface(wpa_global, wpa_s, 0);
+ wpas_ucode_update_interfaces();
+
+out:
+ return ucv_int64_new(ret);
+}
+
+static uc_value_t *
+uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
+{
+ struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface");
+ struct wpa_bss *bss;
+ uc_value_t *ret, *val;
+
+ if (!wpa_s)
+ return NULL;
+
+ ret = ucv_object_new(vm);
+
+ val = ucv_string_new(wpa_supplicant_state_txt(wpa_s->wpa_state));
+ ucv_object_add(ret, "state", ucv_get(val));
+
+ bss = wpa_s->current_bss;
+ if (bss) {
+ int sec_chan = 0;
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ const struct ieee80211_ht_operation *ht_oper;
+ int sec;
+
+ ht_oper = (const void *) (ie + 2);
+ sec = ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(sec_chan));
+ ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
+ }
+
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+
+ ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(ifmsh->conf->secondary_channel));
+ ucv_object_add(ret, "frequency", ucv_int64_new(ifmsh->freq));
+ }
+#endif
+
+ return ret;
+}
+
+int wpas_ucode_init(struct wpa_global *gl)
+{
+ static const uc_function_list_t global_fns[] = {
+ { "printf", uc_wpa_printf },
+ { "getpid", uc_wpa_getpid },
+ { "add_iface", uc_wpas_add_iface },
+ { "remove_iface", uc_wpas_remove_iface },
+ };
+ static const uc_function_list_t iface_fns[] = {
+ { "status", uc_wpas_iface_status },
+ };
+ uc_value_t *data, *proto;
+
+ wpa_global = gl;
+ vm = wpa_ucode_create_vm();
+
+ global_type = uc_type_declare(vm, "wpas.global", global_fns, NULL);
+ iface_type = uc_type_declare(vm, "wpas.iface", iface_fns, NULL);
+
+ iface_registry = ucv_array_new(vm);
+ uc_vm_registry_set(vm, "wpas.iface_registry", iface_registry);
+
+ global = wpa_ucode_global_init("wpas", global_type);
+
+ if (wpa_ucode_run(HOSTAPD_UC_PATH "wpa_supplicant.uc"))
+ goto free_vm;
+
+ ucv_gc(vm);
+ return 0;
+
+free_vm:
+ wpa_ucode_free_vm();
+ return -1;
+}
+
+void wpas_ucode_free(void)
+{
+ if (wpa_ucode_call_prepare("shutdown") == 0)
+ ucv_put(wpa_ucode_call(0));
+ wpa_ucode_free_vm();
+}
diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.h b/package/network/services/hostapd/src/wpa_supplicant/ucode.h
new file mode 100644
index 0000000000..a429a0ed87
--- /dev/null
+++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.h
@@ -0,0 +1,49 @@
+#ifndef __WPAS_UCODE_H
+#define __WPAS_UCODE_H
+
+#include "utils/ucode.h"
+
+struct wpa_global;
+union wpa_event_data;
+struct wpa_supplicant;
+
+struct wpas_ucode_bss {
+#ifdef UCODE_SUPPORT
+ unsigned int idx;
+#endif
+};
+
+#ifdef UCODE_SUPPORT
+int wpas_ucode_init(struct wpa_global *gl);
+void wpas_ucode_free(void);
+void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s);
+void wpas_ucode_update_state(struct wpa_supplicant *wpa_s);
+void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data);
+#else
+static inline int wpas_ucode_init(struct wpa_global *gl)
+{
+ return -EINVAL;
+}
+static inline void wpas_ucode_free(void)
+{
+}
+static inline void wpas_ucode_add_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_free_bss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_update_state(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void wpas_ucode_event(struct wpa_supplicant *wpa_s, int event, union wpa_event_data *data)
+{
+}
+
+#endif
+
+#endif