Detach ctrl_iface monitor if the client socket is removed
[libeap.git] / 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
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"
32 #include "wps_hostapd.h"
33 #include "driver.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, fromlen);
65         return 0;
66 }
67
68
69 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
70                                      struct sockaddr_un *from,
71                                      socklen_t fromlen)
72 {
73         struct wpa_ctrl_dst *dst, *prev = NULL;
74
75         dst = hapd->ctrl_dst;
76         while (dst) {
77                 if (fromlen == dst->addrlen &&
78                     os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
79                     0) {
80                         if (prev == NULL)
81                                 hapd->ctrl_dst = dst->next;
82                         else
83                                 prev->next = dst->next;
84                         os_free(dst);
85                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
86                                     (u8 *) from->sun_path, fromlen);
87                         return 0;
88                 }
89                 prev = dst;
90                 dst = dst->next;
91         }
92         return -1;
93 }
94
95
96 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
97                                     struct sockaddr_un *from,
98                                     socklen_t fromlen,
99                                     char *level)
100 {
101         struct wpa_ctrl_dst *dst;
102
103         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
104
105         dst = hapd->ctrl_dst;
106         while (dst) {
107                 if (fromlen == dst->addrlen &&
108                     os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
109                     0) {
110                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
111                                     "level", (u8 *) from->sun_path, fromlen);
112                         dst->debug_level = atoi(level);
113                         return 0;
114                 }
115                 dst = dst->next;
116         }
117
118         return -1;
119 }
120
121
122 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
123                                       struct sta_info *sta,
124                                       char *buf, size_t buflen)
125 {
126         int len, res, ret;
127
128         if (sta == NULL) {
129                 ret = os_snprintf(buf, buflen, "FAIL\n");
130                 if (ret < 0 || (size_t) ret >= buflen)
131                         return 0;
132                 return ret;
133         }
134
135         len = 0;
136         ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
137                           MAC2STR(sta->addr));
138         if (ret < 0 || (size_t) ret >= buflen - len)
139                 return len;
140         len += ret;
141
142         res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
143         if (res >= 0)
144                 len += res;
145         res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
146         if (res >= 0)
147                 len += res;
148         res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
149         if (res >= 0)
150                 len += res;
151
152         return len;
153 }
154
155
156 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
157                                         char *buf, size_t buflen)
158 {
159         return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
160 }
161
162
163 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
164                                   const char *txtaddr,
165                                   char *buf, size_t buflen)
166 {
167         u8 addr[ETH_ALEN];
168         int ret;
169
170         if (hwaddr_aton(txtaddr, addr)) {
171                 ret = os_snprintf(buf, buflen, "FAIL\n");
172                 if (ret < 0 || (size_t) ret >= buflen)
173                         return 0;
174                 return ret;
175         }
176         return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
177                                           buf, buflen);
178 }
179
180
181 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
182                                        const char *txtaddr,
183                                        char *buf, size_t buflen)
184 {
185         u8 addr[ETH_ALEN];
186         struct sta_info *sta;
187         int ret;
188
189         if (hwaddr_aton(txtaddr, addr) ||
190             (sta = ap_get_sta(hapd, addr)) == NULL) {
191                 ret = os_snprintf(buf, buflen, "FAIL\n");
192                 if (ret < 0 || (size_t) ret >= buflen)
193                         return 0;
194                 return ret;
195         }               
196         return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
197 }
198
199
200 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
201                                       const char *txtaddr)
202 {
203         u8 addr[ETH_ALEN];
204         struct sta_info *sta;
205
206         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
207
208         if (hwaddr_aton(txtaddr, addr))
209                 return -1;
210
211         sta = ap_get_sta(hapd, addr);
212         if (sta)
213                 return 0;
214
215         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
216                    "notification", MAC2STR(addr));
217         sta = ap_sta_add(hapd, addr);
218         if (sta == NULL)
219                 return -1;
220
221         hostapd_new_assoc_sta(hapd, sta, 0);
222         return 0;
223 }
224
225
226 #ifdef CONFIG_IEEE80211W
227 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
228                                        const char *txtaddr)
229 {
230         u8 addr[ETH_ALEN];
231         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
232
233         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
234
235         if (hwaddr_aton(txtaddr, addr))
236                 return -1;
237
238         os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
239         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
240
241         return 0;
242 }
243 #endif /* CONFIG_IEEE80211W */
244
245
246 #ifdef CONFIG_WPS
247 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
248 {
249         char *pin = os_strchr(txt, ' ');
250         if (pin == NULL)
251                 return -1;
252         *pin++ = '\0';
253         return hostapd_wps_add_pin(hapd, txt, pin);
254 }
255
256
257 #ifdef CONFIG_WPS_OOB
258 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
259 {
260         char *path, *method, *name;
261
262         path = os_strchr(txt, ' ');
263         if (path == NULL)
264                 return -1;
265         *path++ = '\0';
266
267         method = os_strchr(path, ' ');
268         if (method == NULL)
269                 return -1;
270         *method++ = '\0';
271
272         name = os_strchr(method, ' ');
273         if (name != NULL)
274                 *name++ = '\0';
275
276         return hostapd_wps_start_oob(hapd, txt, path, method, name);
277 }
278 #endif /* CONFIG_WPS_OOB */
279 #endif /* CONFIG_WPS */
280
281
282 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
283                                        void *sock_ctx)
284 {
285         struct hostapd_data *hapd = eloop_ctx;
286         char buf[256];
287         int res;
288         struct sockaddr_un from;
289         socklen_t fromlen = sizeof(from);
290         char *reply;
291         const int reply_size = 4096;
292         int reply_len;
293
294         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
295                        (struct sockaddr *) &from, &fromlen);
296         if (res < 0) {
297                 perror("recvfrom(ctrl_iface)");
298                 return;
299         }
300         buf[res] = '\0';
301         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
302
303         reply = os_malloc(reply_size);
304         if (reply == NULL) {
305                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
306                        fromlen);
307                 return;
308         }
309
310         os_memcpy(reply, "OK\n", 3);
311         reply_len = 3;
312
313         if (os_strcmp(buf, "PING") == 0) {
314                 os_memcpy(reply, "PONG\n", 5);
315                 reply_len = 5;
316         } else if (os_strcmp(buf, "MIB") == 0) {
317                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
318                 if (reply_len >= 0) {
319                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
320                                           reply_size - reply_len);
321                         if (res < 0)
322                                 reply_len = -1;
323                         else
324                                 reply_len += res;
325                 }
326                 if (reply_len >= 0) {
327                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
328                                                  reply_size - reply_len);
329                         if (res < 0)
330                                 reply_len = -1;
331                         else
332                                 reply_len += res;
333                 }
334                 if (reply_len >= 0) {
335                         res = radius_client_get_mib(hapd->radius,
336                                                     reply + reply_len,
337                                                     reply_size - reply_len);
338                         if (res < 0)
339                                 reply_len = -1;
340                         else
341                                 reply_len += res;
342                 }
343         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
344                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
345                                                          reply_size);
346         } else if (os_strncmp(buf, "STA ", 4) == 0) {
347                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
348                                                    reply_size);
349         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
350                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
351                                                         reply_size);
352         } else if (os_strcmp(buf, "ATTACH") == 0) {
353                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
354                         reply_len = -1;
355         } else if (os_strcmp(buf, "DETACH") == 0) {
356                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
357                         reply_len = -1;
358         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
359                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
360                                                     buf + 6))
361                         reply_len = -1;
362         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
363                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
364                         reply_len = -1;
365 #ifdef CONFIG_IEEE80211W
366         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
367                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
368                         reply_len = -1;
369 #endif /* CONFIG_IEEE80211W */
370 #ifdef CONFIG_WPS
371         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
372                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
373                         reply_len = -1;
374         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
375                 if (hostapd_wps_button_pushed(hapd))
376                         reply_len = -1;
377 #ifdef CONFIG_WPS_OOB
378         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
379                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
380                         reply_len = -1;
381 #endif /* CONFIG_WPS_OOB */
382 #endif /* CONFIG_WPS */
383         } else {
384                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
385                 reply_len = 16;
386         }
387
388         if (reply_len < 0) {
389                 os_memcpy(reply, "FAIL\n", 5);
390                 reply_len = 5;
391         }
392         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
393         os_free(reply);
394 }
395
396
397 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
398 {
399         char *buf;
400         size_t len;
401
402         if (hapd->conf->ctrl_interface == NULL)
403                 return NULL;
404
405         len = os_strlen(hapd->conf->ctrl_interface) +
406                 os_strlen(hapd->conf->iface) + 2;
407         buf = os_malloc(len);
408         if (buf == NULL)
409                 return NULL;
410
411         os_snprintf(buf, len, "%s/%s",
412                     hapd->conf->ctrl_interface, hapd->conf->iface);
413         buf[len - 1] = '\0';
414         return buf;
415 }
416
417
418 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
419                                       const char *txt, size_t len)
420 {
421         struct hostapd_data *hapd = ctx;
422         if (hapd == NULL)
423                 return;
424         hostapd_ctrl_iface_send(hapd, level, txt, len);
425 }
426
427
428 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
429 {
430         struct sockaddr_un addr;
431         int s = -1;
432         char *fname = NULL;
433
434         hapd->ctrl_sock = -1;
435
436         if (hapd->conf->ctrl_interface == NULL)
437                 return 0;
438
439         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
440                 if (errno == EEXIST) {
441                         wpa_printf(MSG_DEBUG, "Using existing control "
442                                    "interface directory.");
443                 } else {
444                         perror("mkdir[ctrl_interface]");
445                         goto fail;
446                 }
447         }
448
449         if (hapd->conf->ctrl_interface_gid_set &&
450             chown(hapd->conf->ctrl_interface, 0,
451                   hapd->conf->ctrl_interface_gid) < 0) {
452                 perror("chown[ctrl_interface]");
453                 return -1;
454         }
455
456         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
457             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
458                 goto fail;
459
460         s = socket(PF_UNIX, SOCK_DGRAM, 0);
461         if (s < 0) {
462                 perror("socket(PF_UNIX)");
463                 goto fail;
464         }
465
466         os_memset(&addr, 0, sizeof(addr));
467         addr.sun_family = AF_UNIX;
468         fname = hostapd_ctrl_iface_path(hapd);
469         if (fname == NULL)
470                 goto fail;
471         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
472         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
473                 perror("bind(PF_UNIX)");
474                 goto fail;
475         }
476
477         if (hapd->conf->ctrl_interface_gid_set &&
478             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
479                 perror("chown[ctrl_interface/ifname]");
480                 goto fail;
481         }
482
483         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
484                 perror("chmod[ctrl_interface/ifname]");
485                 goto fail;
486         }
487         os_free(fname);
488
489         hapd->ctrl_sock = s;
490         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
491                                  NULL);
492         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
493
494         return 0;
495
496 fail:
497         if (s >= 0)
498                 close(s);
499         if (fname) {
500                 unlink(fname);
501                 os_free(fname);
502         }
503         return -1;
504 }
505
506
507 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
508 {
509         struct wpa_ctrl_dst *dst, *prev;
510
511         if (hapd->ctrl_sock > -1) {
512                 char *fname;
513                 eloop_unregister_read_sock(hapd->ctrl_sock);
514                 close(hapd->ctrl_sock);
515                 hapd->ctrl_sock = -1;
516                 fname = hostapd_ctrl_iface_path(hapd);
517                 if (fname)
518                         unlink(fname);
519                 os_free(fname);
520
521                 if (hapd->conf->ctrl_interface &&
522                     rmdir(hapd->conf->ctrl_interface) < 0) {
523                         if (errno == ENOTEMPTY) {
524                                 wpa_printf(MSG_DEBUG, "Control interface "
525                                            "directory not empty - leaving it "
526                                            "behind");
527                         } else {
528                                 perror("rmdir[ctrl_interface]");
529                         }
530                 }
531         }
532
533         dst = hapd->ctrl_dst;
534         while (dst) {
535                 prev = dst;
536                 dst = dst->next;
537                 os_free(prev);
538         }
539 }
540
541
542 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
543                                     const char *buf, size_t len)
544 {
545         struct wpa_ctrl_dst *dst, *next;
546         struct msghdr msg;
547         int idx;
548         struct iovec io[2];
549         char levelstr[10];
550
551         dst = hapd->ctrl_dst;
552         if (hapd->ctrl_sock < 0 || dst == NULL)
553                 return;
554
555         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
556         io[0].iov_base = levelstr;
557         io[0].iov_len = os_strlen(levelstr);
558         io[1].iov_base = (char *) buf;
559         io[1].iov_len = len;
560         os_memset(&msg, 0, sizeof(msg));
561         msg.msg_iov = io;
562         msg.msg_iovlen = 2;
563
564         idx = 0;
565         while (dst) {
566                 next = dst->next;
567                 if (level >= dst->debug_level) {
568                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
569                                     (u8 *) dst->addr.sun_path, dst->addrlen);
570                         msg.msg_name = &dst->addr;
571                         msg.msg_namelen = dst->addrlen;
572                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
573                                 int _errno = errno;
574                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
575                                            "%d - %s",
576                                            idx, errno, strerror(errno));
577                                 dst->errors++;
578                                 if (dst->errors > 10 || _errno == ENOENT) {
579                                         hostapd_ctrl_iface_detach(
580                                                 hapd, &dst->addr,
581                                                 dst->addrlen);
582                                 }
583                         } else
584                                 dst->errors = 0;
585                 }
586                 idx++;
587                 dst = next;
588         }
589 }
590
591 #endif /* CONFIG_NATIVE_WINDOWS */