wpa_ctrl.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
1/* 2 * wpa_supplicant/hostapd control interface library 3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#ifdef CONFIG_CTRL_IFACE 12 13#ifdef CONFIG_CTRL_IFACE_UNIX 14#include <sys/un.h> 15#endif /* CONFIG_CTRL_IFACE_UNIX */ 16 17#ifdef ANDROID 18#include <dirent.h> 19#include <cutils/sockets.h> 20#include "private/android_filesystem_config.h" 21#endif /* ANDROID */ 22 23#include "wpa_ctrl.h" 24#include "common.h" 25 26 27#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 28#define CTRL_IFACE_SOCKET 29#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 30 31 32/** 33 * struct wpa_ctrl - Internal structure for control interface library 34 * 35 * This structure is used by the wpa_supplicant/hostapd control interface 36 * library to store internal data. Programs using the library should not touch 37 * this data directly. They can only use the pointer to the data structure as 38 * an identifier for the control interface connection and use this as one of 39 * the arguments for most of the control interface library functions. 40 */ 41struct wpa_ctrl { 42#ifdef CONFIG_CTRL_IFACE_UDP 43 int s; 44 struct sockaddr_in local; 45 struct sockaddr_in dest; 46 char *cookie; 47#endif /* CONFIG_CTRL_IFACE_UDP */ 48#ifdef CONFIG_CTRL_IFACE_UNIX 49 int s; 50 struct sockaddr_un local; 51 struct sockaddr_un dest; 52#endif /* CONFIG_CTRL_IFACE_UNIX */ 53#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 54 HANDLE pipe; 55#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 56}; 57 58 59#ifdef CONFIG_CTRL_IFACE_UNIX 60 61#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR 62#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" 63#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ 64#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX 65#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" 66#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ 67 68 69struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 70{ 71 struct wpa_ctrl *ctrl; 72 static int counter = 0; 73 int ret; 74 size_t res; 75 int tries = 0; 76 77 ctrl = os_malloc(sizeof(*ctrl)); 78 if (ctrl == NULL) 79 return NULL; 80 os_memset(ctrl, 0, sizeof(*ctrl)); 81 82 ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 83 if (ctrl->s < 0) { 84 os_free(ctrl); 85 return NULL; 86 } 87 88 ctrl->local.sun_family = AF_UNIX; 89 counter++; 90try_again: 91 ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), 92 CONFIG_CTRL_IFACE_CLIENT_DIR "/" 93 CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 94 (int) getpid(), counter); 95 if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { 96 close(ctrl->s); 97 os_free(ctrl); 98 return NULL; 99 } 100 tries++; 101 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 102 sizeof(ctrl->local)) < 0) { 103 if (errno == EADDRINUSE && tries < 2) { 104 /* 105 * getpid() returns unique identifier for this instance 106 * of wpa_ctrl, so the existing socket file must have 107 * been left by unclean termination of an earlier run. 108 * Remove the file and try again. 109 */ 110 unlink(ctrl->local.sun_path); 111 goto try_again; 112 } 113 close(ctrl->s); 114 os_free(ctrl); 115 return NULL; 116 } 117 118#ifdef ANDROID 119 chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 120 chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); 121 /* 122 * If the ctrl_path isn't an absolute pathname, assume that 123 * it's the name of a socket in the Android reserved namespace. 124 * Otherwise, it's a normal UNIX domain socket appearing in the 125 * filesystem. 126 */ 127 if (ctrl_path != NULL && *ctrl_path != '/') { 128 char buf[21]; 129 os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); 130 if (socket_local_client_connect( 131 ctrl->s, buf, 132 ANDROID_SOCKET_NAMESPACE_RESERVED, 133 SOCK_DGRAM) < 0) { 134 close(ctrl->s); 135 unlink(ctrl->local.sun_path); 136 os_free(ctrl); 137 return NULL; 138 } 139 return ctrl; 140 } 141#endif /* ANDROID */ 142 143 ctrl->dest.sun_family = AF_UNIX; 144 res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 145 sizeof(ctrl->dest.sun_path)); 146 if (res >= sizeof(ctrl->dest.sun_path)) { 147 close(ctrl->s); 148 os_free(ctrl); 149 return NULL; 150 } 151 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 152 sizeof(ctrl->dest)) < 0) { 153 close(ctrl->s); 154 unlink(ctrl->local.sun_path); 155 os_free(ctrl); 156 return NULL; 157 } 158 159 return ctrl; 160} 161 162 163void wpa_ctrl_close(struct wpa_ctrl *ctrl) 164{ 165 if (ctrl == NULL) 166 return; 167 unlink(ctrl->local.sun_path); 168 if (ctrl->s >= 0) 169 close(ctrl->s); 170 os_free(ctrl); 171} 172 173 174#ifdef ANDROID 175/** 176 * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 177 * may be left over from clients that were previously connected to 178 * wpa_supplicant. This keeps these files from being orphaned in the 179 * event of crashes that prevented them from being removed as part 180 * of the normal orderly shutdown. 181 */ 182void wpa_ctrl_cleanup(void) 183{ 184 DIR *dir; 185 struct dirent entry; 186 struct dirent *result; 187 size_t dirnamelen; 188 int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX); 189 size_t maxcopy; 190 char pathname[PATH_MAX]; 191 char *namep; 192 193 if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL) 194 return; 195 196 dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/", 197 CONFIG_CTRL_IFACE_CLIENT_DIR); 198 if (dirnamelen >= sizeof(pathname)) { 199 closedir(dir); 200 return; 201 } 202 namep = pathname + dirnamelen; 203 maxcopy = PATH_MAX - dirnamelen; 204 while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 205 if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX, 206 prefixlen) == 0) { 207 if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) 208 unlink(pathname); 209 } 210 } 211 closedir(dir); 212} 213#endif /* ANDROID */ 214 215#else /* CONFIG_CTRL_IFACE_UNIX */ 216 217#ifdef ANDROID 218void wpa_ctrl_cleanup(void) 219{ 220} 221#endif /* ANDROID */ 222 223#endif /* CONFIG_CTRL_IFACE_UNIX */ 224 225 226#ifdef CONFIG_CTRL_IFACE_UDP 227 228struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 229{ 230 struct wpa_ctrl *ctrl; 231 char buf[128]; 232 size_t len; 233 234 ctrl = os_malloc(sizeof(*ctrl)); 235 if (ctrl == NULL) 236 return NULL; 237 os_memset(ctrl, 0, sizeof(*ctrl)); 238 239 ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 240 if (ctrl->s < 0) { 241 perror("socket"); 242 os_free(ctrl); 243 return NULL; 244 } 245 246 ctrl->local.sin_family = AF_INET; 247 ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 248 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 249 sizeof(ctrl->local)) < 0) { 250 close(ctrl->s); 251 os_free(ctrl); 252 return NULL; 253 } 254 255 ctrl->dest.sin_family = AF_INET; 256 ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 257 ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 258 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 259 sizeof(ctrl->dest)) < 0) { 260 perror("connect"); 261 close(ctrl->s); 262 os_free(ctrl); 263 return NULL; 264 } 265 266 len = sizeof(buf) - 1; 267 if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 268 buf[len] = '\0'; 269 ctrl->cookie = os_strdup(buf); 270 } 271 272 return ctrl; 273} 274 275 276void wpa_ctrl_close(struct wpa_ctrl *ctrl) 277{ 278 close(ctrl->s); 279 os_free(ctrl->cookie); 280 os_free(ctrl); 281} 282 283#endif /* CONFIG_CTRL_IFACE_UDP */ 284 285 286#ifdef CTRL_IFACE_SOCKET 287int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 288 char *reply, size_t *reply_len, 289 void (*msg_cb)(char *msg, size_t len)) 290{ 291 struct timeval tv; 292 int res; 293 fd_set rfds; 294 const char *_cmd; 295 char *cmd_buf = NULL; 296 size_t _cmd_len; 297 298#ifdef CONFIG_CTRL_IFACE_UDP 299 if (ctrl->cookie) { 300 char *pos; 301 _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 302 cmd_buf = os_malloc(_cmd_len); 303 if (cmd_buf == NULL) 304 return -1; 305 _cmd = cmd_buf; 306 pos = cmd_buf; 307 os_strlcpy(pos, ctrl->cookie, _cmd_len); 308 pos += os_strlen(ctrl->cookie); 309 *pos++ = ' '; 310 os_memcpy(pos, cmd, cmd_len); 311 } else 312#endif /* CONFIG_CTRL_IFACE_UDP */ 313 { 314 _cmd = cmd; 315 _cmd_len = cmd_len; 316 } 317 318 if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 319 os_free(cmd_buf); 320 return -1; 321 } 322 os_free(cmd_buf); 323 324 for (;;) { 325 tv.tv_sec = 10; 326 tv.tv_usec = 0; 327 FD_ZERO(&rfds); 328 FD_SET(ctrl->s, &rfds); 329 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 330 if (res < 0) 331 return res; 332 if (FD_ISSET(ctrl->s, &rfds)) { 333 res = recv(ctrl->s, reply, *reply_len, 0); 334 if (res < 0) 335 return res; 336 if (res > 0 && reply[0] == '<') { 337 /* This is an unsolicited message from 338 * wpa_supplicant, not the reply to the 339 * request. Use msg_cb to report this to the 340 * caller. */ 341 if (msg_cb) { 342 /* Make sure the message is nul 343 * terminated. */ 344 if ((size_t) res == *reply_len) 345 res = (*reply_len) - 1; 346 reply[res] = '\0'; 347 msg_cb(reply, res); 348 } 349 continue; 350 } 351 *reply_len = res; 352 break; 353 } else { 354 return -2; 355 } 356 } 357 return 0; 358} 359#endif /* CTRL_IFACE_SOCKET */ 360 361 362static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 363{ 364 char buf[10]; 365 int ret; 366 size_t len = 10; 367 368 ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 369 buf, &len, NULL); 370 if (ret < 0) 371 return ret; 372 if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 373 return 0; 374 return -1; 375} 376 377 378int wpa_ctrl_attach(struct wpa_ctrl *ctrl) 379{ 380 return wpa_ctrl_attach_helper(ctrl, 1); 381} 382 383 384int wpa_ctrl_detach(struct wpa_ctrl *ctrl) 385{ 386 return wpa_ctrl_attach_helper(ctrl, 0); 387} 388 389 390#ifdef CTRL_IFACE_SOCKET 391 392int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 393{ 394 int res; 395 396 res = recv(ctrl->s, reply, *reply_len, 0); 397 if (res < 0) 398 return res; 399 *reply_len = res; 400 return 0; 401} 402 403 404int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 405{ 406 struct timeval tv; 407 fd_set rfds; 408 tv.tv_sec = 0; 409 tv.tv_usec = 0; 410 FD_ZERO(&rfds); 411 FD_SET(ctrl->s, &rfds); 412 select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 413 return FD_ISSET(ctrl->s, &rfds); 414} 415 416 417int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 418{ 419 return ctrl->s; 420} 421 422#endif /* CTRL_IFACE_SOCKET */ 423 424 425#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 426 427#ifndef WPA_SUPPLICANT_NAMED_PIPE 428#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 429#endif 430#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 431 432struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 433{ 434 struct wpa_ctrl *ctrl; 435 DWORD mode; 436 TCHAR name[256]; 437 int i, ret; 438 439 ctrl = os_malloc(sizeof(*ctrl)); 440 if (ctrl == NULL) 441 return NULL; 442 os_memset(ctrl, 0, sizeof(*ctrl)); 443 444#ifdef UNICODE 445 if (ctrl_path == NULL) 446 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 447 else 448 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 449 ctrl_path); 450#else /* UNICODE */ 451 if (ctrl_path == NULL) 452 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 453 else 454 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 455 ctrl_path); 456#endif /* UNICODE */ 457 if (ret < 0 || ret >= 256) { 458 os_free(ctrl); 459 return NULL; 460 } 461 462 for (i = 0; i < 10; i++) { 463 ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 464 NULL, OPEN_EXISTING, 0, NULL); 465 /* 466 * Current named pipe server side in wpa_supplicant is 467 * re-opening the pipe for new clients only after the previous 468 * one is taken into use. This leaves a small window for race 469 * conditions when two connections are being opened at almost 470 * the same time. Retry if that was the case. 471 */ 472 if (ctrl->pipe != INVALID_HANDLE_VALUE || 473 GetLastError() != ERROR_PIPE_BUSY) 474 break; 475 WaitNamedPipe(name, 1000); 476 } 477 if (ctrl->pipe == INVALID_HANDLE_VALUE) { 478 os_free(ctrl); 479 return NULL; 480 } 481 482 mode = PIPE_READMODE_MESSAGE; 483 if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 484 CloseHandle(ctrl->pipe); 485 os_free(ctrl); 486 return NULL; 487 } 488 489 return ctrl; 490} 491 492 493void wpa_ctrl_close(struct wpa_ctrl *ctrl) 494{ 495 CloseHandle(ctrl->pipe); 496 os_free(ctrl); 497} 498 499 500int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 501 char *reply, size_t *reply_len, 502 void (*msg_cb)(char *msg, size_t len)) 503{ 504 DWORD written; 505 DWORD readlen = *reply_len; 506 507 if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 508 return -1; 509 510 if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 511 return -1; 512 *reply_len = readlen; 513 514 return 0; 515} 516 517 518int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 519{ 520 DWORD len = *reply_len; 521 if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 522 return -1; 523 *reply_len = len; 524 return 0; 525} 526 527 528int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 529{ 530 DWORD left; 531 532 if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 533 return -1; 534 return left ? 1 : 0; 535} 536 537 538int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 539{ 540 return -1; 541} 542 543#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 544 545#endif /* CONFIG_CTRL_IFACE */ 546