Add resident.conf(5) and varsym.conf(5) manual pages.
[dragonfly/vkernel-mp.git] / contrib / hostapd-0.4.9 / ctrl_iface.c
blobff730d4a95d3b7b822693c70ed19dcddfa4f27f5
1 /*
2 * Host AP (software wireless LAN access point) user space daemon for
3 * Host AP kernel driver / UNIX domain socket -based control interface
4 * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
11 * license.
13 * See README and COPYING for more details.
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/uio.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <netinet/in.h>
28 #include "hostapd.h"
29 #include "eloop.h"
30 #include "config.h"
31 #include "eapol_sm.h"
32 #include "ieee802_1x.h"
33 #include "wpa.h"
34 #include "radius_client.h"
35 #include "ieee802_11.h"
36 #include "ctrl_iface.h"
37 #include "sta_info.h"
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;
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 = malloc(sizeof(*dst));
56 if (dst == NULL)
57 return -1;
58 memset(dst, 0, sizeof(*dst));
59 memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
60 dst->addrlen = fromlen;
61 dst->debug_level = MSG_INFO;
62 dst->next = hapd->ctrl_dst;
63 hapd->ctrl_dst = dst;
64 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
65 (u8 *) from->sun_path, fromlen);
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 memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
80 if (prev == NULL)
81 hapd->ctrl_dst = dst->next;
82 else
83 prev->next = dst->next;
84 free(dst);
85 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
86 (u8 *) from->sun_path, fromlen);
87 return 0;
89 prev = dst;
90 dst = dst->next;
92 return -1;
96 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
97 struct sockaddr_un *from,
98 socklen_t fromlen,
99 char *level)
101 struct wpa_ctrl_dst *dst;
103 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
105 dst = hapd->ctrl_dst;
106 while (dst) {
107 if (fromlen == dst->addrlen &&
108 memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
109 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
110 "level", (u8 *) from->sun_path, fromlen);
111 dst->debug_level = atoi(level);
112 return 0;
114 dst = dst->next;
117 return -1;
121 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
122 struct sta_info *sta,
123 char *buf, size_t buflen)
125 int len, res;
127 if (sta == NULL) {
128 return snprintf(buf, buflen, "FAIL\n");
131 len = 0;
132 len += snprintf(buf + len, buflen - len, MACSTR "\n",
133 MAC2STR(sta->addr));
135 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
136 if (res >= 0)
137 len += res;
138 res = wpa_get_mib_sta(hapd, sta, buf + len, buflen - len);
139 if (res >= 0)
140 len += res;
141 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
142 if (res >= 0)
143 len += res;
145 return len;
149 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
150 char *buf, size_t buflen)
152 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
156 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
157 const char *txtaddr,
158 char *buf, size_t buflen)
160 u8 addr[ETH_ALEN];
162 if (hwaddr_aton(txtaddr, addr))
163 return snprintf(buf, buflen, "FAIL\n");
164 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
165 buf, buflen);
169 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
170 const char *txtaddr,
171 char *buf, size_t buflen)
173 u8 addr[ETH_ALEN];
174 struct sta_info *sta;
176 if (hwaddr_aton(txtaddr, addr) ||
177 (sta = ap_get_sta(hapd, addr)) == NULL)
178 return snprintf(buf, buflen, "FAIL\n");
179 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
183 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
184 void *sock_ctx)
186 struct hostapd_data *hapd = eloop_ctx;
187 char buf[256];
188 int res;
189 struct sockaddr_un from;
190 socklen_t fromlen = sizeof(from);
191 char *reply;
192 const int reply_size = 4096;
193 int reply_len;
195 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
196 (struct sockaddr *) &from, &fromlen);
197 if (res < 0) {
198 perror("recvfrom(ctrl_iface)");
199 return;
201 buf[res] = '\0';
202 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
204 reply = malloc(reply_size);
205 if (reply == NULL) {
206 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
207 fromlen);
208 return;
211 memcpy(reply, "OK\n", 3);
212 reply_len = 3;
214 if (strcmp(buf, "PING") == 0) {
215 memcpy(reply, "PONG\n", 5);
216 reply_len = 5;
217 } else if (strcmp(buf, "MIB") == 0) {
218 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
219 if (reply_len >= 0) {
220 res = wpa_get_mib(hapd, reply + reply_len,
221 reply_size - reply_len);
222 if (res < 0)
223 reply_len = -1;
224 else
225 reply_len += res;
227 if (reply_len >= 0) {
228 res = ieee802_1x_get_mib(hapd, reply + reply_len,
229 reply_size - reply_len);
230 if (res < 0)
231 reply_len = -1;
232 else
233 reply_len += res;
235 if (reply_len >= 0) {
236 res = radius_client_get_mib(hapd->radius,
237 reply + reply_len,
238 reply_size - reply_len);
239 if (res < 0)
240 reply_len = -1;
241 else
242 reply_len += res;
244 } else if (strcmp(buf, "STA-FIRST") == 0) {
245 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
246 reply_size);
247 } else if (strncmp(buf, "STA ", 4) == 0) {
248 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
249 reply_size);
250 } else if (strncmp(buf, "STA-NEXT ", 9) == 0) {
251 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
252 reply_size);
253 } else if (strcmp(buf, "ATTACH") == 0) {
254 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
255 reply_len = -1;
256 } else if (strcmp(buf, "DETACH") == 0) {
257 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
258 reply_len = -1;
259 } else if (strncmp(buf, "LEVEL ", 6) == 0) {
260 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
261 buf + 6))
262 reply_len = -1;
263 } else {
264 memcpy(reply, "UNKNOWN COMMAND\n", 16);
265 reply_len = 16;
268 if (reply_len < 0) {
269 memcpy(reply, "FAIL\n", 5);
270 reply_len = 5;
272 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
273 free(reply);
277 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
279 char *buf;
280 size_t len;
282 if (hapd->conf->ctrl_interface == NULL)
283 return NULL;
285 len = strlen(hapd->conf->ctrl_interface) + strlen(hapd->conf->iface) +
287 buf = malloc(len);
288 if (buf == NULL)
289 return NULL;
291 snprintf(buf, len, "%s/%s",
292 hapd->conf->ctrl_interface, hapd->conf->iface);
293 return buf;
297 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
299 struct sockaddr_un addr;
300 int s = -1;
301 char *fname = NULL;
303 hapd->ctrl_sock = -1;
305 if (hapd->conf->ctrl_interface == NULL)
306 return 0;
308 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
309 if (errno == EEXIST) {
310 wpa_printf(MSG_DEBUG, "Using existing control "
311 "interface directory.");
312 } else {
313 perror("mkdir[ctrl_interface]");
314 goto fail;
318 if (hapd->conf->ctrl_interface_gid_set &&
319 chown(hapd->conf->ctrl_interface, 0,
320 hapd->conf->ctrl_interface_gid) < 0) {
321 perror("chown[ctrl_interface]");
322 return -1;
325 if (strlen(hapd->conf->ctrl_interface) + 1 + strlen(hapd->conf->iface)
326 >= sizeof(addr.sun_path))
327 goto fail;
329 s = socket(PF_UNIX, SOCK_DGRAM, 0);
330 if (s < 0) {
331 perror("socket(PF_UNIX)");
332 goto fail;
335 memset(&addr, 0, sizeof(addr));
336 addr.sun_family = AF_UNIX;
337 fname = hostapd_ctrl_iface_path(hapd);
338 if (fname == NULL)
339 goto fail;
340 strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
341 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
342 perror("bind(PF_UNIX)");
343 goto fail;
346 if (hapd->conf->ctrl_interface_gid_set &&
347 chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
348 perror("chown[ctrl_interface/ifname]");
349 goto fail;
352 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
353 perror("chmod[ctrl_interface/ifname]");
354 goto fail;
356 free(fname);
358 hapd->ctrl_sock = s;
359 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
360 NULL);
362 return 0;
364 fail:
365 if (s >= 0)
366 close(s);
367 if (fname) {
368 unlink(fname);
369 free(fname);
371 return -1;
375 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
377 struct wpa_ctrl_dst *dst, *prev;
379 if (hapd->ctrl_sock > -1) {
380 char *fname;
381 eloop_unregister_read_sock(hapd->ctrl_sock);
382 close(hapd->ctrl_sock);
383 hapd->ctrl_sock = -1;
384 fname = hostapd_ctrl_iface_path(hapd);
385 if (fname)
386 unlink(fname);
387 free(fname);
389 if (hapd->conf->ctrl_interface &&
390 rmdir(hapd->conf->ctrl_interface) < 0) {
391 if (errno == ENOTEMPTY) {
392 wpa_printf(MSG_DEBUG, "Control interface "
393 "directory not empty - leaving it "
394 "behind");
395 } else {
396 perror("rmdir[ctrl_interface]");
401 dst = hapd->ctrl_dst;
402 while (dst) {
403 prev = dst;
404 dst = dst->next;
405 free(prev);
410 void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
411 char *buf, size_t len)
413 struct wpa_ctrl_dst *dst, *next;
414 struct msghdr msg;
415 int idx;
416 struct iovec io[2];
417 char levelstr[10];
419 dst = hapd->ctrl_dst;
420 if (hapd->ctrl_sock < 0 || dst == NULL)
421 return;
423 snprintf(levelstr, sizeof(levelstr), "<%d>", level);
424 io[0].iov_base = levelstr;
425 io[0].iov_len = strlen(levelstr);
426 io[1].iov_base = buf;
427 io[1].iov_len = len;
428 memset(&msg, 0, sizeof(msg));
429 msg.msg_iov = io;
430 msg.msg_iovlen = 2;
432 idx = 0;
433 while (dst) {
434 next = dst->next;
435 if (level >= dst->debug_level) {
436 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
437 (u8 *) dst->addr.sun_path, dst->addrlen);
438 msg.msg_name = &dst->addr;
439 msg.msg_namelen = dst->addrlen;
440 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
441 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
442 idx);
443 perror("sendmsg");
444 dst->errors++;
445 if (dst->errors > 10) {
446 hostapd_ctrl_iface_detach(
447 hapd, &dst->addr,
448 dst->addrlen);
450 } else
451 dst->errors = 0;
453 idx++;
454 dst = next;