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