Use 1Mbits/s as beacon sending rate; it seems to fix TX performance issue
[dragonfly.git] / contrib / hostapd-0.5.8 / ctrl_iface.c
1 /*
2  * hostapd / UNIX domain socket -based control interface
3  * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #ifndef CONFIG_NATIVE_WINDOWS
18
19 #include <sys/un.h>
20 #include <sys/stat.h>
21
22 #include "hostapd.h"
23 #include "eloop.h"
24 #include "config.h"
25 #include "eapol_sm.h"
26 #include "ieee802_1x.h"
27 #include "wpa.h"
28 #include "radius_client.h"
29 #include "ieee802_11.h"
30 #include "ctrl_iface.h"
31 #include "sta_info.h"
32 #include "accounting.h"
33
34
35 struct wpa_ctrl_dst {
36         struct wpa_ctrl_dst *next;
37         struct sockaddr_un addr;
38         socklen_t addrlen;
39         int debug_level;
40         int errors;
41 };
42
43
44 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
45                                      struct sockaddr_un *from,
46                                      socklen_t fromlen)
47 {
48         struct wpa_ctrl_dst *dst;
49
50         dst = wpa_zalloc(sizeof(*dst));
51         if (dst == NULL)
52                 return -1;
53         memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
54         dst->addrlen = fromlen;
55         dst->debug_level = MSG_INFO;
56         dst->next = hapd->ctrl_dst;
57         hapd->ctrl_dst = dst;
58         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
59                     (u8 *) from->sun_path, fromlen);
60         return 0;
61 }
62
63
64 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
65                                      struct sockaddr_un *from,
66                                      socklen_t fromlen)
67 {
68         struct wpa_ctrl_dst *dst, *prev = NULL;
69
70         dst = hapd->ctrl_dst;
71         while (dst) {
72                 if (fromlen == dst->addrlen &&
73                     memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
74                         if (prev == NULL)
75                                 hapd->ctrl_dst = dst->next;
76                         else
77                                 prev->next = dst->next;
78                         free(dst);
79                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
80                                     (u8 *) from->sun_path, fromlen);
81                         return 0;
82                 }
83                 prev = dst;
84                 dst = dst->next;
85         }
86         return -1;
87 }
88
89
90 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
91                                     struct sockaddr_un *from,
92                                     socklen_t fromlen,
93                                     char *level)
94 {
95         struct wpa_ctrl_dst *dst;
96
97         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
98
99         dst = hapd->ctrl_dst;
100         while (dst) {
101                 if (fromlen == dst->addrlen &&
102                     memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
103                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
104                                     "level", (u8 *) from->sun_path, fromlen);
105                         dst->debug_level = atoi(level);
106                         return 0;
107                 }
108                 dst = dst->next;
109         }
110
111         return -1;
112 }
113
114
115 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
116                                       struct sta_info *sta,
117                                       char *buf, size_t buflen)
118 {
119         int len, res, ret;
120
121         if (sta == NULL) {
122                 ret = snprintf(buf, buflen, "FAIL\n");
123                 if (ret < 0 || (size_t) ret >= buflen)
124                         return 0;
125                 return ret;
126         }
127
128         len = 0;
129         ret = snprintf(buf + len, buflen - len, MACSTR "\n",
130                        MAC2STR(sta->addr));
131         if (ret < 0 || (size_t) ret >= buflen - len)
132                 return len;
133         len += ret;
134
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(sta->wpa_sm, 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;
144
145         return len;
146 }
147
148
149 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
150                                         char *buf, size_t buflen)
151 {
152         return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
153 }
154
155
156 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
157                                   const char *txtaddr,
158                                   char *buf, size_t buflen)
159 {
160         u8 addr[ETH_ALEN];
161         int ret;
162
163         if (hwaddr_aton(txtaddr, addr)) {
164                 ret = snprintf(buf, buflen, "FAIL\n");
165                 if (ret < 0 || (size_t) ret >= buflen)
166                         return 0;
167                 return ret;
168         }
169         return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
170                                           buf, buflen);
171 }
172
173
174 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
175                                        const char *txtaddr,
176                                        char *buf, size_t buflen)
177 {
178         u8 addr[ETH_ALEN];
179         struct sta_info *sta;
180         int ret;
181
182         if (hwaddr_aton(txtaddr, addr) ||
183             (sta = ap_get_sta(hapd, addr)) == NULL) {
184                 ret = snprintf(buf, buflen, "FAIL\n");
185                 if (ret < 0 || (size_t) ret >= buflen)
186                         return 0;
187                 return ret;
188         }               
189         return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
190 }
191
192
193 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
194                                       const char *txtaddr)
195 {
196         u8 addr[ETH_ALEN];
197         struct sta_info *sta;
198
199         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
200
201         if (hwaddr_aton(txtaddr, addr))
202                 return -1;
203
204         sta = ap_get_sta(hapd, addr);
205         if (sta)
206                 return 0;
207
208         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
209                    "notification", MAC2STR(addr));
210         sta = ap_sta_add(hapd, addr);
211         if (sta == NULL)
212                 return -1;
213
214         hostapd_new_assoc_sta(hapd, sta, 0);
215         accounting_sta_get_id(hapd, sta);
216         return 0;
217 }
218
219
220 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
221                                        void *sock_ctx)
222 {
223         struct hostapd_data *hapd = eloop_ctx;
224         char buf[256];
225         int res;
226         struct sockaddr_un from;
227         socklen_t fromlen = sizeof(from);
228         char *reply;
229         const int reply_size = 4096;
230         int reply_len;
231
232         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
233                        (struct sockaddr *) &from, &fromlen);
234         if (res < 0) {
235                 perror("recvfrom(ctrl_iface)");
236                 return;
237         }
238         buf[res] = '\0';
239         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
240
241         reply = malloc(reply_size);
242         if (reply == NULL) {
243                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
244                        fromlen);
245                 return;
246         }
247
248         memcpy(reply, "OK\n", 3);
249         reply_len = 3;
250
251         if (strcmp(buf, "PING") == 0) {
252                 memcpy(reply, "PONG\n", 5);
253                 reply_len = 5;
254         } else if (strcmp(buf, "MIB") == 0) {
255                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
256                 if (reply_len >= 0) {
257                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
258                                           reply_size - reply_len);
259                         if (res < 0)
260                                 reply_len = -1;
261                         else
262                                 reply_len += res;
263                 }
264                 if (reply_len >= 0) {
265                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
266                                                  reply_size - reply_len);
267                         if (res < 0)
268                                 reply_len = -1;
269                         else
270                                 reply_len += res;
271                 }
272                 if (reply_len >= 0) {
273                         res = radius_client_get_mib(hapd->radius,
274                                                     reply + reply_len,
275                                                     reply_size - reply_len);
276                         if (res < 0)
277                                 reply_len = -1;
278                         else
279                                 reply_len += res;
280                 }
281         } else if (strcmp(buf, "STA-FIRST") == 0) {
282                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
283                                                          reply_size);
284         } else if (strncmp(buf, "STA ", 4) == 0) {
285                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
286                                                    reply_size);
287         } else if (strncmp(buf, "STA-NEXT ", 9) == 0) {
288                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
289                                                         reply_size);
290         } else if (strcmp(buf, "ATTACH") == 0) {
291                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
292                         reply_len = -1;
293         } else if (strcmp(buf, "DETACH") == 0) {
294                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
295                         reply_len = -1;
296         } else if (strncmp(buf, "LEVEL ", 6) == 0) {
297                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
298                                                     buf + 6))
299                         reply_len = -1;
300         } else if (strncmp(buf, "NEW_STA ", 8) == 0) {
301                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
302                         reply_len = -1;
303         } else {
304                 memcpy(reply, "UNKNOWN COMMAND\n", 16);
305                 reply_len = 16;
306         }
307
308         if (reply_len < 0) {
309                 memcpy(reply, "FAIL\n", 5);
310                 reply_len = 5;
311         }
312         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
313         free(reply);
314 }
315
316
317 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
318 {
319         char *buf;
320         size_t len;
321
322         if (hapd->conf->ctrl_interface == NULL)
323                 return NULL;
324
325         len = strlen(hapd->conf->ctrl_interface) + strlen(hapd->conf->iface) +
326                 2;
327         buf = malloc(len);
328         if (buf == NULL)
329                 return NULL;
330
331         snprintf(buf, len, "%s/%s",
332                  hapd->conf->ctrl_interface, hapd->conf->iface);
333         buf[len - 1] = '\0';
334         return buf;
335 }
336
337
338 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
339 {
340         struct sockaddr_un addr;
341         int s = -1;
342         char *fname = NULL;
343
344         hapd->ctrl_sock = -1;
345
346         if (hapd->conf->ctrl_interface == NULL)
347                 return 0;
348
349         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
350                 if (errno == EEXIST) {
351                         wpa_printf(MSG_DEBUG, "Using existing control "
352                                    "interface directory.");
353                 } else {
354                         perror("mkdir[ctrl_interface]");
355                         goto fail;
356                 }
357         }
358
359         if (hapd->conf->ctrl_interface_gid_set &&
360             chown(hapd->conf->ctrl_interface, 0,
361                   hapd->conf->ctrl_interface_gid) < 0) {
362                 perror("chown[ctrl_interface]");
363                 return -1;
364         }
365
366         if (strlen(hapd->conf->ctrl_interface) + 1 + strlen(hapd->conf->iface)
367             >= sizeof(addr.sun_path))
368                 goto fail;
369
370         s = socket(PF_UNIX, SOCK_DGRAM, 0);
371         if (s < 0) {
372                 perror("socket(PF_UNIX)");
373                 goto fail;
374         }
375
376         memset(&addr, 0, sizeof(addr));
377         addr.sun_family = AF_UNIX;
378         fname = hostapd_ctrl_iface_path(hapd);
379         if (fname == NULL)
380                 goto fail;
381         strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
382         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
383                 perror("bind(PF_UNIX)");
384                 goto fail;
385         }
386
387         if (hapd->conf->ctrl_interface_gid_set &&
388             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
389                 perror("chown[ctrl_interface/ifname]");
390                 goto fail;
391         }
392
393         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
394                 perror("chmod[ctrl_interface/ifname]");
395                 goto fail;
396         }
397         free(fname);
398
399         hapd->ctrl_sock = s;
400         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
401                                  NULL);
402
403         return 0;
404
405 fail:
406         if (s >= 0)
407                 close(s);
408         if (fname) {
409                 unlink(fname);
410                 free(fname);
411         }
412         return -1;
413 }
414
415
416 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
417 {
418         struct wpa_ctrl_dst *dst, *prev;
419
420         if (hapd->ctrl_sock > -1) {
421                 char *fname;
422                 eloop_unregister_read_sock(hapd->ctrl_sock);
423                 close(hapd->ctrl_sock);
424                 hapd->ctrl_sock = -1;
425                 fname = hostapd_ctrl_iface_path(hapd);
426                 if (fname)
427                         unlink(fname);
428                 free(fname);
429
430                 if (hapd->conf->ctrl_interface &&
431                     rmdir(hapd->conf->ctrl_interface) < 0) {
432                         if (errno == ENOTEMPTY) {
433                                 wpa_printf(MSG_DEBUG, "Control interface "
434                                            "directory not empty - leaving it "
435                                            "behind");
436                         } else {
437                                 perror("rmdir[ctrl_interface]");
438                         }
439                 }
440         }
441
442         dst = hapd->ctrl_dst;
443         while (dst) {
444                 prev = dst;
445                 dst = dst->next;
446                 free(prev);
447         }
448 }
449
450
451 void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
452                              char *buf, size_t len)
453 {
454         struct wpa_ctrl_dst *dst, *next;
455         struct msghdr msg;
456         int idx;
457         struct iovec io[2];
458         char levelstr[10];
459
460         dst = hapd->ctrl_dst;
461         if (hapd->ctrl_sock < 0 || dst == NULL)
462                 return;
463
464         snprintf(levelstr, sizeof(levelstr), "<%d>", level);
465         io[0].iov_base = levelstr;
466         io[0].iov_len = strlen(levelstr);
467         io[1].iov_base = buf;
468         io[1].iov_len = len;
469         memset(&msg, 0, sizeof(msg));
470         msg.msg_iov = io;
471         msg.msg_iovlen = 2;
472
473         idx = 0;
474         while (dst) {
475                 next = dst->next;
476                 if (level >= dst->debug_level) {
477                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
478                                     (u8 *) dst->addr.sun_path, dst->addrlen);
479                         msg.msg_name = &dst->addr;
480                         msg.msg_namelen = dst->addrlen;
481                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
482                                 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
483                                         idx);
484                                 perror("sendmsg");
485                                 dst->errors++;
486                                 if (dst->errors > 10) {
487                                         hostapd_ctrl_iface_detach(
488                                                 hapd, &dst->addr,
489                                                 dst->addrlen);
490                                 }
491                         } else
492                                 dst->errors = 0;
493                 }
494                 idx++;
495                 dst = next;
496         }
497 }
498
499 #endif /* CONFIG_NATIVE_WINDOWS */