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
25 #include "ieee802_1x.h"
27 #include "radius/radius_client.h"
28 #include "ieee802_11.h"
29 #include "ctrl_iface.h"
31 #include "accounting.h"
35 struct wpa_ctrl_dst
*next
;
36 struct sockaddr_un addr
;
43 static int hostapd_ctrl_iface_attach(struct hostapd_data
*hapd
,
44 struct sockaddr_un
*from
,
47 struct wpa_ctrl_dst
*dst
;
49 dst
= os_zalloc(sizeof(*dst
));
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
;
57 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor attached",
58 (u8
*) from
->sun_path
, fromlen
);
63 static int hostapd_ctrl_iface_detach(struct hostapd_data
*hapd
,
64 struct sockaddr_un
*from
,
67 struct wpa_ctrl_dst
*dst
, *prev
= NULL
;
71 if (fromlen
== dst
->addrlen
&&
72 os_memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) ==
75 hapd
->ctrl_dst
= dst
->next
;
77 prev
->next
= dst
->next
;
79 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor detached",
80 (u8
*) from
->sun_path
, fromlen
);
90 static int hostapd_ctrl_iface_level(struct hostapd_data
*hapd
,
91 struct sockaddr_un
*from
,
95 struct wpa_ctrl_dst
*dst
;
97 wpa_printf(MSG_DEBUG
, "CTRL_IFACE LEVEL %s", level
);
101 if (fromlen
== dst
->addrlen
&&
102 os_memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) ==
104 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE changed monitor "
105 "level", (u8
*) from
->sun_path
, fromlen
);
106 dst
->debug_level
= atoi(level
);
116 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data
*hapd
,
117 struct sta_info
*sta
,
118 char *buf
, size_t buflen
)
123 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
124 if (ret
< 0 || (size_t) ret
>= buflen
)
130 ret
= os_snprintf(buf
+ len
, buflen
- len
, MACSTR
"\n",
132 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
136 res
= ieee802_11_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
139 res
= wpa_get_mib_sta(sta
->wpa_sm
, buf
+ len
, buflen
- len
);
142 res
= ieee802_1x_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
150 static int hostapd_ctrl_iface_sta_first(struct hostapd_data
*hapd
,
151 char *buf
, size_t buflen
)
153 return hostapd_ctrl_iface_sta_mib(hapd
, hapd
->sta_list
, buf
, buflen
);
157 static int hostapd_ctrl_iface_sta(struct hostapd_data
*hapd
,
159 char *buf
, size_t buflen
)
164 if (hwaddr_aton(txtaddr
, addr
)) {
165 ret
= os_snprintf(buf
, buflen
, "FAIL\n");
166 if (ret
< 0 || (size_t) ret
>= buflen
)
170 return hostapd_ctrl_iface_sta_mib(hapd
, ap_get_sta(hapd
, addr
),
175 static int hostapd_ctrl_iface_sta_next(struct hostapd_data
*hapd
,
177 char *buf
, size_t buflen
)
180 struct sta_info
*sta
;
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
)
190 return hostapd_ctrl_iface_sta_mib(hapd
, sta
->next
, buf
, buflen
);
194 static int hostapd_ctrl_iface_new_sta(struct hostapd_data
*hapd
,
198 struct sta_info
*sta
;
200 wpa_printf(MSG_DEBUG
, "CTRL_IFACE NEW_STA %s", txtaddr
);
202 if (hwaddr_aton(txtaddr
, addr
))
205 sta
= ap_get_sta(hapd
, addr
);
209 wpa_printf(MSG_DEBUG
, "Add new STA " MACSTR
" based on ctrl_iface "
210 "notification", MAC2STR(addr
));
211 sta
= ap_sta_add(hapd
, addr
);
215 hostapd_new_assoc_sta(hapd
, sta
, 0);
216 accounting_sta_get_id(hapd
, sta
);
221 static void hostapd_ctrl_iface_receive(int sock
, void *eloop_ctx
,
224 struct hostapd_data
*hapd
= eloop_ctx
;
227 struct sockaddr_un from
;
228 socklen_t fromlen
= sizeof(from
);
230 const int reply_size
= 4096;
233 res
= recvfrom(sock
, buf
, sizeof(buf
) - 1, 0,
234 (struct sockaddr
*) &from
, &fromlen
);
236 perror("recvfrom(ctrl_iface)");
240 wpa_hexdump_ascii(MSG_DEBUG
, "RX ctrl_iface", (u8
*) buf
, res
);
242 reply
= os_malloc(reply_size
);
244 sendto(sock
, "FAIL\n", 5, 0, (struct sockaddr
*) &from
,
249 os_memcpy(reply
, "OK\n", 3);
252 if (os_strcmp(buf
, "PING") == 0) {
253 os_memcpy(reply
, "PONG\n", 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
);
265 if (reply_len
>= 0) {
266 res
= ieee802_1x_get_mib(hapd
, reply
+ reply_len
,
267 reply_size
- reply_len
);
273 if (reply_len
>= 0) {
274 res
= radius_client_get_mib(hapd
->radius
,
276 reply_size
- reply_len
);
282 } else if (os_strcmp(buf
, "STA-FIRST") == 0) {
283 reply_len
= hostapd_ctrl_iface_sta_first(hapd
, reply
,
285 } else if (os_strncmp(buf
, "STA ", 4) == 0) {
286 reply_len
= hostapd_ctrl_iface_sta(hapd
, buf
+ 4, reply
,
288 } else if (os_strncmp(buf
, "STA-NEXT ", 9) == 0) {
289 reply_len
= hostapd_ctrl_iface_sta_next(hapd
, buf
+ 9, reply
,
291 } else if (os_strcmp(buf
, "ATTACH") == 0) {
292 if (hostapd_ctrl_iface_attach(hapd
, &from
, fromlen
))
294 } else if (os_strcmp(buf
, "DETACH") == 0) {
295 if (hostapd_ctrl_iface_detach(hapd
, &from
, fromlen
))
297 } else if (os_strncmp(buf
, "LEVEL ", 6) == 0) {
298 if (hostapd_ctrl_iface_level(hapd
, &from
, fromlen
,
301 } else if (os_strncmp(buf
, "NEW_STA ", 8) == 0) {
302 if (hostapd_ctrl_iface_new_sta(hapd
, buf
+ 8))
305 os_memcpy(reply
, "UNKNOWN COMMAND\n", 16);
310 os_memcpy(reply
, "FAIL\n", 5);
313 sendto(sock
, reply
, reply_len
, 0, (struct sockaddr
*) &from
, fromlen
);
318 static char * hostapd_ctrl_iface_path(struct hostapd_data
*hapd
)
323 if (hapd
->conf
->ctrl_interface
== NULL
)
326 len
= os_strlen(hapd
->conf
->ctrl_interface
) +
327 os_strlen(hapd
->conf
->iface
) + 2;
328 buf
= os_malloc(len
);
332 os_snprintf(buf
, len
, "%s/%s",
333 hapd
->conf
->ctrl_interface
, hapd
->conf
->iface
);
339 int hostapd_ctrl_iface_init(struct hostapd_data
*hapd
)
341 struct sockaddr_un addr
;
345 hapd
->ctrl_sock
= -1;
347 if (hapd
->conf
->ctrl_interface
== NULL
)
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.");
355 perror("mkdir[ctrl_interface]");
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]");
367 if (os_strlen(hapd
->conf
->ctrl_interface
) + 1 +
368 os_strlen(hapd
->conf
->iface
) >= sizeof(addr
.sun_path
))
371 s
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
373 perror("socket(PF_UNIX)");
377 os_memset(&addr
, 0, sizeof(addr
));
378 addr
.sun_family
= AF_UNIX
;
379 fname
= hostapd_ctrl_iface_path(hapd
);
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)");
388 if (hapd
->conf
->ctrl_interface_gid_set
&&
389 chown(fname
, 0, hapd
->conf
->ctrl_interface_gid
) < 0) {
390 perror("chown[ctrl_interface/ifname]");
394 if (chmod(fname
, S_IRWXU
| S_IRWXG
) < 0) {
395 perror("chmod[ctrl_interface/ifname]");
401 eloop_register_read_sock(s
, hostapd_ctrl_iface_receive
, hapd
,
417 void hostapd_ctrl_iface_deinit(struct hostapd_data
*hapd
)
419 struct wpa_ctrl_dst
*dst
, *prev
;
421 if (hapd
->ctrl_sock
> -1) {
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
);
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 "
438 perror("rmdir[ctrl_interface]");
443 dst
= hapd
->ctrl_dst
;
452 void hostapd_ctrl_iface_send(struct hostapd_data
*hapd
, int level
,
453 char *buf
, size_t len
)
455 struct wpa_ctrl_dst
*dst
, *next
;
461 dst
= hapd
->ctrl_dst
;
462 if (hapd
->ctrl_sock
< 0 || dst
== NULL
)
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
;
470 os_memset(&msg
, 0, sizeof(msg
));
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]: ",
487 if (dst
->errors
> 10) {
488 hostapd_ctrl_iface_detach(
500 #endif /* CONFIG_NATIVE_WINDOWS */