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