Branch data Line data Source code
1 : : /*
2 : : * hostapd / UNIX domain socket -based control interface
3 : : * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "utils/includes.h"
10 : :
11 : : #ifndef CONFIG_NATIVE_WINDOWS
12 : :
13 : : #include <sys/un.h>
14 : : #include <sys/stat.h>
15 : : #include <stddef.h>
16 : :
17 : : #include "utils/common.h"
18 : : #include "utils/eloop.h"
19 : : #include "common/version.h"
20 : : #include "common/ieee802_11_defs.h"
21 : : #include "drivers/driver.h"
22 : : #include "radius/radius_client.h"
23 : : #include "radius/radius_server.h"
24 : : #include "ap/hostapd.h"
25 : : #include "ap/ap_config.h"
26 : : #include "ap/ieee802_1x.h"
27 : : #include "ap/wpa_auth.h"
28 : : #include "ap/ieee802_11.h"
29 : : #include "ap/sta_info.h"
30 : : #include "ap/wps_hostapd.h"
31 : : #include "ap/ctrl_iface_ap.h"
32 : : #include "ap/ap_drv_ops.h"
33 : : #include "ap/hs20.h"
34 : : #include "ap/wnm_ap.h"
35 : : #include "ap/wpa_auth.h"
36 : : #include "wps/wps_defs.h"
37 : : #include "wps/wps.h"
38 : : #include "config_file.h"
39 : : #include "ctrl_iface.h"
40 : :
41 : :
42 : : struct wpa_ctrl_dst {
43 : : struct wpa_ctrl_dst *next;
44 : : struct sockaddr_un addr;
45 : : socklen_t addrlen;
46 : : int debug_level;
47 : : int errors;
48 : : };
49 : :
50 : :
51 : : static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
52 : : const char *buf, size_t len);
53 : :
54 : :
55 : 463 : static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
56 : : struct sockaddr_un *from,
57 : : socklen_t fromlen)
58 : : {
59 : : struct wpa_ctrl_dst *dst;
60 : :
61 : 463 : dst = os_zalloc(sizeof(*dst));
62 [ - + ]: 463 : if (dst == NULL)
63 : 0 : return -1;
64 : 463 : os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
65 : 463 : dst->addrlen = fromlen;
66 : 463 : dst->debug_level = MSG_INFO;
67 : 463 : dst->next = hapd->ctrl_dst;
68 : 463 : hapd->ctrl_dst = dst;
69 : 463 : wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
70 : 463 : (u8 *) from->sun_path,
71 : : fromlen - offsetof(struct sockaddr_un, sun_path));
72 : 463 : return 0;
73 : : }
74 : :
75 : :
76 : 458 : static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
77 : : struct sockaddr_un *from,
78 : : socklen_t fromlen)
79 : : {
80 : 458 : struct wpa_ctrl_dst *dst, *prev = NULL;
81 : :
82 : 458 : dst = hapd->ctrl_dst;
83 [ + + ]: 459 : while (dst) {
84 [ + - ][ + + ]: 458 : if (fromlen == dst->addrlen &&
85 : 458 : os_memcmp(from->sun_path, dst->addr.sun_path,
86 : : fromlen - offsetof(struct sockaddr_un, sun_path))
87 : : == 0) {
88 : 457 : wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
89 : 457 : (u8 *) from->sun_path,
90 : : fromlen -
91 : : offsetof(struct sockaddr_un, sun_path));
92 [ + + ]: 457 : if (prev == NULL)
93 : 456 : hapd->ctrl_dst = dst->next;
94 : : else
95 : 1 : prev->next = dst->next;
96 : 457 : os_free(dst);
97 : 457 : return 0;
98 : : }
99 : 1 : prev = dst;
100 : 1 : dst = dst->next;
101 : : }
102 : 458 : return -1;
103 : : }
104 : :
105 : :
106 : 0 : static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
107 : : struct sockaddr_un *from,
108 : : socklen_t fromlen,
109 : : char *level)
110 : : {
111 : : struct wpa_ctrl_dst *dst;
112 : :
113 : 0 : wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
114 : :
115 : 0 : dst = hapd->ctrl_dst;
116 [ # # ]: 0 : while (dst) {
117 [ # # ][ # # ]: 0 : if (fromlen == dst->addrlen &&
118 : 0 : os_memcmp(from->sun_path, dst->addr.sun_path,
119 : : fromlen - offsetof(struct sockaddr_un, sun_path))
120 : : == 0) {
121 : 0 : wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
122 : 0 : "level", (u8 *) from->sun_path, fromlen -
123 : : offsetof(struct sockaddr_un, sun_path));
124 : 0 : dst->debug_level = atoi(level);
125 : 0 : return 0;
126 : : }
127 : 0 : dst = dst->next;
128 : : }
129 : :
130 : 0 : return -1;
131 : : }
132 : :
133 : :
134 : 0 : static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
135 : : const char *txtaddr)
136 : : {
137 : : u8 addr[ETH_ALEN];
138 : : struct sta_info *sta;
139 : :
140 : 0 : wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
141 : :
142 [ # # ]: 0 : if (hwaddr_aton(txtaddr, addr))
143 : 0 : return -1;
144 : :
145 : 0 : sta = ap_get_sta(hapd, addr);
146 [ # # ]: 0 : if (sta)
147 : 0 : return 0;
148 : :
149 : 0 : wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
150 : 0 : "notification", MAC2STR(addr));
151 : 0 : sta = ap_sta_add(hapd, addr);
152 [ # # ]: 0 : if (sta == NULL)
153 : 0 : return -1;
154 : :
155 : 0 : hostapd_new_assoc_sta(hapd, sta, 0);
156 : 0 : return 0;
157 : : }
158 : :
159 : :
160 : : #ifdef CONFIG_IEEE80211W
161 : : #ifdef NEED_AP_MLME
162 : 2 : static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
163 : : const char *txtaddr)
164 : : {
165 : : u8 addr[ETH_ALEN];
166 : : u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
167 : :
168 : 2 : wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
169 : :
170 [ + - - + ]: 4 : if (hwaddr_aton(txtaddr, addr) ||
171 : 2 : os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
172 : 0 : return -1;
173 : :
174 : 2 : ieee802_11_send_sa_query_req(hapd, addr, trans_id);
175 : :
176 : 2 : return 0;
177 : : }
178 : : #endif /* NEED_AP_MLME */
179 : : #endif /* CONFIG_IEEE80211W */
180 : :
181 : :
182 : : #ifdef CONFIG_WPS
183 : 8 : static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
184 : : {
185 : 8 : char *pin = os_strchr(txt, ' ');
186 : : char *timeout_txt;
187 : : int timeout;
188 : 8 : u8 addr_buf[ETH_ALEN], *addr = NULL;
189 : : char *pos;
190 : :
191 [ - + ]: 8 : if (pin == NULL)
192 : 0 : return -1;
193 : 8 : *pin++ = '\0';
194 : :
195 : 8 : timeout_txt = os_strchr(pin, ' ');
196 [ - + ]: 8 : if (timeout_txt) {
197 : 0 : *timeout_txt++ = '\0';
198 : 0 : timeout = atoi(timeout_txt);
199 : 0 : pos = os_strchr(timeout_txt, ' ');
200 [ # # ]: 0 : if (pos) {
201 : 0 : *pos++ = '\0';
202 [ # # ]: 0 : if (hwaddr_aton(pos, addr_buf) == 0)
203 : 0 : addr = addr_buf;
204 : : }
205 : : } else
206 : 8 : timeout = 0;
207 : :
208 : 8 : return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
209 : : }
210 : :
211 : :
212 : 5 : static int hostapd_ctrl_iface_wps_check_pin(
213 : : struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
214 : : {
215 : : char pin[9];
216 : : size_t len;
217 : : char *pos;
218 : : int ret;
219 : :
220 : 5 : wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
221 : : (u8 *) cmd, os_strlen(cmd));
222 [ + + ]: 51 : for (pos = cmd, len = 0; *pos != '\0'; pos++) {
223 [ + + ][ + + ]: 46 : if (*pos < '0' || *pos > '9')
224 : 6 : continue;
225 : 40 : pin[len++] = *pos;
226 [ - + ]: 40 : if (len == 9) {
227 : 0 : wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
228 : 0 : return -1;
229 : : }
230 : : }
231 [ + - ][ - + ]: 5 : if (len != 4 && len != 8) {
232 : 0 : wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
233 : 0 : return -1;
234 : : }
235 : 5 : pin[len] = '\0';
236 : :
237 [ + - ]: 5 : if (len == 8) {
238 : : unsigned int pin_val;
239 : 5 : pin_val = atoi(pin);
240 [ + + ]: 5 : if (!wps_pin_valid(pin_val)) {
241 : 1 : wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
242 : 1 : ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
243 [ - + ][ + - ]: 1 : if (ret < 0 || (size_t) ret >= buflen)
244 : 0 : return -1;
245 : 1 : return ret;
246 : : }
247 : : }
248 : :
249 : 4 : ret = os_snprintf(buf, buflen, "%s", pin);
250 [ + - ][ - + ]: 4 : if (ret < 0 || (size_t) ret >= buflen)
251 : 0 : return -1;
252 : :
253 : 5 : return ret;
254 : : }
255 : :
256 : :
257 : : #ifdef CONFIG_WPS_NFC
258 : 2 : static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
259 : : char *pos)
260 : : {
261 : : size_t len;
262 : : struct wpabuf *buf;
263 : : int ret;
264 : :
265 : 2 : len = os_strlen(pos);
266 [ - + ]: 2 : if (len & 0x01)
267 : 0 : return -1;
268 : 2 : len /= 2;
269 : :
270 : 2 : buf = wpabuf_alloc(len);
271 [ - + ]: 2 : if (buf == NULL)
272 : 0 : return -1;
273 [ - + ]: 2 : if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
274 : 0 : wpabuf_free(buf);
275 : 0 : return -1;
276 : : }
277 : :
278 : 2 : ret = hostapd_wps_nfc_tag_read(hapd, buf);
279 : 2 : wpabuf_free(buf);
280 : :
281 : 2 : return ret;
282 : : }
283 : :
284 : :
285 : 2 : static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
286 : : char *cmd, char *reply,
287 : : size_t max_len)
288 : : {
289 : : int ndef;
290 : : struct wpabuf *buf;
291 : : int res;
292 : :
293 [ - + ]: 2 : if (os_strcmp(cmd, "WPS") == 0)
294 : 0 : ndef = 0;
295 [ + - ]: 2 : else if (os_strcmp(cmd, "NDEF") == 0)
296 : 2 : ndef = 1;
297 : : else
298 : 0 : return -1;
299 : :
300 : 2 : buf = hostapd_wps_nfc_config_token(hapd, ndef);
301 [ - + ]: 2 : if (buf == NULL)
302 : 0 : return -1;
303 : :
304 : 2 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
305 : : wpabuf_len(buf));
306 : 2 : reply[res++] = '\n';
307 : 2 : reply[res] = '\0';
308 : :
309 : 2 : wpabuf_free(buf);
310 : :
311 : 2 : return res;
312 : : }
313 : :
314 : :
315 : 2 : static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
316 : : char *reply, size_t max_len,
317 : : int ndef)
318 : : {
319 : : struct wpabuf *buf;
320 : : int res;
321 : :
322 : 2 : buf = hostapd_wps_nfc_token_gen(hapd, ndef);
323 [ - + ]: 2 : if (buf == NULL)
324 : 0 : return -1;
325 : :
326 : 2 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
327 : : wpabuf_len(buf));
328 : 2 : reply[res++] = '\n';
329 : 2 : reply[res] = '\0';
330 : :
331 : 2 : wpabuf_free(buf);
332 : :
333 : 2 : return res;
334 : : }
335 : :
336 : :
337 : 4 : static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
338 : : char *cmd, char *reply,
339 : : size_t max_len)
340 : : {
341 [ - + ]: 4 : if (os_strcmp(cmd, "WPS") == 0)
342 : 0 : return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
343 : : max_len, 0);
344 : :
345 [ + + ]: 4 : if (os_strcmp(cmd, "NDEF") == 0)
346 : 2 : return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
347 : : max_len, 1);
348 : :
349 [ + - ]: 2 : if (os_strcmp(cmd, "enable") == 0)
350 : 2 : return hostapd_wps_nfc_token_enable(hapd);
351 : :
352 [ # # ]: 0 : if (os_strcmp(cmd, "disable") == 0) {
353 : 0 : hostapd_wps_nfc_token_disable(hapd);
354 : 0 : return 0;
355 : : }
356 : :
357 : 4 : return -1;
358 : : }
359 : :
360 : :
361 : 5 : static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
362 : : char *cmd, char *reply,
363 : : size_t max_len)
364 : : {
365 : : struct wpabuf *buf;
366 : : int res;
367 : : char *pos;
368 : : int ndef;
369 : :
370 : 5 : pos = os_strchr(cmd, ' ');
371 [ - + ]: 5 : if (pos == NULL)
372 : 0 : return -1;
373 : 5 : *pos++ = '\0';
374 : :
375 [ - + ]: 5 : if (os_strcmp(cmd, "WPS") == 0)
376 : 0 : ndef = 0;
377 [ + - ]: 5 : else if (os_strcmp(cmd, "NDEF") == 0)
378 : 5 : ndef = 1;
379 : : else
380 : 0 : return -1;
381 : :
382 [ + - ]: 5 : if (os_strcmp(pos, "WPS-CR") == 0)
383 : 5 : buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
384 : : else
385 : 0 : buf = NULL;
386 [ - + ]: 5 : if (buf == NULL)
387 : 0 : return -1;
388 : :
389 : 5 : res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
390 : : wpabuf_len(buf));
391 : 5 : reply[res++] = '\n';
392 : 5 : reply[res] = '\0';
393 : :
394 : 5 : wpabuf_free(buf);
395 : :
396 : 5 : return res;
397 : : }
398 : :
399 : :
400 : 5 : static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
401 : : char *cmd)
402 : : {
403 : : size_t len;
404 : : struct wpabuf *req, *sel;
405 : : int ret;
406 : : char *pos, *role, *type, *pos2;
407 : :
408 : 5 : role = cmd;
409 : 5 : pos = os_strchr(role, ' ');
410 [ - + ]: 5 : if (pos == NULL)
411 : 0 : return -1;
412 : 5 : *pos++ = '\0';
413 : :
414 : 5 : type = pos;
415 : 5 : pos = os_strchr(type, ' ');
416 [ - + ]: 5 : if (pos == NULL)
417 : 0 : return -1;
418 : 5 : *pos++ = '\0';
419 : :
420 : 5 : pos2 = os_strchr(pos, ' ');
421 [ - + ]: 5 : if (pos2 == NULL)
422 : 0 : return -1;
423 : 5 : *pos2++ = '\0';
424 : :
425 : 5 : len = os_strlen(pos);
426 [ - + ]: 5 : if (len & 0x01)
427 : 0 : return -1;
428 : 5 : len /= 2;
429 : :
430 : 5 : req = wpabuf_alloc(len);
431 [ - + ]: 5 : if (req == NULL)
432 : 0 : return -1;
433 [ - + ]: 5 : if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
434 : 0 : wpabuf_free(req);
435 : 0 : return -1;
436 : : }
437 : :
438 : 5 : len = os_strlen(pos2);
439 [ - + ]: 5 : if (len & 0x01) {
440 : 0 : wpabuf_free(req);
441 : 0 : return -1;
442 : : }
443 : 5 : len /= 2;
444 : :
445 : 5 : sel = wpabuf_alloc(len);
446 [ - + ]: 5 : if (sel == NULL) {
447 : 0 : wpabuf_free(req);
448 : 0 : return -1;
449 : : }
450 [ - + ]: 5 : if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
451 : 0 : wpabuf_free(req);
452 : 0 : wpabuf_free(sel);
453 : 0 : return -1;
454 : : }
455 : :
456 [ + - ][ + - ]: 5 : if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
457 : 5 : ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
458 : : } else {
459 : 0 : wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
460 : : "reported: role=%s type=%s", role, type);
461 : 0 : ret = -1;
462 : : }
463 : 5 : wpabuf_free(req);
464 : 5 : wpabuf_free(sel);
465 : :
466 : 5 : return ret;
467 : : }
468 : :
469 : : #endif /* CONFIG_WPS_NFC */
470 : :
471 : :
472 : 10 : static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
473 : : char *buf, size_t buflen)
474 : : {
475 : 10 : int timeout = 300;
476 : : char *pos;
477 : : const char *pin_txt;
478 : :
479 : 10 : pos = os_strchr(txt, ' ');
480 [ + + ]: 10 : if (pos)
481 : 3 : *pos++ = '\0';
482 : :
483 [ + + ]: 10 : if (os_strcmp(txt, "disable") == 0) {
484 : 3 : hostapd_wps_ap_pin_disable(hapd);
485 : 3 : return os_snprintf(buf, buflen, "OK\n");
486 : : }
487 : :
488 [ + + ]: 7 : if (os_strcmp(txt, "random") == 0) {
489 [ + + ]: 2 : if (pos)
490 : 1 : timeout = atoi(pos);
491 : 2 : pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
492 [ - + ]: 2 : if (pin_txt == NULL)
493 : 0 : return -1;
494 : 2 : return os_snprintf(buf, buflen, "%s", pin_txt);
495 : : }
496 : :
497 [ + + ]: 5 : if (os_strcmp(txt, "get") == 0) {
498 : 3 : pin_txt = hostapd_wps_ap_pin_get(hapd);
499 [ + + ]: 3 : if (pin_txt == NULL)
500 : 2 : return -1;
501 : 1 : return os_snprintf(buf, buflen, "%s", pin_txt);
502 : : }
503 : :
504 [ + - ]: 2 : if (os_strcmp(txt, "set") == 0) {
505 : : char *pin;
506 [ - + ]: 2 : if (pos == NULL)
507 : 0 : return -1;
508 : 2 : pin = pos;
509 : 2 : pos = os_strchr(pos, ' ');
510 [ + + ]: 2 : if (pos) {
511 : 1 : *pos++ = '\0';
512 : 1 : timeout = atoi(pos);
513 : : }
514 [ - + ]: 2 : if (os_strlen(pin) > buflen)
515 : 0 : return -1;
516 [ - + ]: 2 : if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
517 : 0 : return -1;
518 : 2 : return os_snprintf(buf, buflen, "%s", pin);
519 : : }
520 : :
521 : 10 : return -1;
522 : : }
523 : :
524 : :
525 : 1 : static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
526 : : {
527 : : char *pos;
528 : 1 : char *ssid, *auth, *encr = NULL, *key = NULL;
529 : :
530 : 1 : ssid = txt;
531 : 1 : pos = os_strchr(txt, ' ');
532 [ - + ]: 1 : if (!pos)
533 : 0 : return -1;
534 : 1 : *pos++ = '\0';
535 : :
536 : 1 : auth = pos;
537 : 1 : pos = os_strchr(pos, ' ');
538 [ + - ]: 1 : if (pos) {
539 : 1 : *pos++ = '\0';
540 : 1 : encr = pos;
541 : 1 : pos = os_strchr(pos, ' ');
542 [ + - ]: 1 : if (pos) {
543 : 1 : *pos++ = '\0';
544 : 1 : key = pos;
545 : : }
546 : : }
547 : :
548 : 1 : return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
549 : : }
550 : :
551 : :
552 : 5 : static const char * pbc_status_str(enum pbc_status status)
553 : : {
554 [ + + - - : 5 : switch (status) {
- ]
555 : : case WPS_PBC_STATUS_DISABLE:
556 : 4 : return "Disabled";
557 : : case WPS_PBC_STATUS_ACTIVE:
558 : 1 : return "Active";
559 : : case WPS_PBC_STATUS_TIMEOUT:
560 : 0 : return "Timed-out";
561 : : case WPS_PBC_STATUS_OVERLAP:
562 : 0 : return "Overlap";
563 : : default:
564 : 5 : return "Unknown";
565 : : }
566 : : }
567 : :
568 : :
569 : 5 : static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd,
570 : : char *buf, size_t buflen)
571 : : {
572 : : int ret;
573 : : char *pos, *end;
574 : :
575 : 5 : pos = buf;
576 : 5 : end = buf + buflen;
577 : :
578 : 5 : ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
579 : : pbc_status_str(hapd->wps_stats.pbc_status));
580 : :
581 [ - + ][ + - ]: 5 : if (ret < 0 || ret >= end - pos)
582 : 0 : return pos - buf;
583 : 5 : pos += ret;
584 : :
585 [ + + ]: 9 : ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n",
586 : 5 : (hapd->wps_stats.status == WPS_STATUS_SUCCESS ?
587 : : "Success":
588 : 4 : (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
589 [ + + ]: 4 : "Failed" : "None")));
590 : :
591 [ + - ][ - + ]: 5 : if (ret < 0 || ret >= end - pos)
592 : 0 : return pos - buf;
593 : 5 : pos += ret;
594 : :
595 : : /* If status == Failure - Add possible Reasons */
596 [ + + ][ + + ]: 5 : if(hapd->wps_stats.status == WPS_STATUS_FAILURE &&
597 : 3 : hapd->wps_stats.failure_reason > 0) {
598 : 1 : ret = os_snprintf(pos, end - pos,
599 : : "Failure Reason: %s\n",
600 : : wps_ei_str(hapd->wps_stats.failure_reason));
601 : :
602 [ - + ][ + - ]: 1 : if (ret < 0 || ret >= end - pos)
603 : 0 : return pos - buf;
604 : 1 : pos += ret;
605 : : }
606 : :
607 [ + + ]: 5 : if (hapd->wps_stats.status) {
608 : 24 : ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
609 : 24 : MAC2STR(hapd->wps_stats.peer_addr));
610 : :
611 [ + - ][ - + ]: 4 : if (ret < 0 || ret >= end - pos)
612 : 0 : return pos - buf;
613 : 4 : pos += ret;
614 : : }
615 : :
616 : 5 : return pos - buf;
617 : : }
618 : :
619 : : #endif /* CONFIG_WPS */
620 : :
621 : : #ifdef CONFIG_HS20
622 : :
623 : 0 : static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
624 : : const char *cmd)
625 : : {
626 : : u8 addr[ETH_ALEN];
627 : : const char *url;
628 : :
629 [ # # ]: 0 : if (hwaddr_aton(cmd, addr))
630 : 0 : return -1;
631 : 0 : url = cmd + 17;
632 [ # # ]: 0 : if (*url == '\0') {
633 : 0 : url = NULL;
634 : : } else {
635 [ # # ]: 0 : if (*url != ' ')
636 : 0 : return -1;
637 : 0 : url++;
638 [ # # ]: 0 : if (*url == '\0')
639 : 0 : url = NULL;
640 : : }
641 : :
642 : 0 : return hs20_send_wnm_notification(hapd, addr, 1, url);
643 : : }
644 : :
645 : :
646 : 2 : static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
647 : : const char *cmd)
648 : : {
649 : : u8 addr[ETH_ALEN];
650 : : int code, reauth_delay, ret;
651 : : const char *pos;
652 : : size_t url_len;
653 : : struct wpabuf *req;
654 : :
655 : : /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */
656 [ - + ]: 2 : if (hwaddr_aton(cmd, addr))
657 : 0 : return -1;
658 : :
659 : 2 : pos = os_strchr(cmd, ' ');
660 [ - + ]: 2 : if (pos == NULL)
661 : 0 : return -1;
662 : 2 : pos++;
663 : 2 : code = atoi(pos);
664 : :
665 : 2 : pos = os_strchr(pos, ' ');
666 [ - + ]: 2 : if (pos == NULL)
667 : 0 : return -1;
668 : 2 : pos++;
669 : 2 : reauth_delay = atoi(pos);
670 : :
671 : 2 : url_len = 0;
672 : 2 : pos = os_strchr(pos, ' ');
673 [ + - ]: 2 : if (pos) {
674 : 2 : pos++;
675 : 2 : url_len = os_strlen(pos);
676 : : }
677 : :
678 : 2 : req = wpabuf_alloc(4 + url_len);
679 [ - + ]: 2 : if (req == NULL)
680 : 0 : return -1;
681 : 2 : wpabuf_put_u8(req, code);
682 : 2 : wpabuf_put_le16(req, reauth_delay);
683 : 2 : wpabuf_put_u8(req, url_len);
684 [ + - ]: 2 : if (pos)
685 : 2 : wpabuf_put_data(req, pos, url_len);
686 : :
687 : 2 : wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR
688 : : " to indicate imminent deauthentication (code=%d "
689 : 12 : "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay);
690 : 2 : ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req);
691 : 2 : wpabuf_free(req);
692 : 2 : return ret;
693 : : }
694 : :
695 : : #endif /* CONFIG_HS20 */
696 : :
697 : :
698 : : #ifdef CONFIG_INTERWORKING
699 : :
700 : 1 : static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd,
701 : : const char *cmd)
702 : : {
703 : 1 : u8 qos_map_set[16 + 2 * 21], count = 0;
704 : 1 : const char *pos = cmd;
705 : : int val, ret;
706 : :
707 : : for (;;) {
708 [ - + ]: 18 : if (count == sizeof(qos_map_set)) {
709 : 0 : wpa_printf(MSG_ERROR, "Too many qos_map_set parameters");
710 : 0 : return -1;
711 : : }
712 : :
713 : 18 : val = atoi(pos);
714 [ - + ][ + - ]: 18 : if (val < 0 || val > 255) {
715 : 0 : wpa_printf(MSG_INFO, "Invalid QoS Map Set");
716 : 0 : return -1;
717 : : }
718 : :
719 : 18 : qos_map_set[count++] = val;
720 : 18 : pos = os_strchr(pos, ',');
721 [ + + ]: 18 : if (!pos)
722 : 1 : break;
723 : 17 : pos++;
724 : 17 : }
725 : :
726 [ + - ][ - + ]: 1 : if (count < 16 || count & 1) {
727 : 0 : wpa_printf(MSG_INFO, "Invalid QoS Map Set");
728 : 0 : return -1;
729 : : }
730 : :
731 : 1 : ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count);
732 [ - + ]: 1 : if (ret) {
733 : 0 : wpa_printf(MSG_INFO, "Failed to set QoS Map Set");
734 : 0 : return -1;
735 : : }
736 : :
737 : 1 : os_memcpy(hapd->conf->qos_map_set, qos_map_set, count);
738 : 1 : hapd->conf->qos_map_set_len = count;
739 : :
740 : 1 : return 0;
741 : : }
742 : :
743 : :
744 : 1 : static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
745 : : const char *cmd)
746 : : {
747 : : u8 addr[ETH_ALEN];
748 : : struct sta_info *sta;
749 : : struct wpabuf *buf;
750 : 1 : u8 *qos_map_set = hapd->conf->qos_map_set;
751 : 1 : u8 qos_map_set_len = hapd->conf->qos_map_set_len;
752 : : int ret;
753 : :
754 [ - + ]: 1 : if (!qos_map_set_len) {
755 : 0 : wpa_printf(MSG_INFO, "QoS Map Set is not set");
756 : 0 : return -1;
757 : : }
758 : :
759 [ - + ]: 1 : if (hwaddr_aton(cmd, addr))
760 : 0 : return -1;
761 : :
762 : 1 : sta = ap_get_sta(hapd, addr);
763 [ - + ]: 1 : if (sta == NULL) {
764 : 0 : wpa_printf(MSG_DEBUG, "Station " MACSTR " not found "
765 : : "for QoS Map Configuration message",
766 : 0 : MAC2STR(addr));
767 : 0 : return -1;
768 : : }
769 : :
770 [ - + ]: 1 : if (!sta->qos_map_enabled) {
771 : 0 : wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate "
772 : 0 : "support for QoS Map", MAC2STR(addr));
773 : 0 : return -1;
774 : : }
775 : :
776 : 1 : buf = wpabuf_alloc(2 + 2 + qos_map_set_len);
777 [ - + ]: 1 : if (buf == NULL)
778 : 0 : return -1;
779 : :
780 : 1 : wpabuf_put_u8(buf, WLAN_ACTION_QOS);
781 : 1 : wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG);
782 : :
783 : : /* QoS Map Set Element */
784 : 1 : wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET);
785 : 1 : wpabuf_put_u8(buf, qos_map_set_len);
786 : 1 : wpabuf_put_data(buf, qos_map_set, qos_map_set_len);
787 : :
788 : 2 : ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
789 : 1 : wpabuf_head(buf), wpabuf_len(buf));
790 : 1 : wpabuf_free(buf);
791 : :
792 : 1 : return ret;
793 : : }
794 : :
795 : : #endif /* CONFIG_INTERWORKING */
796 : :
797 : :
798 : : #ifdef CONFIG_WNM
799 : :
800 : 1 : static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
801 : : const char *cmd)
802 : : {
803 : : u8 addr[ETH_ALEN];
804 : : int disassoc_timer;
805 : : struct sta_info *sta;
806 : :
807 [ - + ]: 1 : if (hwaddr_aton(cmd, addr))
808 : 0 : return -1;
809 [ - + ]: 1 : if (cmd[17] != ' ')
810 : 0 : return -1;
811 : 1 : disassoc_timer = atoi(cmd + 17);
812 : :
813 : 1 : sta = ap_get_sta(hapd, addr);
814 [ - + ]: 1 : if (sta == NULL) {
815 : 0 : wpa_printf(MSG_DEBUG, "Station " MACSTR
816 : : " not found for disassociation imminent message",
817 : 0 : MAC2STR(addr));
818 : 0 : return -1;
819 : : }
820 : :
821 : 1 : return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
822 : : }
823 : :
824 : :
825 : 2 : static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
826 : : const char *cmd)
827 : : {
828 : : u8 addr[ETH_ALEN];
829 : : const char *url, *timerstr;
830 : : int disassoc_timer;
831 : : struct sta_info *sta;
832 : :
833 [ - + ]: 2 : if (hwaddr_aton(cmd, addr))
834 : 0 : return -1;
835 : :
836 : 2 : sta = ap_get_sta(hapd, addr);
837 [ - + ]: 2 : if (sta == NULL) {
838 : 0 : wpa_printf(MSG_DEBUG, "Station " MACSTR
839 : : " not found for ESS disassociation imminent message",
840 : 0 : MAC2STR(addr));
841 : 0 : return -1;
842 : : }
843 : :
844 : 2 : timerstr = cmd + 17;
845 [ - + ]: 2 : if (*timerstr != ' ')
846 : 0 : return -1;
847 : 2 : timerstr++;
848 : 2 : disassoc_timer = atoi(timerstr);
849 [ - + ][ + - ]: 2 : if (disassoc_timer < 0 || disassoc_timer > 65535)
850 : 0 : return -1;
851 : :
852 : 2 : url = os_strchr(timerstr, ' ');
853 [ - + ]: 2 : if (url == NULL)
854 : 0 : return -1;
855 : 2 : url++;
856 : :
857 : 2 : return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
858 : : }
859 : :
860 : : #endif /* CONFIG_WNM */
861 : :
862 : :
863 : 1 : static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
864 : : char *buf, size_t buflen)
865 : : {
866 : : int ret;
867 : : char *pos, *end;
868 : :
869 : 1 : pos = buf;
870 : 1 : end = buf + buflen;
871 : :
872 : 1 : ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
873 : : "ssid=%s\n",
874 : 6 : MAC2STR(hapd->own_addr),
875 : 1 : wpa_ssid_txt(hapd->conf->ssid.ssid,
876 : 1 : hapd->conf->ssid.ssid_len));
877 [ - + ][ + - ]: 1 : if (ret < 0 || ret >= end - pos)
878 : 0 : return pos - buf;
879 : 1 : pos += ret;
880 : :
881 : : #ifdef CONFIG_WPS
882 [ + - ]: 2 : ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
883 : 1 : hapd->conf->wps_state == 0 ? "disabled" :
884 [ - + ]: 1 : (hapd->conf->wps_state == 1 ? "not configured" :
885 : : "configured"));
886 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
887 : 0 : return pos - buf;
888 : 1 : pos += ret;
889 : :
890 [ + - ][ + - ]: 1 : if (hapd->conf->wps_state && hapd->conf->wpa &&
[ + - ]
891 : 1 : hapd->conf->ssid.wpa_passphrase) {
892 : 1 : ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
893 : 1 : hapd->conf->ssid.wpa_passphrase);
894 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
895 : 0 : return pos - buf;
896 : 1 : pos += ret;
897 : : }
898 : :
899 [ + - ][ + - ]: 1 : if (hapd->conf->wps_state && hapd->conf->wpa &&
[ + - ]
900 [ + - ]: 1 : hapd->conf->ssid.wpa_psk &&
901 : 1 : hapd->conf->ssid.wpa_psk->group) {
902 : : char hex[PMK_LEN * 2 + 1];
903 : 1 : wpa_snprintf_hex(hex, sizeof(hex),
904 : 1 : hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
905 : 1 : ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
906 [ - + ][ + - ]: 1 : if (ret < 0 || ret >= end - pos)
907 : 0 : return pos - buf;
908 : 1 : pos += ret;
909 : : }
910 : : #endif /* CONFIG_WPS */
911 : :
912 [ + - ][ + - ]: 1 : if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
913 : 1 : ret = os_snprintf(pos, end - pos, "key_mgmt=");
914 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
915 : 0 : return pos - buf;
916 : 1 : pos += ret;
917 : :
918 [ + - ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
919 : 1 : ret = os_snprintf(pos, end - pos, "WPA-PSK ");
920 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
921 : 0 : return pos - buf;
922 : 1 : pos += ret;
923 : : }
924 [ - + ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
925 : 0 : ret = os_snprintf(pos, end - pos, "WPA-EAP ");
926 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
927 : 0 : return pos - buf;
928 : 0 : pos += ret;
929 : : }
930 : : #ifdef CONFIG_IEEE80211R
931 [ - + ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
932 : 0 : ret = os_snprintf(pos, end - pos, "FT-PSK ");
933 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
934 : 0 : return pos - buf;
935 : 0 : pos += ret;
936 : : }
937 [ - + ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
938 : 0 : ret = os_snprintf(pos, end - pos, "FT-EAP ");
939 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
940 : 0 : return pos - buf;
941 : 0 : pos += ret;
942 : : }
943 : : #endif /* CONFIG_IEEE80211R */
944 : : #ifdef CONFIG_IEEE80211W
945 [ - + ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
946 : 0 : ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
947 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
948 : 0 : return pos - buf;
949 : 0 : pos += ret;
950 : : }
951 [ - + ]: 1 : if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
952 : 0 : ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
953 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= end - pos)
954 : 0 : return pos - buf;
955 : 0 : pos += ret;
956 : : }
957 : : #endif /* CONFIG_IEEE80211W */
958 : :
959 : 1 : ret = os_snprintf(pos, end - pos, "\n");
960 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
961 : 0 : return pos - buf;
962 : 1 : pos += ret;
963 : : }
964 : :
965 [ + - ]: 1 : if (hapd->conf->wpa) {
966 : 1 : ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
967 : 1 : wpa_cipher_txt(hapd->conf->wpa_group));
968 [ - + ][ + - ]: 1 : if (ret < 0 || ret >= end - pos)
969 : 0 : return pos - buf;
970 : 1 : pos += ret;
971 : : }
972 : :
973 [ + - ][ + - ]: 1 : if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
974 : 1 : ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
975 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
976 : 0 : return pos - buf;
977 : 1 : pos += ret;
978 : :
979 : 1 : ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
980 : : " ");
981 [ - + ]: 1 : if (ret < 0)
982 : 0 : return pos - buf;
983 : 1 : pos += ret;
984 : :
985 : 1 : ret = os_snprintf(pos, end - pos, "\n");
986 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
987 : 0 : return pos - buf;
988 : 1 : pos += ret;
989 : : }
990 : :
991 [ + - ][ + - ]: 1 : if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
992 : 1 : ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
993 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
994 : 0 : return pos - buf;
995 : 1 : pos += ret;
996 : :
997 : 1 : ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
998 : : " ");
999 [ - + ]: 1 : if (ret < 0)
1000 : 0 : return pos - buf;
1001 : 1 : pos += ret;
1002 : :
1003 : 1 : ret = os_snprintf(pos, end - pos, "\n");
1004 [ + - ][ - + ]: 1 : if (ret < 0 || ret >= end - pos)
1005 : 0 : return pos - buf;
1006 : 1 : pos += ret;
1007 : : }
1008 : :
1009 : 1 : return pos - buf;
1010 : : }
1011 : :
1012 : :
1013 : 6834 : static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1014 : : {
1015 : : char *value;
1016 : 6834 : int ret = 0;
1017 : :
1018 : 6834 : value = os_strchr(cmd, ' ');
1019 [ - + ]: 6834 : if (value == NULL)
1020 : 0 : return -1;
1021 : 6834 : *value++ = '\0';
1022 : :
1023 : 6834 : wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
1024 : : if (0) {
1025 : : #ifdef CONFIG_WPS_TESTING
1026 [ + + ]: 6834 : } else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
1027 : : long int val;
1028 : 2 : val = strtol(value, NULL, 0);
1029 [ - + ][ + - ]: 2 : if (val < 0 || val > 0xff) {
1030 : 0 : ret = -1;
1031 : 0 : wpa_printf(MSG_DEBUG, "WPS: Invalid "
1032 : : "wps_version_number %ld", val);
1033 : : } else {
1034 : 2 : wps_version_number = val;
1035 : 2 : wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
1036 : : "version %u.%u",
1037 : 2 : (wps_version_number & 0xf0) >> 4,
1038 : : wps_version_number & 0x0f);
1039 : 2 : hostapd_wps_update_ie(hapd);
1040 : : }
1041 [ - + ]: 6832 : } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
1042 : 0 : wps_testing_dummy_cred = atoi(value);
1043 : 0 : wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
1044 : : wps_testing_dummy_cred);
1045 [ + + ]: 6832 : } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
1046 : 1 : wps_corrupt_pkhash = atoi(value);
1047 : 1 : wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
1048 : : wps_corrupt_pkhash);
1049 : : #endif /* CONFIG_WPS_TESTING */
1050 : : #ifdef CONFIG_INTERWORKING
1051 [ + + ]: 6831 : } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
1052 : 2 : int val = atoi(value);
1053 [ - + ]: 2 : if (val <= 0)
1054 : 0 : ret = -1;
1055 : : else
1056 : 2 : hapd->gas_frag_limit = val;
1057 : : #endif /* CONFIG_INTERWORKING */
1058 : : #ifdef CONFIG_TESTING_OPTIONS
1059 [ + + ]: 6829 : } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
1060 : 14 : hapd->ext_mgmt_frame_handling = atoi(value);
1061 : : #endif /* CONFIG_TESTING_OPTIONS */
1062 : : } else {
1063 : : struct sta_info *sta;
1064 : : int vlan_id;
1065 : :
1066 : 6815 : ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
1067 [ - + ]: 6815 : if (ret)
1068 : 0 : return ret;
1069 : :
1070 [ - + ]: 6815 : if (os_strcasecmp(cmd, "deny_mac_file") == 0) {
1071 [ # # ]: 0 : for (sta = hapd->sta_list; sta; sta = sta->next) {
1072 [ # # ]: 0 : if (hostapd_maclist_found(
1073 : 0 : hapd->conf->deny_mac,
1074 : 0 : hapd->conf->num_deny_mac, sta->addr,
1075 [ # # ]: 0 : &vlan_id) &&
1076 [ # # ]: 0 : (!vlan_id || vlan_id == sta->vlan_id))
1077 : 0 : ap_sta_deauthenticate(
1078 : : hapd, sta,
1079 : : WLAN_REASON_UNSPECIFIED);
1080 : : }
1081 [ - + ][ # # ]: 6815 : } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED &&
1082 : 0 : os_strcasecmp(cmd, "accept_mac_file") == 0) {
1083 [ # # ]: 0 : for (sta = hapd->sta_list; sta; sta = sta->next) {
1084 [ # # ]: 0 : if (!hostapd_maclist_found(
1085 : 0 : hapd->conf->accept_mac,
1086 : 0 : hapd->conf->num_accept_mac,
1087 [ # # ]: 0 : sta->addr, &vlan_id) ||
1088 [ # # ]: 0 : (vlan_id && vlan_id != sta->vlan_id))
1089 : 0 : ap_sta_deauthenticate(
1090 : : hapd, sta,
1091 : : WLAN_REASON_UNSPECIFIED);
1092 : : }
1093 : : }
1094 : : }
1095 : :
1096 : 6834 : return ret;
1097 : : }
1098 : :
1099 : :
1100 : 0 : static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
1101 : : char *buf, size_t buflen)
1102 : : {
1103 : : int res;
1104 : :
1105 : 0 : wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
1106 : :
1107 [ # # ]: 0 : if (os_strcmp(cmd, "version") == 0) {
1108 : 0 : res = os_snprintf(buf, buflen, "%s", VERSION_STR);
1109 [ # # ][ # # ]: 0 : if (res < 0 || (unsigned int) res >= buflen)
1110 : 0 : return -1;
1111 : 0 : return res;
1112 : : }
1113 : :
1114 : 0 : return -1;
1115 : : }
1116 : :
1117 : :
1118 : 326 : static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
1119 : : {
1120 [ + + ]: 326 : if (hostapd_enable_iface(iface) < 0) {
1121 : 2 : wpa_printf(MSG_ERROR, "Enabling of interface failed");
1122 : 2 : return -1;
1123 : : }
1124 : 326 : return 0;
1125 : : }
1126 : :
1127 : :
1128 : 1 : static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
1129 : : {
1130 [ - + ]: 1 : if (hostapd_reload_iface(iface) < 0) {
1131 : 0 : wpa_printf(MSG_ERROR, "Reloading of interface failed");
1132 : 0 : return -1;
1133 : : }
1134 : 1 : return 0;
1135 : : }
1136 : :
1137 : :
1138 : 0 : static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
1139 : : {
1140 [ # # ]: 0 : if (hostapd_disable_iface(iface) < 0) {
1141 : 0 : wpa_printf(MSG_ERROR, "Disabling of interface failed");
1142 : 0 : return -1;
1143 : : }
1144 : 0 : return 0;
1145 : : }
1146 : :
1147 : :
1148 : : #ifdef CONFIG_TESTING_OPTIONS
1149 : :
1150 : 0 : static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
1151 : : {
1152 : : union wpa_event_data data;
1153 : : char *pos, *param;
1154 : : enum wpa_event_type event;
1155 : :
1156 : 0 : wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd);
1157 : :
1158 : 0 : os_memset(&data, 0, sizeof(data));
1159 : :
1160 : 0 : param = os_strchr(cmd, ' ');
1161 [ # # ]: 0 : if (param == NULL)
1162 : 0 : return -1;
1163 : 0 : *param++ = '\0';
1164 : :
1165 [ # # ]: 0 : if (os_strcmp(cmd, "DETECTED") == 0)
1166 : 0 : event = EVENT_DFS_RADAR_DETECTED;
1167 [ # # ]: 0 : else if (os_strcmp(cmd, "CAC-FINISHED") == 0)
1168 : 0 : event = EVENT_DFS_CAC_FINISHED;
1169 [ # # ]: 0 : else if (os_strcmp(cmd, "CAC-ABORTED") == 0)
1170 : 0 : event = EVENT_DFS_CAC_ABORTED;
1171 [ # # ]: 0 : else if (os_strcmp(cmd, "NOP-FINISHED") == 0)
1172 : 0 : event = EVENT_DFS_NOP_FINISHED;
1173 : : else {
1174 : 0 : wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s",
1175 : : cmd);
1176 : 0 : return -1;
1177 : : }
1178 : :
1179 : 0 : pos = os_strstr(param, "freq=");
1180 [ # # ]: 0 : if (pos)
1181 : 0 : data.dfs_event.freq = atoi(pos + 5);
1182 : :
1183 : 0 : pos = os_strstr(param, "ht_enabled=1");
1184 [ # # ]: 0 : if (pos)
1185 : 0 : data.dfs_event.ht_enabled = 1;
1186 : :
1187 : 0 : pos = os_strstr(param, "chan_offset=");
1188 [ # # ]: 0 : if (pos)
1189 : 0 : data.dfs_event.chan_offset = atoi(pos + 12);
1190 : :
1191 : 0 : pos = os_strstr(param, "chan_width=");
1192 [ # # ]: 0 : if (pos)
1193 : 0 : data.dfs_event.chan_width = atoi(pos + 11);
1194 : :
1195 : 0 : pos = os_strstr(param, "cf1=");
1196 [ # # ]: 0 : if (pos)
1197 : 0 : data.dfs_event.cf1 = atoi(pos + 4);
1198 : :
1199 : 0 : pos = os_strstr(param, "cf2=");
1200 [ # # ]: 0 : if (pos)
1201 : 0 : data.dfs_event.cf2 = atoi(pos + 4);
1202 : :
1203 : 0 : wpa_supplicant_event(hapd, event, &data);
1204 : :
1205 : 0 : return 0;
1206 : : }
1207 : :
1208 : :
1209 : 230 : static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd)
1210 : : {
1211 : : size_t len;
1212 : : u8 *buf;
1213 : : int res;
1214 : :
1215 : 230 : wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd);
1216 : :
1217 : 230 : len = os_strlen(cmd);
1218 [ - + ]: 230 : if (len & 1)
1219 : 0 : return -1;
1220 : 230 : len /= 2;
1221 : :
1222 : 230 : buf = os_malloc(len);
1223 [ - + ]: 230 : if (buf == NULL)
1224 : 0 : return -1;
1225 : :
1226 [ - + ]: 230 : if (hexstr2bin(cmd, buf, len) < 0) {
1227 : 0 : os_free(buf);
1228 : 0 : return -1;
1229 : : }
1230 : :
1231 : 230 : res = hostapd_drv_send_mlme(hapd, buf, len, 0);
1232 : 230 : os_free(buf);
1233 : 230 : return res;
1234 : : }
1235 : :
1236 : : #endif /* CONFIG_TESTING_OPTIONS */
1237 : :
1238 : :
1239 : 0 : static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos)
1240 : : {
1241 : : #ifdef NEED_AP_MLME
1242 : : struct csa_settings settings;
1243 : 0 : int ret = hostapd_parse_csa_settings(pos, &settings);
1244 : :
1245 [ # # ]: 0 : if (ret)
1246 : 0 : return ret;
1247 : :
1248 : 0 : return hostapd_switch_channel(hapd, &settings);
1249 : : #else /* NEED_AP_MLME */
1250 : : return -1;
1251 : : #endif /* NEED_AP_MLME */
1252 : : }
1253 : :
1254 : :
1255 : 2 : static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
1256 : : int reply_size, const char *param)
1257 : : {
1258 : : #ifdef RADIUS_SERVER
1259 [ + - ]: 2 : if (os_strcmp(param, "radius_server") == 0) {
1260 : 2 : return radius_server_get_mib(hapd->radius_srv, reply,
1261 : : reply_size);
1262 : : }
1263 : : #endif /* RADIUS_SERVER */
1264 : 2 : return -1;
1265 : : }
1266 : :
1267 : :
1268 : 8766 : static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
1269 : : void *sock_ctx)
1270 : : {
1271 : 8766 : struct hostapd_data *hapd = eloop_ctx;
1272 : : char buf[4096];
1273 : : int res;
1274 : : struct sockaddr_un from;
1275 : 8766 : socklen_t fromlen = sizeof(from);
1276 : : char *reply;
1277 : 8766 : const int reply_size = 4096;
1278 : : int reply_len;
1279 : 8766 : int level = MSG_DEBUG;
1280 : :
1281 : 8766 : res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1282 : : (struct sockaddr *) &from, &fromlen);
1283 [ - + ]: 8766 : if (res < 0) {
1284 : 0 : perror("recvfrom(ctrl_iface)");
1285 : 0 : return;
1286 : : }
1287 : 8766 : buf[res] = '\0';
1288 [ + + ]: 8766 : if (os_strcmp(buf, "PING") == 0)
1289 : 342 : level = MSG_EXCESSIVE;
1290 : 8766 : wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
1291 : :
1292 : 8766 : reply = os_malloc(reply_size);
1293 [ - + ]: 8766 : if (reply == NULL) {
1294 : 0 : sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
1295 : : fromlen);
1296 : 0 : return;
1297 : : }
1298 : :
1299 : 8766 : os_memcpy(reply, "OK\n", 3);
1300 : 8766 : reply_len = 3;
1301 : :
1302 [ + + ]: 8766 : if (os_strcmp(buf, "PING") == 0) {
1303 : 342 : os_memcpy(reply, "PONG\n", 5);
1304 : 342 : reply_len = 5;
1305 [ - + ]: 8424 : } else if (os_strncmp(buf, "RELOG", 5) == 0) {
1306 [ # # ]: 0 : if (wpa_debug_reopen_file() < 0)
1307 : 0 : reply_len = -1;
1308 [ + + ]: 8424 : } else if (os_strcmp(buf, "STATUS") == 0) {
1309 : 13 : reply_len = hostapd_ctrl_iface_status(hapd, reply,
1310 : : reply_size);
1311 [ - + ]: 8411 : } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) {
1312 : 0 : reply_len = hostapd_drv_status(hapd, reply, reply_size);
1313 [ + + ]: 8411 : } else if (os_strcmp(buf, "MIB") == 0) {
1314 : 3 : reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
1315 [ + - ]: 3 : if (reply_len >= 0) {
1316 : 3 : res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
1317 : 3 : reply_size - reply_len);
1318 [ - + ]: 3 : if (res < 0)
1319 : 0 : reply_len = -1;
1320 : : else
1321 : 3 : reply_len += res;
1322 : : }
1323 [ + - ]: 3 : if (reply_len >= 0) {
1324 : 3 : res = ieee802_1x_get_mib(hapd, reply + reply_len,
1325 : 3 : reply_size - reply_len);
1326 [ - + ]: 3 : if (res < 0)
1327 : 0 : reply_len = -1;
1328 : : else
1329 : 3 : reply_len += res;
1330 : : }
1331 : : #ifndef CONFIG_NO_RADIUS
1332 [ + - ]: 3 : if (reply_len >= 0) {
1333 : 3 : res = radius_client_get_mib(hapd->radius,
1334 : 3 : reply + reply_len,
1335 : 3 : reply_size - reply_len);
1336 [ - + ]: 3 : if (res < 0)
1337 : 0 : reply_len = -1;
1338 : : else
1339 : 3 : reply_len += res;
1340 : : }
1341 : : #endif /* CONFIG_NO_RADIUS */
1342 [ + + ]: 8408 : } else if (os_strncmp(buf, "MIB ", 4) == 0) {
1343 : 2 : reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size,
1344 : : buf + 4);
1345 [ + + ]: 8406 : } else if (os_strcmp(buf, "STA-FIRST") == 0) {
1346 : 1 : reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
1347 : : reply_size);
1348 [ + + ]: 8405 : } else if (os_strncmp(buf, "STA ", 4) == 0) {
1349 : 16 : reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
1350 : : reply_size);
1351 [ + + ]: 8389 : } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
1352 : 2 : reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
1353 : : reply_size);
1354 [ + + ]: 8387 : } else if (os_strcmp(buf, "ATTACH") == 0) {
1355 [ - + ]: 463 : if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
1356 : 0 : reply_len = -1;
1357 [ + + ]: 7924 : } else if (os_strcmp(buf, "DETACH") == 0) {
1358 [ + + ]: 457 : if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
1359 : 1 : reply_len = -1;
1360 [ - + ]: 7467 : } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
1361 [ # # ]: 0 : if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
1362 : : buf + 6))
1363 : 0 : reply_len = -1;
1364 [ - + ]: 7467 : } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
1365 [ # # ]: 0 : if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
1366 : 0 : reply_len = -1;
1367 [ + + ]: 7467 : } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
1368 [ - + ]: 2 : if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
1369 : 0 : reply_len = -1;
1370 [ - + ]: 7465 : } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
1371 [ # # ]: 0 : if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
1372 : 0 : reply_len = -1;
1373 : : #ifdef CONFIG_IEEE80211W
1374 : : #ifdef NEED_AP_MLME
1375 [ + + ]: 7465 : } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
1376 [ - + ]: 2 : if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
1377 : 0 : reply_len = -1;
1378 : : #endif /* NEED_AP_MLME */
1379 : : #endif /* CONFIG_IEEE80211W */
1380 : : #ifdef CONFIG_WPS
1381 [ + + ]: 7463 : } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
1382 [ - + ]: 8 : if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
1383 : 0 : reply_len = -1;
1384 [ + + ]: 7455 : } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
1385 : 5 : reply_len = hostapd_ctrl_iface_wps_check_pin(
1386 : : hapd, buf + 14, reply, reply_size);
1387 [ + + ]: 7450 : } else if (os_strcmp(buf, "WPS_PBC") == 0) {
1388 [ + + ]: 14 : if (hostapd_wps_button_pushed(hapd, NULL))
1389 : 1 : reply_len = -1;
1390 [ + + ]: 7436 : } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
1391 [ - + ]: 3 : if (hostapd_wps_cancel(hapd))
1392 : 0 : reply_len = -1;
1393 [ + + ]: 7433 : } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
1394 : 10 : reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
1395 : : reply, reply_size);
1396 [ + + ]: 7423 : } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
1397 [ - + ]: 1 : if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
1398 : 0 : reply_len = -1;
1399 [ + + ]: 7422 : } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) {
1400 : 5 : reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply,
1401 : : reply_size);
1402 : : #ifdef CONFIG_WPS_NFC
1403 [ + + ]: 7417 : } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
1404 [ - + ]: 2 : if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
1405 : 0 : reply_len = -1;
1406 [ + + ]: 7415 : } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
1407 : 2 : reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
1408 : : hapd, buf + 21, reply, reply_size);
1409 [ + + ]: 7413 : } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
1410 : 4 : reply_len = hostapd_ctrl_iface_wps_nfc_token(
1411 : : hapd, buf + 14, reply, reply_size);
1412 [ + + ]: 7409 : } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
1413 : 5 : reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
1414 : : hapd, buf + 21, reply, reply_size);
1415 [ + + ]: 7404 : } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
1416 [ - + ]: 5 : if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
1417 : 0 : reply_len = -1;
1418 : : #endif /* CONFIG_WPS_NFC */
1419 : : #endif /* CONFIG_WPS */
1420 : : #ifdef CONFIG_INTERWORKING
1421 [ + + ]: 7399 : } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) {
1422 [ - + ]: 1 : if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16))
1423 : 0 : reply_len = -1;
1424 [ + + ]: 7398 : } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) {
1425 [ - + ]: 1 : if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18))
1426 : 0 : reply_len = -1;
1427 : : #endif /* CONFIG_INTERWORKING */
1428 : : #ifdef CONFIG_HS20
1429 [ - + ]: 7397 : } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
1430 [ # # ]: 0 : if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
1431 : 0 : reply_len = -1;
1432 [ + + ]: 7397 : } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
1433 [ - + ]: 2 : if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
1434 : 0 : reply_len = -1;
1435 : : #endif /* CONFIG_HS20 */
1436 : : #ifdef CONFIG_WNM
1437 [ + + ]: 7395 : } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
1438 [ - + ]: 1 : if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
1439 : 0 : reply_len = -1;
1440 [ + + ]: 7394 : } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
1441 [ - + ]: 2 : if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
1442 : 0 : reply_len = -1;
1443 : : #endif /* CONFIG_WNM */
1444 [ + + ]: 7392 : } else if (os_strcmp(buf, "GET_CONFIG") == 0) {
1445 : 1 : reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
1446 : : reply_size);
1447 [ + + ]: 7391 : } else if (os_strncmp(buf, "SET ", 4) == 0) {
1448 [ - + ]: 6834 : if (hostapd_ctrl_iface_set(hapd, buf + 4))
1449 : 0 : reply_len = -1;
1450 [ - + ]: 557 : } else if (os_strncmp(buf, "GET ", 4) == 0) {
1451 : 0 : reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
1452 : : reply_size);
1453 [ + + ]: 557 : } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
1454 [ + + ]: 326 : if (hostapd_ctrl_iface_enable(hapd->iface))
1455 : 2 : reply_len = -1;
1456 [ + + ]: 231 : } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
1457 [ - + ]: 1 : if (hostapd_ctrl_iface_reload(hapd->iface))
1458 : 0 : reply_len = -1;
1459 [ - + ]: 230 : } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
1460 [ # # ]: 0 : if (hostapd_ctrl_iface_disable(hapd->iface))
1461 : 0 : reply_len = -1;
1462 : : #ifdef CONFIG_TESTING_OPTIONS
1463 [ - + ]: 230 : } else if (os_strncmp(buf, "RADAR ", 6) == 0) {
1464 [ # # ]: 0 : if (hostapd_ctrl_iface_radar(hapd, buf + 6))
1465 : 0 : reply_len = -1;
1466 [ + - ]: 230 : } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
1467 [ - + ]: 230 : if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
1468 : 0 : reply_len = -1;
1469 : : #endif /* CONFIG_TESTING_OPTIONS */
1470 [ # # ]: 0 : } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
1471 [ # # ]: 0 : if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12))
1472 : 0 : reply_len = -1;
1473 : : } else {
1474 : 0 : os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
1475 : 0 : reply_len = 16;
1476 : : }
1477 : :
1478 [ + + ]: 8766 : if (reply_len < 0) {
1479 : 6 : os_memcpy(reply, "FAIL\n", 5);
1480 : 6 : reply_len = 5;
1481 : : }
1482 : 8766 : sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1483 : 8766 : os_free(reply);
1484 : : }
1485 : :
1486 : :
1487 : 702 : static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
1488 : : {
1489 : : char *buf;
1490 : : size_t len;
1491 : :
1492 [ - + ]: 702 : if (hapd->conf->ctrl_interface == NULL)
1493 : 0 : return NULL;
1494 : :
1495 : 1404 : len = os_strlen(hapd->conf->ctrl_interface) +
1496 : 702 : os_strlen(hapd->conf->iface) + 2;
1497 : 702 : buf = os_malloc(len);
1498 [ - + ]: 702 : if (buf == NULL)
1499 : 0 : return NULL;
1500 : :
1501 : 702 : os_snprintf(buf, len, "%s/%s",
1502 : 702 : hapd->conf->ctrl_interface, hapd->conf->iface);
1503 : 702 : buf[len - 1] = '\0';
1504 : 702 : return buf;
1505 : : }
1506 : :
1507 : :
1508 : 16144 : static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
1509 : : const char *txt, size_t len)
1510 : : {
1511 : 16144 : struct hostapd_data *hapd = ctx;
1512 [ - + ]: 16144 : if (hapd == NULL)
1513 : 16144 : return;
1514 : 16144 : hostapd_ctrl_iface_send(hapd, level, txt, len);
1515 : : }
1516 : :
1517 : :
1518 : 683 : int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
1519 : : {
1520 : : struct sockaddr_un addr;
1521 : 683 : int s = -1;
1522 : 683 : char *fname = NULL;
1523 : :
1524 [ + + ]: 683 : if (hapd->ctrl_sock > -1) {
1525 : 332 : wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
1526 : 332 : return 0;
1527 : : }
1528 : :
1529 [ - + ]: 351 : if (hapd->conf->ctrl_interface == NULL)
1530 : 0 : return 0;
1531 : :
1532 [ + + ]: 351 : if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1533 [ + - ]: 350 : if (errno == EEXIST) {
1534 : 350 : wpa_printf(MSG_DEBUG, "Using existing control "
1535 : : "interface directory.");
1536 : : } else {
1537 : 0 : perror("mkdir[ctrl_interface]");
1538 : 0 : goto fail;
1539 : : }
1540 : : }
1541 : :
1542 [ + + - + ]: 352 : if (hapd->conf->ctrl_interface_gid_set &&
1543 : 1 : chown(hapd->conf->ctrl_interface, -1,
1544 : 1 : hapd->conf->ctrl_interface_gid) < 0) {
1545 : 0 : perror("chown[ctrl_interface]");
1546 : 0 : return -1;
1547 : : }
1548 : :
1549 [ + + ][ - + ]: 351 : if (!hapd->conf->ctrl_interface_gid_set &&
1550 [ # # ]: 0 : hapd->iface->interfaces->ctrl_iface_group &&
1551 : 0 : chown(hapd->conf->ctrl_interface, -1,
1552 : 0 : hapd->iface->interfaces->ctrl_iface_group) < 0) {
1553 : 0 : perror("chown[ctrl_interface]");
1554 : 0 : return -1;
1555 : : }
1556 : :
1557 : : #ifdef ANDROID
1558 : : /*
1559 : : * Android is using umask 0077 which would leave the control interface
1560 : : * directory without group access. This breaks things since Wi-Fi
1561 : : * framework assumes that this directory can be accessed by other
1562 : : * applications in the wifi group. Fix this by adding group access even
1563 : : * if umask value would prevent this.
1564 : : */
1565 : : if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
1566 : : wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
1567 : : strerror(errno));
1568 : : /* Try to continue anyway */
1569 : : }
1570 : : #endif /* ANDROID */
1571 : :
1572 [ - + ]: 351 : if (os_strlen(hapd->conf->ctrl_interface) + 1 +
1573 : 351 : os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
1574 : 0 : goto fail;
1575 : :
1576 : 351 : s = socket(PF_UNIX, SOCK_DGRAM, 0);
1577 [ - + ]: 351 : if (s < 0) {
1578 : 0 : perror("socket(PF_UNIX)");
1579 : 0 : goto fail;
1580 : : }
1581 : :
1582 : 351 : os_memset(&addr, 0, sizeof(addr));
1583 : : #ifdef __FreeBSD__
1584 : : addr.sun_len = sizeof(addr);
1585 : : #endif /* __FreeBSD__ */
1586 : 351 : addr.sun_family = AF_UNIX;
1587 : 351 : fname = hostapd_ctrl_iface_path(hapd);
1588 [ - + ]: 351 : if (fname == NULL)
1589 : 0 : goto fail;
1590 : 351 : os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1591 [ - + ]: 351 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1592 : 0 : wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1593 : 0 : strerror(errno));
1594 [ # # ]: 0 : if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1595 : 0 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1596 : : " allow connections - assuming it was left"
1597 : : "over from forced program termination");
1598 [ # # ]: 0 : if (unlink(fname) < 0) {
1599 : 0 : perror("unlink[ctrl_iface]");
1600 : 0 : wpa_printf(MSG_ERROR, "Could not unlink "
1601 : : "existing ctrl_iface socket '%s'",
1602 : : fname);
1603 : 0 : goto fail;
1604 : : }
1605 [ # # ]: 0 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1606 : : 0) {
1607 : 0 : perror("hostapd-ctrl-iface: bind(PF_UNIX)");
1608 : 0 : goto fail;
1609 : : }
1610 : 0 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1611 : : "ctrl_iface socket '%s'", fname);
1612 : : } else {
1613 : 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1614 : : "be in use - cannot override it");
1615 : 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1616 : : "not used anymore", fname);
1617 : 0 : os_free(fname);
1618 : 0 : fname = NULL;
1619 : 0 : goto fail;
1620 : : }
1621 : : }
1622 : :
1623 [ + + - + ]: 352 : if (hapd->conf->ctrl_interface_gid_set &&
1624 : 1 : chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
1625 : 0 : perror("chown[ctrl_interface/ifname]");
1626 : 0 : goto fail;
1627 : : }
1628 : :
1629 [ + + ][ - + ]: 351 : if (!hapd->conf->ctrl_interface_gid_set &&
1630 [ # # ]: 0 : hapd->iface->interfaces->ctrl_iface_group &&
1631 : 0 : chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
1632 : 0 : perror("chown[ctrl_interface/ifname]");
1633 : 0 : goto fail;
1634 : : }
1635 : :
1636 [ - + ]: 351 : if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1637 : 0 : perror("chmod[ctrl_interface/ifname]");
1638 : 0 : goto fail;
1639 : : }
1640 : 351 : os_free(fname);
1641 : :
1642 : 351 : hapd->ctrl_sock = s;
1643 : 351 : eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
1644 : : NULL);
1645 : 351 : hapd->msg_ctx = hapd;
1646 : 351 : wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
1647 : :
1648 : 351 : return 0;
1649 : :
1650 : : fail:
1651 [ # # ]: 0 : if (s >= 0)
1652 : 0 : close(s);
1653 [ # # ]: 0 : if (fname) {
1654 : 0 : unlink(fname);
1655 : 0 : os_free(fname);
1656 : : }
1657 : 683 : return -1;
1658 : : }
1659 : :
1660 : :
1661 : 351 : void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
1662 : : {
1663 : : struct wpa_ctrl_dst *dst, *prev;
1664 : :
1665 [ + - ]: 351 : if (hapd->ctrl_sock > -1) {
1666 : : char *fname;
1667 : 351 : eloop_unregister_read_sock(hapd->ctrl_sock);
1668 : 351 : close(hapd->ctrl_sock);
1669 : 351 : hapd->ctrl_sock = -1;
1670 : 351 : fname = hostapd_ctrl_iface_path(hapd);
1671 [ + - ]: 351 : if (fname)
1672 : 351 : unlink(fname);
1673 : 351 : os_free(fname);
1674 : :
1675 [ + - + + ]: 702 : if (hapd->conf->ctrl_interface &&
1676 : 351 : rmdir(hapd->conf->ctrl_interface) < 0) {
1677 [ + - ]: 350 : if (errno == ENOTEMPTY) {
1678 : 350 : wpa_printf(MSG_DEBUG, "Control interface "
1679 : : "directory not empty - leaving it "
1680 : : "behind");
1681 : : } else {
1682 : 0 : wpa_printf(MSG_ERROR,
1683 : : "rmdir[ctrl_interface=%s]: %s",
1684 : 0 : hapd->conf->ctrl_interface,
1685 : 0 : strerror(errno));
1686 : : }
1687 : : }
1688 : : }
1689 : :
1690 : 351 : dst = hapd->ctrl_dst;
1691 [ + + ]: 357 : while (dst) {
1692 : 6 : prev = dst;
1693 : 6 : dst = dst->next;
1694 : 6 : os_free(prev);
1695 : : }
1696 : 351 : }
1697 : :
1698 : :
1699 : 345 : static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
1700 : : char *buf)
1701 : : {
1702 [ + + ]: 345 : if (hostapd_add_iface(interfaces, buf) < 0) {
1703 : 1 : wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
1704 : 1 : return -1;
1705 : : }
1706 : 345 : return 0;
1707 : : }
1708 : :
1709 : :
1710 : 1903 : static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
1711 : : char *buf)
1712 : : {
1713 [ + + ]: 1903 : if (hostapd_remove_iface(interfaces, buf) < 0) {
1714 : 1556 : wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
1715 : 1556 : return -1;
1716 : : }
1717 : 1903 : return 0;
1718 : : }
1719 : :
1720 : :
1721 : 390 : static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
1722 : : {
1723 : : #ifdef CONFIG_WPS_TESTING
1724 : 390 : wps_version_number = 0x20;
1725 : 390 : wps_testing_dummy_cred = 0;
1726 : 390 : wps_corrupt_pkhash = 0;
1727 : : #endif /* CONFIG_WPS_TESTING */
1728 : 390 : }
1729 : :
1730 : :
1731 : 3029 : static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
1732 : : void *sock_ctx)
1733 : : {
1734 : 3029 : void *interfaces = eloop_ctx;
1735 : : char buf[256];
1736 : : int res;
1737 : : struct sockaddr_un from;
1738 : 3029 : socklen_t fromlen = sizeof(from);
1739 : : char reply[24];
1740 : : int reply_len;
1741 : :
1742 : 3029 : res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
1743 : : (struct sockaddr *) &from, &fromlen);
1744 [ - + ]: 3029 : if (res < 0) {
1745 : 0 : perror("recvfrom(ctrl_iface)");
1746 : 3029 : return;
1747 : : }
1748 : 3029 : buf[res] = '\0';
1749 : 3029 : wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
1750 : :
1751 : 3029 : os_memcpy(reply, "OK\n", 3);
1752 : 3029 : reply_len = 3;
1753 : :
1754 [ + + ]: 3029 : if (os_strcmp(buf, "PING") == 0) {
1755 : 1 : os_memcpy(reply, "PONG\n", 5);
1756 : 1 : reply_len = 5;
1757 [ + + ]: 3028 : } else if (os_strncmp(buf, "RELOG", 5) == 0) {
1758 [ - + ]: 389 : if (wpa_debug_reopen_file() < 0)
1759 : 0 : reply_len = -1;
1760 [ + + ]: 2639 : } else if (os_strcmp(buf, "FLUSH") == 0) {
1761 : 390 : hostapd_ctrl_iface_flush(interfaces);
1762 [ + + ]: 2249 : } else if (os_strncmp(buf, "ADD ", 4) == 0) {
1763 [ + + ]: 345 : if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
1764 : 1 : reply_len = -1;
1765 [ + + ]: 1904 : } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
1766 [ + + ]: 1903 : if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
1767 : 1556 : reply_len = -1;
1768 : : #ifdef CONFIG_MODULE_TESTS
1769 [ + - ]: 1 : } else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
1770 : : int hapd_module_tests(void);
1771 [ - + ]: 1 : if (hapd_module_tests() < 0)
1772 : 0 : reply_len = -1;
1773 : : #endif /* CONFIG_MODULE_TESTS */
1774 : : } else {
1775 : 0 : wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
1776 : : "ignored");
1777 : 0 : reply_len = -1;
1778 : : }
1779 : :
1780 [ + + ]: 3029 : if (reply_len < 0) {
1781 : 1557 : os_memcpy(reply, "FAIL\n", 5);
1782 : 1557 : reply_len = 5;
1783 : : }
1784 : :
1785 : 3029 : sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
1786 : : }
1787 : :
1788 : :
1789 : 2 : static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
1790 : : {
1791 : : char *buf;
1792 : : size_t len;
1793 : :
1794 [ - + ]: 2 : if (interface->global_iface_path == NULL)
1795 : 0 : return NULL;
1796 : :
1797 : 4 : len = os_strlen(interface->global_iface_path) +
1798 : 2 : os_strlen(interface->global_iface_name) + 2;
1799 : 2 : buf = os_malloc(len);
1800 [ - + ]: 2 : if (buf == NULL)
1801 : 0 : return NULL;
1802 : :
1803 : 2 : os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
1804 : : interface->global_iface_name);
1805 : 2 : buf[len - 1] = '\0';
1806 : 2 : return buf;
1807 : : }
1808 : :
1809 : :
1810 : 2 : int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
1811 : : {
1812 : : struct sockaddr_un addr;
1813 : 2 : int s = -1;
1814 : 2 : char *fname = NULL;
1815 : :
1816 [ + + ]: 2 : if (interface->global_iface_path == NULL) {
1817 : 1 : wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
1818 : 1 : return 0;
1819 : : }
1820 : :
1821 [ + - ]: 1 : if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
1822 [ + - ]: 1 : if (errno == EEXIST) {
1823 : 1 : wpa_printf(MSG_DEBUG, "Using existing control "
1824 : : "interface directory.");
1825 : : } else {
1826 : 0 : perror("mkdir[ctrl_interface]");
1827 : 0 : goto fail;
1828 : : }
1829 [ # # # # ]: 0 : } else if (interface->ctrl_iface_group &&
1830 : 0 : chown(interface->global_iface_path, -1,
1831 : : interface->ctrl_iface_group) < 0) {
1832 : 0 : perror("chown[ctrl_interface]");
1833 : 0 : goto fail;
1834 : : }
1835 : :
1836 [ - + ]: 1 : if (os_strlen(interface->global_iface_path) + 1 +
1837 : 1 : os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
1838 : 0 : goto fail;
1839 : :
1840 : 1 : s = socket(PF_UNIX, SOCK_DGRAM, 0);
1841 [ - + ]: 1 : if (s < 0) {
1842 : 0 : perror("socket(PF_UNIX)");
1843 : 0 : goto fail;
1844 : : }
1845 : :
1846 : 1 : os_memset(&addr, 0, sizeof(addr));
1847 : : #ifdef __FreeBSD__
1848 : : addr.sun_len = sizeof(addr);
1849 : : #endif /* __FreeBSD__ */
1850 : 1 : addr.sun_family = AF_UNIX;
1851 : 1 : fname = hostapd_global_ctrl_iface_path(interface);
1852 [ - + ]: 1 : if (fname == NULL)
1853 : 0 : goto fail;
1854 : 1 : os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
1855 [ - + ]: 1 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1856 : 0 : wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
1857 : 0 : strerror(errno));
1858 [ # # ]: 0 : if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1859 : 0 : wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
1860 : : " allow connections - assuming it was left"
1861 : : "over from forced program termination");
1862 [ # # ]: 0 : if (unlink(fname) < 0) {
1863 : 0 : perror("unlink[ctrl_iface]");
1864 : 0 : wpa_printf(MSG_ERROR, "Could not unlink "
1865 : : "existing ctrl_iface socket '%s'",
1866 : : fname);
1867 : 0 : goto fail;
1868 : : }
1869 [ # # ]: 0 : if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
1870 : : 0) {
1871 : 0 : perror("bind(PF_UNIX)");
1872 : 0 : goto fail;
1873 : : }
1874 : 0 : wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
1875 : : "ctrl_iface socket '%s'", fname);
1876 : : } else {
1877 : 0 : wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
1878 : : "be in use - cannot override it");
1879 : 0 : wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
1880 : : "not used anymore", fname);
1881 : 0 : os_free(fname);
1882 : 0 : fname = NULL;
1883 : 0 : goto fail;
1884 : : }
1885 : : }
1886 : :
1887 [ - + # # ]: 1 : if (interface->ctrl_iface_group &&
1888 : 0 : chown(fname, -1, interface->ctrl_iface_group) < 0) {
1889 : 0 : perror("chown[ctrl_interface]");
1890 : 0 : goto fail;
1891 : : }
1892 : :
1893 [ - + ]: 1 : if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
1894 : 0 : perror("chmod[ctrl_interface/ifname]");
1895 : 0 : goto fail;
1896 : : }
1897 : 1 : os_free(fname);
1898 : :
1899 : 1 : interface->global_ctrl_sock = s;
1900 : 1 : eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
1901 : : interface, NULL);
1902 : :
1903 : 1 : return 0;
1904 : :
1905 : : fail:
1906 [ # # ]: 0 : if (s >= 0)
1907 : 0 : close(s);
1908 [ # # ]: 0 : if (fname) {
1909 : 0 : unlink(fname);
1910 : 0 : os_free(fname);
1911 : : }
1912 : 2 : return -1;
1913 : : }
1914 : :
1915 : :
1916 : 2 : void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
1917 : : {
1918 : 2 : char *fname = NULL;
1919 : :
1920 [ + + ]: 2 : if (interfaces->global_ctrl_sock > -1) {
1921 : 1 : eloop_unregister_read_sock(interfaces->global_ctrl_sock);
1922 : 1 : close(interfaces->global_ctrl_sock);
1923 : 1 : interfaces->global_ctrl_sock = -1;
1924 : 1 : fname = hostapd_global_ctrl_iface_path(interfaces);
1925 [ + - ]: 1 : if (fname) {
1926 : 1 : unlink(fname);
1927 : 1 : os_free(fname);
1928 : : }
1929 : :
1930 [ + - + - ]: 2 : if (interfaces->global_iface_path &&
1931 : 1 : rmdir(interfaces->global_iface_path) < 0) {
1932 [ - + ]: 1 : if (errno == ENOTEMPTY) {
1933 : 0 : wpa_printf(MSG_DEBUG, "Control interface "
1934 : : "directory not empty - leaving it "
1935 : : "behind");
1936 : : } else {
1937 : 1 : wpa_printf(MSG_ERROR,
1938 : : "rmdir[ctrl_interface=%s]: %s",
1939 : : interfaces->global_iface_path,
1940 : 1 : strerror(errno));
1941 : : }
1942 : : }
1943 : 1 : os_free(interfaces->global_iface_path);
1944 : 1 : interfaces->global_iface_path = NULL;
1945 : : }
1946 : 2 : }
1947 : :
1948 : :
1949 : 16144 : static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
1950 : : const char *buf, size_t len)
1951 : : {
1952 : : struct wpa_ctrl_dst *dst, *next;
1953 : : struct msghdr msg;
1954 : : int idx;
1955 : : struct iovec io[2];
1956 : : char levelstr[10];
1957 : :
1958 : 16144 : dst = hapd->ctrl_dst;
1959 [ + - ][ + + ]: 16144 : if (hapd->ctrl_sock < 0 || dst == NULL)
1960 : 16144 : return;
1961 : :
1962 : 5379 : os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
1963 : 5379 : io[0].iov_base = levelstr;
1964 : 5379 : io[0].iov_len = os_strlen(levelstr);
1965 : 5379 : io[1].iov_base = (char *) buf;
1966 : 5379 : io[1].iov_len = len;
1967 : 5379 : os_memset(&msg, 0, sizeof(msg));
1968 : 5379 : msg.msg_iov = io;
1969 : 5379 : msg.msg_iovlen = 2;
1970 : :
1971 : 5379 : idx = 0;
1972 [ + + ]: 10880 : while (dst) {
1973 : 5501 : next = dst->next;
1974 [ + + ]: 5501 : if (level >= dst->debug_level) {
1975 : 1267 : wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
1976 : 2534 : (u8 *) dst->addr.sun_path, dst->addrlen -
1977 : : offsetof(struct sockaddr_un, sun_path));
1978 : 1267 : msg.msg_name = &dst->addr;
1979 : 1267 : msg.msg_namelen = dst->addrlen;
1980 [ + + ]: 1267 : if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
1981 : 1 : int _errno = errno;
1982 : 2 : wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
1983 : : "%d - %s",
1984 : 2 : idx, errno, strerror(errno));
1985 : 1 : dst->errors++;
1986 [ + - ][ + - ]: 1 : if (dst->errors > 10 || _errno == ENOENT) {
1987 : 1 : hostapd_ctrl_iface_detach(
1988 : : hapd, &dst->addr,
1989 : : dst->addrlen);
1990 : : }
1991 : : } else
1992 : 1266 : dst->errors = 0;
1993 : : }
1994 : 5501 : idx++;
1995 : 5501 : dst = next;
1996 : : }
1997 : : }
1998 : :
1999 : : #endif /* CONFIG_NATIVE_WINDOWS */
|