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