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