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