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 enum wpa_msg_type type, 428 const char *txt, size_t len) 429 { 430 struct wpa_supplicant *wpa_s = ctx; 431 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 432 return; 433 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 434 } 435 436 437 struct ctrl_iface_priv * 438 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 439 { 440 struct ctrl_iface_priv *priv; 441 442 priv = os_zalloc(sizeof(*priv)); 443 if (priv == NULL) 444 return NULL; 445 priv->wpa_s = wpa_s; 446 447 if (wpa_s->conf->ctrl_interface == NULL) 448 return priv; 449 450 if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { 451 os_free(priv); 452 return NULL; 453 } 454 455 if (ctrl_open_pipe(priv) < 0) { 456 os_free(priv); 457 return NULL; 458 } 459 460 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 461 462 return priv; 463 } 464 465 466 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 467 { 468 while (priv->ctrl_dst) 469 ctrl_close_pipe(priv->ctrl_dst); 470 if (priv->sec_attr_set) 471 LocalFree(priv->attr.lpSecurityDescriptor); 472 os_free(priv); 473 } 474 475 476 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 477 int level, const char *buf, 478 size_t len) 479 { 480 struct wpa_ctrl_dst *dst, *next; 481 char levelstr[10]; 482 int idx; 483 char *sbuf; 484 int llen; 485 DWORD written; 486 487 dst = priv->ctrl_dst; 488 if (dst == NULL) 489 return; 490 491 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 492 493 llen = os_strlen(levelstr); 494 sbuf = os_malloc(llen + len); 495 if (sbuf == NULL) 496 return; 497 498 os_memcpy(sbuf, levelstr, llen); 499 os_memcpy(sbuf + llen, buf, len); 500 501 idx = 0; 502 while (dst) { 503 next = dst->next; 504 if (dst->attached && level >= dst->debug_level) { 505 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 506 dst); 507 if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 508 NULL)) { 509 wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 510 "%p failed: %d", 511 dst, (int) GetLastError()); 512 dst->errors++; 513 if (dst->errors > 10) 514 ctrl_close_pipe(dst); 515 } else 516 dst->errors = 0; 517 } 518 idx++; 519 dst = next; 520 } 521 os_free(sbuf); 522 } 523 524 525 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 526 { 527 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 528 priv->wpa_s->ifname); 529 if (priv->ctrl_dst == NULL) 530 return; 531 WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 532 } 533 534 535 /* Global ctrl_iface */ 536 537 struct ctrl_iface_global_priv; 538 539 struct wpa_global_dst { 540 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 541 */ 542 OVERLAPPED overlap; 543 struct wpa_global_dst *next, *prev; 544 struct ctrl_iface_global_priv *priv; 545 HANDLE pipe; 546 char req_buf[REQUEST_BUFSIZE]; 547 char *rsp_buf; 548 int used; 549 }; 550 551 struct ctrl_iface_global_priv { 552 struct wpa_global *global; 553 struct wpa_global_dst *ctrl_dst; 554 }; 555 556 557 static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 558 { 559 struct wpa_global_dst *dst, *next; 560 561 dst = priv->ctrl_dst; 562 563 while (dst) { 564 next = dst->next; 565 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 566 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 567 dst); 568 global_close_pipe(dst); 569 } 570 dst = next; 571 } 572 } 573 574 575 static int global_open_pipe(struct ctrl_iface_global_priv *priv) 576 { 577 struct wpa_global_dst *dst; 578 DWORD err; 579 580 dst = os_zalloc(sizeof(*dst)); 581 if (dst == NULL) 582 return -1; 583 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 584 585 dst->priv = priv; 586 dst->pipe = INVALID_HANDLE_VALUE; 587 588 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 589 if (dst->overlap.hEvent == NULL) { 590 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 591 (int) GetLastError()); 592 goto fail; 593 } 594 595 eloop_register_event(dst->overlap.hEvent, 596 sizeof(dst->overlap.hEvent), 597 wpa_supplicant_global_iface_receive, dst, NULL); 598 599 /* TODO: add support for configuring access list for the pipe */ 600 dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 601 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 602 PIPE_TYPE_MESSAGE | 603 PIPE_READMODE_MESSAGE | 604 PIPE_WAIT, 605 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 606 1000, NULL); 607 if (dst->pipe == INVALID_HANDLE_VALUE) { 608 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 609 (int) GetLastError()); 610 goto fail; 611 } 612 613 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 614 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 615 (int) GetLastError()); 616 CloseHandle(dst->pipe); 617 os_free(dst); 618 return -1; 619 } 620 621 err = GetLastError(); 622 switch (err) { 623 case ERROR_IO_PENDING: 624 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 625 "progress"); 626 break; 627 case ERROR_PIPE_CONNECTED: 628 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 629 "connected"); 630 if (SetEvent(dst->overlap.hEvent)) 631 break; 632 /* fall through */ 633 default: 634 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 635 (int) err); 636 CloseHandle(dst->pipe); 637 os_free(dst); 638 return -1; 639 } 640 641 dst->next = priv->ctrl_dst; 642 if (dst->next) 643 dst->next->prev = dst; 644 priv->ctrl_dst = dst; 645 646 return 0; 647 648 fail: 649 global_close_pipe(dst); 650 return -1; 651 } 652 653 654 static void global_close_pipe(struct wpa_global_dst *dst) 655 { 656 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 657 658 if (dst->overlap.hEvent) { 659 eloop_unregister_event(dst->overlap.hEvent, 660 sizeof(dst->overlap.hEvent)); 661 CloseHandle(dst->overlap.hEvent); 662 } 663 664 if (dst->pipe != INVALID_HANDLE_VALUE) { 665 /* 666 * Could use FlushFileBuffers() here to guarantee that all data 667 * gets delivered to the client, but that can block, so let's 668 * not do this for now. 669 * FlushFileBuffers(dst->pipe); 670 */ 671 CloseHandle(dst->pipe); 672 } 673 674 if (dst->prev) 675 dst->prev->next = dst->next; 676 else 677 dst->priv->ctrl_dst = dst->next; 678 if (dst->next) 679 dst->next->prev = dst->prev; 680 681 os_free(dst->rsp_buf); 682 os_free(dst); 683 } 684 685 686 static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 687 LPOVERLAPPED overlap) 688 { 689 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 690 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 691 "err=%d bytes=%d", dst, (int) err, (int) bytes); 692 if (err) { 693 global_close_pipe(dst); 694 return; 695 } 696 697 os_free(dst->rsp_buf); 698 dst->rsp_buf = NULL; 699 700 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 701 &dst->overlap, global_iface_read_completed)) { 702 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 703 (int) GetLastError()); 704 global_close_pipe(dst); 705 /* FIX: if this was the pipe waiting for new global 706 * connections, at this point there are no open global pipes.. 707 * Should try to open a new pipe.. */ 708 return; 709 } 710 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 711 } 712 713 714 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 715 size_t len) 716 { 717 struct wpa_global *global = dst->priv->global; 718 char *reply = NULL, *send_buf; 719 size_t reply_len = 0, send_len; 720 char *buf = dst->req_buf; 721 722 dst->used = 1; 723 if (len >= REQUEST_BUFSIZE) 724 len = REQUEST_BUFSIZE - 1; 725 buf[len] = '\0'; 726 727 reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 728 &reply_len); 729 if (reply) { 730 send_buf = reply; 731 send_len = reply_len; 732 } else if (reply_len) { 733 send_buf = "FAIL\n"; 734 send_len = 5; 735 } else { 736 os_free(dst->rsp_buf); 737 dst->rsp_buf = NULL; 738 return; 739 } 740 741 os_free(dst->rsp_buf); 742 dst->rsp_buf = os_malloc(send_len); 743 if (dst->rsp_buf == NULL) { 744 global_close_pipe(dst); 745 os_free(reply); 746 return; 747 } 748 os_memcpy(dst->rsp_buf, send_buf, send_len); 749 os_free(reply); 750 751 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 752 global_iface_write_completed)) { 753 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 754 (int) GetLastError()); 755 global_close_pipe(dst); 756 } else { 757 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 758 dst); 759 } 760 } 761 762 763 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 764 LPOVERLAPPED overlap) 765 { 766 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 767 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 768 "bytes=%d", dst, (int) err, (int) bytes); 769 if (err == 0 && bytes > 0) 770 wpa_supplicant_global_iface_rx(dst, bytes); 771 } 772 773 774 static void wpa_supplicant_global_iface_receive(void *eloop_data, 775 void *user_ctx) 776 { 777 struct wpa_global_dst *dst = eloop_data; 778 struct ctrl_iface_global_priv *priv = dst->priv; 779 DWORD bytes; 780 781 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 782 ResetEvent(dst->overlap.hEvent); 783 784 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 785 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 786 (int) GetLastError()); 787 return; 788 } 789 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 790 "connected"); 791 792 /* Open a new named pipe for the next client. */ 793 if (global_open_pipe(priv) < 0) { 794 wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 795 return; 796 } 797 798 /* Use write completion function to start reading a command */ 799 global_iface_write_completed(0, 0, &dst->overlap); 800 801 global_flush_broken_pipes(priv); 802 } 803 804 805 struct ctrl_iface_global_priv * 806 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 807 { 808 struct ctrl_iface_global_priv *priv; 809 810 priv = os_zalloc(sizeof(*priv)); 811 if (priv == NULL) 812 return NULL; 813 priv->global = global; 814 815 if (global_open_pipe(priv) < 0) { 816 os_free(priv); 817 return NULL; 818 } 819 820 return priv; 821 } 822 823 824 void 825 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 826 { 827 while (priv->ctrl_dst) 828 global_close_pipe(priv->ctrl_dst); 829 os_free(priv); 830 } 831