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 */