ctrl_iface_named_pipe.c revision 252726
155714Skris/* 255714Skris * WPA Supplicant / Windows Named Pipe -based control interface 355714Skris * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi> 455714Skris * 555714Skris * This software may be distributed under the terms of the BSD license. 655714Skris * See README for more details. 755714Skris */ 855714Skris 955714Skris#include "includes.h" 1055714Skris 1155714Skris#include "common.h" 1255714Skris#include "eloop.h" 1355714Skris#include "config.h" 1455714Skris#include "eapol_supp/eapol_supp_sm.h" 1555714Skris#include "wpa_supplicant_i.h" 1655714Skris#include "ctrl_iface.h" 1755714Skris#include "common/wpa_ctrl.h" 1855714Skris 1955714Skris#ifdef __MINGW32_VERSION 2055714Skris/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here 2155714Skris */ 2255714Skris#define SDDL_REVISION_1 1 2355714SkrisBOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA( 2455714Skris LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 2555714SkrisBOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW( 2655714Skris LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG); 2755714Skris#ifdef UNICODE 2855714Skris#define ConvertStringSecurityDescriptorToSecurityDescriptor \ 2955714SkrisConvertStringSecurityDescriptorToSecurityDescriptorW 3055714Skris#else 3155714Skris#define ConvertStringSecurityDescriptorToSecurityDescriptor \ 3255714SkrisConvertStringSecurityDescriptorToSecurityDescriptorA 3355714Skris#endif 3455714Skris#else /* __MINGW32_VERSION */ 3555714Skris#ifndef _WIN32_WINNT 3655714Skris#define _WIN32_WINNT 0x0500 3755714Skris#endif 3855714Skris#include <sddl.h> 3955714Skris#endif /* __MINGW32_VERSION */ 4055714Skris 4155714Skris#ifndef WPA_SUPPLICANT_NAMED_PIPE 4255714Skris#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 4355714Skris#endif 4455714Skris#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 4555714Skris 4655714Skris/* Per-interface ctrl_iface */ 4755714Skris 4855714Skris#define REQUEST_BUFSIZE 256 4955714Skris#define REPLY_BUFSIZE 4096 5055714Skris 5155714Skrisstruct ctrl_iface_priv; 5255714Skris 5355714Skris/** 5455714Skris * struct wpa_ctrl_dst - Internal data structure of control interface clients 5555714Skris * 5655714Skris * This structure is used to store information about registered control 5755714Skris * interface monitors into struct wpa_supplicant. This data is private to 5855714Skris * ctrl_iface_named_pipe.c and should not be touched directly from other files. 5955714Skris */ 6055714Skrisstruct wpa_ctrl_dst { 6155714Skris /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */ 6255714Skris OVERLAPPED overlap; 6355714Skris struct wpa_ctrl_dst *next, *prev; 6455714Skris struct ctrl_iface_priv *priv; 6555714Skris HANDLE pipe; 6655714Skris int attached; 6755714Skris int debug_level; 6855714Skris int errors; 6955714Skris char req_buf[REQUEST_BUFSIZE]; 7055714Skris char *rsp_buf; 7155714Skris int used; 7255714Skris}; 7355714Skris 7455714Skris 7555714Skrisstruct ctrl_iface_priv { 7655714Skris struct wpa_supplicant *wpa_s; 7755714Skris struct wpa_ctrl_dst *ctrl_dst; 7855714Skris SECURITY_ATTRIBUTES attr; 7955714Skris int sec_attr_set; 8055714Skris}; 8155714Skris 8255714Skris 8355714Skrisstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 8455714Skris int level, const char *buf, 8555714Skris size_t len); 8655714Skris 8755714Skrisstatic void ctrl_close_pipe(struct wpa_ctrl_dst *dst); 8855714Skrisstatic void wpa_supplicant_ctrl_iface_receive(void *, void *); 8955714Skrisstatic VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 9055714Skris LPOVERLAPPED overlap); 9155714Skris 9255714Skrisstruct wpa_global_dst; 9355714Skrisstatic void global_close_pipe(struct wpa_global_dst *dst); 9455714Skrisstatic void wpa_supplicant_global_iface_receive(void *eloop_data, 9555714Skris void *user_ctx); 9655714Skrisstatic VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 9755714Skris LPOVERLAPPED overlap); 9855714Skris 9955714Skris 10055714Skrisstatic int ctrl_broken_pipe(HANDLE pipe, int used) 10155714Skris{ 10255714Skris DWORD err; 10355714Skris 10455714Skris if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL)) 10555714Skris return 0; 10655714Skris 10755714Skris err = GetLastError(); 10855714Skris if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used)) 10955714Skris return 1; 11055714Skris return 0; 11155714Skris} 11255714Skris 11355714Skris 11455714Skrisstatic void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv) 11555714Skris{ 11655714Skris struct wpa_ctrl_dst *dst, *next; 11755714Skris 11855714Skris dst = priv->ctrl_dst; 11955714Skris 12055714Skris while (dst) { 12155714Skris next = dst->next; 12255714Skris if (ctrl_broken_pipe(dst->pipe, dst->used)) { 12355714Skris wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 12455714Skris dst); 12555714Skris ctrl_close_pipe(dst); 12655714Skris } 12755714Skris dst = next; 12855714Skris } 12955714Skris} 13055714Skris 13155714Skris 13255714Skrisstatic int ctrl_open_pipe(struct ctrl_iface_priv *priv) 13355714Skris{ 13455714Skris struct wpa_ctrl_dst *dst; 13555714Skris DWORD err; 13655714Skris TCHAR name[256]; 13755714Skris 13855714Skris dst = os_zalloc(sizeof(*dst)); 13955714Skris if (dst == NULL) 14055714Skris return -1; 14155714Skris wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 14255714Skris 14355714Skris dst->priv = priv; 14455714Skris dst->debug_level = MSG_INFO; 14555714Skris dst->pipe = INVALID_HANDLE_VALUE; 14655714Skris 14755714Skris dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 14855714Skris if (dst->overlap.hEvent == NULL) { 14955714Skris wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 15055714Skris (int) GetLastError()); 15155714Skris goto fail; 15255714Skris } 15355714Skris 15455714Skris eloop_register_event(dst->overlap.hEvent, 15555714Skris sizeof(dst->overlap.hEvent), 15655714Skris wpa_supplicant_ctrl_iface_receive, dst, NULL); 15755714Skris 15855714Skris#ifdef UNICODE 15955714Skris _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 16055714Skris priv->wpa_s->ifname); 16155714Skris#else /* UNICODE */ 16255714Skris os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 16355714Skris priv->wpa_s->ifname); 16455714Skris#endif /* UNICODE */ 16555714Skris 16655714Skris /* TODO: add support for configuring access list for the pipe */ 16755714Skris dst->pipe = CreateNamedPipe(name, 16855714Skris PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 16955714Skris PIPE_TYPE_MESSAGE | 17055714Skris PIPE_READMODE_MESSAGE | 17155714Skris PIPE_WAIT, 17255714Skris 15, REPLY_BUFSIZE, REQUEST_BUFSIZE, 17355714Skris 1000, 17455714Skris priv->sec_attr_set ? &priv->attr : NULL); 17555714Skris if (dst->pipe == INVALID_HANDLE_VALUE) { 17655714Skris wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 17755714Skris (int) GetLastError()); 17855714Skris goto fail; 17955714Skris } 18055714Skris 18155714Skris if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 18255714Skris wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 18355714Skris (int) GetLastError()); 18455714Skris CloseHandle(dst->pipe); 18555714Skris os_free(dst); 18655714Skris return -1; 18755714Skris } 18855714Skris 18955714Skris err = GetLastError(); 19055714Skris switch (err) { 19155714Skris case ERROR_IO_PENDING: 19255714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 19355714Skris "progress"); 19455714Skris break; 19555714Skris case ERROR_PIPE_CONNECTED: 19655714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 19755714Skris "connected"); 19855714Skris if (SetEvent(dst->overlap.hEvent)) 19955714Skris break; 20055714Skris /* fall through */ 20155714Skris default: 20255714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 20355714Skris (int) err); 20455714Skris CloseHandle(dst->pipe); 20555714Skris os_free(dst); 20655714Skris return -1; 20755714Skris } 20855714Skris 20955714Skris dst->next = priv->ctrl_dst; 21055714Skris if (dst->next) 21155714Skris dst->next->prev = dst; 21255714Skris priv->ctrl_dst = dst; 21355714Skris 21455714Skris return 0; 21555714Skris 21655714Skrisfail: 21755714Skris ctrl_close_pipe(dst); 21855714Skris return -1; 21955714Skris} 22055714Skris 22155714Skris 22255714Skrisstatic void ctrl_close_pipe(struct wpa_ctrl_dst *dst) 22355714Skris{ 22455714Skris wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 22555714Skris 22655714Skris if (dst->overlap.hEvent) { 22755714Skris eloop_unregister_event(dst->overlap.hEvent, 22855714Skris sizeof(dst->overlap.hEvent)); 22955714Skris CloseHandle(dst->overlap.hEvent); 23055714Skris } 23155714Skris 23255714Skris if (dst->pipe != INVALID_HANDLE_VALUE) { 23355714Skris /* 23455714Skris * Could use FlushFileBuffers() here to guarantee that all data 23555714Skris * gets delivered to the client, but that can block, so let's 23655714Skris * not do this for now. 23755714Skris * FlushFileBuffers(dst->pipe); 23855714Skris */ 23955714Skris CloseHandle(dst->pipe); 24055714Skris } 24155714Skris 24255714Skris if (dst->prev) 24355714Skris dst->prev->next = dst->next; 24455714Skris else 24555714Skris dst->priv->ctrl_dst = dst->next; 24655714Skris if (dst->next) 24755714Skris dst->next->prev = dst->prev; 24855714Skris 24955714Skris os_free(dst->rsp_buf); 25055714Skris os_free(dst); 25155714Skris} 25255714Skris 25355714Skris 25455714Skrisstatic VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes, 25555714Skris LPOVERLAPPED overlap) 25655714Skris{ 25755714Skris struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 25855714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 25955714Skris "err=%d bytes=%d", dst, (int) err, (int) bytes); 26055714Skris if (err) { 26155714Skris ctrl_close_pipe(dst); 26255714Skris return; 26355714Skris } 26455714Skris 26555714Skris os_free(dst->rsp_buf); 26655714Skris dst->rsp_buf = NULL; 26755714Skris 26855714Skris if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 26955714Skris &dst->overlap, ctrl_iface_read_completed)) { 27055714Skris wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 27155714Skris (int) GetLastError()); 27255714Skris ctrl_close_pipe(dst); 27355714Skris return; 27455714Skris } 27555714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 27655714Skris} 27755714Skris 27855714Skris 27955714Skrisstatic void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len) 28055714Skris{ 28155714Skris struct wpa_supplicant *wpa_s = dst->priv->wpa_s; 28255714Skris char *reply = NULL, *send_buf; 28355714Skris size_t reply_len = 0, send_len; 28455714Skris int new_attached = 0; 28555714Skris char *buf = dst->req_buf; 28655714Skris 28755714Skris dst->used = 1; 28855714Skris if (len >= REQUEST_BUFSIZE) 28955714Skris len = REQUEST_BUFSIZE - 1; 29055714Skris buf[len] = '\0'; 29155714Skris 29255714Skris if (os_strcmp(buf, "ATTACH") == 0) { 29355714Skris dst->attached = 1; 29455714Skris wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached"); 29555714Skris new_attached = 1; 29655714Skris reply_len = 2; 29755714Skris } else if (os_strcmp(buf, "DETACH") == 0) { 29855714Skris dst->attached = 0; 29955714Skris wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached"); 30055714Skris reply_len = 2; 30155714Skris } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 30255714Skris wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6); 30355714Skris dst->debug_level = atoi(buf + 6); 30455714Skris reply_len = 2; 30555714Skris } else { 30655714Skris reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 30755714Skris &reply_len); 30855714Skris } 30955714Skris 31055714Skris if (reply) { 31155714Skris send_buf = reply; 31255714Skris send_len = reply_len; 31355714Skris } else if (reply_len == 2) { 31455714Skris send_buf = "OK\n"; 31555714Skris send_len = 3; 31655714Skris } else { 31755714Skris send_buf = "FAIL\n"; 31855714Skris send_len = 5; 31955714Skris } 32055714Skris 32155714Skris os_free(dst->rsp_buf); 32255714Skris dst->rsp_buf = os_malloc(send_len); 32355714Skris if (dst->rsp_buf == NULL) { 32455714Skris ctrl_close_pipe(dst); 32555714Skris os_free(reply); 32655714Skris return; 32755714Skris } 32855714Skris os_memcpy(dst->rsp_buf, send_buf, send_len); 32955714Skris os_free(reply); 33055714Skris 33155714Skris if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 33255714Skris ctrl_iface_write_completed)) { 33355714Skris wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 33455714Skris (int) GetLastError()); 33555714Skris ctrl_close_pipe(dst); 33655714Skris } else { 33755714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 33855714Skris dst); 33955714Skris } 34055714Skris 34155714Skris if (new_attached) 34255714Skris eapol_sm_notify_ctrl_attached(wpa_s->eapol); 34355714Skris} 34455714Skris 34555714Skris 34655714Skrisstatic VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes, 34755714Skris LPOVERLAPPED overlap) 34855714Skris{ 34955714Skris struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap; 35055714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 35155714Skris "bytes=%d", dst, (int) err, (int) bytes); 35255714Skris if (err == 0 && bytes > 0) 35355714Skris wpa_supplicant_ctrl_iface_rx(dst, bytes); 35455714Skris} 35555714Skris 35655714Skris 35755714Skrisstatic void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx) 35855714Skris{ 35955714Skris struct wpa_ctrl_dst *dst = eloop_data; 36055714Skris struct ctrl_iface_priv *priv = dst->priv; 36155714Skris DWORD bytes; 36255714Skris 36355714Skris wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive"); 36455714Skris ResetEvent(dst->overlap.hEvent); 36555714Skris 36655714Skris if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 36755714Skris wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 36855714Skris (int) GetLastError()); 36955714Skris return; 37055714Skris } 37155714Skris wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 37255714Skris "connected"); 37355714Skris 37455714Skris /* Open a new named pipe for the next client. */ 37555714Skris ctrl_open_pipe(priv); 37655714Skris 37755714Skris /* Use write completion function to start reading a command */ 37855714Skris ctrl_iface_write_completed(0, 0, &dst->overlap); 37955714Skris 38055714Skris ctrl_flush_broken_pipes(priv); 38155714Skris} 38255714Skris 38355714Skris 38455714Skrisstatic int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params) 38555714Skris{ 38655714Skris const char *sddl = NULL; 38755714Skris TCHAR *t_sddl; 38855714Skris 38955714Skris if (os_strncmp(params, "SDDL=", 5) == 0) 39055714Skris sddl = params + 5; 39155714Skris if (!sddl) { 39255714Skris sddl = os_strstr(params, " SDDL="); 39355714Skris if (sddl) 39455714Skris sddl += 6; 39555714Skris } 39655714Skris 39755714Skris if (!sddl) 39855714Skris return 0; 39955714Skris 40055714Skris wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl); 40155714Skris os_memset(&priv->attr, 0, sizeof(priv->attr)); 40255714Skris priv->attr.nLength = sizeof(priv->attr); 40355714Skris priv->attr.bInheritHandle = FALSE; 40455714Skris t_sddl = wpa_strdup_tchar(sddl); 40555714Skris if (t_sddl == NULL) 40655714Skris return -1; 40755714Skris if (!ConvertStringSecurityDescriptorToSecurityDescriptor( 40855714Skris t_sddl, SDDL_REVISION_1, 40955714Skris (PSECURITY_DESCRIPTOR *) (void *) 41055714Skris &priv->attr.lpSecurityDescriptor, 41155714Skris NULL)) { 41255714Skris os_free(t_sddl); 41355714Skris wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to " 41455714Skris "security descriptor: %d", 41555714Skris sddl, (int) GetLastError()); 41655714Skris return -1; 41755714Skris } 41855714Skris os_free(t_sddl); 41955714Skris 42055714Skris priv->sec_attr_set = 1; 42155714Skris 42255714Skris return 0; 42355714Skris} 42455714Skris 42555714Skris 42655714Skrisstatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 42755714Skris const char *txt, size_t len) 42855714Skris{ 42955714Skris struct wpa_supplicant *wpa_s = ctx; 43055714Skris if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 43155714Skris return; 43255714Skris wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 43355714Skris} 43455714Skris 43555714Skris 43655714Skrisstruct ctrl_iface_priv * 43755714Skriswpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 43855714Skris{ 43955714Skris struct ctrl_iface_priv *priv; 44055714Skris 44155714Skris priv = os_zalloc(sizeof(*priv)); 44255714Skris if (priv == NULL) 44355714Skris return NULL; 44455714Skris priv->wpa_s = wpa_s; 44555714Skris 44655714Skris if (wpa_s->conf->ctrl_interface == NULL) 44755714Skris return priv; 44855714Skris 44955714Skris if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) { 45055714Skris os_free(priv); 45155714Skris return NULL; 45255714Skris } 45355714Skris 45455714Skris if (ctrl_open_pipe(priv) < 0) { 45555714Skris os_free(priv); 45655714Skris return NULL; 45755714Skris } 45855714Skris 45955714Skris wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 46055714Skris 46155714Skris return priv; 46255714Skris} 46355714Skris 46455714Skris 46555714Skrisvoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 46655714Skris{ 46755714Skris while (priv->ctrl_dst) 46855714Skris ctrl_close_pipe(priv->ctrl_dst); 46955714Skris if (priv->sec_attr_set) 47055714Skris LocalFree(priv->attr.lpSecurityDescriptor); 47155714Skris os_free(priv); 47255714Skris} 47355714Skris 47455714Skris 47555714Skrisstatic void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 47655714Skris int level, const char *buf, 47755714Skris size_t len) 47855714Skris{ 47955714Skris struct wpa_ctrl_dst *dst, *next; 48055714Skris char levelstr[10]; 48155714Skris int idx; 48255714Skris char *sbuf; 48355714Skris int llen; 48455714Skris DWORD written; 48555714Skris 48655714Skris dst = priv->ctrl_dst; 48755714Skris if (dst == NULL) 48855714Skris return; 48955714Skris 49055714Skris os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 49155714Skris 49255714Skris llen = os_strlen(levelstr); 49355714Skris sbuf = os_malloc(llen + len); 49455714Skris if (sbuf == NULL) 49555714Skris return; 49655714Skris 49755714Skris os_memcpy(sbuf, levelstr, llen); 49855714Skris os_memcpy(sbuf + llen, buf, len); 49955714Skris 50055714Skris idx = 0; 50155714Skris while (dst) { 50255714Skris next = dst->next; 50355714Skris if (dst->attached && level >= dst->debug_level) { 50455714Skris wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p", 50555714Skris dst); 50655714Skris if (!WriteFile(dst->pipe, sbuf, llen + len, &written, 50755714Skris NULL)) { 50855714Skris wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst " 50955714Skris "%p failed: %d", 51055714Skris dst, (int) GetLastError()); 51155714Skris dst->errors++; 51255714Skris if (dst->errors > 10) 51355714Skris ctrl_close_pipe(dst); 51455714Skris } else 51555714Skris dst->errors = 0; 51655714Skris } 51755714Skris idx++; 51855714Skris dst = next; 51955714Skris } 52055714Skris os_free(sbuf); 52155714Skris} 52255714Skris 52355714Skris 52455714Skrisvoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 52555714Skris{ 52655714Skris wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 52755714Skris priv->wpa_s->ifname); 52855714Skris if (priv->ctrl_dst == NULL) 52955714Skris return; 53055714Skris WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE); 53155714Skris} 53255714Skris 53355714Skris 53455714Skris/* Global ctrl_iface */ 53555714Skris 53655714Skrisstruct ctrl_iface_global_priv; 53755714Skris 53855714Skrisstruct wpa_global_dst { 53955714Skris /* Note: OVERLAPPED must be the first member of struct wpa_global_dst 54055714Skris */ 54155714Skris OVERLAPPED overlap; 54255714Skris struct wpa_global_dst *next, *prev; 54355714Skris struct ctrl_iface_global_priv *priv; 54455714Skris HANDLE pipe; 54555714Skris char req_buf[REQUEST_BUFSIZE]; 54655714Skris char *rsp_buf; 54755714Skris int used; 54855714Skris}; 54955714Skris 55055714Skrisstruct ctrl_iface_global_priv { 55155714Skris struct wpa_global *global; 55255714Skris struct wpa_global_dst *ctrl_dst; 55355714Skris}; 55455714Skris 55555714Skris 55655714Skrisstatic void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv) 55755714Skris{ 55855714Skris struct wpa_global_dst *dst, *next; 55955714Skris 56055714Skris dst = priv->ctrl_dst; 56155714Skris 56255714Skris while (dst) { 56355714Skris next = dst->next; 56455714Skris if (ctrl_broken_pipe(dst->pipe, dst->used)) { 56555714Skris wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p", 56655714Skris dst); 56755714Skris global_close_pipe(dst); 56855714Skris } 56955714Skris dst = next; 57055714Skris } 57155714Skris} 57255714Skris 57355714Skris 57455714Skrisstatic int global_open_pipe(struct ctrl_iface_global_priv *priv) 57555714Skris{ 57655714Skris struct wpa_global_dst *dst; 57755714Skris DWORD err; 57855714Skris 57955714Skris dst = os_zalloc(sizeof(*dst)); 58055714Skris if (dst == NULL) 58155714Skris return -1; 58255714Skris wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst); 58355714Skris 58455714Skris dst->priv = priv; 58555714Skris dst->pipe = INVALID_HANDLE_VALUE; 58655714Skris 58755714Skris dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 58855714Skris if (dst->overlap.hEvent == NULL) { 58955714Skris wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d", 59055714Skris (int) GetLastError()); 59155714Skris goto fail; 59255714Skris } 59355714Skris 59455714Skris eloop_register_event(dst->overlap.hEvent, 59555714Skris sizeof(dst->overlap.hEvent), 59655714Skris wpa_supplicant_global_iface_receive, dst, NULL); 59755714Skris 59855714Skris /* TODO: add support for configuring access list for the pipe */ 59955714Skris dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX, 60055714Skris PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 60155714Skris PIPE_TYPE_MESSAGE | 60255714Skris PIPE_READMODE_MESSAGE | 60355714Skris PIPE_WAIT, 60455714Skris 10, REPLY_BUFSIZE, REQUEST_BUFSIZE, 60555714Skris 1000, NULL); 60655714Skris if (dst->pipe == INVALID_HANDLE_VALUE) { 60755714Skris wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d", 60855714Skris (int) GetLastError()); 60955714Skris goto fail; 61055714Skris } 61155714Skris 61255714Skris if (ConnectNamedPipe(dst->pipe, &dst->overlap)) { 61355714Skris wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d", 61455714Skris (int) GetLastError()); 61555714Skris CloseHandle(dst->pipe); 61655714Skris os_free(dst); 61755714Skris return -1; 61855714Skris } 61955714Skris 62055714Skris err = GetLastError(); 62155714Skris switch (err) { 62255714Skris case ERROR_IO_PENDING: 62355714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in " 62455714Skris "progress"); 62555714Skris break; 62655714Skris case ERROR_PIPE_CONNECTED: 62755714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already " 62855714Skris "connected"); 62955714Skris if (SetEvent(dst->overlap.hEvent)) 63055714Skris break; 63155714Skris /* fall through */ 63255714Skris default: 63355714Skris wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", 63455714Skris (int) err); 63555714Skris CloseHandle(dst->pipe); 63655714Skris os_free(dst); 63755714Skris return -1; 63855714Skris } 63955714Skris 64055714Skris dst->next = priv->ctrl_dst; 64155714Skris if (dst->next) 64255714Skris dst->next->prev = dst; 64355714Skris priv->ctrl_dst = dst; 64455714Skris 64555714Skris return 0; 64655714Skris 64755714Skrisfail: 64855714Skris global_close_pipe(dst); 64955714Skris return -1; 65055714Skris} 65155714Skris 65255714Skris 65355714Skrisstatic void global_close_pipe(struct wpa_global_dst *dst) 65455714Skris{ 65555714Skris wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst); 65655714Skris 65755714Skris if (dst->overlap.hEvent) { 65855714Skris eloop_unregister_event(dst->overlap.hEvent, 65955714Skris sizeof(dst->overlap.hEvent)); 66055714Skris CloseHandle(dst->overlap.hEvent); 66155714Skris } 66255714Skris 66355714Skris if (dst->pipe != INVALID_HANDLE_VALUE) { 66455714Skris /* 66555714Skris * Could use FlushFileBuffers() here to guarantee that all data 66655714Skris * gets delivered to the client, but that can block, so let's 66755714Skris * not do this for now. 66855714Skris * FlushFileBuffers(dst->pipe); 66955714Skris */ 67055714Skris CloseHandle(dst->pipe); 67155714Skris } 67255714Skris 67355714Skris if (dst->prev) 67455714Skris dst->prev->next = dst->next; 67555714Skris else 67655714Skris dst->priv->ctrl_dst = dst->next; 67755714Skris if (dst->next) 67855714Skris dst->next->prev = dst->prev; 67955714Skris 68055714Skris os_free(dst->rsp_buf); 68155714Skris os_free(dst); 68255714Skris} 68355714Skris 68455714Skris 68555714Skrisstatic VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes, 68655714Skris LPOVERLAPPED overlap) 68755714Skris{ 68855714Skris struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 68955714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p " 69055714Skris "err=%d bytes=%d", dst, (int) err, (int) bytes); 69155714Skris if (err) { 69255714Skris global_close_pipe(dst); 69355714Skris return; 69455714Skris } 69555714Skris 69655714Skris os_free(dst->rsp_buf); 69755714Skris dst->rsp_buf = NULL; 69855714Skris 69955714Skris if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf), 70055714Skris &dst->overlap, global_iface_read_completed)) { 70155714Skris wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d", 70255714Skris (int) GetLastError()); 70355714Skris global_close_pipe(dst); 70455714Skris /* FIX: if this was the pipe waiting for new global 70555714Skris * connections, at this point there are no open global pipes.. 70655714Skris * Should try to open a new pipe.. */ 70755714Skris return; 70855714Skris } 70955714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst); 71055714Skris} 71155714Skris 71255714Skris 71355714Skrisstatic void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst, 71455714Skris size_t len) 71555714Skris{ 71655714Skris struct wpa_global *global = dst->priv->global; 71755714Skris char *reply = NULL, *send_buf; 71855714Skris size_t reply_len = 0, send_len; 71955714Skris char *buf = dst->req_buf; 72055714Skris 72155714Skris dst->used = 1; 72255714Skris if (len >= REQUEST_BUFSIZE) 72355714Skris len = REQUEST_BUFSIZE - 1; 72455714Skris buf[len] = '\0'; 72555714Skris 72655714Skris reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 72755714Skris &reply_len); 72855714Skris if (reply) { 72955714Skris send_buf = reply; 73055714Skris send_len = reply_len; 73155714Skris } else if (reply_len) { 73255714Skris send_buf = "FAIL\n"; 73355714Skris send_len = 5; 73455714Skris } else { 73555714Skris os_free(dst->rsp_buf); 73655714Skris dst->rsp_buf = NULL; 73755714Skris return; 73855714Skris } 73955714Skris 74055714Skris os_free(dst->rsp_buf); 74155714Skris dst->rsp_buf = os_malloc(send_len); 74255714Skris if (dst->rsp_buf == NULL) { 74355714Skris global_close_pipe(dst); 74455714Skris os_free(reply); 74555714Skris return; 74655714Skris } 74755714Skris os_memcpy(dst->rsp_buf, send_buf, send_len); 74855714Skris os_free(reply); 74955714Skris 75055714Skris if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap, 75155714Skris global_iface_write_completed)) { 75255714Skris wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d", 75355714Skris (int) GetLastError()); 75455714Skris global_close_pipe(dst); 75555714Skris } else { 75655714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p", 75755714Skris dst); 75855714Skris } 75955714Skris} 76055714Skris 76155714Skris 76255714Skrisstatic VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes, 76355714Skris LPOVERLAPPED overlap) 76455714Skris{ 76555714Skris struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap; 76655714Skris wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d " 76755714Skris "bytes=%d", dst, (int) err, (int) bytes); 76855714Skris if (err == 0 && bytes > 0) 76955714Skris wpa_supplicant_global_iface_rx(dst, bytes); 77055714Skris} 77155714Skris 77255714Skris 77355714Skrisstatic void wpa_supplicant_global_iface_receive(void *eloop_data, 77455714Skris void *user_ctx) 77555714Skris{ 77655714Skris struct wpa_global_dst *dst = eloop_data; 77755714Skris struct ctrl_iface_global_priv *priv = dst->priv; 77855714Skris DWORD bytes; 77955714Skris 78055714Skris wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive"); 78155714Skris ResetEvent(dst->overlap.hEvent); 78255714Skris 78355714Skris if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) { 78455714Skris wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d", 78555714Skris (int) GetLastError()); 78655714Skris return; 78755714Skris } 78855714Skris wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client " 78955714Skris "connected"); 79055714Skris 79155714Skris /* Open a new named pipe for the next client. */ 79255714Skris if (global_open_pipe(priv) < 0) { 79355714Skris wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed"); 79455714Skris return; 79555714Skris } 79655714Skris 79755714Skris /* Use write completion function to start reading a command */ 79855714Skris global_iface_write_completed(0, 0, &dst->overlap); 79955714Skris 80055714Skris global_flush_broken_pipes(priv); 80155714Skris} 80255714Skris 80355714Skris 80455714Skrisstruct ctrl_iface_global_priv * 80555714Skriswpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 80655714Skris{ 80755714Skris struct ctrl_iface_global_priv *priv; 80855714Skris 80955714Skris priv = os_zalloc(sizeof(*priv)); 81055714Skris if (priv == NULL) 81155714Skris return NULL; 81255714Skris priv->global = global; 81355714Skris 81455714Skris if (global_open_pipe(priv) < 0) { 81555714Skris os_free(priv); 81655714Skris return NULL; 81755714Skris } 81855714Skris 81955714Skris return priv; 82055714Skris} 82155714Skris 82255714Skris 82355714Skrisvoid 82455714Skriswpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 82555714Skris{ 82655714Skris while (priv->ctrl_dst) 82755714Skris global_close_pipe(priv->ctrl_dst); 82855714Skris os_free(priv); 82955714Skris} 83055714Skris