Sync usage with man page.
[netbsd-mini2440.git] / dist / wpa / hostapd / ctrl_iface.c
blob781c9f33b07c68f2e398d1c9748877cb6da686d1
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>
22 #include "hostapd.h"
23 #include "eloop.h"
24 #include "config.h"
25 #include "ieee802_1x.h"
26 #include "wpa.h"
27 #include "radius/radius_client.h"
28 #include "ieee802_11.h"
29 #include "ctrl_iface.h"
30 #include "sta_info.h"
31 #include "accounting.h"
34 struct wpa_ctrl_dst {
35 struct wpa_ctrl_dst *next;
36 struct sockaddr_un addr;
37 socklen_t addrlen;
38 int debug_level;
39 int errors;
43 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
44 struct sockaddr_un *from,
45 socklen_t fromlen)
47 struct wpa_ctrl_dst *dst;
49 dst = os_zalloc(sizeof(*dst));
50 if (dst == NULL)
51 return -1;
52 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
53 dst->addrlen = fromlen;
54 dst->debug_level = MSG_INFO;
55 dst->next = hapd->ctrl_dst;
56 hapd->ctrl_dst = dst;
57 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
58 (u8 *) from->sun_path, fromlen);
59 return 0;
63 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
64 struct sockaddr_un *from,
65 socklen_t fromlen)
67 struct wpa_ctrl_dst *dst, *prev = NULL;
69 dst = hapd->ctrl_dst;
70 while (dst) {
71 if (fromlen == dst->addrlen &&
72 os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
73 0) {
74 if (prev == NULL)
75 hapd->ctrl_dst = dst->next;
76 else
77 prev->next = dst->next;
78 os_free(dst);
79 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
80 (u8 *) from->sun_path, fromlen);
81 return 0;
83 prev = dst;
84 dst = dst->next;
86 return -1;
90 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
91 struct sockaddr_un *from,
92 socklen_t fromlen,
93 char *level)
95 struct wpa_ctrl_dst *dst;
97 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
99 dst = hapd->ctrl_dst;
100 while (dst) {
101 if (fromlen == dst->addrlen &&
102 os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
103 0) {
104 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
105 "level", (u8 *) from->sun_path, fromlen);
106 dst->debug_level = atoi(level);
107 return 0;
109 dst = dst->next;
112 return -1;
116 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
117 struct sta_info *sta,
118 char *buf, size_t buflen)
120 int len, res, ret;
122 if (sta == NULL) {
123 ret = os_snprintf(buf, buflen, "FAIL\n");
124 if (ret < 0 || (size_t) ret >= buflen)
125 return 0;
126 return ret;
129 len = 0;
130 ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
131 MAC2STR(sta->addr));
132 if (ret < 0 || (size_t) ret >= buflen - len)
133 return len;
134 len += ret;
136 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
137 if (res >= 0)
138 len += res;
139 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
140 if (res >= 0)
141 len += res;
142 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
143 if (res >= 0)
144 len += res;
146 return len;
150 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
151 char *buf, size_t buflen)
153 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
157 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
158 const char *txtaddr,
159 char *buf, size_t buflen)
161 u8 addr[ETH_ALEN];
162 int ret;
164 if (hwaddr_aton(txtaddr, addr)) {
165 ret = os_snprintf(buf, buflen, "FAIL\n");
166 if (ret < 0 || (size_t) ret >= buflen)
167 return 0;
168 return ret;
170 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
171 buf, buflen);
175 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
176 const char *txtaddr,
177 char *buf, size_t buflen)
179 u8 addr[ETH_ALEN];
180 struct sta_info *sta;
181 int ret;
183 if (hwaddr_aton(txtaddr, addr) ||
184 (sta = ap_get_sta(hapd, addr)) == NULL) {
185 ret = os_snprintf(buf, buflen, "FAIL\n");
186 if (ret < 0 || (size_t) ret >= buflen)
187 return 0;
188 return ret;
190 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
194 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
195 const char *txtaddr)
197 u8 addr[ETH_ALEN];
198 struct sta_info *sta;
200 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
202 if (hwaddr_aton(txtaddr, addr))
203 return -1;
205 sta = ap_get_sta(hapd, addr);
206 if (sta)
207 return 0;
209 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
210 "notification", MAC2STR(addr));
211 sta = ap_sta_add(hapd, addr);
212 if (sta == NULL)
213 return -1;
215 hostapd_new_assoc_sta(hapd, sta, 0);
216 accounting_sta_get_id(hapd, sta);
217 return 0;
221 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
222 void *sock_ctx)
224 struct hostapd_data *hapd = eloop_ctx;
225 char buf[256];
226 int res;
227 struct sockaddr_un from;
228 socklen_t fromlen = sizeof(from);
229 char *reply;
230 const int reply_size = 4096;
231 int reply_len;
233 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
234 (struct sockaddr *) &from, &fromlen);
235 if (res < 0) {
236 perror("recvfrom(ctrl_iface)");
237 return;
239 buf[res] = '\0';
240 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
242 reply = os_malloc(reply_size);
243 if (reply == NULL) {
244 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
245 fromlen);
246 return;
249 os_memcpy(reply, "OK\n", 3);
250 reply_len = 3;
252 if (os_strcmp(buf, "PING") == 0) {
253 os_memcpy(reply, "PONG\n", 5);
254 reply_len = 5;
255 } else if (os_strcmp(buf, "MIB") == 0) {
256 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
257 if (reply_len >= 0) {
258 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
259 reply_size - reply_len);
260 if (res < 0)
261 reply_len = -1;
262 else
263 reply_len += res;
265 if (reply_len >= 0) {
266 res = ieee802_1x_get_mib(hapd, reply + reply_len,
267 reply_size - reply_len);
268 if (res < 0)
269 reply_len = -1;
270 else
271 reply_len += res;
273 if (reply_len >= 0) {
274 res = radius_client_get_mib(hapd->radius,
275 reply + reply_len,
276 reply_size - reply_len);
277 if (res < 0)
278 reply_len = -1;
279 else
280 reply_len += res;
282 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
283 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
284 reply_size);
285 } else if (os_strncmp(buf, "STA ", 4) == 0) {
286 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
287 reply_size);
288 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
289 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
290 reply_size);
291 } else if (os_strcmp(buf, "ATTACH") == 0) {
292 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
293 reply_len = -1;
294 } else if (os_strcmp(buf, "DETACH") == 0) {
295 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
296 reply_len = -1;
297 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
298 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
299 buf + 6))
300 reply_len = -1;
301 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
302 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
303 reply_len = -1;
304 } else {
305 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
306 reply_len = 16;
309 if (reply_len < 0) {
310 os_memcpy(reply, "FAIL\n", 5);
311 reply_len = 5;
313 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
314 os_free(reply);
318 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
320 char *buf;
321 size_t len;
323 if (hapd->conf->ctrl_interface == NULL)
324 return NULL;
326 len = os_strlen(hapd->conf->ctrl_interface) +
327 os_strlen(hapd->conf->iface) + 2;
328 buf = os_malloc(len);
329 if (buf == NULL)
330 return NULL;
332 os_snprintf(buf, len, "%s/%s",
333 hapd->conf->ctrl_interface, hapd->conf->iface);
334 buf[len - 1] = '\0';
335 return buf;
339 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
341 struct sockaddr_un addr;
342 int s = -1;
343 char *fname = NULL;
345 hapd->ctrl_sock = -1;
347 if (hapd->conf->ctrl_interface == NULL)
348 return 0;
350 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
351 if (errno == EEXIST) {
352 wpa_printf(MSG_DEBUG, "Using existing control "
353 "interface directory.");
354 } else {
355 perror("mkdir[ctrl_interface]");
356 goto fail;
360 if (hapd->conf->ctrl_interface_gid_set &&
361 chown(hapd->conf->ctrl_interface, 0,
362 hapd->conf->ctrl_interface_gid) < 0) {
363 perror("chown[ctrl_interface]");
364 return -1;
367 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
368 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
369 goto fail;
371 s = socket(PF_UNIX, SOCK_DGRAM, 0);
372 if (s < 0) {
373 perror("socket(PF_UNIX)");
374 goto fail;
377 os_memset(&addr, 0, sizeof(addr));
378 addr.sun_family = AF_UNIX;
379 fname = hostapd_ctrl_iface_path(hapd);
380 if (fname == NULL)
381 goto fail;
382 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
383 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
384 perror("bind(PF_UNIX)");
385 goto fail;
388 if (hapd->conf->ctrl_interface_gid_set &&
389 chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
390 perror("chown[ctrl_interface/ifname]");
391 goto fail;
394 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
395 perror("chmod[ctrl_interface/ifname]");
396 goto fail;
398 os_free(fname);
400 hapd->ctrl_sock = s;
401 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
402 NULL);
404 return 0;
406 fail:
407 if (s >= 0)
408 close(s);
409 if (fname) {
410 unlink(fname);
411 os_free(fname);
413 return -1;
417 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
419 struct wpa_ctrl_dst *dst, *prev;
421 if (hapd->ctrl_sock > -1) {
422 char *fname;
423 eloop_unregister_read_sock(hapd->ctrl_sock);
424 close(hapd->ctrl_sock);
425 hapd->ctrl_sock = -1;
426 fname = hostapd_ctrl_iface_path(hapd);
427 if (fname)
428 unlink(fname);
429 os_free(fname);
431 if (hapd->conf->ctrl_interface &&
432 rmdir(hapd->conf->ctrl_interface) < 0) {
433 if (errno == ENOTEMPTY) {
434 wpa_printf(MSG_DEBUG, "Control interface "
435 "directory not empty - leaving it "
436 "behind");
437 } else {
438 perror("rmdir[ctrl_interface]");
443 dst = hapd->ctrl_dst;
444 while (dst) {
445 prev = dst;
446 dst = dst->next;
447 os_free(prev);
452 void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
453 char *buf, size_t len)
455 struct wpa_ctrl_dst *dst, *next;
456 struct msghdr msg;
457 int idx;
458 struct iovec io[2];
459 char levelstr[10];
461 dst = hapd->ctrl_dst;
462 if (hapd->ctrl_sock < 0 || dst == NULL)
463 return;
465 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
466 io[0].iov_base = levelstr;
467 io[0].iov_len = os_strlen(levelstr);
468 io[1].iov_base = buf;
469 io[1].iov_len = len;
470 os_memset(&msg, 0, sizeof(msg));
471 msg.msg_iov = io;
472 msg.msg_iovlen = 2;
474 idx = 0;
475 while (dst) {
476 next = dst->next;
477 if (level >= dst->debug_level) {
478 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
479 (u8 *) dst->addr.sun_path, dst->addrlen);
480 msg.msg_name = &dst->addr;
481 msg.msg_namelen = dst->addrlen;
482 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
483 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
484 idx);
485 perror("sendmsg");
486 dst->errors++;
487 if (dst->errors > 10) {
488 hostapd_ctrl_iface_detach(
489 hapd, &dst->addr,
490 dst->addrlen);
492 } else
493 dst->errors = 0;
495 idx++;
496 dst = next;
500 #endif /* CONFIG_NATIVE_WINDOWS */