2 * hostapd / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
17 #ifndef CONFIG_NATIVE_WINDOWS
26 #include "ieee802_1x.h"
28 #include "radius/radius_client.h"
29 #include "ieee802_11.h"
30 #include "ctrl_iface.h"
32 #include "accounting.h"
33 #include "wps_hostapd.h"
34 #include "drivers/driver.h"
38 struct wpa_ctrl_dst
*next
;
39 struct sockaddr_un addr
;
46 static void hostapd_ctrl_iface_send(struct hostapd_data
*hapd
, int level
,
47 const char *buf
, size_t len
);
50 static int hostapd_ctrl_iface_attach(struct hostapd_data
*hapd
,
51 struct sockaddr_un
*from
,
54 struct wpa_ctrl_dst
*dst
;
56 dst
= os_zalloc(sizeof(*dst
));
59 os_memcpy(&dst
->addr
, from
, sizeof(struct sockaddr_un
));
60 dst
->addrlen
= fromlen
;
61 dst
->debug_level
= MSG_INFO
;
62 dst
->next
= hapd
->ctrl_dst
;
64 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor attached",
65 (u8
*) from
->sun_path
,
66 fromlen
- offsetof(struct sockaddr_un
, sun_path
));
71 static int hostapd_ctrl_iface_detach(struct hostapd_data
*hapd
,
72 struct sockaddr_un
*from
,
75 struct wpa_ctrl_dst
*dst
, *prev
= NULL
;
79 if (fromlen
== dst
->addrlen
&&
80 os_memcmp(from
->sun_path
, dst
->addr
.sun_path
,
81 fromlen
- offsetof(struct sockaddr_un
, sun_path
))
84 hapd
->ctrl_dst
= dst
->next
;
86 prev
->next
= dst
->next
;
88 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor detached",
89 (u8
*) from
->sun_path
,
91 offsetof(struct sockaddr_un
, sun_path
));
101 static int hostapd_ctrl_iface_level(struct hostapd_data
*hapd
,
102 struct sockaddr_un
*from
,
106 struct wpa_ctrl_dst
*dst
;
108 wpa_printf(MSG_DEBUG
, "CTRL_IFACE LEVEL %s", level
);
110 dst
= hapd
->ctrl_dst
;
112 if (fromlen
== dst
->addrlen
&&
113 os_memcmp(from
->sun_path
, dst
->addr
.sun_path
,
114 fromlen
- offsetof(struct sockaddr_un
, sun_path
))
116 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE changed monitor "
117 "level", (u8
*) from
->sun_path
, fromlen
-
118 offsetof(struct sockaddr_un
, sun_path
));
119 dst
->debug_level
= atoi(level
);
129 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data
*hapd
,
130 struct sta_info
*sta
,
131 char *buf
, size_t buflen
)
136 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
137 if (ret
< 0 || (size_t) ret
>= buflen
)
143 ret
= os_snprintf(buf
+ len
, buflen
- len
, MACSTR
"\n",
145 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
149 res
= ieee802_11_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
152 res
= wpa_get_mib_sta(sta
->wpa_sm
, buf
+ len
, buflen
- len
);
155 res
= ieee802_1x_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
163 static int hostapd_ctrl_iface_sta_first(struct hostapd_data
*hapd
,
164 char *buf
, size_t buflen
)
166 return hostapd_ctrl_iface_sta_mib(hapd
, hapd
->sta_list
, buf
, buflen
);
170 static int hostapd_ctrl_iface_sta(struct hostapd_data
*hapd
,
172 char *buf
, size_t buflen
)
177 if (hwaddr_aton(txtaddr
, addr
)) {
178 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
179 if (ret
< 0 || (size_t) ret
>= buflen
)
183 return hostapd_ctrl_iface_sta_mib(hapd
, ap_get_sta(hapd
, addr
),
188 static int hostapd_ctrl_iface_sta_next(struct hostapd_data
*hapd
,
190 char *buf
, size_t buflen
)
193 struct sta_info
*sta
;
196 if (hwaddr_aton(txtaddr
, addr
) ||
197 (sta
= ap_get_sta(hapd
, addr
)) == NULL
) {
198 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
199 if (ret
< 0 || (size_t) ret
>= buflen
)
203 return hostapd_ctrl_iface_sta_mib(hapd
, sta
->next
, buf
, buflen
);
207 static int hostapd_ctrl_iface_new_sta(struct hostapd_data
*hapd
,
211 struct sta_info
*sta
;
213 wpa_printf(MSG_DEBUG
, "CTRL_IFACE NEW_STA %s", txtaddr
);
215 if (hwaddr_aton(txtaddr
, addr
))
218 sta
= ap_get_sta(hapd
, addr
);
222 wpa_printf(MSG_DEBUG
, "Add new STA " MACSTR
" based on ctrl_iface "
223 "notification", MAC2STR(addr
));
224 sta
= ap_sta_add(hapd
, addr
);
228 hostapd_new_assoc_sta(hapd
, sta
, 0);
233 #ifdef CONFIG_IEEE80211W
235 static int hostapd_ctrl_iface_sa_query(struct hostapd_data
*hapd
,
239 u8 trans_id
[WLAN_SA_QUERY_TR_ID_LEN
];
241 wpa_printf(MSG_DEBUG
, "CTRL_IFACE SA_QUERY %s", txtaddr
);
243 if (hwaddr_aton(txtaddr
, addr
))
246 os_get_random(trans_id
, WLAN_SA_QUERY_TR_ID_LEN
);
247 ieee802_11_send_sa_query_req(hapd
, addr
, trans_id
);
251 #endif /* NEED_MLME */
252 #endif /* CONFIG_IEEE80211W */
256 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data
*hapd
, char *txt
)
258 char *pin
= os_strchr(txt
, ' ');
262 return hostapd_wps_add_pin(hapd
, txt
, pin
);
266 #ifdef CONFIG_WPS_OOB
267 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data
*hapd
, char *txt
)
269 char *path
, *method
, *name
;
271 path
= os_strchr(txt
, ' ');
276 method
= os_strchr(path
, ' ');
281 name
= os_strchr(method
, ' ');
285 return hostapd_wps_start_oob(hapd
, txt
, path
, method
, name
);
287 #endif /* CONFIG_WPS_OOB */
288 #endif /* CONFIG_WPS */
291 static void hostapd_ctrl_iface_receive(int sock
, void *eloop_ctx
,
294 struct hostapd_data
*hapd
= eloop_ctx
;
297 struct sockaddr_un from
;
298 socklen_t fromlen
= sizeof(from
);
300 const int reply_size
= 4096;
303 res
= recvfrom(sock
, buf
, sizeof(buf
) - 1, 0,
304 (struct sockaddr
*) &from
, &fromlen
);
306 perror("recvfrom(ctrl_iface)");
310 wpa_hexdump_ascii(MSG_DEBUG
, "RX ctrl_iface", (u8
*) buf
, res
);
312 reply
= os_malloc(reply_size
);
314 sendto(sock
, "FAIL\n", 5, 0, (struct sockaddr
*) &from
,
319 os_memcpy(reply
, "OK\n", 3);
322 if (os_strcmp(buf
, "PING") == 0) {
323 os_memcpy(reply
, "PONG\n", 5);
325 } else if (os_strcmp(buf
, "MIB") == 0) {
326 reply_len
= ieee802_11_get_mib(hapd
, reply
, reply_size
);
327 if (reply_len
>= 0) {
328 res
= wpa_get_mib(hapd
->wpa_auth
, reply
+ reply_len
,
329 reply_size
- reply_len
);
335 if (reply_len
>= 0) {
336 res
= ieee802_1x_get_mib(hapd
, reply
+ reply_len
,
337 reply_size
- reply_len
);
343 if (reply_len
>= 0) {
344 res
= radius_client_get_mib(hapd
->radius
,
346 reply_size
- reply_len
);
352 } else if (os_strcmp(buf
, "STA-FIRST") == 0) {
353 reply_len
= hostapd_ctrl_iface_sta_first(hapd
, reply
,
355 } else if (os_strncmp(buf
, "STA ", 4) == 0) {
356 reply_len
= hostapd_ctrl_iface_sta(hapd
, buf
+ 4, reply
,
358 } else if (os_strncmp(buf
, "STA-NEXT ", 9) == 0) {
359 reply_len
= hostapd_ctrl_iface_sta_next(hapd
, buf
+ 9, reply
,
361 } else if (os_strcmp(buf
, "ATTACH") == 0) {
362 if (hostapd_ctrl_iface_attach(hapd
, &from
, fromlen
))
364 } else if (os_strcmp(buf
, "DETACH") == 0) {
365 if (hostapd_ctrl_iface_detach(hapd
, &from
, fromlen
))
367 } else if (os_strncmp(buf
, "LEVEL ", 6) == 0) {
368 if (hostapd_ctrl_iface_level(hapd
, &from
, fromlen
,
371 } else if (os_strncmp(buf
, "NEW_STA ", 8) == 0) {
372 if (hostapd_ctrl_iface_new_sta(hapd
, buf
+ 8))
374 #ifdef CONFIG_IEEE80211W
376 } else if (os_strncmp(buf
, "SA_QUERY ", 9) == 0) {
377 if (hostapd_ctrl_iface_sa_query(hapd
, buf
+ 9))
379 #endif /* NEED_MLME */
380 #endif /* CONFIG_IEEE80211W */
382 } else if (os_strncmp(buf
, "WPS_PIN ", 8) == 0) {
383 if (hostapd_ctrl_iface_wps_pin(hapd
, buf
+ 8))
385 } else if (os_strcmp(buf
, "WPS_PBC") == 0) {
386 if (hostapd_wps_button_pushed(hapd
))
388 #ifdef CONFIG_WPS_OOB
389 } else if (os_strncmp(buf
, "WPS_OOB ", 8) == 0) {
390 if (hostapd_ctrl_iface_wps_oob(hapd
, buf
+ 8))
392 #endif /* CONFIG_WPS_OOB */
393 #endif /* CONFIG_WPS */
395 os_memcpy(reply
, "UNKNOWN COMMAND\n", 16);
400 os_memcpy(reply
, "FAIL\n", 5);
403 sendto(sock
, reply
, reply_len
, 0, (struct sockaddr
*) &from
, fromlen
);
408 static char * hostapd_ctrl_iface_path(struct hostapd_data
*hapd
)
413 if (hapd
->conf
->ctrl_interface
== NULL
)
416 len
= os_strlen(hapd
->conf
->ctrl_interface
) +
417 os_strlen(hapd
->conf
->iface
) + 2;
418 buf
= os_malloc(len
);
422 os_snprintf(buf
, len
, "%s/%s",
423 hapd
->conf
->ctrl_interface
, hapd
->conf
->iface
);
429 static void hostapd_ctrl_iface_msg_cb(void *ctx
, int level
,
430 const char *txt
, size_t len
)
432 struct hostapd_data
*hapd
= ctx
;
435 hostapd_ctrl_iface_send(hapd
, level
, txt
, len
);
439 int hostapd_ctrl_iface_init(struct hostapd_data
*hapd
)
441 struct sockaddr_un addr
;
445 hapd
->ctrl_sock
= -1;
447 if (hapd
->conf
->ctrl_interface
== NULL
)
450 if (mkdir(hapd
->conf
->ctrl_interface
, S_IRWXU
| S_IRWXG
) < 0) {
451 if (errno
== EEXIST
) {
452 wpa_printf(MSG_DEBUG
, "Using existing control "
453 "interface directory.");
455 perror("mkdir[ctrl_interface]");
460 if (hapd
->conf
->ctrl_interface_gid_set
&&
461 chown(hapd
->conf
->ctrl_interface
, 0,
462 hapd
->conf
->ctrl_interface_gid
) < 0) {
463 perror("chown[ctrl_interface]");
467 if (os_strlen(hapd
->conf
->ctrl_interface
) + 1 +
468 os_strlen(hapd
->conf
->iface
) >= sizeof(addr
.sun_path
))
471 s
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
473 perror("socket(PF_UNIX)");
477 os_memset(&addr
, 0, sizeof(addr
));
479 addr
.sun_len
= sizeof(addr
);
480 #endif /* __FreeBSD__ */
481 addr
.sun_family
= AF_UNIX
;
482 fname
= hostapd_ctrl_iface_path(hapd
);
485 os_strlcpy(addr
.sun_path
, fname
, sizeof(addr
.sun_path
));
486 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
487 perror("bind(PF_UNIX)");
491 if (hapd
->conf
->ctrl_interface_gid_set
&&
492 chown(fname
, 0, hapd
->conf
->ctrl_interface_gid
) < 0) {
493 perror("chown[ctrl_interface/ifname]");
497 if (chmod(fname
, S_IRWXU
| S_IRWXG
) < 0) {
498 perror("chmod[ctrl_interface/ifname]");
504 eloop_register_read_sock(s
, hostapd_ctrl_iface_receive
, hapd
,
506 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb
);
521 void hostapd_ctrl_iface_deinit(struct hostapd_data
*hapd
)
523 struct wpa_ctrl_dst
*dst
, *prev
;
525 if (hapd
->ctrl_sock
> -1) {
527 eloop_unregister_read_sock(hapd
->ctrl_sock
);
528 close(hapd
->ctrl_sock
);
529 hapd
->ctrl_sock
= -1;
530 fname
= hostapd_ctrl_iface_path(hapd
);
535 if (hapd
->conf
->ctrl_interface
&&
536 rmdir(hapd
->conf
->ctrl_interface
) < 0) {
537 if (errno
== ENOTEMPTY
) {
538 wpa_printf(MSG_DEBUG
, "Control interface "
539 "directory not empty - leaving it "
542 perror("rmdir[ctrl_interface]");
547 dst
= hapd
->ctrl_dst
;
556 static void hostapd_ctrl_iface_send(struct hostapd_data
*hapd
, int level
,
557 const char *buf
, size_t len
)
559 struct wpa_ctrl_dst
*dst
, *next
;
565 dst
= hapd
->ctrl_dst
;
566 if (hapd
->ctrl_sock
< 0 || dst
== NULL
)
569 os_snprintf(levelstr
, sizeof(levelstr
), "<%d>", level
);
570 io
[0].iov_base
= levelstr
;
571 io
[0].iov_len
= os_strlen(levelstr
);
572 io
[1].iov_base
= (char *) buf
;
574 os_memset(&msg
, 0, sizeof(msg
));
581 if (level
>= dst
->debug_level
) {
582 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor send",
583 (u8
*) dst
->addr
.sun_path
, dst
->addrlen
-
584 offsetof(struct sockaddr_un
, sun_path
));
585 msg
.msg_name
= &dst
->addr
;
586 msg
.msg_namelen
= dst
->addrlen
;
587 if (sendmsg(hapd
->ctrl_sock
, &msg
, 0) < 0) {
589 wpa_printf(MSG_INFO
, "CTRL_IFACE monitor[%d]: "
591 idx
, errno
, strerror(errno
));
593 if (dst
->errors
> 10 || _errno
== ENOENT
) {
594 hostapd_ctrl_iface_detach(
606 #endif /* CONFIG_NATIVE_WINDOWS */