00001
00016 #include "includes.h"
00017
00018 #ifndef CONFIG_NATIVE_WINDOWS
00019
00020 #include <sys/un.h>
00021 #include <sys/stat.h>
00022 #include <stddef.h>
00023
00024 #include "hostapd.h"
00025 #include "eloop.h"
00026 #include "config.h"
00027 #include "ieee802_1x.h"
00028 #include "wpa.h"
00029 #include "radius/radius_client.h"
00030 #include "ieee802_11.h"
00031 #include "ctrl_iface.h"
00032 #include "sta_info.h"
00033 #include "accounting.h"
00034 #include "wps_hostapd.h"
00035 #include "drivers/driver.h"
00036 #include "ctrl_iface_ap.h"
00037
00038
00039 struct wpa_ctrl_dst {
00040 struct wpa_ctrl_dst *next;
00041 struct sockaddr_un addr;
00042 socklen_t addrlen;
00043 int debug_level;
00044 int errors;
00045 };
00046
00047
00048 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
00049 const char *buf, size_t len);
00050
00051
00052 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
00053 struct sockaddr_un *from,
00054 socklen_t fromlen)
00055 {
00056 struct wpa_ctrl_dst *dst;
00057
00058 dst = os_zalloc(sizeof(*dst));
00059 if (dst == NULL)
00060 return -1;
00061 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
00062 dst->addrlen = fromlen;
00063 dst->debug_level = MSG_INFO;
00064 dst->next = hapd->ctrl_dst;
00065 hapd->ctrl_dst = dst;
00066 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
00067 (u8 *) from->sun_path,
00068 fromlen - offsetof(struct sockaddr_un, sun_path));
00069 return 0;
00070 }
00071
00072
00073 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
00074 struct sockaddr_un *from,
00075 socklen_t fromlen)
00076 {
00077 struct wpa_ctrl_dst *dst, *prev = NULL;
00078
00079 dst = hapd->ctrl_dst;
00080 while (dst) {
00081 if (fromlen == dst->addrlen &&
00082 os_memcmp(from->sun_path, dst->addr.sun_path,
00083 fromlen - offsetof(struct sockaddr_un, sun_path))
00084 == 0) {
00085 if (prev == NULL)
00086 hapd->ctrl_dst = dst->next;
00087 else
00088 prev->next = dst->next;
00089 os_free(dst);
00090 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
00091 (u8 *) from->sun_path,
00092 fromlen -
00093 offsetof(struct sockaddr_un, sun_path));
00094 return 0;
00095 }
00096 prev = dst;
00097 dst = dst->next;
00098 }
00099 return -1;
00100 }
00101
00102
00103 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
00104 struct sockaddr_un *from,
00105 socklen_t fromlen,
00106 char *level)
00107 {
00108 struct wpa_ctrl_dst *dst;
00109
00110 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
00111
00112 dst = hapd->ctrl_dst;
00113 while (dst) {
00114 if (fromlen == dst->addrlen &&
00115 os_memcmp(from->sun_path, dst->addr.sun_path,
00116 fromlen - offsetof(struct sockaddr_un, sun_path))
00117 == 0) {
00118 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
00119 "level", (u8 *) from->sun_path, fromlen -
00120 offsetof(struct sockaddr_un, sun_path));
00121 dst->debug_level = atoi(level);
00122 return 0;
00123 }
00124 dst = dst->next;
00125 }
00126
00127 return -1;
00128 }
00129
00130
00131 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
00132 const char *txtaddr)
00133 {
00134 u8 addr[ETH_ALEN];
00135 struct sta_info *sta;
00136
00137 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
00138
00139 if (hwaddr_aton(txtaddr, addr))
00140 return -1;
00141
00142 sta = ap_get_sta(hapd, addr);
00143 if (sta)
00144 return 0;
00145
00146 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
00147 "notification", MAC2STR(addr));
00148 sta = ap_sta_add(hapd, addr);
00149 if (sta == NULL)
00150 return -1;
00151
00152 hostapd_new_assoc_sta(hapd, sta, 0);
00153 return 0;
00154 }
00155
00156
00157 #ifdef CONFIG_IEEE80211W
00158 #ifdef NEED_AP_MLME
00159 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
00160 const char *txtaddr)
00161 {
00162 u8 addr[ETH_ALEN];
00163 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
00164
00165 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
00166
00167 if (hwaddr_aton(txtaddr, addr))
00168 return -1;
00169
00170 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
00171 ieee802_11_send_sa_query_req(hapd, addr, trans_id);
00172
00173 return 0;
00174 }
00175 #endif
00176 #endif
00177
00178
00179 #ifdef CONFIG_WPS
00180 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
00181 {
00182 char *pin = os_strchr(txt, ' ');
00183 char *timeout_txt;
00184 int timeout;
00185
00186 if (pin == NULL)
00187 return -1;
00188 *pin++ = '\0';
00189
00190 timeout_txt = os_strchr(pin, ' ');
00191 if (timeout_txt) {
00192 *timeout_txt++ = '\0';
00193 timeout = atoi(timeout_txt);
00194 } else
00195 timeout = 0;
00196
00197 return hostapd_wps_add_pin(hapd, txt, pin, timeout);
00198 }
00199
00200
00201 #ifdef CONFIG_WPS_OOB
00202 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
00203 {
00204 char *path, *method, *name;
00205
00206 path = os_strchr(txt, ' ');
00207 if (path == NULL)
00208 return -1;
00209 *path++ = '\0';
00210
00211 method = os_strchr(path, ' ');
00212 if (method == NULL)
00213 return -1;
00214 *method++ = '\0';
00215
00216 name = os_strchr(method, ' ');
00217 if (name != NULL)
00218 *name++ = '\0';
00219
00220 return hostapd_wps_start_oob(hapd, txt, path, method, name);
00221 }
00222 #endif
00223 #endif
00224
00225
00226 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
00227 void *sock_ctx)
00228 {
00229 struct hostapd_data *hapd = eloop_ctx;
00230 char buf[256];
00231 int res;
00232 struct sockaddr_un from;
00233 socklen_t fromlen = sizeof(from);
00234 char *reply;
00235 const int reply_size = 4096;
00236 int reply_len;
00237
00238 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
00239 (struct sockaddr *) &from, &fromlen);
00240 if (res < 0) {
00241 perror("recvfrom(ctrl_iface)");
00242 return;
00243 }
00244 buf[res] = '\0';
00245 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
00246
00247 reply = os_malloc(reply_size);
00248 if (reply == NULL) {
00249 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
00250 fromlen);
00251 return;
00252 }
00253
00254 os_memcpy(reply, "OK\n", 3);
00255 reply_len = 3;
00256
00257 if (os_strcmp(buf, "PING") == 0) {
00258 os_memcpy(reply, "PONG\n", 5);
00259 reply_len = 5;
00260 } else if (os_strcmp(buf, "MIB") == 0) {
00261 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
00262 if (reply_len >= 0) {
00263 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
00264 reply_size - reply_len);
00265 if (res < 0)
00266 reply_len = -1;
00267 else
00268 reply_len += res;
00269 }
00270 if (reply_len >= 0) {
00271 res = ieee802_1x_get_mib(hapd, reply + reply_len,
00272 reply_size - reply_len);
00273 if (res < 0)
00274 reply_len = -1;
00275 else
00276 reply_len += res;
00277 }
00278 if (reply_len >= 0) {
00279 res = radius_client_get_mib(hapd->radius,
00280 reply + reply_len,
00281 reply_size - reply_len);
00282 if (res < 0)
00283 reply_len = -1;
00284 else
00285 reply_len += res;
00286 }
00287 } else if (os_strcmp(buf, "STA-FIRST") == 0) {
00288 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
00289 reply_size);
00290 } else if (os_strncmp(buf, "STA ", 4) == 0) {
00291 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
00292 reply_size);
00293 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
00294 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
00295 reply_size);
00296 } else if (os_strcmp(buf, "ATTACH") == 0) {
00297 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
00298 reply_len = -1;
00299 } else if (os_strcmp(buf, "DETACH") == 0) {
00300 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
00301 reply_len = -1;
00302 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
00303 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
00304 buf + 6))
00305 reply_len = -1;
00306 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
00307 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
00308 reply_len = -1;
00309 #ifdef CONFIG_IEEE80211W
00310 #ifdef NEED_AP_MLME
00311 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
00312 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
00313 reply_len = -1;
00314 #endif
00315 #endif
00316 #ifdef CONFIG_WPS
00317 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
00318 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
00319 reply_len = -1;
00320 } else if (os_strcmp(buf, "WPS_PBC") == 0) {
00321 if (hostapd_wps_button_pushed(hapd))
00322 reply_len = -1;
00323 #ifdef CONFIG_WPS_OOB
00324 } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
00325 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
00326 reply_len = -1;
00327 #endif
00328 #endif
00329 } else {
00330 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
00331 reply_len = 16;
00332 }
00333
00334 if (reply_len < 0) {
00335 os_memcpy(reply, "FAIL\n", 5);
00336 reply_len = 5;
00337 }
00338 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
00339 os_free(reply);
00340 }
00341
00342
00343 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
00344 {
00345 char *buf;
00346 size_t len;
00347
00348 if (hapd->conf->ctrl_interface == NULL)
00349 return NULL;
00350
00351 len = os_strlen(hapd->conf->ctrl_interface) +
00352 os_strlen(hapd->conf->iface) + 2;
00353 buf = os_malloc(len);
00354 if (buf == NULL)
00355 return NULL;
00356
00357 os_snprintf(buf, len, "%s/%s",
00358 hapd->conf->ctrl_interface, hapd->conf->iface);
00359 buf[len - 1] = '\0';
00360 return buf;
00361 }
00362
00363
00364 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
00365 const char *txt, size_t len)
00366 {
00367 struct hostapd_data *hapd = ctx;
00368 if (hapd == NULL)
00369 return;
00370 hostapd_ctrl_iface_send(hapd, level, txt, len);
00371 }
00372
00373
00374 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
00375 {
00376 struct sockaddr_un addr;
00377 int s = -1;
00378 char *fname = NULL;
00379
00380 hapd->ctrl_sock = -1;
00381
00382 if (hapd->conf->ctrl_interface == NULL)
00383 return 0;
00384
00385 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
00386 if (errno == EEXIST) {
00387 wpa_printf(MSG_DEBUG, "Using existing control "
00388 "interface directory.");
00389 } else {
00390 perror("mkdir[ctrl_interface]");
00391 goto fail;
00392 }
00393 }
00394
00395 if (hapd->conf->ctrl_interface_gid_set &&
00396 chown(hapd->conf->ctrl_interface, 0,
00397 hapd->conf->ctrl_interface_gid) < 0) {
00398 perror("chown[ctrl_interface]");
00399 return -1;
00400 }
00401
00402 if (os_strlen(hapd->conf->ctrl_interface) + 1 +
00403 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
00404 goto fail;
00405
00406 s = socket(PF_UNIX, SOCK_DGRAM, 0);
00407 if (s < 0) {
00408 perror("socket(PF_UNIX)");
00409 goto fail;
00410 }
00411
00412 os_memset(&addr, 0, sizeof(addr));
00413 #ifdef __FreeBSD__
00414 addr.sun_len = sizeof(addr);
00415 #endif
00416 addr.sun_family = AF_UNIX;
00417 fname = hostapd_ctrl_iface_path(hapd);
00418 if (fname == NULL)
00419 goto fail;
00420 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
00421 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00422 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
00423 strerror(errno));
00424 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00425 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
00426 " allow connections - assuming it was left"
00427 "over from forced program termination");
00428 if (unlink(fname) < 0) {
00429 perror("unlink[ctrl_iface]");
00430 wpa_printf(MSG_ERROR, "Could not unlink "
00431 "existing ctrl_iface socket '%s'",
00432 fname);
00433 goto fail;
00434 }
00435 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
00436 0) {
00437 perror("bind(PF_UNIX)");
00438 goto fail;
00439 }
00440 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
00441 "ctrl_iface socket '%s'", fname);
00442 } else {
00443 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
00444 "be in use - cannot override it");
00445 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
00446 "not used anymore", fname);
00447 os_free(fname);
00448 fname = NULL;
00449 goto fail;
00450 }
00451 }
00452
00453 if (hapd->conf->ctrl_interface_gid_set &&
00454 chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
00455 perror("chown[ctrl_interface/ifname]");
00456 goto fail;
00457 }
00458
00459 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
00460 perror("chmod[ctrl_interface/ifname]");
00461 goto fail;
00462 }
00463 os_free(fname);
00464
00465 hapd->ctrl_sock = s;
00466 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
00467 NULL);
00468 hapd->msg_ctx = hapd;
00469 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
00470
00471 return 0;
00472
00473 fail:
00474 if (s >= 0)
00475 close(s);
00476 if (fname) {
00477 unlink(fname);
00478 os_free(fname);
00479 }
00480 return -1;
00481 }
00482
00483
00484 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
00485 {
00486 struct wpa_ctrl_dst *dst, *prev;
00487
00488 if (hapd->ctrl_sock > -1) {
00489 char *fname;
00490 eloop_unregister_read_sock(hapd->ctrl_sock);
00491 close(hapd->ctrl_sock);
00492 hapd->ctrl_sock = -1;
00493 fname = hostapd_ctrl_iface_path(hapd);
00494 if (fname)
00495 unlink(fname);
00496 os_free(fname);
00497
00498 if (hapd->conf->ctrl_interface &&
00499 rmdir(hapd->conf->ctrl_interface) < 0) {
00500 if (errno == ENOTEMPTY) {
00501 wpa_printf(MSG_DEBUG, "Control interface "
00502 "directory not empty - leaving it "
00503 "behind");
00504 } else {
00505 perror("rmdir[ctrl_interface]");
00506 }
00507 }
00508 }
00509
00510 dst = hapd->ctrl_dst;
00511 while (dst) {
00512 prev = dst;
00513 dst = dst->next;
00514 os_free(prev);
00515 }
00516 }
00517
00518
00519 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
00520 const char *buf, size_t len)
00521 {
00522 struct wpa_ctrl_dst *dst, *next;
00523 struct msghdr msg;
00524 int idx;
00525 struct iovec io[2];
00526 char levelstr[10];
00527
00528 dst = hapd->ctrl_dst;
00529 if (hapd->ctrl_sock < 0 || dst == NULL)
00530 return;
00531
00532 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
00533 io[0].iov_base = levelstr;
00534 io[0].iov_len = os_strlen(levelstr);
00535 io[1].iov_base = (char *) buf;
00536 io[1].iov_len = len;
00537 os_memset(&msg, 0, sizeof(msg));
00538 msg.msg_iov = io;
00539 msg.msg_iovlen = 2;
00540
00541 idx = 0;
00542 while (dst) {
00543 next = dst->next;
00544 if (level >= dst->debug_level) {
00545 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
00546 (u8 *) dst->addr.sun_path, dst->addrlen -
00547 offsetof(struct sockaddr_un, sun_path));
00548 msg.msg_name = &dst->addr;
00549 msg.msg_namelen = dst->addrlen;
00550 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
00551 int _errno = errno;
00552 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
00553 "%d - %s",
00554 idx, errno, strerror(errno));
00555 dst->errors++;
00556 if (dst->errors > 10 || _errno == ENOENT) {
00557 hostapd_ctrl_iface_detach(
00558 hapd, &dst->addr,
00559 dst->addrlen);
00560 }
00561 } else
00562 dst->errors = 0;
00563 }
00564 idx++;
00565 dst = next;
00566 }
00567 }
00568
00569 #endif
00570