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