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