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(