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