hostapd: add ucode support, use ucode for the main ubus object
[openwrt/staging/wigyori.git] / package / network / services / hostapd / src / wpa_supplicant / ubus.c
1 /*
2 * wpa_supplicant / ubus support
3 * Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
4 * Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "utils/eloop.h"
13 #include "utils/wpabuf.h"
14 #include "common/ieee802_11_defs.h"
15 #include "wpa_supplicant_i.h"
16 #include "wps_supplicant.h"
17 #include "ubus.h"
18
19 static struct ubus_context *ctx;
20 static struct blob_buf b;
21 static int ctx_ref;
22
23 static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj)
24 {
25 return container_of(obj, struct wpa_global, ubus_global);
26 }
27
28 static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj)
29 {
30 return container_of(obj, struct wpa_supplicant, ubus.obj);
31 }
32
33 static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
34 {
35 if (ubus_reconnect(ctx, NULL)) {
36 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
37 return;
38 }
39
40 ubus_add_uloop(ctx);
41 }
42
43 static void wpas_ubus_connection_lost(struct ubus_context *ctx)
44 {
45 uloop_fd_delete(&ctx->sock);
46 eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
47 }
48
49 static bool wpas_ubus_init(void)
50 {
51 if (ctx)
52 return true;
53
54 eloop_add_uloop();
55 ctx = ubus_connect(NULL);
56 if (!ctx)
57 return false;
58
59 ctx->connection_lost = wpas_ubus_connection_lost;
60 ubus_add_uloop(ctx);
61
62 return true;
63 }
64
65 static void wpas_ubus_ref_inc(void)
66 {
67 ctx_ref++;
68 }
69
70 static void wpas_ubus_ref_dec(void)
71 {
72 ctx_ref--;
73 if (!ctx)
74 return;
75
76 if (ctx_ref)
77 return;
78
79 uloop_fd_delete(&ctx->sock);
80 ubus_free(ctx);
81 ctx = NULL;
82 }
83
84 static int
85 wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
86 struct ubus_request_data *req, const char *method,
87 struct blob_attr *msg)
88 {
89 struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
90
91 blob_buf_init(&b, 0);
92 blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes));
93 blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes));
94 ubus_send_reply(ctx, req, b.head);
95
96 return 0;
97 }
98
99 static int
100 wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
101 struct ubus_request_data *req, const char *method,
102 struct blob_attr *msg)
103 {
104 struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
105
106 if (wpa_supplicant_reload_configuration(wpa_s))
107 return UBUS_STATUS_UNKNOWN_ERROR;
108 else
109 return 0;
110 }
111
112 #ifdef CONFIG_WPS
113 enum {
114 WPS_START_MULTI_AP,
115 __WPS_START_MAX
116 };
117
118 static const struct blobmsg_policy wps_start_policy[] = {
119 [WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL },
120 };
121
122 static int
123 wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
124 struct ubus_request_data *req, const char *method,
125 struct blob_attr *msg)
126 {
127 int rc;
128 struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
129 struct blob_attr *tb[__WPS_START_MAX], *cur;
130 int multi_ap = 0;
131
132 blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
133
134 if (tb[WPS_START_MULTI_AP])
135 multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]);
136
137 rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap);
138
139 if (rc != 0)
140 return UBUS_STATUS_NOT_SUPPORTED;
141
142 return 0;
143 }
144
145 static int
146 wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
147 struct ubus_request_data *req, const char *method,
148 struct blob_attr *msg)
149 {
150 int rc;
151 struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
152
153 rc = wpas_wps_cancel(wpa_s);
154
155 if (rc != 0)
156 return UBUS_STATUS_NOT_SUPPORTED;
157
158 return 0;
159 }
160 #endif
161
162 static const struct ubus_method bss_methods[] = {
163 UBUS_METHOD_NOARG("reload", wpas_bss_reload),
164 UBUS_METHOD_NOARG("get_features", wpas_bss_get_features),
165 #ifdef CONFIG_WPS
166 UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start),
167 UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel),
168 #endif
169 };
170
171 static struct ubus_object_type bss_object_type =
172 UBUS_OBJECT_TYPE("wpas_bss", bss_methods);
173
174 void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
175 {
176 struct ubus_object *obj = &wpa_s->ubus.obj;
177 char *name;
178 int ret;
179
180 if (!wpas_ubus_init())
181 return;
182
183 if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0)
184 return;
185
186 obj->name = name;
187 obj->type = &bss_object_type;
188 obj->methods = bss_object_type.methods;
189 obj->n_methods = bss_object_type.n_methods;
190 ret = ubus_add_object(ctx, obj);
191 wpas_ubus_ref_inc();
192 }
193
194 void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
195 {
196 struct ubus_object *obj = &wpa_s->ubus.obj;
197 char *name = (char *) obj->name;
198
199 if (!ctx)
200 return;
201
202 if (obj->id) {
203 ubus_remove_object(ctx, obj);
204 wpas_ubus_ref_dec();
205 }
206
207 free(name);
208 }
209
210 #ifdef CONFIG_WPS
211 void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
212 {
213 u16 auth_type;
214 char *ifname, *encryption, *ssid, *key;
215 size_t ifname_len;
216
217 if (!cred)
218 return;
219
220 auth_type = cred->auth_type;
221
222 if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))
223 auth_type = WPS_AUTH_WPA2PSK;
224
225 if (auth_type != WPS_AUTH_OPEN &&
226 auth_type != WPS_AUTH_WPAPSK &&
227 auth_type != WPS_AUTH_WPA2PSK) {
228 wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
229 "unsupported authentication type 0x%x",
230 auth_type);
231 return;
232 }
233
234 if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
235 if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
236 wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
237 "invalid Network Key length %lu",
238 (unsigned long) cred->key_len);
239 return;
240 }
241 }
242
243 blob_buf_init(&b, 0);
244
245 ifname_len = strlen(wpa_s->ifname);
246 ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1);
247 memcpy(ifname, wpa_s->ifname, ifname_len + 1);
248 ifname[ifname_len] = '\0';
249 blobmsg_add_string_buffer(&b);
250
251 switch (auth_type) {
252 case WPS_AUTH_WPA2PSK:
253 encryption = "psk2";
254 break;
255 case WPS_AUTH_WPAPSK:
256 encryption = "psk";
257 break;
258 default:
259 encryption = "none";
260 break;
261 }
262
263 blobmsg_add_string(&b, "encryption", encryption);
264
265 ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1);
266 memcpy(ssid, cred->ssid, cred->ssid_len);
267 ssid[cred->ssid_len] = '\0';
268 blobmsg_add_string_buffer(&b);
269
270 if (cred->key_len > 0) {
271 key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1);
272 memcpy(key, cred->key, cred->key_len);
273 key[cred->key_len] = '\0';
274 blobmsg_add_string_buffer(&b);
275 }
276
277 // ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1);
278 ubus_send_event(ctx, "wps_credentials", b.head);
279 }
280 #endif /* CONFIG_WPS */