Enable wpa_msg() for hostapd
[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 #endif /* CONFIG_WPS */
256
257
258 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
259                                        void *sock_ctx)
260 {
261         struct hostapd_data *hapd = eloop_ctx;
262         char buf[256];
263         int res;
264         struct sockaddr_un from;
265         socklen_t fromlen = sizeof(from);
266         char *reply;
267         const int reply_size = 4096;
268         int reply_len;
269
270         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
271                        (struct sockaddr *) &from, &fromlen);
272         if (res < 0) {
273                 perror("recvfrom(ctrl_iface)");
274                 return;
275         }
276         buf[res] = '\0';
277         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
278
279         reply = os_malloc(reply_size);
280         if (reply == NULL) {
281                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
282                        fromlen);
283                 return;
284         }
285
286         os_memcpy(reply, "OK\n", 3);
287         reply_len = 3;
288
289         if (os_strcmp(buf, "PING") == 0) {
290                 os_memcpy(reply, "PONG\n", 5);
291                 reply_len = 5;
292         } else if (os_strcmp(buf, "MIB") == 0) {
293                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
294                 if (reply_len >= 0) {
295                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
296                                           reply_size - reply_len);
297                         if (res < 0)
298                                 reply_len = -1;
299                         else
300                                 reply_len += res;
301                 }
302                 if (reply_len >= 0) {
303                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
304                                                  reply_size - reply_len);
305                         if (res < 0)
306                                 reply_len = -1;
307                         else
308                                 reply_len += res;
309                 }
310                 if (reply_len >= 0) {
311                         res = radius_client_get_mib(hapd->radius,
312                                                     reply + reply_len,
313                                                     reply_size - reply_len);
314                         if (res < 0)
315                                 reply_len = -1;
316                         else
317                                 reply_len += res;
318                 }
319         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
320                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
321                                                          reply_size);
322         } else if (os_strncmp(buf, "STA ", 4) == 0) {
323                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
324                                                    reply_size);
325         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
326                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
327                                                         reply_size);
328         } else if (os_strcmp(buf, "ATTACH") == 0) {
329                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
330                         reply_len = -1;
331         } else if (os_strcmp(buf, "DETACH") == 0) {
332                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
333                         reply_len = -1;
334         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
335                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
336                                                     buf + 6))
337                         reply_len = -1;
338         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
339                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
340                         reply_len = -1;
341 #ifdef CONFIG_IEEE80211W
342         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
343                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
344                         reply_len = -1;
345 #endif /* CONFIG_IEEE80211W */
346 #ifdef CONFIG_WPS
347         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
348                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
349                         reply_len = -1;
350         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
351                 if (hostapd_wps_button_pushed(hapd))
352                         reply_len = -1;
353 #endif /* CONFIG_WPS */
354         } else {
355                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
356                 reply_len = 16;
357         }
358
359         if (reply_len < 0) {
360                 os_memcpy(reply, "FAIL\n", 5);
361                 reply_len = 5;
362         }
363         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
364         os_free(reply);
365 }
366
367
368 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
369 {
370         char *buf;
371         size_t len;
372
373         if (hapd->conf->ctrl_interface == NULL)
374                 return NULL;
375
376         len = os_strlen(hapd->conf->ctrl_interface) +
377                 os_strlen(hapd->conf->iface) + 2;
378         buf = os_malloc(len);
379         if (buf == NULL)
380                 return NULL;
381
382         os_snprintf(buf, len, "%s/%s",
383                     hapd->conf->ctrl_interface, hapd->conf->iface);
384         buf[len - 1] = '\0';
385         return buf;
386 }
387
388
389 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
390                                       const char *txt, size_t len)
391 {
392         struct hostapd_data *hapd = ctx;
393         if (hapd == NULL)
394                 return;
395         hostapd_ctrl_iface_send(hapd, level, txt, len);
396 }
397
398
399 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
400 {
401         struct sockaddr_un addr;
402         int s = -1;
403         char *fname = NULL;
404
405         hapd->ctrl_sock = -1;
406
407         if (hapd->conf->ctrl_interface == NULL)
408                 return 0;
409
410         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
411                 if (errno == EEXIST) {
412                         wpa_printf(MSG_DEBUG, "Using existing control "
413                                    "interface directory.");
414                 } else {
415                         perror("mkdir[ctrl_interface]");
416                         goto fail;
417                 }
418         }
419
420         if (hapd->conf->ctrl_interface_gid_set &&
421             chown(hapd->conf->ctrl_interface, 0,
422                   hapd->conf->ctrl_interface_gid) < 0) {
423                 perror("chown[ctrl_interface]");
424                 return -1;
425         }
426
427         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
428             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
429                 goto fail;
430
431         s = socket(PF_UNIX, SOCK_DGRAM, 0);
432         if (s < 0) {
433                 perror("socket(PF_UNIX)");
434                 goto fail;
435         }
436
437         os_memset(&addr, 0, sizeof(addr));
438         addr.sun_family = AF_UNIX;
439         fname = hostapd_ctrl_iface_path(hapd);
440         if (fname == NULL)
441                 goto fail;
442         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
443         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
444                 perror("bind(PF_UNIX)");
445                 goto fail;
446         }
447
448         if (hapd->conf->ctrl_interface_gid_set &&
449             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
450                 perror("chown[ctrl_interface/ifname]");
451                 goto fail;
452         }
453
454         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
455                 perror("chmod[ctrl_interface/ifname]");
456                 goto fail;
457         }
458         os_free(fname);
459
460         hapd->ctrl_sock = s;
461         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
462                                  NULL);
463         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
464
465         return 0;
466
467 fail:
468         if (s >= 0)
469                 close(s);
470         if (fname) {
471                 unlink(fname);
472                 os_free(fname);
473         }
474         return -1;
475 }
476
477
478 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
479 {
480         struct wpa_ctrl_dst *dst, *prev;
481
482         if (hapd->ctrl_sock > -1) {
483                 char *fname;
484                 eloop_unregister_read_sock(hapd->ctrl_sock);
485                 close(hapd->ctrl_sock);
486                 hapd->ctrl_sock = -1;
487                 fname = hostapd_ctrl_iface_path(hapd);
488                 if (fname)
489                         unlink(fname);
490                 os_free(fname);
491
492                 if (hapd->conf->ctrl_interface &&
493                     rmdir(hapd->conf->ctrl_interface) < 0) {
494                         if (errno == ENOTEMPTY) {
495                                 wpa_printf(MSG_DEBUG, "Control interface "
496                                            "directory not empty - leaving it "
497                                            "behind");
498                         } else {
499                                 perror("rmdir[ctrl_interface]");
500                         }
501                 }
502         }
503
504         dst = hapd->ctrl_dst;
505         while (dst) {
506                 prev = dst;
507                 dst = dst->next;
508                 os_free(prev);
509         }
510 }
511
512
513 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
514                                     const char *buf, size_t len)
515 {
516         struct wpa_ctrl_dst *dst, *next;
517         struct msghdr msg;
518         int idx;
519         struct iovec io[2];
520         char levelstr[10];
521
522         dst = hapd->ctrl_dst;
523         if (hapd->ctrl_sock < 0 || dst == NULL)
524                 return;
525
526         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
527         io[0].iov_base = levelstr;
528         io[0].iov_len = os_strlen(levelstr);
529         io[1].iov_base = (char *) buf;
530         io[1].iov_len = len;
531         os_memset(&msg, 0, sizeof(msg));
532         msg.msg_iov = io;
533         msg.msg_iovlen = 2;
534
535         idx = 0;
536         while (dst) {
537                 next = dst->next;
538                 if (level >= dst->debug_level) {
539                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
540                                     (u8 *) dst->addr.sun_path, dst->addrlen);
541                         msg.msg_name = &dst->addr;
542                         msg.msg_namelen = dst->addrlen;
543                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
544                                 fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
545                                         idx);
546                                 perror("sendmsg");
547                                 dst->errors++;
548                                 if (dst->errors > 10) {
549                                         hostapd_ctrl_iface_detach(
550                                                 hapd, &dst->addr,
551                                                 dst->addrlen);
552                                 }
553                         } else
554                                 dst->errors = 0;
555                 }
556                 idx++;
557                 dst = next;
558         }
559 }
560
561 #endif /* CONFIG_NATIVE_WINDOWS */