Home | History | Annotate | Download | only in common
      1 /*
      2  * wpa_supplicant/hostapd control interface library
      3  * Copyright (c) 2004-2007, Jouni Malinen <j (at) 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 #ifdef CONFIG_CTRL_IFACE
     12 
     13 #ifdef CONFIG_CTRL_IFACE_UNIX
     14 #include <sys/un.h>
     15 #include <unistd.h>
     16 #include <fcntl.h>
     17 #endif /* CONFIG_CTRL_IFACE_UNIX */
     18 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
     19 #include <netdb.h>
     20 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
     21 
     22 #ifdef ANDROID
     23 #include <dirent.h>
     24 #include <cutils/sockets.h>
     25 #include "private/android_filesystem_config.h"
     26 #endif /* ANDROID */
     27 
     28 #include "wpa_ctrl.h"
     29 #include "common.h"
     30 
     31 
     32 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
     33 #define CTRL_IFACE_SOCKET
     34 #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
     35 
     36 
     37 /**
     38  * struct wpa_ctrl - Internal structure for control interface library
     39  *
     40  * This structure is used by the wpa_supplicant/hostapd control interface
     41  * library to store internal data. Programs using the library should not touch
     42  * this data directly. They can only use the pointer to the data structure as
     43  * an identifier for the control interface connection and use this as one of
     44  * the arguments for most of the control interface library functions.
     45  */
     46 struct wpa_ctrl {
     47 #ifdef CONFIG_CTRL_IFACE_UDP
     48 	int s;
     49 	struct sockaddr_in local;
     50 	struct sockaddr_in dest;
     51 	char *cookie;
     52 	char *remote_ifname;
     53 	char *remote_ip;
     54 #endif /* CONFIG_CTRL_IFACE_UDP */
     55 #ifdef CONFIG_CTRL_IFACE_UNIX
     56 	int s;
     57 	struct sockaddr_un local;
     58 	struct sockaddr_un dest;
     59 #endif /* CONFIG_CTRL_IFACE_UNIX */
     60 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
     61 	HANDLE pipe;
     62 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
     63 };
     64 
     65 
     66 #ifdef CONFIG_CTRL_IFACE_UNIX
     67 
     68 #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
     69 #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
     70 #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
     71 #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
     72 #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
     73 #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
     74 
     75 
     76 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
     77 {
     78 	struct wpa_ctrl *ctrl;
     79 	static int counter = 0;
     80 	int ret;
     81 	size_t res;
     82 	int tries = 0;
     83 	int flags;
     84 
     85 	if (ctrl_path == NULL)
     86 		return NULL;
     87 
     88 	ctrl = os_malloc(sizeof(*ctrl));
     89 	if (ctrl == NULL)
     90 		return NULL;
     91 	os_memset(ctrl, 0, sizeof(*ctrl));
     92 
     93 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
     94 	if (ctrl->s < 0) {
     95 		os_free(ctrl);
     96 		return NULL;
     97 	}
     98 
     99 	ctrl->local.sun_family = AF_UNIX;
    100 	counter++;
    101 try_again:
    102 	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
    103 			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
    104 			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
    105 			  (int) getpid(), counter);
    106 	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
    107 		close(ctrl->s);
    108 		os_free(ctrl);
    109 		return NULL;
    110 	}
    111 	tries++;
    112 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
    113 		    sizeof(ctrl->local)) < 0) {
    114 		if (errno == EADDRINUSE && tries < 2) {
    115 			/*
    116 			 * getpid() returns unique identifier for this instance
    117 			 * of wpa_ctrl, so the existing socket file must have
    118 			 * been left by unclean termination of an earlier run.
    119 			 * Remove the file and try again.
    120 			 */
    121 			unlink(ctrl->local.sun_path);
    122 			goto try_again;
    123 		}
    124 		close(ctrl->s);
    125 		os_free(ctrl);
    126 		return NULL;
    127 	}
    128 
    129 #ifdef ANDROID
    130 	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    131 	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
    132 
    133 	if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
    134 		if (socket_local_client_connect(
    135 			    ctrl->s, ctrl_path + 9,
    136 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
    137 			    SOCK_DGRAM) < 0) {
    138 			close(ctrl->s);
    139 			unlink(ctrl->local.sun_path);
    140 			os_free(ctrl);
    141 			return NULL;
    142 		}
    143 		return ctrl;
    144 	}
    145 
    146 	/*
    147 	 * If the ctrl_path isn't an absolute pathname, assume that
    148 	 * it's the name of a socket in the Android reserved namespace.
    149 	 * Otherwise, it's a normal UNIX domain socket appearing in the
    150 	 * filesystem.
    151 	 */
    152 	if (*ctrl_path != '/') {
    153 		char buf[21];
    154 		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
    155 		if (socket_local_client_connect(
    156 			    ctrl->s, buf,
    157 			    ANDROID_SOCKET_NAMESPACE_RESERVED,
    158 			    SOCK_DGRAM) < 0) {
    159 			close(ctrl->s);
    160 			unlink(ctrl->local.sun_path);
    161 			os_free(ctrl);
    162 			return NULL;
    163 		}
    164 		return ctrl;
    165 	}
    166 #endif /* ANDROID */
    167 
    168 	ctrl->dest.sun_family = AF_UNIX;
    169 	if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
    170 		ctrl->dest.sun_path[0] = '\0';
    171 		os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
    172 			   sizeof(ctrl->dest.sun_path) - 1);
    173 	} else {
    174 		res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
    175 				 sizeof(ctrl->dest.sun_path));
    176 		if (res >= sizeof(ctrl->dest.sun_path)) {
    177 			close(ctrl->s);
    178 			os_free(ctrl);
    179 			return NULL;
    180 		}
    181 	}
    182 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
    183 		    sizeof(ctrl->dest)) < 0) {
    184 		close(ctrl->s);
    185 		unlink(ctrl->local.sun_path);
    186 		os_free(ctrl);
    187 		return NULL;
    188 	}
    189 
    190 	/*
    191 	 * Make socket non-blocking so that we don't hang forever if
    192 	 * target dies unexpectedly.
    193 	 */
    194 	flags = fcntl(ctrl->s, F_GETFL);
    195 	if (flags >= 0) {
    196 		flags |= O_NONBLOCK;
    197 		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
    198 			perror("fcntl(ctrl->s, O_NONBLOCK)");
    199 			/* Not fatal, continue on.*/
    200 		}
    201 	}
    202 
    203 	return ctrl;
    204 }
    205 
    206 
    207 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
    208 {
    209 	if (ctrl == NULL)
    210 		return;
    211 	unlink(ctrl->local.sun_path);
    212 	if (ctrl->s >= 0)
    213 		close(ctrl->s);
    214 	os_free(ctrl);
    215 }
    216 
    217 
    218 #ifdef ANDROID
    219 /**
    220  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
    221  * may be left over from clients that were previously connected to
    222  * wpa_supplicant. This keeps these files from being orphaned in the
    223  * event of crashes that prevented them from being removed as part
    224  * of the normal orderly shutdown.
    225  */
    226 void wpa_ctrl_cleanup(void)
    227 {
    228 	DIR *dir;
    229 	struct dirent entry;
    230 	struct dirent *result;
    231 	size_t dirnamelen;
    232 	size_t maxcopy;
    233 	char pathname[PATH_MAX];
    234 	char *namep;
    235 
    236 	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
    237 		return;
    238 
    239 	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
    240 					  CONFIG_CTRL_IFACE_CLIENT_DIR);
    241 	if (dirnamelen >= sizeof(pathname)) {
    242 		closedir(dir);
    243 		return;
    244 	}
    245 	namep = pathname + dirnamelen;
    246 	maxcopy = PATH_MAX - dirnamelen;
    247 	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
    248 		if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
    249 			unlink(pathname);
    250 	}
    251 	closedir(dir);
    252 }
    253 #endif /* ANDROID */
    254 
    255 #else /* CONFIG_CTRL_IFACE_UNIX */
    256 
    257 #ifdef ANDROID
    258 void wpa_ctrl_cleanup(void)
    259 {
    260 }
    261 #endif /* ANDROID */
    262 
    263 #endif /* CONFIG_CTRL_IFACE_UNIX */
    264 
    265 
    266 #ifdef CONFIG_CTRL_IFACE_UDP
    267 
    268 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
    269 {
    270 	struct wpa_ctrl *ctrl;
    271 	char buf[128];
    272 	size_t len;
    273 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
    274 	struct hostent *h;
    275 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
    276 
    277 	ctrl = os_malloc(sizeof(*ctrl));
    278 	if (ctrl == NULL)
    279 		return NULL;
    280 	os_memset(ctrl, 0, sizeof(*ctrl));
    281 
    282 	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
    283 	if (ctrl->s < 0) {
    284 		perror("socket");
    285 		os_free(ctrl);
    286 		return NULL;
    287 	}
    288 
    289 	ctrl->local.sin_family = AF_INET;
    290 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
    291 	ctrl->local.sin_addr.s_addr = INADDR_ANY;
    292 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
    293 	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
    294 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
    295 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
    296 		 sizeof(ctrl->local)) < 0) {
    297 		close(ctrl->s);
    298 		os_free(ctrl);
    299 		return NULL;
    300 	}
    301 
    302 	ctrl->dest.sin_family = AF_INET;
    303 	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
    304 	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
    305 
    306 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
    307 	if (ctrl_path) {
    308 		char *port, *name;
    309 		int port_id;
    310 
    311 		name = os_strdup(ctrl_path);
    312 		if (name == NULL) {
    313 			close(ctrl->s);
    314 			os_free(ctrl);
    315 			return NULL;
    316 		}
    317 		port = os_strchr(name, ':');
    318 
    319 		if (port) {
    320 			port_id = atoi(&port[1]);
    321 			port[0] = '\0';
    322 		} else
    323 			port_id = WPA_CTRL_IFACE_PORT;
    324 
    325 		h = gethostbyname(name);
    326 		ctrl->remote_ip = os_strdup(name);
    327 		os_free(name);
    328 		if (h == NULL) {
    329 			perror("gethostbyname");
    330 			close(ctrl->s);
    331 			os_free(ctrl->remote_ip);
    332 			os_free(ctrl);
    333 			return NULL;
    334 		}
    335 		ctrl->dest.sin_port = htons(port_id);
    336 		os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
    337 			  h->h_length);
    338 	} else
    339 		ctrl->remote_ip = os_strdup("localhost");
    340 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
    341 
    342 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
    343 		    sizeof(ctrl->dest)) < 0) {
    344 		perror("connect");
    345 		close(ctrl->s);
    346 		os_free(ctrl->remote_ip);
    347 		os_free(ctrl);
    348 		return NULL;
    349 	}
    350 
    351 	len = sizeof(buf) - 1;
    352 	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
    353 		buf[len] = '\0';
    354 		ctrl->cookie = os_strdup(buf);
    355 	}
    356 
    357 	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
    358 		buf[len] = '\0';
    359 		ctrl->remote_ifname = os_strdup(buf);
    360 	}
    361 
    362 	return ctrl;
    363 }
    364 
    365 
    366 char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
    367 {
    368 #define WPA_CTRL_MAX_PS_NAME 100
    369 	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
    370 	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
    371 		    ctrl->remote_ip, ctrl->remote_ifname);
    372 	return ps;
    373 }
    374 
    375 
    376 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
    377 {
    378 	close(ctrl->s);
    379 	os_free(ctrl->cookie);
    380 	os_free(ctrl->remote_ifname);
    381 	os_free(ctrl->remote_ip);
    382 	os_free(ctrl);
    383 }
    384 
    385 #endif /* CONFIG_CTRL_IFACE_UDP */
    386 
    387 
    388 #ifdef CTRL_IFACE_SOCKET
    389 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
    390 		     char *reply, size_t *reply_len,
    391 		     void (*msg_cb)(char *msg, size_t len))
    392 {
    393 	struct timeval tv;
    394 	struct os_time started_at;
    395 	int res;
    396 	fd_set rfds;
    397 	const char *_cmd;
    398 	char *cmd_buf = NULL;
    399 	size_t _cmd_len;
    400 
    401 #ifdef CONFIG_CTRL_IFACE_UDP
    402 	if (ctrl->cookie) {
    403 		char *pos;
    404 		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
    405 		cmd_buf = os_malloc(_cmd_len);
    406 		if (cmd_buf == NULL)
    407 			return -1;
    408 		_cmd = cmd_buf;
    409 		pos = cmd_buf;
    410 		os_strlcpy(pos, ctrl->cookie, _cmd_len);
    411 		pos += os_strlen(ctrl->cookie);
    412 		*pos++ = ' ';
    413 		os_memcpy(pos, cmd, cmd_len);
    414 	} else
    415 #endif /* CONFIG_CTRL_IFACE_UDP */
    416 	{
    417 		_cmd = cmd;
    418 		_cmd_len = cmd_len;
    419 	}
    420 
    421 	errno = 0;
    422 	started_at.sec = 0;
    423 	started_at.usec = 0;
    424 retry_send:
    425 	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
    426 		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
    427 		{
    428 			/*
    429 			 * Must be a non-blocking socket... Try for a bit
    430 			 * longer before giving up.
    431 			 */
    432 			if (started_at.sec == 0)
    433 				os_get_time(&started_at);
    434 			else {
    435 				struct os_time n;
    436 				os_get_time(&n);
    437 				/* Try for a few seconds. */
    438 				if (n.sec > started_at.sec + 5)
    439 					goto send_err;
    440 			}
    441 			os_sleep(1, 0);
    442 			goto retry_send;
    443 		}
    444 	send_err:
    445 		os_free(cmd_buf);
    446 		return -1;
    447 	}
    448 	os_free(cmd_buf);
    449 
    450 	for (;;) {
    451 		tv.tv_sec = 10;
    452 		tv.tv_usec = 0;
    453 		FD_ZERO(&rfds);
    454 		FD_SET(ctrl->s, &rfds);
    455 		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
    456 		if (res < 0)
    457 			return res;
    458 		if (FD_ISSET(ctrl->s, &rfds)) {
    459 			res = recv(ctrl->s, reply, *reply_len, 0);
    460 			if (res < 0)
    461 				return res;
    462 			if (res > 0 && reply[0] == '<') {
    463 				/* This is an unsolicited message from
    464 				 * wpa_supplicant, not the reply to the
    465 				 * request. Use msg_cb to report this to the
    466 				 * caller. */
    467 				if (msg_cb) {
    468 					/* Make sure the message is nul
    469 					 * terminated. */
    470 					if ((size_t) res == *reply_len)
    471 						res = (*reply_len) - 1;
    472 					reply[res] = '\0';
    473 					msg_cb(reply, res);
    474 				}
    475 				continue;
    476 			}
    477 			*reply_len = res;
    478 			break;
    479 		} else {
    480 			return -2;
    481 		}
    482 	}
    483 	return 0;
    484 }
    485 #endif /* CTRL_IFACE_SOCKET */
    486 
    487 
    488 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
    489 {
    490 	char buf[10];
    491 	int ret;
    492 	size_t len = 10;
    493 
    494 	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
    495 			       buf, &len, NULL);
    496 	if (ret < 0)
    497 		return ret;
    498 	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
    499 		return 0;
    500 	return -1;
    501 }
    502 
    503 
    504 int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
    505 {
    506 	return wpa_ctrl_attach_helper(ctrl, 1);
    507 }
    508 
    509 
    510 int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
    511 {
    512 	return wpa_ctrl_attach_helper(ctrl, 0);
    513 }
    514 
    515 
    516 #ifdef CTRL_IFACE_SOCKET
    517 
    518 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
    519 {
    520 	int res;
    521 
    522 	res = recv(ctrl->s, reply, *reply_len, 0);
    523 	if (res < 0)
    524 		return res;
    525 	*reply_len = res;
    526 	return 0;
    527 }
    528 
    529 
    530 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
    531 {
    532 	struct timeval tv;
    533 	fd_set rfds;
    534 	tv.tv_sec = 0;
    535 	tv.tv_usec = 0;
    536 	FD_ZERO(&rfds);
    537 	FD_SET(ctrl->s, &rfds);
    538 	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
    539 	return FD_ISSET(ctrl->s, &rfds);
    540 }
    541 
    542 
    543 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
    544 {
    545 	return ctrl->s;
    546 }
    547 
    548 #endif /* CTRL_IFACE_SOCKET */
    549 
    550 
    551 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
    552 
    553 #ifndef WPA_SUPPLICANT_NAMED_PIPE
    554 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
    555 #endif
    556 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
    557 
    558 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
    559 {
    560 	struct wpa_ctrl *ctrl;
    561 	DWORD mode;
    562 	TCHAR name[256];
    563 	int i, ret;
    564 
    565 	ctrl = os_malloc(sizeof(*ctrl));
    566 	if (ctrl == NULL)
    567 		return NULL;
    568 	os_memset(ctrl, 0, sizeof(*ctrl));
    569 
    570 #ifdef UNICODE
    571 	if (ctrl_path == NULL)
    572 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
    573 	else
    574 		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
    575 				 ctrl_path);
    576 #else /* UNICODE */
    577 	if (ctrl_path == NULL)
    578 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
    579 	else
    580 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
    581 				  ctrl_path);
    582 #endif /* UNICODE */
    583 	if (ret < 0 || ret >= 256) {
    584 		os_free(ctrl);
    585 		return NULL;
    586 	}
    587 
    588 	for (i = 0; i < 10; i++) {
    589 		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
    590 					NULL, OPEN_EXISTING, 0, NULL);
    591 		/*
    592 		 * Current named pipe server side in wpa_supplicant is
    593 		 * re-opening the pipe for new clients only after the previous
    594 		 * one is taken into use. This leaves a small window for race
    595 		 * conditions when two connections are being opened at almost
    596 		 * the same time. Retry if that was the case.
    597 		 */
    598 		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
    599 		    GetLastError() != ERROR_PIPE_BUSY)
    600 			break;
    601 		WaitNamedPipe(name, 1000);
    602 	}
    603 	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
    604 		os_free(ctrl);
    605 		return NULL;
    606 	}
    607 
    608 	mode = PIPE_READMODE_MESSAGE;
    609 	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
    610 		CloseHandle(ctrl->pipe);
    611 		os_free(ctrl);
    612 		return NULL;
    613 	}
    614 
    615 	return ctrl;
    616 }
    617 
    618 
    619 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
    620 {
    621 	CloseHandle(ctrl->pipe);
    622 	os_free(ctrl);
    623 }
    624 
    625 
    626 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
    627 		     char *reply, size_t *reply_len,
    628 		     void (*msg_cb)(char *msg, size_t len))
    629 {
    630 	DWORD written;
    631 	DWORD readlen = *reply_len;
    632 
    633 	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
    634 		return -1;
    635 
    636 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
    637 		return -1;
    638 	*reply_len = readlen;
    639 
    640 	return 0;
    641 }
    642 
    643 
    644 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
    645 {
    646 	DWORD len = *reply_len;
    647 	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
    648 		return -1;
    649 	*reply_len = len;
    650 	return 0;
    651 }
    652 
    653 
    654 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
    655 {
    656 	DWORD left;
    657 
    658 	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
    659 		return -1;
    660 	return left ? 1 : 0;
    661 }
    662 
    663 
    664 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
    665 {
    666 	return -1;
    667 }
    668 
    669 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
    670 
    671 #endif /* CONFIG_CTRL_IFACE */
    672