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#include <unistd.h> 16#include <fcntl.h> 17#endif /* CONFIG_CTRL_IFACE_UNIX */ 18#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 19#include <netdb.h> 20#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 21 22#ifdef ANDROID 23#include <dirent.h> 24#include <sys/stat.h> 25#include <cutils/sockets.h> 26#include "private/android_filesystem_config.h" 27#endif /* ANDROID */ 28 29#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 30#include <net/if.h> 31#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 32 33#include "wpa_ctrl.h" 34#include "common.h" 35 36 37#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 38#define CTRL_IFACE_SOCKET 39#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 40 41 42/** 43 * struct wpa_ctrl - Internal structure for control interface library 44 * 45 * This structure is used by the wpa_supplicant/hostapd control interface 46 * library to store internal data. Programs using the library should not touch 47 * this data directly. They can only use the pointer to the data structure as 48 * an identifier for the control interface connection and use this as one of 49 * the arguments for most of the control interface library functions. 50 */ 51struct wpa_ctrl { 52#ifdef CONFIG_CTRL_IFACE_UDP 53 int s; 54#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 55 struct sockaddr_in6 local; 56 struct sockaddr_in6 dest; 57#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 58 struct sockaddr_in local; 59 struct sockaddr_in dest; 60#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 61 char *cookie; 62 char *remote_ifname; 63 char *remote_ip; 64#endif /* CONFIG_CTRL_IFACE_UDP */ 65#ifdef CONFIG_CTRL_IFACE_UNIX 66 int s; 67 struct sockaddr_un local; 68 struct sockaddr_un dest; 69#endif /* CONFIG_CTRL_IFACE_UNIX */ 70#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 71 HANDLE pipe; 72#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 73}; 74 75 76#ifdef CONFIG_CTRL_IFACE_UNIX 77 78#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR 79#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" 80#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ 81#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX 82#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" 83#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ 84 85 86struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 87{ 88 return wpa_ctrl_open2(ctrl_path, NULL); 89} 90 91 92struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path, 93 const char *cli_path) 94{ 95 struct wpa_ctrl *ctrl; 96 static int counter = 0; 97 int ret; 98 size_t res; 99 int tries = 0; 100 int flags; 101 102 if (ctrl_path == NULL) 103 return NULL; 104 105 ctrl = os_zalloc(sizeof(*ctrl)); 106 if (ctrl == NULL) 107 return NULL; 108 109 ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 110 if (ctrl->s < 0) { 111 os_free(ctrl); 112 return NULL; 113 } 114 115 ctrl->local.sun_family = AF_UNIX; 116 counter++; 117try_again: 118 if (cli_path && cli_path[0] == '/') { 119 ret = os_snprintf(ctrl->local.sun_path, 120 sizeof(ctrl->local.sun_path), 121 "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 122 cli_path, (int) getpid(), counter); 123 } else { 124 ret = os_snprintf(ctrl->local.sun_path, 125 sizeof(ctrl->local.sun_path), 126 CONFIG_CTRL_IFACE_CLIENT_DIR "/" 127 CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 128 (int) getpid(), counter); 129 } 130 if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) { 131 close(ctrl->s); 132 os_free(ctrl); 133 return NULL; 134 } 135 tries++; 136 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 137 sizeof(ctrl->local)) < 0) { 138 if (errno == EADDRINUSE && tries < 2) { 139 /* 140 * getpid() returns unique identifier for this instance 141 * of wpa_ctrl, so the existing socket file must have 142 * been left by unclean termination of an earlier run. 143 * Remove the file and try again. 144 */ 145 unlink(ctrl->local.sun_path); 146 goto try_again; 147 } 148 close(ctrl->s); 149 os_free(ctrl); 150 return NULL; 151 } 152 153#ifdef ANDROID 154 chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 155 /* Set group even if we do not have privileges to change owner */ 156 chown(ctrl->local.sun_path, -1, AID_WIFI); 157 chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); 158 159 if (os_strncmp(ctrl_path, "@android:", 9) == 0) { 160 if (socket_local_client_connect( 161 ctrl->s, ctrl_path + 9, 162 ANDROID_SOCKET_NAMESPACE_RESERVED, 163 SOCK_DGRAM) < 0) { 164 close(ctrl->s); 165 unlink(ctrl->local.sun_path); 166 os_free(ctrl); 167 return NULL; 168 } 169 return ctrl; 170 } 171 172 /* 173 * If the ctrl_path isn't an absolute pathname, assume that 174 * it's the name of a socket in the Android reserved namespace. 175 * Otherwise, it's a normal UNIX domain socket appearing in the 176 * filesystem. 177 */ 178 if (*ctrl_path != '/') { 179 char buf[21]; 180 os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); 181 if (socket_local_client_connect( 182 ctrl->s, buf, 183 ANDROID_SOCKET_NAMESPACE_RESERVED, 184 SOCK_DGRAM) < 0) { 185 close(ctrl->s); 186 unlink(ctrl->local.sun_path); 187 os_free(ctrl); 188 return NULL; 189 } 190 return ctrl; 191 } 192#endif /* ANDROID */ 193 194 ctrl->dest.sun_family = AF_UNIX; 195 if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) { 196 ctrl->dest.sun_path[0] = '\0'; 197 os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10, 198 sizeof(ctrl->dest.sun_path) - 1); 199 } else { 200 res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 201 sizeof(ctrl->dest.sun_path)); 202 if (res >= sizeof(ctrl->dest.sun_path)) { 203 close(ctrl->s); 204 os_free(ctrl); 205 return NULL; 206 } 207 } 208 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 209 sizeof(ctrl->dest)) < 0) { 210 close(ctrl->s); 211 unlink(ctrl->local.sun_path); 212 os_free(ctrl); 213 return NULL; 214 } 215 216 /* 217 * Make socket non-blocking so that we don't hang forever if 218 * target dies unexpectedly. 219 */ 220 flags = fcntl(ctrl->s, F_GETFL); 221 if (flags >= 0) { 222 flags |= O_NONBLOCK; 223 if (fcntl(ctrl->s, F_SETFL, flags) < 0) { 224 perror("fcntl(ctrl->s, O_NONBLOCK)"); 225 /* Not fatal, continue on.*/ 226 } 227 } 228 229 return ctrl; 230} 231 232 233void wpa_ctrl_close(struct wpa_ctrl *ctrl) 234{ 235 if (ctrl == NULL) 236 return; 237 unlink(ctrl->local.sun_path); 238 if (ctrl->s >= 0) 239 close(ctrl->s); 240 os_free(ctrl); 241} 242 243 244#ifdef ANDROID 245/** 246 * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 247 * may be left over from clients that were previously connected to 248 * wpa_supplicant. This keeps these files from being orphaned in the 249 * event of crashes that prevented them from being removed as part 250 * of the normal orderly shutdown. 251 */ 252void wpa_ctrl_cleanup(void) 253{ 254 DIR *dir; 255 struct dirent entry; 256 struct dirent *result; 257 size_t dirnamelen; 258 size_t maxcopy; 259 char pathname[PATH_MAX]; 260 char *namep; 261 262 if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL) 263 return; 264 265 dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/", 266 CONFIG_CTRL_IFACE_CLIENT_DIR); 267 if (dirnamelen >= sizeof(pathname)) { 268 closedir(dir); 269 return; 270 } 271 namep = pathname + dirnamelen; 272 maxcopy = PATH_MAX - dirnamelen; 273 while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 274 if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) 275 unlink(pathname); 276 } 277 closedir(dir); 278} 279#endif /* ANDROID */ 280 281#else /* CONFIG_CTRL_IFACE_UNIX */ 282 283#ifdef ANDROID 284void wpa_ctrl_cleanup(void) 285{ 286} 287#endif /* ANDROID */ 288 289#endif /* CONFIG_CTRL_IFACE_UNIX */ 290 291 292#ifdef CONFIG_CTRL_IFACE_UDP 293 294struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 295{ 296 struct wpa_ctrl *ctrl; 297 char buf[128]; 298 size_t len; 299#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 300 struct hostent *h; 301#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 302 303 ctrl = os_zalloc(sizeof(*ctrl)); 304 if (ctrl == NULL) 305 return NULL; 306 307#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 308 ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0); 309#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 310 ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 311#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 312 if (ctrl->s < 0) { 313 perror("socket"); 314 os_free(ctrl); 315 return NULL; 316 } 317 318#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 319 ctrl->local.sin6_family = AF_INET6; 320#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 321 ctrl->local.sin6_addr = in6addr_any; 322#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 323 inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr); 324#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 325#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 326 ctrl->local.sin_family = AF_INET; 327#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 328 ctrl->local.sin_addr.s_addr = INADDR_ANY; 329#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 330 ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 331#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 332#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 333 334 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 335 sizeof(ctrl->local)) < 0) { 336 close(ctrl->s); 337 os_free(ctrl); 338 return NULL; 339 } 340 341#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 342 ctrl->dest.sin6_family = AF_INET6; 343 inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr); 344 ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT); 345#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 346 ctrl->dest.sin_family = AF_INET; 347 ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 348 ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 349#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 350 351#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 352 if (ctrl_path) { 353 char *port, *name; 354 int port_id; 355#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 356 char *scope; 357 int scope_id = 0; 358#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 359 360 name = os_strdup(ctrl_path); 361 if (name == NULL) { 362 close(ctrl->s); 363 os_free(ctrl); 364 return NULL; 365 } 366#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 367 port = os_strchr(name, ','); 368#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 369 port = os_strchr(name, ':'); 370#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 371 372 if (port) { 373 port_id = atoi(&port[1]); 374 port[0] = '\0'; 375 } else 376 port_id = WPA_CTRL_IFACE_PORT; 377 378#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 379 scope = os_strchr(name, '%'); 380 if (scope) { 381 scope_id = if_nametoindex(&scope[1]); 382 scope[0] = '\0'; 383 } 384 h = gethostbyname2(name, AF_INET6); 385#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 386 h = gethostbyname(name); 387#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 388 ctrl->remote_ip = os_strdup(name); 389 os_free(name); 390 if (h == NULL) { 391 perror("gethostbyname"); 392 close(ctrl->s); 393 os_free(ctrl->remote_ip); 394 os_free(ctrl); 395 return NULL; 396 } 397#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 398 ctrl->dest.sin6_scope_id = scope_id; 399 ctrl->dest.sin6_port = htons(port_id); 400 os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length); 401#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 402 ctrl->dest.sin_port = htons(port_id); 403 os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length); 404#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 405 } else 406 ctrl->remote_ip = os_strdup("localhost"); 407#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 408 409 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 410 sizeof(ctrl->dest)) < 0) { 411#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 412 char addr[INET6_ADDRSTRLEN]; 413 wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", 414 inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr, 415 sizeof(ctrl->dest)), 416 ntohs(ctrl->dest.sin6_port), 417 strerror(errno)); 418#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 419 wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", 420 inet_ntoa(ctrl->dest.sin_addr), 421 ntohs(ctrl->dest.sin_port), 422 strerror(errno)); 423#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 424 close(ctrl->s); 425 os_free(ctrl->remote_ip); 426 os_free(ctrl); 427 return NULL; 428 } 429 430 len = sizeof(buf) - 1; 431 if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 432 buf[len] = '\0'; 433 ctrl->cookie = os_strdup(buf); 434 } 435 436 if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) { 437 buf[len] = '\0'; 438 ctrl->remote_ifname = os_strdup(buf); 439 } 440 441 return ctrl; 442} 443 444 445char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl) 446{ 447#define WPA_CTRL_MAX_PS_NAME 100 448 static char ps[WPA_CTRL_MAX_PS_NAME] = {}; 449 os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s", 450 ctrl->remote_ip, ctrl->remote_ifname); 451 return ps; 452} 453 454 455void wpa_ctrl_close(struct wpa_ctrl *ctrl) 456{ 457 close(ctrl->s); 458 os_free(ctrl->cookie); 459 os_free(ctrl->remote_ifname); 460 os_free(ctrl->remote_ip); 461 os_free(ctrl); 462} 463 464#endif /* CONFIG_CTRL_IFACE_UDP */ 465 466 467#ifdef CTRL_IFACE_SOCKET 468int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 469 char *reply, size_t *reply_len, 470 void (*msg_cb)(char *msg, size_t len)) 471{ 472 struct timeval tv; 473 struct os_reltime started_at; 474 int res; 475 fd_set rfds; 476 const char *_cmd; 477 char *cmd_buf = NULL; 478 size_t _cmd_len; 479 480#ifdef CONFIG_CTRL_IFACE_UDP 481 if (ctrl->cookie) { 482 char *pos; 483 _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 484 cmd_buf = os_malloc(_cmd_len); 485 if (cmd_buf == NULL) 486 return -1; 487 _cmd = cmd_buf; 488 pos = cmd_buf; 489 os_strlcpy(pos, ctrl->cookie, _cmd_len); 490 pos += os_strlen(ctrl->cookie); 491 *pos++ = ' '; 492 os_memcpy(pos, cmd, cmd_len); 493 } else 494#endif /* CONFIG_CTRL_IFACE_UDP */ 495 { 496 _cmd = cmd; 497 _cmd_len = cmd_len; 498 } 499 500 errno = 0; 501 started_at.sec = 0; 502 started_at.usec = 0; 503retry_send: 504 if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 505 if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) 506 { 507 /* 508 * Must be a non-blocking socket... Try for a bit 509 * longer before giving up. 510 */ 511 if (started_at.sec == 0) 512 os_get_reltime(&started_at); 513 else { 514 struct os_reltime n; 515 os_get_reltime(&n); 516 /* Try for a few seconds. */ 517 if (os_reltime_expired(&n, &started_at, 5)) 518 goto send_err; 519 } 520 os_sleep(1, 0); 521 goto retry_send; 522 } 523 send_err: 524 os_free(cmd_buf); 525 return -1; 526 } 527 os_free(cmd_buf); 528 529 for (;;) { 530 tv.tv_sec = 10; 531 tv.tv_usec = 0; 532 FD_ZERO(&rfds); 533 FD_SET(ctrl->s, &rfds); 534 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 535 if (res < 0 && errno == EINTR) 536 continue; 537 if (res < 0) 538 return res; 539 if (FD_ISSET(ctrl->s, &rfds)) { 540 res = recv(ctrl->s, reply, *reply_len, 0); 541 if (res < 0) 542 return res; 543 if (res > 0 && reply[0] == '<') { 544 /* This is an unsolicited message from 545 * wpa_supplicant, not the reply to the 546 * request. Use msg_cb to report this to the 547 * caller. */ 548 if (msg_cb) { 549 /* Make sure the message is nul 550 * terminated. */ 551 if ((size_t) res == *reply_len) 552 res = (*reply_len) - 1; 553 reply[res] = '\0'; 554 msg_cb(reply, res); 555 } 556 continue; 557 } 558 *reply_len = res; 559 break; 560 } else { 561 return -2; 562 } 563 } 564 return 0; 565} 566#endif /* CTRL_IFACE_SOCKET */ 567 568 569static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 570{ 571 char buf[10]; 572 int ret; 573 size_t len = 10; 574 575 ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 576 buf, &len, NULL); 577 if (ret < 0) 578 return ret; 579 if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 580 return 0; 581 return -1; 582} 583 584 585int wpa_ctrl_attach(struct wpa_ctrl *ctrl) 586{ 587 return wpa_ctrl_attach_helper(ctrl, 1); 588} 589 590 591int wpa_ctrl_detach(struct wpa_ctrl *ctrl) 592{ 593 return wpa_ctrl_attach_helper(ctrl, 0); 594} 595 596 597#ifdef CTRL_IFACE_SOCKET 598 599int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 600{ 601 int res; 602 603 res = recv(ctrl->s, reply, *reply_len, 0); 604 if (res < 0) 605 return res; 606 *reply_len = res; 607 return 0; 608} 609 610 611int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 612{ 613 struct timeval tv; 614 fd_set rfds; 615 tv.tv_sec = 0; 616 tv.tv_usec = 0; 617 FD_ZERO(&rfds); 618 FD_SET(ctrl->s, &rfds); 619 select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 620 return FD_ISSET(ctrl->s, &rfds); 621} 622 623 624int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 625{ 626 return ctrl->s; 627} 628 629#endif /* CTRL_IFACE_SOCKET */ 630 631 632#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 633 634#ifndef WPA_SUPPLICANT_NAMED_PIPE 635#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 636#endif 637#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 638 639struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 640{ 641 struct wpa_ctrl *ctrl; 642 DWORD mode; 643 TCHAR name[256]; 644 int i, ret; 645 646 ctrl = os_malloc(sizeof(*ctrl)); 647 if (ctrl == NULL) 648 return NULL; 649 os_memset(ctrl, 0, sizeof(*ctrl)); 650 651#ifdef UNICODE 652 if (ctrl_path == NULL) 653 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 654 else 655 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 656 ctrl_path); 657#else /* UNICODE */ 658 if (ctrl_path == NULL) 659 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 660 else 661 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 662 ctrl_path); 663#endif /* UNICODE */ 664 if (os_snprintf_error(256, ret)) { 665 os_free(ctrl); 666 return NULL; 667 } 668 669 for (i = 0; i < 10; i++) { 670 ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 671 NULL, OPEN_EXISTING, 0, NULL); 672 /* 673 * Current named pipe server side in wpa_supplicant is 674 * re-opening the pipe for new clients only after the previous 675 * one is taken into use. This leaves a small window for race 676 * conditions when two connections are being opened at almost 677 * the same time. Retry if that was the case. 678 */ 679 if (ctrl->pipe != INVALID_HANDLE_VALUE || 680 GetLastError() != ERROR_PIPE_BUSY) 681 break; 682 WaitNamedPipe(name, 1000); 683 } 684 if (ctrl->pipe == INVALID_HANDLE_VALUE) { 685 os_free(ctrl); 686 return NULL; 687 } 688 689 mode = PIPE_READMODE_MESSAGE; 690 if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 691 CloseHandle(ctrl->pipe); 692 os_free(ctrl); 693 return NULL; 694 } 695 696 return ctrl; 697} 698 699 700void wpa_ctrl_close(struct wpa_ctrl *ctrl) 701{ 702 CloseHandle(ctrl->pipe); 703 os_free(ctrl); 704} 705 706 707int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 708 char *reply, size_t *reply_len, 709 void (*msg_cb)(char *msg, size_t len)) 710{ 711 DWORD written; 712 DWORD readlen = *reply_len; 713 714 if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 715 return -1; 716 717 if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 718 return -1; 719 *reply_len = readlen; 720 721 return 0; 722} 723 724 725int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 726{ 727 DWORD len = *reply_len; 728 if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 729 return -1; 730 *reply_len = len; 731 return 0; 732} 733 734 735int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 736{ 737 DWORD left; 738 739 if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 740 return -1; 741 return left ? 1 : 0; 742} 743 744 745int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 746{ 747 return -1; 748} 749 750#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 751 752#endif /* CONFIG_CTRL_IFACE */ 753