1 /* 2 * WPA Supplicant / Windows Named Pipe -based control interface 3 * Copyright (c) 2004-2006, 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 #include "common.h" 12 #include "eloop.h" 13 #include "config.h" 14 #include "eapol_supp/eapol_supp_sm.h" 15 #include "wpa_supplicant_i.h" 16 #include "ctrl_iface.h" 17 #include "common/wpa_ctrl.h" 18 19 #ifdef __MINGW32_VERSION 20 /* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here 21 */ 22 #define SDDL_REVISION_1 1 23 BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( 24 LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 25 BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( 26 LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 27 #ifdef UNICODE 28 #define ConvertStringSecurityDescriptorToSecurityDescriptor \ 29 ConvertStringSecurityDescriptorToSecurityDescriptorW 30 #else 31 #define ConvertStringSecurityDescriptorToSecurityDescriptor \ 32 ConvertStringSecurityDescriptorToSecurityDescriptorA 33 #endif 34 #else /* __MINGW32_VERSION */ 35 #ifndef _WIN32_WINNT 36 #define _WIN32_WINNT 0x0500 37 #endif 38 #include <sddl.h> 39 #endif /* __MINGW32_VERSION */ 40 41 #ifndef WPA_SUPPLICANT_NAMED_PIPE 42 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 43 #endif 44 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 45 46 /* Per-interface ctrl_iface */ 47 48 #define REQUEST_BUFSIZE 256 49 #define REPLY_BUFSIZE 4096 50 51 struct ctrl_iface_priv; 52 53 /** 54 * struct wpa_ctrl_dst - Internal data structure of control interface clients 55 * 56 * This structure is used to store information about registered control 57 * interface monitors into struct wpa_supplicant. This data is private to 58 * ctrl_iface_named_pipe.c and should not be touched directly from other files. 59 */ 60 struct wpa_ctrl_dst { 61 /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ 62 OVERLAPPED overlap; 63 struct wpa_ctrl_dst *next, *prev; 64 struct ctrl_iface_priv *priv; 65 HANDLE pipe; 66 int attached; 67 int debug_level; 68 int errors; 69 char req_buf[REQUEST_BUFSIZE]; 70 char *rsp_buf; 71 int used; 72 }; 73 74 75 struct ctrl_iface_priv { 76 struct wpa_supplicant *wpa_s; 77 struct wpa_ctrl_dst *ctrl_dst; 78 SECURITY_ATTRIBUTES attr; 79 int sec_attr_set; 80 }; 81 82 83 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 84 int level, const char *buf, 85 size_t len); 86 87 static void ctrl_close_pipe(struct wpa_ctrl_dst *dst); 88 static void wpa_supplicant_ctrl_iface_receive(void *, void *); 89 static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 90 LPOVERLAPPED overlap); 91 92 struct wpa_global_dst; 93 static void global_close_pipe(struct wpa_global_dst *dst); 94 static void wpa_supplicant_global_iface_receive(void *eloop_data, 95 void *user_ctx); 96 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 97 LPOVERLAPPED overlap); 98 99 100 static int ctrl_broken_pipe(HANDLE pipe, int used) 101 { 102 DWORD err; 103 104 if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) 105 return 0; 106 107 err = GetLastError(); 108 if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) 109 return 1; 110 return 0; 111 } 112 113 114 static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) 115 { 116 struct wpa_ctrl_dst *dst, *next; 117 118 dst = priv->ctrl_dst; 119 120 while (dst) { 121 next = dst->next; 122 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 123 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 124 dst); 125 ctrl_close_pipe(dst); 126 } 127 dst = next; 128 } 129 } 130 131 132 static int ctrl_open_pipe(struct ctrl_iface_priv *priv) 133 { 134 struct wpa_ctrl_dst *dst; 135 DWORD err; 136 TCHAR name[256]; 137 138 dst = os_zalloc(sizeof(*dst)); 139 if (dst == NULL) 140 return -1; 141 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 142 143 dst->priv = priv; 144 dst->debug_level = MSG_INFO; 145 dst->pipe = INVALID_HANDLE_VALUE; 146 147 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 148 if (dst->overlap.hEvent == NULL) { 149 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 150 (int) GetLastError()); 151 goto fail; 152 } 153 154 eloop_register_event(dst->overlap.hEvent, 155 sizeof(dst->overlap.hEvent), 156 wpa_supplicant_ctrl_iface_receive, dst, NULL); 157 158 #ifdef UNICODE 159 _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 160 priv->wpa_s->ifname); 161 #else /* UNICODE */ 162 os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 163 priv->wpa_s->ifname); 164 #endif /* UNICODE */ 165 166 /* TODO: add support for configuring access list for the pipe */ 167 dst->pipe = CreateNamedPipe(name, 168 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 169 PIPE_TYPE_MESSAGE | 170 PIPE_READMODE_MESSAGE | 171 PIPE_WAIT, 172 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, 173 1000, 174 priv->sec_attr_set ? &priv->attr : NULL); 175 if (dst->pipe == INVALID_HANDLE_VALUE) { 176 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 177 (int) GetLastError()); 178 goto fail; 179 } 180 181 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 182 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 183 (int) GetLastError()); 184 CloseHandle(dst->pipe); 185 os_free(dst); 186 return -1; 187 } 188 189 err = GetLastError(); 190 switch (err) { 191 case ERROR_IO_PENDING: 192 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 193 "progress"); 194 break; 195 case ERROR_PIPE_CONNECTED: 196 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 197 "connected"); 198 if (SetEvent(dst->overlap.hEvent)) 199 break; 200 /* fall through */ 201 default: 202 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 203 (int) err); 204 CloseHandle(dst->pipe); 205 os_free(dst); 206 return -1; 207 } 208 209 dst->next = priv->ctrl_dst; 210 if (dst->next) 211 dst->next->prev = dst; 212 priv->ctrl_dst = dst; 213 214 return 0; 215 216 fail: 217 ctrl_close_pipe(dst); 218 return -1; 219 } 220 221 222 static void ctrl_close_pipe(struct wpa_ctrl_dst *dst) 223 { 224 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 225 226 if (dst->overlap.hEvent) { 227 eloop_unregister_event(dst->overlap.hEvent, 228 sizeof(dst->overlap.hEvent)); 229 CloseHandle(dst->overlap.hEvent); 230 } 231 232 if (dst->pipe != INVALID_HANDLE_VALUE) { 233 /* 234 * Could use FlushFileBuffers() here to guarantee that all data 235 * gets delivered to the client, but that can block, so let's 236 * not do this for now. 237 * FlushFileBuffers(dst->pipe); 238 */ 239 CloseHandle(dst->pipe); 240 } 241 242 if (dst->prev) 243 dst->prev->next = dst->next; 244 else 245 dst->priv->ctrl_dst = dst->next; 246 if (dst->next) 247 dst->next->prev = dst->prev; 248 249 os_free(dst->rsp_buf); 250 os_free(dst); 251 } 252 253 254 static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, 255 LPOVERLAPPED overlap) 256 { 257 struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 258 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 259 "err=%d bytes=%d", dst, (int) err, (int) bytes); 260 if (err) { 261 ctrl_close_pipe(dst); 262 return; 263 } 264 265 os_free(dst->rsp_buf); 266 dst->rsp_buf = NULL; 267 268 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 269 &dst->overlap, ctrl_iface_read_completed)) { 270 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 271 (int) GetLastError()); 272 ctrl_close_pipe(dst); 273 return; 274 } 275 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 276 } 277 278 279 static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) 280 { 281 struct wpa_supplicant *wpa_s = dst->priv->wpa_s; 282 char *reply = NULL, *send_buf; 283 size_t reply_len = 0, send_len; 284 int new_attached = 0; 285 char *buf = dst->req_buf; 286 287 dst->used = 1; 288 if (len >= REQUEST_BUFSIZE) 289 len = REQUEST_BUFSIZE - 1; 290 buf[len] = '\0'; 291 292 if (os_strcmp(buf, "ATTACH") == 0) { 293 dst->attached = 1; 294 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); 295 new_attached = 1; 296 reply_len = 2; 297 } else if (os_strcmp(buf, "DETACH") == 0) { 298 dst->attached = 0; 299 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); 300 reply_len = 2; 301 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 302 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); 303 dst->debug_level = atoi(buf + 6); 304 reply_len = 2; 305 } else { 306 reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 307 &reply_len); 308 } 309 310 if (reply) { 311 send_buf = reply; 312 send_len = reply_len; 313 } else if (reply_len == 2) { 314 send_buf = "OK\n"; 315 send_len = 3; 316 } else { 317 send_buf = "FAIL\n"; 318 send_len = 5; 319 } 320 321 os_free(dst->rsp_buf); 322 dst->rsp_buf = os_malloc(send_len); 323 if (dst->rsp_buf == NULL) { 324 ctrl_close_pipe(dst); 325 os_free(reply); 326 return; 327 } 328 os_memcpy(dst->rsp_buf, send_buf, send_len); 329 os_free(reply); 330 331 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 332 ctrl_iface_write_completed)) { 333 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 334 (int) GetLastError()); 335 ctrl_close_pipe(dst); 336 } else { 337 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 338 dst); 339 } 340 341 if (new_attached) 342 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 343 } 344 345 346 static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 347 LPOVERLAPPED overlap) 348 { 349 struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 350 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 351 "bytes=%d", dst, (int) err, (int) bytes); 352 if (err == 0 && bytes > 0) 353 wpa_supplicant_ctrl_iface_rx(dst, bytes); 354 } 355 356 357 static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) 358 { 359 struct wpa_ctrl_dst *dst = eloop_data; 360 struct ctrl_iface_priv *priv = dst->priv; 361 DWORD bytes; 362 363 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); 364 ResetEvent(dst->overlap.hEvent); 365 366 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 367 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 368 (int) GetLastError()); 369 return; 370 } 371 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 372 "connected"); 373 374 /* Open a new named pipe for the next client. */ 375 ctrl_open_pipe(priv); 376 377 /* Use write completion function to start reading a command */ 378 ctrl_iface_write_completed(0, 0, &dst->overlap); 379 380 ctrl_flush_broken_pipes(priv); 381 } 382 383 384 static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) 385 { 386 const char *sddl = NULL; 387 TCHAR *t_sddl; 388 389 if (os_strncmp(params, "SDDL=", 5) == 0) 390 sddl = params + 5; 391 if (!sddl) { 392 sddl = os_strstr(params, " SDDL="); 393 if (sddl) 394 sddl += 6; 395 } 396 397 if (!sddl) 398 return 0; 399 400 wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); 401 os_memset(&priv->attr, 0, sizeof(priv->attr)); 402 priv->attr.nLength = sizeof(priv->attr); 403 priv->attr.bInheritHandle = FALSE; 404 t_sddl = wpa_strdup_tchar(sddl); 405 if (t_sddl == NULL) 406 return -1; 407 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 408 t_sddl, SDDL_REVISION_1, 409 (PSECURITY_DESCRIPTOR *) (void *) 410 &priv->attr.lpSecurityDescriptor, 411 NULL)) { 412 os_free(t_sddl); 413 wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " 414 "security descriptor: %d", 415 sddl, (int) GetLastError()); 416 return -1; 417 } 418 os_free(t_sddl); 419 420 priv->sec_attr_set = 1; 421 422 return 0; 423 } 424 425 426 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 427 const char *txt, size_t len) 428 { 429 struct wpa_supplicant *wpa_s = ctx; 430 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 431 return; 432 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 433 } 434 435 436 struct ctrl_iface_priv * 437 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 438 { 439 struct ctrl_iface_priv *priv; 440 441 priv = os_zalloc(sizeof(*priv)); 442 if (priv == NULL) 443 return NULL; 444 priv->wpa_s = wpa_s; 445 446 if (wpa_s->conf->ctrl_interface == NULL) 447 return priv; 448 449 if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { 450 os_free(priv); 451 return NULL; 452 } 453 454 if (ctrl_open_pipe(priv) < 0) { 455 os_free(priv); 456 return NULL; 457 } 458 459 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 460 461 return priv; 462 } 463 464 465 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 466 { 467 while (priv->ctrl_dst) 468 ctrl_close_pipe(priv->ctrl_dst); 469 if (priv->sec_attr_set) 470 LocalFree(priv->attr.lpSecurityDescriptor); 471 os_free(priv); 472 } 473 474 475 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 476 int level, const char *buf, 477 size_t len) 478 { 479 struct wpa_ctrl_dst *dst, *next; 480 char levelstr[10]; 481 int idx; 482 char *sbuf; 483 int llen; 484 DWORD written; 485 486 dst = priv->ctrl_dst; 487 if (dst == NULL) 488 return; 489 490 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 491 492 llen = os_strlen(levelstr); 493 sbuf = os_malloc(llen + len); 494 if (sbuf == NULL) 495 return; 496 497 os_memcpy(sbuf, levelstr, llen); 498 os_memcpy(sbuf + llen, buf, len); 499 500 idx = 0; 501 while (dst) { 502 next = dst->next; 503 if (dst->attached && level >= dst->debug_level) { 504 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 505 dst); 506 if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 507 NULL)) { 508 wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 509 "%p failed: %d", 510 dst, (int) GetLastError()); 511 dst->errors++; 512 if (dst->errors > 10) 513 ctrl_close_pipe(dst); 514 } else 515 dst->errors = 0; 516 } 517 idx++; 518 dst = next; 519 } 520 os_free(sbuf); 521 } 522 523 524 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 525 { 526 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 527 priv->wpa_s->ifname); 528 if (priv->ctrl_dst == NULL) 529 return; 530 WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 531 } 532 533 534 /* Global ctrl_iface */ 535 536 struct ctrl_iface_global_priv; 537 538 struct wpa_global_dst { 539 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 540 */ 541 OVERLAPPED overlap; 542 struct wpa_global_dst *next, *prev; 543 struct ctrl_iface_global_priv *priv; 544 HANDLE pipe; 545 char req_buf[REQUEST_BUFSIZE]; 546 char *rsp_buf; 547 int used; 548 }; 549 550 struct ctrl_iface_global_priv { 551 struct wpa_global *global; 552 struct wpa_global_dst *ctrl_dst; 553 }; 554 555 556 static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 557 { 558 struct wpa_global_dst *dst, *next; 559 560 dst = priv->ctrl_dst; 561 562 while (dst) { 563 next = dst->next; 564 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 565 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 566 dst); 567 global_close_pipe(dst); 568 } 569 dst = next; 570 } 571 } 572 573 574 static int global_open_pipe(struct ctrl_iface_global_priv *priv) 575 { 576 struct wpa_global_dst *dst; 577 DWORD err; 578 579 dst = os_zalloc(sizeof(*dst)); 580 if (dst == NULL) 581 return -1; 582 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 583 584 dst->priv = priv; 585 dst->pipe = INVALID_HANDLE_VALUE; 586 587 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 588 if (dst->overlap.hEvent == NULL) { 589 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 590 (int) GetLastError()); 591 goto fail; 592 } 593 594 eloop_register_event(dst->overlap.hEvent, 595 sizeof(dst->overlap.hEvent), 596 wpa_supplicant_global_iface_receive, dst, NULL); 597 598 /* TODO: add support for configuring access list for the pipe */ 599 dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 600 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 601 PIPE_TYPE_MESSAGE | 602 PIPE_READMODE_MESSAGE | 603 PIPE_WAIT, 604 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 605 1000, NULL); 606 if (dst->pipe == INVALID_HANDLE_VALUE) { 607 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 608 (int) GetLastError()); 609 goto fail; 610 } 611 612 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 613 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 614 (int) GetLastError()); 615 CloseHandle(dst->pipe); 616 os_free(dst); 617 return -1; 618 } 619 620 err = GetLastError(); 621 switch (err) { 622 case ERROR_IO_PENDING: 623 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 624 "progress"); 625 break; 626 case ERROR_PIPE_CONNECTED: 627 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 628 "connected"); 629 if (SetEvent(dst->overlap.hEvent)) 630 break; 631 /* fall through */ 632 default: 633 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 634 (int) err); 635 CloseHandle(dst->pipe); 636 os_free(dst); 637 return -1; 638 } 639 640 dst->next = priv->ctrl_dst; 641 if (dst->next) 642 dst->next->prev = dst; 643 priv->ctrl_dst = dst; 644 645 return 0; 646 647 fail: 648 global_close_pipe(dst); 649 return -1; 650 } 651 652 653 static void global_close_pipe(struct wpa_global_dst *dst) 654 { 655 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 656 657 if (dst->overlap.hEvent) { 658 eloop_unregister_event(dst->overlap.hEvent, 659 sizeof(dst->overlap.hEvent)); 660 CloseHandle(dst->overlap.hEvent); 661 } 662 663 if (dst->pipe != INVALID_HANDLE_VALUE) { 664 /* 665 * Could use FlushFileBuffers() here to guarantee that all data 666 * gets delivered to the client, but that can block, so let's 667 * not do this for now. 668 * FlushFileBuffers(dst->pipe); 669 */ 670 CloseHandle(dst->pipe); 671 } 672 673 if (dst->prev) 674 dst->prev->next = dst->next; 675 else 676 dst->priv->ctrl_dst = dst->next; 677 if (dst->next) 678 dst->next->prev = dst->prev; 679 680 os_free(dst->rsp_buf); 681 os_free(dst); 682 } 683 684 685 static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 686 LPOVERLAPPED overlap) 687 { 688 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 689 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 690 "err=%d bytes=%d", dst, (int) err, (int) bytes); 691 if (err) { 692 global_close_pipe(dst); 693 return; 694 } 695 696 os_free(dst->rsp_buf); 697 dst->rsp_buf = NULL; 698 699 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 700 &dst->overlap, global_iface_read_completed)) { 701 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 702 (int) GetLastError()); 703 global_close_pipe(dst); 704 /* FIX: if this was the pipe waiting for new global 705 * connections, at this point there are no open global pipes.. 706 * Should try to open a new pipe.. */ 707 return; 708 } 709 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 710 } 711 712 713 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 714 size_t len) 715 { 716 struct wpa_global *global = dst->priv->global; 717 char *reply = NULL, *send_buf; 718 size_t reply_len = 0, send_len; 719 char *buf = dst->req_buf; 720 721 dst->used = 1; 722 if (len >= REQUEST_BUFSIZE) 723 len = REQUEST_BUFSIZE - 1; 724 buf[len] = '\0'; 725 726 reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 727 &reply_len); 728 if (reply) { 729 send_buf = reply; 730 send_len = reply_len; 731 } else if (reply_len) { 732 send_buf = "FAIL\n"; 733 send_len = 5; 734 } else { 735 os_free(dst->rsp_buf); 736 dst->rsp_buf = NULL; 737 return; 738 } 739 740 os_free(dst->rsp_buf); 741 dst->rsp_buf = os_malloc(send_len); 742 if (dst->rsp_buf == NULL) { 743 global_close_pipe(dst); 744 os_free(reply); 745 return; 746 } 747 os_memcpy(dst->rsp_buf, send_buf, send_len); 748 os_free(reply); 749 750 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 751 global_iface_write_completed)) { 752 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 753 (int) GetLastError()); 754 global_close_pipe(dst); 755 } else { 756 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 757 dst); 758 } 759 } 760 761 762 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 763 LPOVERLAPPED overlap) 764 { 765 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 766 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 767 "bytes=%d", dst, (int) err, (int) bytes); 768 if (err == 0 && bytes > 0) 769 wpa_supplicant_global_iface_rx(dst, bytes); 770 } 771 772 773 static void wpa_supplicant_global_iface_receive(void *eloop_data, 774 void *user_ctx) 775 { 776 struct wpa_global_dst *dst = eloop_data; 777 struct ctrl_iface_global_priv *priv = dst->priv; 778 DWORD bytes; 779 780 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 781 ResetEvent(dst->overlap.hEvent); 782 783 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 784 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 785 (int) GetLastError()); 786 return; 787 } 788 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 789 "connected"); 790 791 /* Open a new named pipe for the next client. */ 792 if (global_open_pipe(priv) < 0) { 793 wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 794 return; 795 } 796 797 /* Use write completion function to start reading a command */ 798 global_iface_write_completed(0, 0, &dst->overlap); 799 800 global_flush_broken_pipes(priv); 801 } 802 803 804 struct ctrl_iface_global_priv * 805 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 806 { 807 struct ctrl_iface_global_priv *priv; 808 809 priv = os_zalloc(sizeof(*priv)); 810 if (priv == NULL) 811 return NULL; 812 priv->global = global; 813 814 if (global_open_pipe(priv) < 0) { 815 os_free(priv); 816 return NULL; 817 } 818 819 return priv; 820 } 821 822 823 void 824 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 825 { 826 while (priv->ctrl_dst) 827 global_close_pipe(priv->ctrl_dst); 828 os_free(priv); 829 } 830