2 * hostapd / UNIX domain socket -based control interface
3 * Copyright (c) 2004, 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_client.h"
29 #include "ieee802_11.h"
30 #include "ctrl_iface.h"
32 #include "accounting.h"
36 struct wpa_ctrl_dst
*next
;
37 struct sockaddr_un addr
;
44 static int hostapd_ctrl_iface_attach(struct hostapd_data
*hapd
,
45 struct sockaddr_un
*from
,
48 struct wpa_ctrl_dst
*dst
;
50 dst
= wpa_zalloc(sizeof(*dst
));
53 memcpy(&dst
->addr
, from
, sizeof(struct sockaddr_un
));
54 dst
->addrlen
= fromlen
;
55 dst
->debug_level
= MSG_INFO
;
56 dst
->next
= hapd
->ctrl_dst
;
58 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor attached",
59 (u8
*) from
->sun_path
, fromlen
);
64 static int hostapd_ctrl_iface_detach(struct hostapd_data
*hapd
,
65 struct sockaddr_un
*from
,
68 struct wpa_ctrl_dst
*dst
, *prev
= NULL
;
72 if (fromlen
== dst
->addrlen
&&
73 memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) == 0) {
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 memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) == 0) {
103 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE changed monitor "
104 "level", (u8
*) from
->sun_path
, fromlen
);
105 dst
->debug_level
= atoi(level
);
115 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data
*hapd
,
116 struct sta_info
*sta
,
117 char *buf
, size_t buflen
)
122 ret
= snprintf(buf
, buflen
, "FAIL\n");
123 if (ret
< 0 || (size_t) ret
>= buflen
)
129 ret
= snprintf(buf
+ len
, buflen
- len
, MACSTR
"\n",
131 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
135 res
= ieee802_11_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
138 res
= wpa_get_mib_sta(sta
->wpa_sm
, buf
+ len
, buflen
- len
);
141 res
= ieee802_1x_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
149 static int hostapd_ctrl_iface_sta_first(struct hostapd_data
*hapd
,
150 char *buf
, size_t buflen
)
152 return hostapd_ctrl_iface_sta_mib(hapd
, hapd
->sta_list
, buf
, buflen
);
156 static int hostapd_ctrl_iface_sta(struct hostapd_data
*hapd
,
158 char *buf
, size_t buflen
)
163 if (hwaddr_aton(txtaddr
, addr
)) {
164 ret
= snprintf(buf
, buflen
, "FAIL\n");
165 if (ret
< 0 || (size_t) ret
>= buflen
)
169 return hostapd_ctrl_iface_sta_mib(hapd
, ap_get_sta(hapd
, addr
),
174 static int hostapd_ctrl_iface_sta_next(struct hostapd_data
*hapd
,
176 char *buf
, size_t buflen
)
179 struct sta_info
*sta
;
182 if (hwaddr_aton(txtaddr
, addr
) ||
183 (sta
= ap_get_sta(hapd
, addr
)) == NULL
) {
184 ret
= snprintf(buf
, buflen
, "FAIL\n");
185 if (ret
< 0 || (size_t) ret
>= buflen
)
189 return hostapd_ctrl_iface_sta_mib(hapd
, sta
->next
, buf
, buflen
);
193 static int hostapd_ctrl_iface_new_sta(struct hostapd_data
*hapd
,
197 struct sta_info
*sta
;
199 wpa_printf(MSG_DEBUG
, "CTRL_IFACE NEW_STA %s", txtaddr
);
201 if (hwaddr_aton(txtaddr
, addr
))
204 sta
= ap_get_sta(hapd
, addr
);
208 wpa_printf(MSG_DEBUG
, "Add new STA " MACSTR
" based on ctrl_iface "
209 "notification", MAC2STR(addr
));
210 sta
= ap_sta_add(hapd
, addr
);
214 hostapd_new_assoc_sta(hapd
, sta
, 0);
215 accounting_sta_get_id(hapd
, sta
);
220 static void hostapd_ctrl_iface_receive(int sock
, void *eloop_ctx
,
223 struct hostapd_data
*hapd
= eloop_ctx
;
226 struct sockaddr_un from
;
227 socklen_t fromlen
= sizeof(from
);
229 const int reply_size
= 4096;
232 res
= recvfrom(sock
, buf
, sizeof(buf
) - 1, 0,
233 (struct sockaddr
*) &from
, &fromlen
);
235 perror("recvfrom(ctrl_iface)");
239 wpa_hexdump_ascii(MSG_DEBUG
, "RX ctrl_iface", (u8
*) buf
, res
);
241 reply
= malloc(reply_size
);
243 sendto(sock
, "FAIL\n", 5, 0, (struct sockaddr
*) &from
,
248 memcpy(reply
, "OK\n", 3);
251 if (strcmp(buf
, "PING") == 0) {
252 memcpy(reply
, "PONG\n", 5);
254 } else if (strcmp(buf
, "MIB") == 0) {
255 reply_len
= ieee802_11_get_mib(hapd
, reply
, reply_size
);
256 if (reply_len
>= 0) {
257 res
= wpa_get_mib(hapd
->wpa_auth
, reply
+ reply_len
,
258 reply_size
- reply_len
);
264 if (reply_len
>= 0) {
265 res
= ieee802_1x_get_mib(hapd
, reply
+ reply_len
,
266 reply_size
- reply_len
);
272 if (reply_len
>= 0) {
273 res
= radius_client_get_mib(hapd
->radius
,
275 reply_size
- reply_len
);
281 } else if (strcmp(buf
, "STA-FIRST") == 0) {
282 reply_len
= hostapd_ctrl_iface_sta_first(hapd
, reply
,
284 } else if (strncmp(buf
, "STA ", 4) == 0) {
285 reply_len
= hostapd_ctrl_iface_sta(hapd
, buf
+ 4, reply
,
287 } else if (strncmp(buf
, "STA-NEXT ", 9) == 0) {
288 reply_len
= hostapd_ctrl_iface_sta_next(hapd
, buf
+ 9, reply
,
290 } else if (strcmp(buf
, "ATTACH") == 0) {
291 if (hostapd_ctrl_iface_attach(hapd
, &from
, fromlen
))
293 } else if (strcmp(buf
, "DETACH") == 0) {
294 if (hostapd_ctrl_iface_detach(hapd
, &from
, fromlen
))
296 } else if (strncmp(buf
, "LEVEL ", 6) == 0) {
297 if (hostapd_ctrl_iface_level(hapd
, &from
, fromlen
,
300 } else if (strncmp(buf
, "NEW_STA ", 8) == 0) {
301 if (hostapd_ctrl_iface_new_sta(hapd
, buf
+ 8))
304 memcpy(reply
, "UNKNOWN COMMAND\n", 16);
309 memcpy(reply
, "FAIL\n", 5);
312 sendto(sock
, reply
, reply_len
, 0, (struct sockaddr
*) &from
, fromlen
);
317 static char * hostapd_ctrl_iface_path(struct hostapd_data
*hapd
)
322 if (hapd
->conf
->ctrl_interface
== NULL
)
325 len
= strlen(hapd
->conf
->ctrl_interface
) + strlen(hapd
->conf
->iface
) +
331 snprintf(buf
, len
, "%s/%s",
332 hapd
->conf
->ctrl_interface
, hapd
->conf
->iface
);
338 int hostapd_ctrl_iface_init(struct hostapd_data
*hapd
)
340 struct sockaddr_un addr
;
344 hapd
->ctrl_sock
= -1;
346 if (hapd
->conf
->ctrl_interface
== NULL
)
349 if (mkdir(hapd
->conf
->ctrl_interface
, S_IRWXU
| S_IRWXG
) < 0) {
350 if (errno
== EEXIST
) {
351 wpa_printf(MSG_DEBUG
, "Using existing control "
352 "interface directory.");
354 perror("mkdir[ctrl_interface]");
359 if (hapd
->conf
->ctrl_interface_gid_set
&&
360 chown(hapd
->conf
->ctrl_interface
, 0,
361 hapd
->conf
->ctrl_interface_gid
) < 0) {
362 perror("chown[ctrl_interface]");
366 if (strlen(hapd
->conf
->ctrl_interface
) + 1 + strlen(hapd
->conf
->iface
)
367 >= sizeof(addr
.sun_path
))
370 s
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
372 perror("socket(PF_UNIX)");
376 memset(&addr
, 0, sizeof(addr
));
377 addr
.sun_family
= AF_UNIX
;
378 fname
= hostapd_ctrl_iface_path(hapd
);
381 strncpy(addr
.sun_path
, fname
, sizeof(addr
.sun_path
));
382 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
383 perror("bind(PF_UNIX)");
387 if (hapd
->conf
->ctrl_interface_gid_set
&&
388 chown(fname
, 0, hapd
->conf
->ctrl_interface_gid
) < 0) {
389 perror("chown[ctrl_interface/ifname]");
393 if (chmod(fname
, S_IRWXU
| S_IRWXG
) < 0) {
394 perror("chmod[ctrl_interface/ifname]");
400 eloop_register_read_sock(s
, hostapd_ctrl_iface_receive
, hapd
,
416 void hostapd_ctrl_iface_deinit(struct hostapd_data
*hapd
)
418 struct wpa_ctrl_dst
*dst
, *prev
;
420 if (hapd
->ctrl_sock
> -1) {
422 eloop_unregister_read_sock(hapd
->ctrl_sock
);
423 close(hapd
->ctrl_sock
);
424 hapd
->ctrl_sock
= -1;
425 fname
= hostapd_ctrl_iface_path(hapd
);
430 if (hapd
->conf
->ctrl_interface
&&
431 rmdir(hapd
->conf
->ctrl_interface
) < 0) {
432 if (errno
== ENOTEMPTY
) {
433 wpa_printf(MSG_DEBUG
, "Control interface "
434 "directory not empty - leaving it "
437 perror("rmdir[ctrl_interface]");
442 dst
= hapd
->ctrl_dst
;
451 void hostapd_ctrl_iface_send(struct hostapd_data
*hapd
, int level
,
452 char *buf
, size_t len
)
454 struct wpa_ctrl_dst
*dst
, *next
;
460 dst
= hapd
->ctrl_dst
;
461 if (hapd
->ctrl_sock
< 0 || dst
== NULL
)
464 snprintf(levelstr
, sizeof(levelstr
), "<%d>", level
);
465 io
[0].iov_base
= levelstr
;
466 io
[0].iov_len
= strlen(levelstr
);
467 io
[1].iov_base
= buf
;
469 memset(&msg
, 0, sizeof(msg
));
476 if (level
>= dst
->debug_level
) {
477 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor send",
478 (u8
*) dst
->addr
.sun_path
, dst
->addrlen
);
479 msg
.msg_name
= &dst
->addr
;
480 msg
.msg_namelen
= dst
->addrlen
;
481 if (sendmsg(hapd
->ctrl_sock
, &msg
, 0) < 0) {
482 fprintf(stderr
, "CTRL_IFACE monitor[%d]: ",
486 if (dst
->errors
> 10) {
487 hostapd_ctrl_iface_detach(
499 #endif /* CONFIG_NATIVE_WINDOWS */