Merge branch 'vendor/GDB'
[dragonfly.git] / contrib / hostapd / hostapd / ctrl_iface.c
1 /*
2  * hostapd / UNIX domain socket -based control interface
3  * Copyright (c) 2004-2008, 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 #include <stddef.h>
22
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"
34
35
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;
42 };
43
44
45 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
46                                     const char *buf, size_t len);
47
48
49 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
50                                      struct sockaddr_un *from,
51                                      socklen_t fromlen)
52 {
53         struct wpa_ctrl_dst *dst;
54
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;
67 }
68
69
70 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
71                                      struct sockaddr_un *from,
72                                      socklen_t fromlen)
73 {
74         struct wpa_ctrl_dst *dst, *prev = NULL;
75
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;
92                 }
93                 prev = dst;
94                 dst = dst->next;
95         }
96         return -1;
97 }
98
99
100 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
101                                     struct sockaddr_un *from,
102                                     socklen_t fromlen,
103                                     char *level)
104 {
105         struct wpa_ctrl_dst *dst;
106
107         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
108
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;
120                 }
121                 dst = dst->next;
122         }
123
124         return -1;
125 }
126
127
128 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
129                                       struct sta_info *sta,
130                                       char *buf, size_t buflen)
131 {
132         int len, res, ret;
133
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;
139         }
140
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;
147
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;
157
158         return len;
159 }
160
161
162 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
163                                         char *buf, size_t buflen)
164 {
165         return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
166 }
167
168
169 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
170                                   const char *txtaddr,
171                                   char *buf, size_t buflen)
172 {
173         u8 addr[ETH_ALEN];
174         int ret;
175
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;
181         }
182         return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
183                                           buf, buflen);
184 }
185
186
187 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
188                                        const char *txtaddr,
189                                        char *buf, size_t buflen)
190 {
191         u8 addr[ETH_ALEN];
192         struct sta_info *sta;
193         int ret;
194
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;
201         }               
202         return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
203 }
204
205
206 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
207                                       const char *txtaddr)
208 {
209         u8 addr[ETH_ALEN];
210         struct sta_info *sta;
211
212         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
213
214         if (hwaddr_aton(txtaddr, addr))
215                 return -1;
216
217         sta = ap_get_sta(hapd, addr);
218         if (sta)
219                 return 0;
220
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;
226
227         hostapd_new_assoc_sta(hapd, sta, 0);
228         return 0;
229 }
230
231
232 #ifdef CONFIG_IEEE80211W
233 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
234                                        const char *txtaddr)
235 {
236         u8 addr[ETH_ALEN];
237         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
238
239         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
240
241         if (hwaddr_aton(txtaddr, addr))
242                 return -1;
243
244         os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
245         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
246
247         return 0;
248 }
249 #endif /* CONFIG_IEEE80211W */
250
251
252 #ifdef CONFIG_WPS
253 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
254 {
255         char *pin = os_strchr(txt, ' ');
256         char *timeout_txt;
257         int timeout;
258
259         if (pin == NULL)
260                 return -1;
261         *pin++ = '\0';
262
263         timeout_txt = os_strchr(pin, ' ');
264         if (timeout_txt) {
265                 *timeout_txt++ = '\0';
266                 timeout = atoi(timeout_txt);
267         } else
268                 timeout = 0;
269
270         return hostapd_wps_add_pin(hapd, txt, pin, timeout);
271 }
272 #endif /* CONFIG_WPS */
273
274
275 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
276                                        void *sock_ctx)
277 {
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;
286
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;
292         }
293         buf[res] = '\0';
294         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
295
296         reply = os_malloc(reply_size);
297         if (reply == NULL) {
298                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
299                        fromlen);
300                 return;
301         }
302
303         os_memcpy(reply, "OK\n", 3);
304         reply_len = 3;
305
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;
318                 }
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;
326                 }
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;
335                 }
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;
374         }
375
376         if (reply_len < 0) {
377                 os_memcpy(reply, "FAIL\n", 5);
378                 reply_len = 5;
379         }
380         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
381         os_free(reply);
382 }
383
384
385 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
386 {
387         char *buf;
388         size_t len;
389
390         if (hapd->conf->ctrl_interface == NULL)
391                 return NULL;
392
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;
398
399         os_snprintf(buf, len, "%s/%s",
400                     hapd->conf->ctrl_interface, hapd->conf->iface);
401         buf[len - 1] = '\0';
402         return buf;
403 }
404
405
406 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
407                                       const char *txt, size_t len)
408 {
409         struct hostapd_data *hapd = ctx;
410         if (hapd == NULL)
411                 return;
412         hostapd_ctrl_iface_send(hapd, level, txt, len);
413 }
414
415
416 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
417 {
418         struct sockaddr_un addr;
419         int s = -1;
420         char *fname = NULL;
421
422         hapd->ctrl_sock = -1;
423
424         if (hapd->conf->ctrl_interface == NULL)
425                 return 0;
426
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;
434                 }
435         }
436
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;
442         }
443
444         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
445             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
446                 goto fail;
447
448         s = socket(PF_UNIX, SOCK_DGRAM, 0);
449         if (s < 0) {
450                 perror("socket(PF_UNIX)");
451                 goto fail;
452         }
453
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;
476                         }
477                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
478                             0) {
479                                 perror("bind(PF_UNIX)");
480                                 goto fail;
481                         }
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;
492                 }
493         }
494
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;
499         }
500
501         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
502                 perror("chmod[ctrl_interface/ifname]");
503                 goto fail;
504         }
505         os_free(fname);
506
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);
511
512         return 0;
513
514 fail:
515         if (s >= 0)
516                 close(s);
517         if (fname) {
518                 unlink(fname);
519                 os_free(fname);
520         }
521         return -1;
522 }
523
524
525 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
526 {
527         struct wpa_ctrl_dst *dst, *prev;
528
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);
538
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]");
547                         }
548                 }
549         }
550
551         dst = hapd->ctrl_dst;
552         while (dst) {
553                 prev = dst;
554                 dst = dst->next;
555                 os_free(prev);
556         }
557 }
558
559
560 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
561                                     const char *buf, size_t len)
562 {
563         struct wpa_ctrl_dst *dst, *next;
564         struct msghdr msg;
565         int idx;
566         struct iovec io[2];
567         char levelstr[10];
568
569         dst = hapd->ctrl_dst;
570         if (hapd->ctrl_sock < 0 || dst == NULL)
571                 return;
572
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;
581
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);
601                                 }
602                         } else
603                                 dst->errors = 0;
604                 }
605                 idx++;
606                 dst = next;
607         }
608 }
609
610 #endif /* CONFIG_NATIVE_WINDOWS */