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 CTRL_IFACE_MAX_LEN 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_memdup(send_buf, send_len); 323 if (dst->rsp_buf == NULL) { 324 ctrl_close_pipe(dst); 325 os_free(reply); 326 return; 327 } 328 os_free(reply); 329 330 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 331 ctrl_iface_write_completed)) { 332 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 333 (int) GetLastError()); 334 ctrl_close_pipe(dst); 335 } else { 336 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 337 dst); 338 } 339 340 if (new_attached) 341 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 342 } 343 344 345 static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 346 LPOVERLAPPED overlap) 347 { 348 struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 349 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 350 "bytes=%d", dst, (int) err, (int) bytes); 351 if (err == 0 && bytes > 0) 352 wpa_supplicant_ctrl_iface_rx(dst, bytes); 353 } 354 355 356 static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) 357 { 358 struct wpa_ctrl_dst *dst = eloop_data; 359 struct ctrl_iface_priv *priv = dst->priv; 360 DWORD bytes; 361 362 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); 363 ResetEvent(dst->overlap.hEvent); 364 365 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 366 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 367 (int) GetLastError()); 368 return; 369 } 370 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 371 "connected"); 372 373 /* Open a new named pipe for the next client. */ 374 ctrl_open_pipe(priv); 375 376 /* Use write completion function to start reading a command */ 377 ctrl_iface_write_completed(0, 0, &dst->overlap); 378 379 ctrl_flush_broken_pipes(priv); 380 } 381 382 383 static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) 384 { 385 const char *sddl = NULL; 386 TCHAR *t_sddl; 387 388 if (os_strncmp(params, "SDDL=", 5) == 0) 389 sddl = params + 5; 390 if (!sddl) { 391 sddl = os_strstr(params, " SDDL="); 392 if (sddl) 393 sddl += 6; 394 } 395 396 if (!sddl) 397 return 0; 398 399 wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); 400 os_memset(&priv->attr, 0, sizeof(priv->attr)); 401 priv->attr.nLength = sizeof(priv->attr); 402 priv->attr.bInheritHandle = FALSE; 403 t_sddl = wpa_strdup_tchar(sddl); 404 if (t_sddl == NULL) 405 return -1; 406 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 407 t_sddl, SDDL_REVISION_1, 408 (PSECURITY_DESCRIPTOR *) (void *) 409 &priv->attr.lpSecurityDescriptor, 410 NULL)) { 411 os_free(t_sddl); 412 wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " 413 "security descriptor: %d", 414 sddl, (int) GetLastError()); 415 return -1; 416 } 417 os_free(t_sddl); 418 419 priv->sec_attr_set = 1; 420 421 return 0; 422 } 423 424 425 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 426 enum wpa_msg_type type, 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 wpa_supplicant *wpa_s, 466 struct ctrl_iface_priv *priv) 467 { 468 if (!priv) 469 return; 470 while (priv->ctrl_dst) 471 ctrl_close_pipe(priv->ctrl_dst); 472 if (priv->sec_attr_set) 473 LocalFree(priv->attr.lpSecurityDescriptor); 474 os_free(priv); 475 } 476 477 478 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 479 int level, const char *buf, 480 size_t len) 481 { 482 struct wpa_ctrl_dst *dst, *next; 483 char levelstr[10]; 484 int idx; 485 char *sbuf; 486 int llen; 487 DWORD written; 488 489 dst = priv->ctrl_dst; 490 if (dst == NULL) 491 return; 492 493 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 494 495 llen = os_strlen(levelstr); 496 sbuf = os_malloc(llen + len); 497 if (sbuf == NULL) 498 return; 499 500 os_memcpy(sbuf, levelstr, llen); 501 os_memcpy(sbuf + llen, buf, len); 502 503 idx = 0; 504 while (dst) { 505 next = dst->next; 506 if (dst->attached && level >= dst->debug_level) { 507 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 508 dst); 509 if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 510 NULL)) { 511 wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 512 "%p failed: %d", 513 dst, (int) GetLastError()); 514 dst->errors++; 515 if (dst->errors > 10) 516 ctrl_close_pipe(dst); 517 } else 518 dst->errors = 0; 519 } 520 idx++; 521 dst = next; 522 } 523 os_free(sbuf); 524 } 525 526 527 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 528 { 529 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 530 priv->wpa_s->ifname); 531 if (priv->ctrl_dst == NULL) 532 return; 533 WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 534 } 535 536 537 /* Global ctrl_iface */ 538 539 struct ctrl_iface_global_priv; 540 541 struct wpa_global_dst { 542 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 543 */ 544 OVERLAPPED overlap; 545 struct wpa_global_dst *next, *prev; 546 struct ctrl_iface_global_priv *priv; 547 HANDLE pipe; 548 char req_buf[REQUEST_BUFSIZE]; 549 char *rsp_buf; 550 int used; 551 }; 552 553 struct ctrl_iface_global_priv { 554 struct wpa_global *global; 555 struct wpa_global_dst *ctrl_dst; 556 }; 557 558 559 static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 560 { 561 struct wpa_global_dst *dst, *next; 562 563 dst = priv->ctrl_dst; 564 565 while (dst) { 566 next = dst->next; 567 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 568 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 569 dst); 570 global_close_pipe(dst); 571 } 572 dst = next; 573 } 574 } 575 576 577 static int global_open_pipe(struct ctrl_iface_global_priv *priv) 578 { 579 struct wpa_global_dst *dst; 580 DWORD err; 581 582 dst = os_zalloc(sizeof(*dst)); 583 if (dst == NULL) 584 return -1; 585 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 586 587 dst->priv = priv; 588 dst->pipe = INVALID_HANDLE_VALUE; 589 590 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 591 if (dst->overlap.hEvent == NULL) { 592 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 593 (int) GetLastError()); 594 goto fail; 595 } 596 597 eloop_register_event(dst->overlap.hEvent, 598 sizeof(dst->overlap.hEvent), 599 wpa_supplicant_global_iface_receive, dst, NULL); 600 601 /* TODO: add support for configuring access list for the pipe */ 602 dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 603 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 604 PIPE_TYPE_MESSAGE | 605 PIPE_READMODE_MESSAGE | 606 PIPE_WAIT, 607 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 608 1000, NULL); 609 if (dst->pipe == INVALID_HANDLE_VALUE) { 610 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 611 (int) GetLastError()); 612 goto fail; 613 } 614 615 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 616 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 617 (int) GetLastError()); 618 CloseHandle(dst->pipe); 619 os_free(dst); 620 return -1; 621 } 622 623 err = GetLastError(); 624 switch (err) { 625 case ERROR_IO_PENDING: 626 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 627 "progress"); 628 break; 629 case ERROR_PIPE_CONNECTED: 630 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 631 "connected"); 632 if (SetEvent(dst->overlap.hEvent)) 633 break; 634 /* fall through */ 635 default: 636 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 637 (int) err); 638 CloseHandle(dst->pipe); 639 os_free(dst); 640 return -1; 641 } 642 643 dst->next = priv->ctrl_dst; 644 if (dst->next) 645 dst->next->prev = dst; 646 priv->ctrl_dst = dst; 647 648 return 0; 649 650 fail: 651 global_close_pipe(dst); 652 return -1; 653 } 654 655 656 static void global_close_pipe(struct wpa_global_dst *dst) 657 { 658 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 659 660 if (dst->overlap.hEvent) { 661 eloop_unregister_event(dst->overlap.hEvent, 662 sizeof(dst->overlap.hEvent)); 663 CloseHandle(dst->overlap.hEvent); 664 } 665 666 if (dst->pipe != INVALID_HANDLE_VALUE) { 667 /* 668 * Could use FlushFileBuffers() here to guarantee that all data 669 * gets delivered to the client, but that can block, so let's 670 * not do this for now. 671 * FlushFileBuffers(dst->pipe); 672 */ 673 CloseHandle(dst->pipe); 674 } 675 676 if (dst->prev) 677 dst->prev->next = dst->next; 678 else 679 dst->priv->ctrl_dst = dst->next; 680 if (dst->next) 681 dst->next->prev = dst->prev; 682 683 os_free(dst->rsp_buf); 684 os_free(dst); 685 } 686 687 688 static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 689 LPOVERLAPPED overlap) 690 { 691 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 692 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 693 "err=%d bytes=%d", dst, (int) err, (int) bytes); 694 if (err) { 695 global_close_pipe(dst); 696 return; 697 } 698 699 os_free(dst->rsp_buf); 700 dst->rsp_buf = NULL; 701 702 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 703 &dst->overlap, global_iface_read_completed)) { 704 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 705 (int) GetLastError()); 706 global_close_pipe(dst); 707 /* FIX: if this was the pipe waiting for new global 708 * connections, at this point there are no open global pipes.. 709 * Should try to open a new pipe.. */ 710 return; 711 } 712 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 713 } 714 715 716 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 717 size_t len) 718 { 719 struct wpa_global *global = dst->priv->global; 720 char *reply = NULL, *send_buf; 721 size_t reply_len = 0, send_len; 722 char *buf = dst->req_buf; 723 724 dst->used = 1; 725 if (len >= REQUEST_BUFSIZE) 726 len = REQUEST_BUFSIZE - 1; 727 buf[len] = '\0'; 728 729 reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 730 &reply_len); 731 if (reply) { 732 send_buf = reply; 733 send_len = reply_len; 734 } else if (reply_len) { 735 send_buf = "FAIL\n"; 736 send_len = 5; 737 } else { 738 os_free(dst->rsp_buf); 739 dst->rsp_buf = NULL; 740 return; 741 } 742 743 os_free(dst->rsp_buf); 744 dst->rsp_buf = os_memdup(send_buf, send_len); 745 if (dst->rsp_buf == NULL) { 746 global_close_pipe(dst); 747 os_free(reply); 748 return; 749 } 750 os_free(reply); 751 752 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 753 global_iface_write_completed)) { 754 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 755 (int) GetLastError()); 756 global_close_pipe(dst); 757 } else { 758 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 759 dst); 760 } 761 } 762 763 764 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 765 LPOVERLAPPED overlap) 766 { 767 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 768 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 769 "bytes=%d", dst, (int) err, (int) bytes); 770 if (err == 0 && bytes > 0) 771 wpa_supplicant_global_iface_rx(dst, bytes); 772 } 773 774 775 static void wpa_supplicant_global_iface_receive(void *eloop_data, 776 void *user_ctx) 777 { 778 struct wpa_global_dst *dst = eloop_data; 779 struct ctrl_iface_global_priv *priv = dst->priv; 780 DWORD bytes; 781 782 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 783 ResetEvent(dst->overlap.hEvent); 784 785 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 786 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 787 (int) GetLastError()); 788 return; 789 } 790 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 791 "connected"); 792 793 /* Open a new named pipe for the next client. */ 794 if (global_open_pipe(priv) < 0) { 795 wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 796 return; 797 } 798 799 /* Use write completion function to start reading a command */ 800 global_iface_write_completed(0, 0, &dst->overlap); 801 802 global_flush_broken_pipes(priv); 803 } 804 805 806 struct ctrl_iface_global_priv * 807 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 808 { 809 struct ctrl_iface_global_priv *priv; 810 811 priv = os_zalloc(sizeof(*priv)); 812 if (priv == NULL) 813 return NULL; 814 priv->global = global; 815 816 if (global_open_pipe(priv) < 0) { 817 os_free(priv); 818 return NULL; 819 } 820 821 return priv; 822 } 823 824 825 void 826 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 827 { 828 while (priv->ctrl_dst) 829 global_close_pipe(priv->ctrl_dst); 830 os_free(priv); 831 } 832