hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / hostapd / ctrl_iface.c
blob9dec7247cdd7d178cce5d3f103d799a5ee57af55
1 /*
2 * hostapd / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #ifndef CONFIG_NATIVE_WINDOWS
19 #include <sys/un.h>
20 #include <sys/stat.h>
21 #include <stddef.h>
23 #include "hostapd.h"
24 #include "eloop.h"
25 #include "config.h"
26 #include "ieee802_1x.h"
27 #include "wpa.h"
28 #include "radius/radius_client.h"
29 #include "ieee802_11.h"
30 #include "ctrl_iface.h"
31 #include "sta_info.h"
32 #include "accounting.h"
33 #include "wps_hostapd.h"
36 struct wpa_ctrl_dst {
37 struct wpa_ctrl_dst *next;
38 struct sockaddr_un addr;
39 socklen_t addrlen;
40 int debug_level;
41 int errors;
45 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
46 const char *buf, size_t len);
49 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
50 struct sockaddr_un *from,
51 socklen_t fromlen)
53 struct wpa_ctrl_dst *dst;
55 dst = os_zalloc(sizeof(*dst));
56 if (dst == NULL)
57 return -1;
58 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
59 dst->addrlen = fromlen;
60 dst->debug_level = MSG_INFO;
61 dst->next = hapd->ctrl_dst;
62 hapd->ctrl_dst = dst;
63 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
64 (u8 *) from->sun_path,
65 fromlen - offsetof(struct sockaddr_un, sun_path));
66 return 0;
70 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
71 struct sockaddr_un *from,
72 socklen_t fromlen)
74 struct wpa_ctrl_dst *dst, *prev = NULL;
76 dst = hapd->ctrl_dst;
77 while (dst) {
78 if (fromlen == dst->addrlen &&
79 os_memcmp(from->sun_path, dst->addr.sun_path,
80 fromlen - offsetof(struct sockaddr_un, sun_path))
81 == 0) {
82 if (prev == NULL)
83 hapd->ctrl_dst = dst->next;
84 else
85 prev->next = dst->next;
86 os_free(dst);
87 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
88 (u8 *) from->sun_path,
89 fromlen -
90 offsetof(struct sockaddr_un, sun_path));
91 return 0;
93 prev = dst;
94 dst = dst->next;
96 return -1;
100 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
101 struct sockaddr_un *from,
102 socklen_t fromlen,
103 char *level)
105 struct wpa_ctrl_dst *dst;
107 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
109 dst = hapd->ctrl_dst;
110 while (dst) {
111 if (fromlen == dst->addrlen &&
112 os_memcmp(from->sun_path, dst->addr.sun_path,
113 fromlen - offsetof(struct sockaddr_un, sun_path))
114 == 0) {
115 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
116 "level", (u8 *) from->sun_path, fromlen -
117 offsetof(struct sockaddr_un, sun_path));
118 dst->debug_level = atoi(level);
119 return 0;
121 dst = dst->next;
124 return -1;
128 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
129 struct sta_info *sta,
130 char *buf, size_t buflen)
132 int len, res, ret;
134 if (sta == NULL) {
135 ret = os_snprintf(buf, buflen, "FAIL\n");
136 if (ret < 0 || (size_t) ret >= buflen)
137 return 0;
138 return ret;
141 len = 0;
142 ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
143 MAC2STR(sta->addr));
144 if (ret < 0 || (size_t) ret >= buflen - len)
145 return len;
146 len += ret;
148 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
149 if (res >= 0)
150 len += res;
151 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
152 if (res >= 0)
153 len += res;
154 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
155 if (res >= 0)
156 len += res;
158 return len;
162 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
163 char *buf, size_t buflen)
165 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
169 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
170 const char *txtaddr,
171 char *buf, size_t buflen)
173 u8 addr[ETH_ALEN];
174 int ret;
176 if (hwaddr_aton(txtaddr, addr)) {
177 ret = os_snprintf(buf, buflen, "FAIL\n");
178 if (ret < 0 || (size_t) ret >= buflen)
179 return 0;
180 return ret;
182 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
183 buf, buflen);
187 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
188 const char *txtaddr,
189 char *buf, size_t buflen)
191 u8 addr[ETH_ALEN];
192 struct sta_info *sta;
193 int ret;
195 if (hwaddr_aton(txtaddr, addr) ||
196 (sta = ap_get_sta(hapd, addr)) == NULL) {
197 ret = os_snprintf(buf, buflen, "FAIL\n");
198 if (ret < 0 || (size_t) ret >= buflen)
199 return 0;
200 return ret;
202 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
206 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
207 const char *txtaddr)
209 u8 addr[ETH_ALEN];
210 struct sta_info *sta;
212 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
214 if (hwaddr_aton(txtaddr, addr))
215 return -1;
217 sta = ap_get_sta(hapd, addr);
218 if (sta)
219 return 0;
221 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
222 "notification", MAC2STR(addr));
223 sta = ap_sta_add(hapd, addr);
224 if (sta == NULL)
225 return -1;
227 hostapd_new_assoc_sta(hapd, sta, 0);
228 return 0;
232 #ifdef CONFIG_IEEE80211W
233 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
234 const char *txtaddr)
236 u8 addr[ETH_ALEN];
237 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
239 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
241 if (hwaddr_aton(txtaddr, addr))
242 return -1;
244 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
245 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
247 return 0;
249 #endif /* CONFIG_IEEE80211W */
252 #ifdef CONFIG_WPS
253 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
255 char *pin = os_strchr(txt, ' ');
256 char *timeout_txt;
257 int timeout;
259 if (pin == NULL)
260 return -1;
261 *pin++ = '\0';
263 timeout_txt = os_strchr(pin, ' ');
264 if (timeout_txt) {
265 *timeout_txt++ = '\0';
266 timeout = atoi(timeout_txt);
267 } else
268 timeout = 0;
270 return hostapd_wps_add_pin(hapd, txt, pin, timeout);
272 #endif /* CONFIG_WPS */
275 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
276 void *sock_ctx)
278 struct hostapd_data *hapd = eloop_ctx;
279 char buf[256];
280 int res;
281 struct sockaddr_un from;
282 socklen_t fromlen = sizeof(from);
283 char *reply;
284 const int reply_size = 4096;
285 int reply_len;
287 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
288 (struct sockaddr *) &from, &fromlen);
289 if (res < 0) {
290 perror("recvfrom(ctrl_iface)");
291 return;
293 buf[res] = '\0';
294 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
296 reply = os_malloc(reply_size);
297 if (reply == NULL) {
298 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
299 fromlen);
300 return;
303 os_memcpy(reply, "OK\n", 3);
304 reply_len = 3;
306 if (os_strcmp(buf, "PING") == 0) {
307 os_memcpy(reply, "PONG\n", 5);
308 reply_len = 5;
309 } else if (os_strcmp(buf, "MIB") == 0) {
310 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
311 if (reply_len >= 0) {
312 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
313 reply_size - reply_len);
314 if (res < 0)
315 reply_len = -1;
316 else
317 reply_len += res;
319 if (reply_len >= 0) {
320 res = ieee802_1x_get_mib(hapd, reply + reply_len,
321 reply_size - reply_len);
322 if (res < 0)
323 reply_len = -1;
324 else
325 reply_len += res;
327 if (reply_len >= 0) {
328 res = radius_client_get_mib(hapd->radius,
329 reply + reply_len,
330 reply_size - reply_len);
331 if (res < 0)
332 reply_len = -1;
333 else
334 reply_len += res;
336 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
337 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
338 reply_size);
339 } else if (os_strncmp(buf, "STA ", 4) == 0) {
340 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
341 reply_size);
342 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
343 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
344 reply_size);
345 } else if (os_strcmp(buf, "ATTACH") == 0) {
346 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
347 reply_len = -1;
348 } else if (os_strcmp(buf, "DETACH") == 0) {
349 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
350 reply_len = -1;
351 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
352 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
353 buf + 6))
354 reply_len = -1;
355 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
356 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
357 reply_len = -1;
358 #ifdef CONFIG_IEEE80211W
359 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
360 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
361 reply_len = -1;
362 #endif /* CONFIG_IEEE80211W */
363 #ifdef CONFIG_WPS
364 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
365 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
366 reply_len = -1;
367 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
368 if (hostapd_wps_button_pushed(hapd))
369 reply_len = -1;
370 #endif /* CONFIG_WPS */
371 } else {
372 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
373 reply_len = 16;
376 if (reply_len < 0) {
377 os_memcpy(reply, "FAIL\n", 5);
378 reply_len = 5;
380 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
381 os_free(reply);
385 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
387 char *buf;
388 size_t len;
390 if (hapd->conf->ctrl_interface == NULL)
391 return NULL;
393 len = os_strlen(hapd->conf->ctrl_interface) +
394 os_strlen(hapd->conf->iface) + 2;
395 buf = os_malloc(len);
396 if (buf == NULL)
397 return NULL;
399 os_snprintf(buf, len, "%s/%s",
400 hapd->conf->ctrl_interface, hapd->conf->iface);
401 buf[len - 1] = '\0';
402 return buf;
406 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
407 const char *txt, size_t len)
409 struct hostapd_data *hapd = ctx;
410 if (hapd == NULL)
411 return;
412 hostapd_ctrl_iface_send(hapd, level, txt, len);
416 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
418 struct sockaddr_un addr;
419 int s = -1;
420 char *fname = NULL;
422 hapd->ctrl_sock = -1;
424 if (hapd->conf->ctrl_interface == NULL)
425 return 0;
427 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
428 if (errno == EEXIST) {
429 wpa_printf(MSG_DEBUG, "Using existing control "
430 "interface directory.");
431 } else {
432 perror("mkdir[ctrl_interface]");
433 goto fail;
437 if (hapd->conf->ctrl_interface_gid_set &&
438 chown(hapd->conf->ctrl_interface, 0,
439 hapd->conf->ctrl_interface_gid) < 0) {
440 perror("chown[ctrl_interface]");
441 return -1;
444 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
445 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
446 goto fail;
448 s = socket(PF_UNIX, SOCK_DGRAM, 0);
449 if (s < 0) {
450 perror("socket(PF_UNIX)");
451 goto fail;
454 os_memset(&addr, 0, sizeof(addr));
455 #ifdef __FreeBSD__
456 addr.sun_len = sizeof(addr);
457 #endif /* __FreeBSD__ */
458 addr.sun_family = AF_UNIX;
459 fname = hostapd_ctrl_iface_path(hapd);
460 if (fname == NULL)
461 goto fail;
462 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
463 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
464 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
465 strerror(errno));
466 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
467 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
468 " allow connections - assuming it was left"
469 "over from forced program termination");
470 if (unlink(fname) < 0) {
471 perror("unlink[ctrl_iface]");
472 wpa_printf(MSG_ERROR, "Could not unlink "
473 "existing ctrl_iface socket '%s'",
474 fname);
475 goto fail;
477 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
478 0) {
479 perror("bind(PF_UNIX)");
480 goto fail;
482 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
483 "ctrl_iface socket '%s'", fname);
484 } else {
485 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
486 "be in use - cannot override it");
487 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
488 "not used anymore", fname);
489 os_free(fname);
490 fname = NULL;
491 goto fail;
495 if (hapd->conf->ctrl_interface_gid_set &&
496 chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
497 perror("chown[ctrl_interface/ifname]");
498 goto fail;
501 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
502 perror("chmod[ctrl_interface/ifname]");
503 goto fail;
505 os_free(fname);
507 hapd->ctrl_sock = s;
508 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
509 NULL);
510 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
512 return 0;
514 fail:
515 if (s >= 0)
516 close(s);
517 if (fname) {
518 unlink(fname);
519 os_free(fname);
521 return -1;
525 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
527 struct wpa_ctrl_dst *dst, *prev;
529 if (hapd->ctrl_sock > -1) {
530 char *fname;
531 eloop_unregister_read_sock(hapd->ctrl_sock);
532 close(hapd->ctrl_sock);
533 hapd->ctrl_sock = -1;
534 fname = hostapd_ctrl_iface_path(hapd);
535 if (fname)
536 unlink(fname);
537 os_free(fname);
539 if (hapd->conf->ctrl_interface &&
540 rmdir(hapd->conf->ctrl_interface) < 0) {
541 if (errno == ENOTEMPTY) {
542 wpa_printf(MSG_DEBUG, "Control interface "
543 "directory not empty - leaving it "
544 "behind");
545 } else {
546 perror("rmdir[ctrl_interface]");
551 dst = hapd->ctrl_dst;
552 while (dst) {
553 prev = dst;
554 dst = dst->next;
555 os_free(prev);
560 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
561 const char *buf, size_t len)
563 struct wpa_ctrl_dst *dst, *next;
564 struct msghdr msg;
565 int idx;
566 struct iovec io[2];
567 char levelstr[10];
569 dst = hapd->ctrl_dst;
570 if (hapd->ctrl_sock < 0 || dst == NULL)
571 return;
573 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
574 io[0].iov_base = levelstr;
575 io[0].iov_len = os_strlen(levelstr);
576 io[1].iov_base = (char *) buf;
577 io[1].iov_len = len;
578 os_memset(&msg, 0, sizeof(msg));
579 msg.msg_iov = io;
580 msg.msg_iovlen = 2;
582 idx = 0;
583 while (dst) {
584 next = dst->next;
585 if (level >= dst->debug_level) {
586 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
587 (u8 *) dst->addr.sun_path, dst->addrlen -
588 offsetof(struct sockaddr_un, sun_path));
589 msg.msg_name = &dst->addr;
590 msg.msg_namelen = dst->addrlen;
591 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
592 int _errno = errno;
593 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
594 "%d - %s",
595 idx, errno, strerror(errno));
596 dst->errors++;
597 if (dst->errors > 10 || _errno == ENOENT) {
598 hostapd_ctrl_iface_detach(
599 hapd, &dst->addr,
600 dst->addrlen);
602 } else
603 dst->errors = 0;
605 idx++;
606 dst = next;
610 #endif /* CONFIG_NATIVE_WINDOWS */