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