2 * Host AP (software wireless LAN access point) user space daemon for
3 * Host AP kernel driver / UNIX domain socket -based control interface
4 * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
20 #include <sys/types.h>
21 #include <sys/socket.h>
26 #include <netinet/in.h>
32 #include "ieee802_1x.h"
34 #include "radius_client.h"
35 #include "ieee802_11.h"
36 #include "ctrl_iface.h"
41 struct wpa_ctrl_dst
*next
;
42 struct sockaddr_un addr
;
49 static int hostapd_ctrl_iface_attach(struct hostapd_data
*hapd
,
50 struct sockaddr_un
*from
,
53 struct wpa_ctrl_dst
*dst
;
55 dst
= malloc(sizeof(*dst
));
58 memset(dst
, 0, sizeof(*dst
));
59 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
, fromlen
);
70 static int hostapd_ctrl_iface_detach(struct hostapd_data
*hapd
,
71 struct sockaddr_un
*from
,
74 struct wpa_ctrl_dst
*dst
, *prev
= NULL
;
78 if (fromlen
== dst
->addrlen
&&
79 memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) == 0) {
81 hapd
->ctrl_dst
= dst
->next
;
83 prev
->next
= dst
->next
;
85 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor detached",
86 (u8
*) from
->sun_path
, fromlen
);
96 static int hostapd_ctrl_iface_level(struct hostapd_data
*hapd
,
97 struct sockaddr_un
*from
,
101 struct wpa_ctrl_dst
*dst
;
103 wpa_printf(MSG_DEBUG
, "CTRL_IFACE LEVEL %s", level
);
105 dst
= hapd
->ctrl_dst
;
107 if (fromlen
== dst
->addrlen
&&
108 memcmp(from
->sun_path
, dst
->addr
.sun_path
, fromlen
) == 0) {
109 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE changed monitor "
110 "level", (u8
*) from
->sun_path
, fromlen
);
111 dst
->debug_level
= atoi(level
);
121 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data
*hapd
,
122 struct sta_info
*sta
,
123 char *buf
, size_t buflen
)
128 return snprintf(buf
, buflen
, "FAIL\n");
132 len
+= snprintf(buf
+ len
, buflen
- len
, MACSTR
"\n",
135 res
= ieee802_11_get_mib_sta(hapd
, sta
, buf
+ len
, buflen
- len
);
138 res
= wpa_get_mib_sta(hapd
, sta
, 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
)
162 if (hwaddr_aton(txtaddr
, addr
))
163 return snprintf(buf
, buflen
, "FAIL\n");
164 return hostapd_ctrl_iface_sta_mib(hapd
, ap_get_sta(hapd
, addr
),
169 static int hostapd_ctrl_iface_sta_next(struct hostapd_data
*hapd
,
171 char *buf
, size_t buflen
)
174 struct sta_info
*sta
;
176 if (hwaddr_aton(txtaddr
, addr
) ||
177 (sta
= ap_get_sta(hapd
, addr
)) == NULL
)
178 return snprintf(buf
, buflen
, "FAIL\n");
179 return hostapd_ctrl_iface_sta_mib(hapd
, sta
->next
, buf
, buflen
);
183 static void hostapd_ctrl_iface_receive(int sock
, void *eloop_ctx
,
186 struct hostapd_data
*hapd
= eloop_ctx
;
189 struct sockaddr_un from
;
190 socklen_t fromlen
= sizeof(from
);
192 const int reply_size
= 4096;
195 res
= recvfrom(sock
, buf
, sizeof(buf
) - 1, 0,
196 (struct sockaddr
*) &from
, &fromlen
);
198 perror("recvfrom(ctrl_iface)");
202 wpa_hexdump_ascii(MSG_DEBUG
, "RX ctrl_iface", (u8
*) buf
, res
);
204 reply
= malloc(reply_size
);
206 sendto(sock
, "FAIL\n", 5, 0, (struct sockaddr
*) &from
,
211 memcpy(reply
, "OK\n", 3);
214 if (strcmp(buf
, "PING") == 0) {
215 memcpy(reply
, "PONG\n", 5);
217 } else if (strcmp(buf
, "MIB") == 0) {
218 reply_len
= ieee802_11_get_mib(hapd
, reply
, reply_size
);
219 if (reply_len
>= 0) {
220 res
= wpa_get_mib(hapd
, reply
+ reply_len
,
221 reply_size
- reply_len
);
227 if (reply_len
>= 0) {
228 res
= ieee802_1x_get_mib(hapd
, reply
+ reply_len
,
229 reply_size
- reply_len
);
235 if (reply_len
>= 0) {
236 res
= radius_client_get_mib(hapd
->radius
,
238 reply_size
- reply_len
);
244 } else if (strcmp(buf
, "STA-FIRST") == 0) {
245 reply_len
= hostapd_ctrl_iface_sta_first(hapd
, reply
,
247 } else if (strncmp(buf
, "STA ", 4) == 0) {
248 reply_len
= hostapd_ctrl_iface_sta(hapd
, buf
+ 4, reply
,
250 } else if (strncmp(buf
, "STA-NEXT ", 9) == 0) {
251 reply_len
= hostapd_ctrl_iface_sta_next(hapd
, buf
+ 9, reply
,
253 } else if (strcmp(buf
, "ATTACH") == 0) {
254 if (hostapd_ctrl_iface_attach(hapd
, &from
, fromlen
))
256 } else if (strcmp(buf
, "DETACH") == 0) {
257 if (hostapd_ctrl_iface_detach(hapd
, &from
, fromlen
))
259 } else if (strncmp(buf
, "LEVEL ", 6) == 0) {
260 if (hostapd_ctrl_iface_level(hapd
, &from
, fromlen
,
264 memcpy(reply
, "UNKNOWN COMMAND\n", 16);
269 memcpy(reply
, "FAIL\n", 5);
272 sendto(sock
, reply
, reply_len
, 0, (struct sockaddr
*) &from
, fromlen
);
277 static char * hostapd_ctrl_iface_path(struct hostapd_data
*hapd
)
282 if (hapd
->conf
->ctrl_interface
== NULL
)
285 len
= strlen(hapd
->conf
->ctrl_interface
) + strlen(hapd
->conf
->iface
) +
291 snprintf(buf
, len
, "%s/%s",
292 hapd
->conf
->ctrl_interface
, hapd
->conf
->iface
);
297 int hostapd_ctrl_iface_init(struct hostapd_data
*hapd
)
299 struct sockaddr_un addr
;
303 hapd
->ctrl_sock
= -1;
305 if (hapd
->conf
->ctrl_interface
== NULL
)
308 if (mkdir(hapd
->conf
->ctrl_interface
, S_IRWXU
| S_IRWXG
) < 0) {
309 if (errno
== EEXIST
) {
310 wpa_printf(MSG_DEBUG
, "Using existing control "
311 "interface directory.");
313 perror("mkdir[ctrl_interface]");
318 if (hapd
->conf
->ctrl_interface_gid_set
&&
319 chown(hapd
->conf
->ctrl_interface
, 0,
320 hapd
->conf
->ctrl_interface_gid
) < 0) {
321 perror("chown[ctrl_interface]");
325 if (strlen(hapd
->conf
->ctrl_interface
) + 1 + strlen(hapd
->conf
->iface
)
326 >= sizeof(addr
.sun_path
))
329 s
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
331 perror("socket(PF_UNIX)");
335 memset(&addr
, 0, sizeof(addr
));
336 addr
.sun_family
= AF_UNIX
;
337 fname
= hostapd_ctrl_iface_path(hapd
);
340 strncpy(addr
.sun_path
, fname
, sizeof(addr
.sun_path
));
341 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
342 perror("bind(PF_UNIX)");
346 if (hapd
->conf
->ctrl_interface_gid_set
&&
347 chown(fname
, 0, hapd
->conf
->ctrl_interface_gid
) < 0) {
348 perror("chown[ctrl_interface/ifname]");
352 if (chmod(fname
, S_IRWXU
| S_IRWXG
) < 0) {
353 perror("chmod[ctrl_interface/ifname]");
359 eloop_register_read_sock(s
, hostapd_ctrl_iface_receive
, hapd
,
375 void hostapd_ctrl_iface_deinit(struct hostapd_data
*hapd
)
377 struct wpa_ctrl_dst
*dst
, *prev
;
379 if (hapd
->ctrl_sock
> -1) {
381 eloop_unregister_read_sock(hapd
->ctrl_sock
);
382 close(hapd
->ctrl_sock
);
383 hapd
->ctrl_sock
= -1;
384 fname
= hostapd_ctrl_iface_path(hapd
);
389 if (hapd
->conf
->ctrl_interface
&&
390 rmdir(hapd
->conf
->ctrl_interface
) < 0) {
391 if (errno
== ENOTEMPTY
) {
392 wpa_printf(MSG_DEBUG
, "Control interface "
393 "directory not empty - leaving it "
396 perror("rmdir[ctrl_interface]");
401 dst
= hapd
->ctrl_dst
;
410 void hostapd_ctrl_iface_send(struct hostapd_data
*hapd
, int level
,
411 char *buf
, size_t len
)
413 struct wpa_ctrl_dst
*dst
, *next
;
419 dst
= hapd
->ctrl_dst
;
420 if (hapd
->ctrl_sock
< 0 || dst
== NULL
)
423 snprintf(levelstr
, sizeof(levelstr
), "<%d>", level
);
424 io
[0].iov_base
= levelstr
;
425 io
[0].iov_len
= strlen(levelstr
);
426 io
[1].iov_base
= buf
;
428 memset(&msg
, 0, sizeof(msg
));
435 if (level
>= dst
->debug_level
) {
436 wpa_hexdump(MSG_DEBUG
, "CTRL_IFACE monitor send",
437 (u8
*) dst
->addr
.sun_path
, dst
->addrlen
);
438 msg
.msg_name
= &dst
->addr
;
439 msg
.msg_namelen
= dst
->addrlen
;
440 if (sendmsg(hapd
->ctrl_sock
, &msg
, 0) < 0) {
441 fprintf(stderr
, "CTRL_IFACE monitor[%d]: ",
445 if (dst
->errors
> 10) {
446 hostapd_ctrl_iface_detach(