1 /* 2 * hostapd / UNIX domain socket -based control interface 3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4 * 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. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #ifndef CONFIG_NATIVE_WINDOWS 18 19 #include <sys/un.h> 20 #include <sys/stat.h> 21 22 #include "hostapd.h" 23 #include "eloop.h" 24 #include "config.h" 25 #include "ieee802_1x.h" 26 #include "wpa.h" 27 #include "radius/radius_client.h" 28 #include "ieee802_11.h" 29 #include "ctrl_iface.h" 30 #include "sta_info.h" 31 #include "accounting.h" 32 #include "wps_hostapd.h" 33 34 35 struct wpa_ctrl_dst { 36 struct wpa_ctrl_dst *next; 37 struct sockaddr_un addr; 38 socklen_t addrlen; 39 int debug_level; 40 int errors; 41 }; 42 43 44 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 45 const char *buf, size_t len); 46 47 48 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, 49 struct sockaddr_un *from, 50 socklen_t fromlen) 51 { 52 struct wpa_ctrl_dst *dst; 53 54 dst = os_zalloc(sizeof(*dst)); 55 if (dst == NULL) 56 return -1; 57 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 58 dst->addrlen = fromlen; 59 dst->debug_level = MSG_INFO; 60 dst->next = hapd->ctrl_dst; 61 hapd->ctrl_dst = dst; 62 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 63 (u8 *) from->sun_path, fromlen); 64 return 0; 65 } 66 67 68 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, 69 struct sockaddr_un *from, 70 socklen_t fromlen) 71 { 72 struct wpa_ctrl_dst *dst, *prev = NULL; 73 74 dst = hapd->ctrl_dst; 75 while (dst) { 76 if (fromlen == dst->addrlen && 77 os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 78 0) { 79 if (prev == NULL) 80 hapd->ctrl_dst = dst->next; 81 else 82 prev->next = dst->next; 83 os_free(dst); 84 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 85 (u8 *) from->sun_path, fromlen); 86 return 0; 87 } 88 prev = dst; 89 dst = dst->next; 90 } 91 return -1; 92 } 93 94 95 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, 96 struct sockaddr_un *from, 97 socklen_t fromlen, 98 char *level) 99 { 100 struct wpa_ctrl_dst *dst; 101 102 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 103 104 dst = hapd->ctrl_dst; 105 while (dst) { 106 if (fromlen == dst->addrlen && 107 os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 108 0) { 109 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 110 "level", (u8 *) from->sun_path, fromlen); 111 dst->debug_level = atoi(level); 112 return 0; 113 } 114 dst = dst->next; 115 } 116 117 return -1; 118 } 119 120 121 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, 122 struct sta_info *sta, 123 char *buf, size_t buflen) 124 { 125 int len, res, ret; 126 127 if (sta == NULL) { 128 ret = os_snprintf(buf, buflen, "FAIL\n"); 129 if (ret < 0 || (size_t) ret >= buflen) 130 return 0; 131 return ret; 132 } 133 134 len = 0; 135 ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", 136 MAC2STR(sta->addr)); 137 if (ret < 0 || (size_t) ret >= buflen - len) 138 return len; 139 len += ret; 140 141 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); 142 if (res >= 0) 143 len += res; 144 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); 145 if (res >= 0) 146 len += res; 147 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); 148 if (res >= 0) 149 len += res; 150 151 return len; 152 } 153 154 155 static int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, 156 char *buf, size_t buflen) 157 { 158 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); 159 } 160 161 162 static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, 163 const char *txtaddr, 164 char *buf, size_t buflen) 165 { 166 u8 addr[ETH_ALEN]; 167 int ret; 168 169 if (hwaddr_aton(txtaddr, addr)) { 170 ret = os_snprintf(buf, buflen, "FAIL\n"); 171 if (ret < 0 || (size_t) ret >= buflen) 172 return 0; 173 return ret; 174 } 175 return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), 176 buf, buflen); 177 } 178 179 180 static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, 181 const char *txtaddr, 182 char *buf, size_t buflen) 183 { 184 u8 addr[ETH_ALEN]; 185 struct sta_info *sta; 186 int ret; 187 188 if (hwaddr_aton(txtaddr, addr) || 189 (sta = ap_get_sta(hapd, addr)) == NULL) { 190 ret = os_snprintf(buf, buflen, "FAIL\n"); 191 if (ret < 0 || (size_t) ret >= buflen) 192 return 0; 193 return ret; 194 } 195 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); 196 } 197 198 199 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, 200 const char *txtaddr) 201 { 202 u8 addr[ETH_ALEN]; 203 struct sta_info *sta; 204 205 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); 206 207 if (hwaddr_aton(txtaddr, addr)) 208 return -1; 209 210 sta = ap_get_sta(hapd, addr); 211 if (sta) 212 return 0; 213 214 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " 215 "notification", MAC2STR(addr)); 216 sta = ap_sta_add(hapd, addr); 217 if (sta == NULL) 218 return -1; 219 220 hostapd_new_assoc_sta(hapd, sta, 0); 221 return 0; 222 } 223 224 225 #ifdef CONFIG_IEEE80211W 226 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, 227 const char *txtaddr) 228 { 229 u8 addr[ETH_ALEN]; 230 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; 231 232 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); 233 234 if (hwaddr_aton(txtaddr, addr)) 235 return -1; 236 237 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN); 238 ieee802_11_send_sa_query_req(hapd, addr, trans_id); 239 240 return 0; 241 } 242 #endif /* CONFIG_IEEE80211W */ 243 244 245 #ifdef CONFIG_WPS 246 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) 247 { 248 char *pin = os_strchr(txt, ' '); 249 if (pin == NULL) 250 return -1; 251 *pin++ = '\0'; 252 return hostapd_wps_add_pin(hapd, txt, pin); 253 } 254 #endif /* CONFIG_WPS */ 255 256 257 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 258 void *sock_ctx) 259 { 260 struct hostapd_data *hapd = eloop_ctx; 261 char buf[256]; 262 int res; 263 struct sockaddr_un from; 264 socklen_t fromlen = sizeof(from); 265 char *reply; 266 const int reply_size = 4096; 267 int reply_len; 268 269 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 270 (struct sockaddr *) &from, &fromlen); 271 if (res < 0) { 272 perror("recvfrom(ctrl_iface)"); 273 return; 274 } 275 buf[res] = '\0'; 276 wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res); 277 278 reply = os_malloc(reply_size); 279 if (reply == NULL) { 280 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 281 fromlen); 282 return; 283 } 284 285 os_memcpy(reply, "OK\n", 3); 286 reply_len = 3; 287 288 if (os_strcmp(buf, "PING") == 0) { 289 os_memcpy(reply, "PONG\n", 5); 290 reply_len = 5; 291 } else if (os_strcmp(buf, "MIB") == 0) { 292 reply_len = ieee802_11_get_mib(hapd, reply, reply_size); 293 if (reply_len >= 0) { 294 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, 295 reply_size - reply_len); 296 if (res < 0) 297 reply_len = -1; 298 else 299 reply_len += res; 300 } 301 if (reply_len >= 0) { 302 res = ieee802_1x_get_mib(hapd, reply + reply_len, 303 reply_size - reply_len); 304 if (res < 0) 305 reply_len = -1; 306 else 307 reply_len += res; 308 } 309 if (reply_len >= 0) { 310 res = radius_client_get_mib(hapd->radius, 311 reply + reply_len, 312 reply_size - reply_len); 313 if (res < 0) 314 reply_len = -1; 315 else 316 reply_len += res; 317 } 318 } else if (os_strcmp(buf, "STA-FIRST") == 0) { 319 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, 320 reply_size); 321 } else if (os_strncmp(buf, "STA ", 4) == 0) { 322 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, 323 reply_size); 324 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 325 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, 326 reply_size); 327 } else if (os_strcmp(buf, "ATTACH") == 0) { 328 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) 329 reply_len = -1; 330 } else if (os_strcmp(buf, "DETACH") == 0) { 331 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) 332 reply_len = -1; 333 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 334 if (hostapd_ctrl_iface_level(hapd, &from, fromlen, 335 buf + 6)) 336 reply_len = -1; 337 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { 338 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) 339 reply_len = -1; 340 #ifdef CONFIG_IEEE80211W 341 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { 342 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) 343 reply_len = -1; 344 #endif /* CONFIG_IEEE80211W */ 345 #ifdef CONFIG_WPS 346 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 347 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) 348 reply_len = -1; 349 } else if (os_strcmp(buf, "WPS_PBC") == 0) { 350 if (hostapd_wps_button_pushed(hapd)) 351 reply_len = -1; 352 #endif /* CONFIG_WPS */ 353 } else { 354 os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 355 reply_len = 16; 356 } 357 358 if (reply_len < 0) { 359 os_memcpy(reply, "FAIL\n", 5); 360 reply_len = 5; 361 } 362 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 363 os_free(reply); 364 } 365 366 367 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) 368 { 369 char *buf; 370 size_t len; 371 372 if (hapd->conf->ctrl_interface == NULL) 373 return NULL; 374 375 len = os_strlen(hapd->conf->ctrl_interface) + 376 os_strlen(hapd->conf->iface) + 2; 377 buf = os_malloc(len); 378 if (buf == NULL) 379 return NULL; 380 381 os_snprintf(buf, len, "%s/%s", 382 hapd->conf->ctrl_interface, hapd->conf->iface); 383 buf[len - 1] = '\0'; 384 return buf; 385 } 386 387 388 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, 389 const char *txt, size_t len) 390 { 391 struct hostapd_data *hapd = ctx; 392 if (hapd == NULL) 393 return; 394 hostapd_ctrl_iface_send(hapd, level, txt, len); 395 } 396 397 398 int hostapd_ctrl_iface_init(struct hostapd_data *hapd) 399 { 400 struct sockaddr_un addr; 401 int s = -1; 402 char *fname = NULL; 403 404 hapd->ctrl_sock = -1; 405 406 if (hapd->conf->ctrl_interface == NULL) 407 return 0; 408 409 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 410 if (errno == EEXIST) { 411 wpa_printf(MSG_DEBUG, "Using existing control " 412 "interface directory."); 413 } else { 414 perror("mkdir[ctrl_interface]"); 415 goto fail; 416 } 417 } 418 419 if (hapd->conf->ctrl_interface_gid_set && 420 chown(hapd->conf->ctrl_interface, 0, 421 hapd->conf->ctrl_interface_gid) < 0) { 422 perror("chown[ctrl_interface]"); 423 return -1; 424 } 425 426 if (os_strlen(hapd->conf->ctrl_interface) + 1 + 427 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) 428 goto fail; 429 430 s = socket(PF_UNIX, SOCK_DGRAM, 0); 431 if (s < 0) { 432 perror("socket(PF_UNIX)"); 433 goto fail; 434 } 435 436 os_memset(&addr, 0, sizeof(addr)); 437 addr.sun_family = AF_UNIX; 438 fname = hostapd_ctrl_iface_path(hapd); 439 if (fname == NULL) 440 goto fail; 441 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 442 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 443 perror("bind(PF_UNIX)"); 444 goto fail; 445 } 446 447 if (hapd->conf->ctrl_interface_gid_set && 448 chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) { 449 perror("chown[ctrl_interface/ifname]"); 450 goto fail; 451 } 452 453 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 454 perror("chmod[ctrl_interface/ifname]"); 455 goto fail; 456 } 457 os_free(fname); 458 459 hapd->ctrl_sock = s; 460 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, 461 NULL); 462 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); 463 464 return 0; 465 466 fail: 467 if (s >= 0) 468 close(s); 469 if (fname) { 470 unlink(fname); 471 os_free(fname); 472 } 473 return -1; 474 } 475 476 477 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) 478 { 479 struct wpa_ctrl_dst *dst, *prev; 480 481 if (hapd->ctrl_sock > -1) { 482 char *fname; 483 eloop_unregister_read_sock(hapd->ctrl_sock); 484 close(hapd->ctrl_sock); 485 hapd->ctrl_sock = -1; 486 fname = hostapd_ctrl_iface_path(hapd); 487 if (fname) 488 unlink(fname); 489 os_free(fname); 490 491 if (hapd->conf->ctrl_interface && 492 rmdir(hapd->conf->ctrl_interface) < 0) { 493 if (errno == ENOTEMPTY) { 494 wpa_printf(MSG_DEBUG, "Control interface " 495 "directory not empty - leaving it " 496 "behind"); 497 } else { 498 perror("rmdir[ctrl_interface]"); 499 } 500 } 501 } 502 503 dst = hapd->ctrl_dst; 504 while (dst) { 505 prev = dst; 506 dst = dst->next; 507 os_free(prev); 508 } 509 } 510 511 512 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 513 const char *buf, size_t len) 514 { 515 struct wpa_ctrl_dst *dst, *next; 516 struct msghdr msg; 517 int idx; 518 struct iovec io[2]; 519 char levelstr[10]; 520 521 dst = hapd->ctrl_dst; 522 if (hapd->ctrl_sock < 0 || dst == NULL) 523 return; 524 525 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 526 io[0].iov_base = levelstr; 527 io[0].iov_len = os_strlen(levelstr); 528 io[1].iov_base = (char *) buf; 529 io[1].iov_len = len; 530 os_memset(&msg, 0, sizeof(msg)); 531 msg.msg_iov = io; 532 msg.msg_iovlen = 2; 533 534 idx = 0; 535 while (dst) { 536 next = dst->next; 537 if (level >= dst->debug_level) { 538 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 539 (u8 *) dst->addr.sun_path, dst->addrlen); 540 msg.msg_name = &dst->addr; 541 msg.msg_namelen = dst->addrlen; 542 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { 543 fprintf(stderr, "CTRL_IFACE monitor[%d]: ", 544 idx); 545 perror("sendmsg"); 546 dst->errors++; 547 if (dst->errors > 10) { 548 hostapd_ctrl_iface_detach( 549 hapd, &dst->addr, 550 dst->addrlen); 551 } 552 } else 553 dst->errors = 0; 554 } 555 idx++; 556 dst = next; 557 } 558 } 559 560 #endif /* CONFIG_NATIVE_WINDOWS */ 561