$search
00001 /* 00002 * WPA Supplicant / Windows Named Pipe -based control interface 00003 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eloop.h" 00019 #include "config.h" 00020 #include "eapol_supp/eapol_supp_sm.h" 00021 #include "wpa_supplicant_i.h" 00022 #include "ctrl_iface.h" 00023 #include "common/wpa_ctrl.h" 00024 00025 #ifdef __MINGW32_VERSION 00026 /* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here 00027 */ 00028 #define SDDL_REVISION_1 1 00029 BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( 00030 LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 00031 BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( 00032 LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 00033 #ifdef UNICODE 00034 #define ConvertStringSecurityDescriptorToSecurityDescriptor \ 00035 ConvertStringSecurityDescriptorToSecurityDescriptorW 00036 #else 00037 #define ConvertStringSecurityDescriptorToSecurityDescriptor \ 00038 ConvertStringSecurityDescriptorToSecurityDescriptorA 00039 #endif 00040 #else /* __MINGW32_VERSION */ 00041 #ifndef _WIN32_WINNT 00042 #define _WIN32_WINNT 0x0500 00043 #endif 00044 #include <sddl.h> 00045 #endif /* __MINGW32_VERSION */ 00046 00047 #ifndef WPA_SUPPLICANT_NAMED_PIPE 00048 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 00049 #endif 00050 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 00051 00052 /* Per-interface ctrl_iface */ 00053 00054 #define REQUEST_BUFSIZE 256 00055 #define REPLY_BUFSIZE 4096 00056 00057 struct ctrl_iface_priv; 00058 00066 struct wpa_ctrl_dst { 00067 /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ 00068 OVERLAPPED overlap; 00069 struct wpa_ctrl_dst *next, *prev; 00070 struct ctrl_iface_priv *priv; 00071 HANDLE pipe; 00072 int attached; 00073 int debug_level; 00074 int errors; 00075 char req_buf[REQUEST_BUFSIZE]; 00076 char *rsp_buf; 00077 int used; 00078 }; 00079 00080 00081 struct ctrl_iface_priv { 00082 struct wpa_supplicant *wpa_s; 00083 struct wpa_ctrl_dst *ctrl_dst; 00084 SECURITY_ATTRIBUTES attr; 00085 int sec_attr_set; 00086 }; 00087 00088 00089 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 00090 int level, const char *buf, 00091 size_t len); 00092 00093 static void ctrl_close_pipe(struct wpa_ctrl_dst *dst); 00094 static void wpa_supplicant_ctrl_iface_receive(void *, void *); 00095 static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 00096 LPOVERLAPPED overlap); 00097 00098 struct wpa_global_dst; 00099 static void global_close_pipe(struct wpa_global_dst *dst); 00100 static void wpa_supplicant_global_iface_receive(void *eloop_data, 00101 void *user_ctx); 00102 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 00103 LPOVERLAPPED overlap); 00104 00105 00106 static int ctrl_broken_pipe(HANDLE pipe, int used) 00107 { 00108 DWORD err; 00109 00110 if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) 00111 return 0; 00112 00113 err = GetLastError(); 00114 if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) 00115 return 1; 00116 return 0; 00117 } 00118 00119 00120 static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) 00121 { 00122 struct wpa_ctrl_dst *dst, *next; 00123 00124 dst = priv->ctrl_dst; 00125 00126 while (dst) { 00127 next = dst->next; 00128 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 00129 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 00130 dst); 00131 ctrl_close_pipe(dst); 00132 } 00133 dst = next; 00134 } 00135 } 00136 00137 00138 static int ctrl_open_pipe(struct ctrl_iface_priv *priv) 00139 { 00140 struct wpa_ctrl_dst *dst; 00141 DWORD err; 00142 TCHAR name[256]; 00143 00144 dst = os_zalloc(sizeof(*dst)); 00145 if (dst == NULL) 00146 return -1; 00147 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 00148 00149 dst->priv = priv; 00150 dst->debug_level = MSG_INFO; 00151 dst->pipe = INVALID_HANDLE_VALUE; 00152 00153 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 00154 if (dst->overlap.hEvent == NULL) { 00155 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 00156 (int) GetLastError()); 00157 goto fail; 00158 } 00159 00160 eloop_register_event(dst->overlap.hEvent, 00161 sizeof(dst->overlap.hEvent), 00162 wpa_supplicant_ctrl_iface_receive, dst, NULL); 00163 00164 #ifdef UNICODE 00165 _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 00166 priv->wpa_s->ifname); 00167 #else /* UNICODE */ 00168 os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 00169 priv->wpa_s->ifname); 00170 #endif /* UNICODE */ 00171 00172 /* TODO: add support for configuring access list for the pipe */ 00173 dst->pipe = CreateNamedPipe(name, 00174 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 00175 PIPE_TYPE_MESSAGE | 00176 PIPE_READMODE_MESSAGE | 00177 PIPE_WAIT, 00178 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, 00179 1000, 00180 priv->sec_attr_set ? &priv->attr : NULL); 00181 if (dst->pipe == INVALID_HANDLE_VALUE) { 00182 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 00183 (int) GetLastError()); 00184 goto fail; 00185 } 00186 00187 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 00188 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 00189 (int) GetLastError()); 00190 CloseHandle(dst->pipe); 00191 os_free(dst); 00192 return -1; 00193 } 00194 00195 err = GetLastError(); 00196 switch (err) { 00197 case ERROR_IO_PENDING: 00198 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 00199 "progress"); 00200 break; 00201 case ERROR_PIPE_CONNECTED: 00202 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 00203 "connected"); 00204 if (SetEvent(dst->overlap.hEvent)) 00205 break; 00206 /* fall through */ 00207 default: 00208 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 00209 (int) err); 00210 CloseHandle(dst->pipe); 00211 os_free(dst); 00212 return -1; 00213 } 00214 00215 dst->next = priv->ctrl_dst; 00216 if (dst->next) 00217 dst->next->prev = dst; 00218 priv->ctrl_dst = dst; 00219 00220 return 0; 00221 00222 fail: 00223 ctrl_close_pipe(dst); 00224 return -1; 00225 } 00226 00227 00228 static void ctrl_close_pipe(struct wpa_ctrl_dst *dst) 00229 { 00230 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 00231 00232 if (dst->overlap.hEvent) { 00233 eloop_unregister_event(dst->overlap.hEvent, 00234 sizeof(dst->overlap.hEvent)); 00235 CloseHandle(dst->overlap.hEvent); 00236 } 00237 00238 if (dst->pipe != INVALID_HANDLE_VALUE) { 00239 /* 00240 * Could use FlushFileBuffers() here to guarantee that all data 00241 * gets delivered to the client, but that can block, so let's 00242 * not do this for now. 00243 * FlushFileBuffers(dst->pipe); 00244 */ 00245 CloseHandle(dst->pipe); 00246 } 00247 00248 if (dst->prev) 00249 dst->prev->next = dst->next; 00250 else 00251 dst->priv->ctrl_dst = dst->next; 00252 if (dst->next) 00253 dst->next->prev = dst->prev; 00254 00255 os_free(dst->rsp_buf); 00256 os_free(dst); 00257 } 00258 00259 00260 static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, 00261 LPOVERLAPPED overlap) 00262 { 00263 struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 00264 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 00265 "err=%d bytes=%d", dst, (int) err, (int) bytes); 00266 if (err) { 00267 ctrl_close_pipe(dst); 00268 return; 00269 } 00270 00271 os_free(dst->rsp_buf); 00272 dst->rsp_buf = NULL; 00273 00274 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 00275 &dst->overlap, ctrl_iface_read_completed)) { 00276 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 00277 (int) GetLastError()); 00278 ctrl_close_pipe(dst); 00279 return; 00280 } 00281 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 00282 } 00283 00284 00285 static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) 00286 { 00287 struct wpa_supplicant *wpa_s = dst->priv->wpa_s; 00288 char *reply = NULL, *send_buf; 00289 size_t reply_len = 0, send_len; 00290 int new_attached = 0; 00291 char *buf = dst->req_buf; 00292 00293 dst->used = 1; 00294 if (len >= REQUEST_BUFSIZE) 00295 len = REQUEST_BUFSIZE - 1; 00296 buf[len] = '\0'; 00297 00298 if (os_strcmp(buf, "ATTACH") == 0) { 00299 dst->attached = 1; 00300 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); 00301 new_attached = 1; 00302 reply_len = 2; 00303 } else if (os_strcmp(buf, "DETACH") == 0) { 00304 dst->attached = 0; 00305 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); 00306 reply_len = 2; 00307 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 00308 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); 00309 dst->debug_level = atoi(buf + 6); 00310 reply_len = 2; 00311 } else { 00312 reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 00313 &reply_len); 00314 } 00315 00316 if (reply) { 00317 send_buf = reply; 00318 send_len = reply_len; 00319 } else if (reply_len == 2) { 00320 send_buf = "OK\n"; 00321 send_len = 3; 00322 } else { 00323 send_buf = "FAIL\n"; 00324 send_len = 5; 00325 } 00326 00327 os_free(dst->rsp_buf); 00328 dst->rsp_buf = os_malloc(send_len); 00329 if (dst->rsp_buf == NULL) { 00330 ctrl_close_pipe(dst); 00331 os_free(reply); 00332 return; 00333 } 00334 os_memcpy(dst->rsp_buf, send_buf, send_len); 00335 os_free(reply); 00336 00337 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 00338 ctrl_iface_write_completed)) { 00339 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 00340 (int) GetLastError()); 00341 ctrl_close_pipe(dst); 00342 } else { 00343 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 00344 dst); 00345 } 00346 00347 if (new_attached) 00348 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 00349 } 00350 00351 00352 static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 00353 LPOVERLAPPED overlap) 00354 { 00355 struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 00356 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 00357 "bytes=%d", dst, (int) err, (int) bytes); 00358 if (err == 0 && bytes > 0) 00359 wpa_supplicant_ctrl_iface_rx(dst, bytes); 00360 } 00361 00362 00363 static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) 00364 { 00365 struct wpa_ctrl_dst *dst = eloop_data; 00366 struct ctrl_iface_priv *priv = dst->priv; 00367 DWORD bytes; 00368 00369 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); 00370 ResetEvent(dst->overlap.hEvent); 00371 00372 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 00373 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 00374 (int) GetLastError()); 00375 return; 00376 } 00377 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 00378 "connected"); 00379 00380 /* Open a new named pipe for the next client. */ 00381 ctrl_open_pipe(priv); 00382 00383 /* Use write completion function to start reading a command */ 00384 ctrl_iface_write_completed(0, 0, &dst->overlap); 00385 00386 ctrl_flush_broken_pipes(priv); 00387 } 00388 00389 00390 static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) 00391 { 00392 const char *sddl = NULL; 00393 TCHAR *t_sddl; 00394 00395 if (os_strncmp(params, "SDDL=", 5) == 0) 00396 sddl = params + 5; 00397 if (!sddl) { 00398 sddl = os_strstr(params, " SDDL="); 00399 if (sddl) 00400 sddl += 6; 00401 } 00402 00403 if (!sddl) 00404 return 0; 00405 00406 wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); 00407 os_memset(&priv->attr, 0, sizeof(priv->attr)); 00408 priv->attr.nLength = sizeof(priv->attr); 00409 priv->attr.bInheritHandle = FALSE; 00410 t_sddl = wpa_strdup_tchar(sddl); 00411 if (t_sddl == NULL) 00412 return -1; 00413 if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 00414 t_sddl, SDDL_REVISION_1, 00415 (PSECURITY_DESCRIPTOR *) (void *) 00416 &priv->attr.lpSecurityDescriptor, 00417 NULL)) { 00418 os_free(t_sddl); 00419 wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " 00420 "security descriptor: %d", 00421 sddl, (int) GetLastError()); 00422 return -1; 00423 } 00424 os_free(t_sddl); 00425 00426 priv->sec_attr_set = 1; 00427 00428 return 0; 00429 } 00430 00431 00432 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 00433 const char *txt, size_t len) 00434 { 00435 struct wpa_supplicant *wpa_s = ctx; 00436 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 00437 return; 00438 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 00439 } 00440 00441 00442 struct ctrl_iface_priv * 00443 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 00444 { 00445 struct ctrl_iface_priv *priv; 00446 00447 priv = os_zalloc(sizeof(*priv)); 00448 if (priv == NULL) 00449 return NULL; 00450 priv->wpa_s = wpa_s; 00451 00452 if (wpa_s->conf->ctrl_interface == NULL) 00453 return priv; 00454 00455 if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { 00456 os_free(priv); 00457 return NULL; 00458 } 00459 00460 if (ctrl_open_pipe(priv) < 0) { 00461 os_free(priv); 00462 return NULL; 00463 } 00464 00465 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 00466 00467 return priv; 00468 } 00469 00470 00471 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 00472 { 00473 while (priv->ctrl_dst) 00474 ctrl_close_pipe(priv->ctrl_dst); 00475 if (priv->sec_attr_set) 00476 LocalFree(priv->attr.lpSecurityDescriptor); 00477 os_free(priv); 00478 } 00479 00480 00481 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 00482 int level, const char *buf, 00483 size_t len) 00484 { 00485 struct wpa_ctrl_dst *dst, *next; 00486 char levelstr[10]; 00487 int idx; 00488 char *sbuf; 00489 int llen; 00490 DWORD written; 00491 00492 dst = priv->ctrl_dst; 00493 if (dst == NULL) 00494 return; 00495 00496 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 00497 00498 llen = os_strlen(levelstr); 00499 sbuf = os_malloc(llen + len); 00500 if (sbuf == NULL) 00501 return; 00502 00503 os_memcpy(sbuf, levelstr, llen); 00504 os_memcpy(sbuf + llen, buf, len); 00505 00506 idx = 0; 00507 while (dst) { 00508 next = dst->next; 00509 if (dst->attached && level >= dst->debug_level) { 00510 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 00511 dst); 00512 if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 00513 NULL)) { 00514 wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 00515 "%p failed: %d", 00516 dst, (int) GetLastError()); 00517 dst->errors++; 00518 if (dst->errors > 10) 00519 ctrl_close_pipe(dst); 00520 } else 00521 dst->errors = 0; 00522 } 00523 idx++; 00524 dst = next; 00525 } 00526 os_free(sbuf); 00527 } 00528 00529 00530 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 00531 { 00532 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 00533 priv->wpa_s->ifname); 00534 if (priv->ctrl_dst == NULL) 00535 return; 00536 WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 00537 } 00538 00539 00540 /* Global ctrl_iface */ 00541 00542 struct ctrl_iface_global_priv; 00543 00544 struct wpa_global_dst { 00545 /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 00546 */ 00547 OVERLAPPED overlap; 00548 struct wpa_global_dst *next, *prev; 00549 struct ctrl_iface_global_priv *priv; 00550 HANDLE pipe; 00551 char req_buf[REQUEST_BUFSIZE]; 00552 char *rsp_buf; 00553 int used; 00554 }; 00555 00556 struct ctrl_iface_global_priv { 00557 struct wpa_global *global; 00558 struct wpa_global_dst *ctrl_dst; 00559 }; 00560 00561 00562 static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 00563 { 00564 struct wpa_global_dst *dst, *next; 00565 00566 dst = priv->ctrl_dst; 00567 00568 while (dst) { 00569 next = dst->next; 00570 if (ctrl_broken_pipe(dst->pipe, dst->used)) { 00571 wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 00572 dst); 00573 global_close_pipe(dst); 00574 } 00575 dst = next; 00576 } 00577 } 00578 00579 00580 static int global_open_pipe(struct ctrl_iface_global_priv *priv) 00581 { 00582 struct wpa_global_dst *dst; 00583 DWORD err; 00584 00585 dst = os_zalloc(sizeof(*dst)); 00586 if (dst == NULL) 00587 return -1; 00588 wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 00589 00590 dst->priv = priv; 00591 dst->pipe = INVALID_HANDLE_VALUE; 00592 00593 dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 00594 if (dst->overlap.hEvent == NULL) { 00595 wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 00596 (int) GetLastError()); 00597 goto fail; 00598 } 00599 00600 eloop_register_event(dst->overlap.hEvent, 00601 sizeof(dst->overlap.hEvent), 00602 wpa_supplicant_global_iface_receive, dst, NULL); 00603 00604 /* TODO: add support for configuring access list for the pipe */ 00605 dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 00606 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 00607 PIPE_TYPE_MESSAGE | 00608 PIPE_READMODE_MESSAGE | 00609 PIPE_WAIT, 00610 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 00611 1000, NULL); 00612 if (dst->pipe == INVALID_HANDLE_VALUE) { 00613 wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 00614 (int) GetLastError()); 00615 goto fail; 00616 } 00617 00618 if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 00619 wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 00620 (int) GetLastError()); 00621 CloseHandle(dst->pipe); 00622 os_free(dst); 00623 return -1; 00624 } 00625 00626 err = GetLastError(); 00627 switch (err) { 00628 case ERROR_IO_PENDING: 00629 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 00630 "progress"); 00631 break; 00632 case ERROR_PIPE_CONNECTED: 00633 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 00634 "connected"); 00635 if (SetEvent(dst->overlap.hEvent)) 00636 break; 00637 /* fall through */ 00638 default: 00639 wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 00640 (int) err); 00641 CloseHandle(dst->pipe); 00642 os_free(dst); 00643 return -1; 00644 } 00645 00646 dst->next = priv->ctrl_dst; 00647 if (dst->next) 00648 dst->next->prev = dst; 00649 priv->ctrl_dst = dst; 00650 00651 return 0; 00652 00653 fail: 00654 global_close_pipe(dst); 00655 return -1; 00656 } 00657 00658 00659 static void global_close_pipe(struct wpa_global_dst *dst) 00660 { 00661 wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 00662 00663 if (dst->overlap.hEvent) { 00664 eloop_unregister_event(dst->overlap.hEvent, 00665 sizeof(dst->overlap.hEvent)); 00666 CloseHandle(dst->overlap.hEvent); 00667 } 00668 00669 if (dst->pipe != INVALID_HANDLE_VALUE) { 00670 /* 00671 * Could use FlushFileBuffers() here to guarantee that all data 00672 * gets delivered to the client, but that can block, so let's 00673 * not do this for now. 00674 * FlushFileBuffers(dst->pipe); 00675 */ 00676 CloseHandle(dst->pipe); 00677 } 00678 00679 if (dst->prev) 00680 dst->prev->next = dst->next; 00681 else 00682 dst->priv->ctrl_dst = dst->next; 00683 if (dst->next) 00684 dst->next->prev = dst->prev; 00685 00686 os_free(dst->rsp_buf); 00687 os_free(dst); 00688 } 00689 00690 00691 static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 00692 LPOVERLAPPED overlap) 00693 { 00694 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 00695 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 00696 "err=%d bytes=%d", dst, (int) err, (int) bytes); 00697 if (err) { 00698 global_close_pipe(dst); 00699 return; 00700 } 00701 00702 os_free(dst->rsp_buf); 00703 dst->rsp_buf = NULL; 00704 00705 if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 00706 &dst->overlap, global_iface_read_completed)) { 00707 wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 00708 (int) GetLastError()); 00709 global_close_pipe(dst); 00710 /* FIX: if this was the pipe waiting for new global 00711 * connections, at this point there are no open global pipes.. 00712 * Should try to open a new pipe.. */ 00713 return; 00714 } 00715 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 00716 } 00717 00718 00719 static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 00720 size_t len) 00721 { 00722 struct wpa_global *global = dst->priv->global; 00723 char *reply = NULL, *send_buf; 00724 size_t reply_len = 0, send_len; 00725 char *buf = dst->req_buf; 00726 00727 dst->used = 1; 00728 if (len >= REQUEST_BUFSIZE) 00729 len = REQUEST_BUFSIZE - 1; 00730 buf[len] = '\0'; 00731 00732 reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 00733 &reply_len); 00734 if (reply) { 00735 send_buf = reply; 00736 send_len = reply_len; 00737 } else if (reply_len) { 00738 send_buf = "FAIL\n"; 00739 send_len = 5; 00740 } else { 00741 os_free(dst->rsp_buf); 00742 dst->rsp_buf = NULL; 00743 return; 00744 } 00745 00746 os_free(dst->rsp_buf); 00747 dst->rsp_buf = os_malloc(send_len); 00748 if (dst->rsp_buf == NULL) { 00749 global_close_pipe(dst); 00750 os_free(reply); 00751 return; 00752 } 00753 os_memcpy(dst->rsp_buf, send_buf, send_len); 00754 os_free(reply); 00755 00756 if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 00757 global_iface_write_completed)) { 00758 wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 00759 (int) GetLastError()); 00760 global_close_pipe(dst); 00761 } else { 00762 wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 00763 dst); 00764 } 00765 } 00766 00767 00768 static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 00769 LPOVERLAPPED overlap) 00770 { 00771 struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 00772 wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 00773 "bytes=%d", dst, (int) err, (int) bytes); 00774 if (err == 0 && bytes > 0) 00775 wpa_supplicant_global_iface_rx(dst, bytes); 00776 } 00777 00778 00779 static void wpa_supplicant_global_iface_receive(void *eloop_data, 00780 void *user_ctx) 00781 { 00782 struct wpa_global_dst *dst = eloop_data; 00783 struct ctrl_iface_global_priv *priv = dst->priv; 00784 DWORD bytes; 00785 00786 wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 00787 ResetEvent(dst->overlap.hEvent); 00788 00789 if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 00790 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 00791 (int) GetLastError()); 00792 return; 00793 } 00794 wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 00795 "connected"); 00796 00797 /* Open a new named pipe for the next client. */ 00798 if (global_open_pipe(priv) < 0) { 00799 wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 00800 return; 00801 } 00802 00803 /* Use write completion function to start reading a command */ 00804 global_iface_write_completed(0, 0, &dst->overlap); 00805 00806 global_flush_broken_pipes(priv); 00807 } 00808 00809 00810 struct ctrl_iface_global_priv * 00811 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 00812 { 00813 struct ctrl_iface_global_priv *priv; 00814 00815 priv = os_zalloc(sizeof(*priv)); 00816 if (priv == NULL) 00817 return NULL; 00818 priv->global = global; 00819 00820 if (global_open_pipe(priv) < 0) { 00821 os_free(priv); 00822 return NULL; 00823 } 00824 00825 return priv; 00826 } 00827 00828 00829 void 00830 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 00831 { 00832 while (priv->ctrl_dst) 00833 global_close_pipe(priv->ctrl_dst); 00834 os_free(priv); 00835 }