1/*
2 * wpa_supplicant/hostapd control interface library
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#ifdef CONFIG_CTRL_IFACE
18
19#ifdef CONFIG_CTRL_IFACE_UNIX
20#include <sys/un.h>
21#endif /* CONFIG_CTRL_IFACE_UNIX */
22
23#ifdef ANDROID
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 */
46struct 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#endif /* CONFIG_CTRL_IFACE_UDP */
53#ifdef CONFIG_CTRL_IFACE_UNIX
54	int s;
55	struct sockaddr_un local;
56	struct sockaddr_un dest;
57#endif /* CONFIG_CTRL_IFACE_UNIX */
58#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
59	HANDLE pipe;
60#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
61};
62
63
64#ifdef CONFIG_CTRL_IFACE_UNIX
65
66#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
67#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
68#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
69#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
70#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
71#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
72
73
74struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
75{
76	struct wpa_ctrl *ctrl;
77	static int counter = 0;
78	int ret;
79	size_t res;
80	int tries = 0;
81
82	ctrl = os_malloc(sizeof(*ctrl));
83	if (ctrl == NULL)
84		return NULL;
85	os_memset(ctrl, 0, sizeof(*ctrl));
86
87	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
88	if (ctrl->s < 0) {
89		os_free(ctrl);
90		return NULL;
91	}
92
93	ctrl->local.sun_family = AF_UNIX;
94	counter++;
95try_again:
96	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
97			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
98			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
99			  (int) getpid(), counter);
100	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
101		close(ctrl->s);
102		os_free(ctrl);
103		return NULL;
104	}
105	tries++;
106	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
107		    sizeof(ctrl->local)) < 0) {
108		if (errno == EADDRINUSE && tries < 2) {
109			/*
110			 * getpid() returns unique identifier for this instance
111			 * of wpa_ctrl, so the existing socket file must have
112			 * been left by unclean termination of an earlier run.
113			 * Remove the file and try again.
114			 */
115			unlink(ctrl->local.sun_path);
116			goto try_again;
117		}
118		close(ctrl->s);
119		os_free(ctrl);
120		return NULL;
121	}
122
123#ifdef ANDROID
124	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
125	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
126	/*
127	 * If the ctrl_path isn't an absolute pathname, assume that
128	 * it's the name of a socket in the Android reserved namespace.
129	 * Otherwise, it's a normal UNIX domain socket appearing in the
130	 * filesystem.
131	 */
132	if (ctrl_path != NULL && *ctrl_path != '/') {
133		char buf[21];
134		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
135		if (socket_local_client_connect(
136			    ctrl->s, buf,
137			    ANDROID_SOCKET_NAMESPACE_RESERVED,
138			    SOCK_DGRAM) < 0) {
139			close(ctrl->s);
140			unlink(ctrl->local.sun_path);
141			os_free(ctrl);
142			return NULL;
143		}
144		return ctrl;
145	}
146#endif /* ANDROID */
147
148	ctrl->dest.sun_family = AF_UNIX;
149	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
150			 sizeof(ctrl->dest.sun_path));
151	if (res >= sizeof(ctrl->dest.sun_path)) {
152		close(ctrl->s);
153		os_free(ctrl);
154		return NULL;
155	}
156	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
157		    sizeof(ctrl->dest)) < 0) {
158		close(ctrl->s);
159		unlink(ctrl->local.sun_path);
160		os_free(ctrl);
161		return NULL;
162	}
163
164	return ctrl;
165}
166
167
168void wpa_ctrl_close(struct wpa_ctrl *ctrl)
169{
170	if (ctrl == NULL)
171		return;
172	unlink(ctrl->local.sun_path);
173	if (ctrl->s >= 0)
174		close(ctrl->s);
175	os_free(ctrl);
176}
177
178#endif /* CONFIG_CTRL_IFACE_UNIX */
179
180
181#ifdef CONFIG_CTRL_IFACE_UDP
182
183struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
184{
185	struct wpa_ctrl *ctrl;
186	char buf[128];
187	size_t len;
188
189	ctrl = os_malloc(sizeof(*ctrl));
190	if (ctrl == NULL)
191		return NULL;
192	os_memset(ctrl, 0, sizeof(*ctrl));
193
194	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
195	if (ctrl->s < 0) {
196		perror("socket");
197		os_free(ctrl);
198		return NULL;
199	}
200
201	ctrl->local.sin_family = AF_INET;
202	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
203	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
204		 sizeof(ctrl->local)) < 0) {
205		close(ctrl->s);
206		os_free(ctrl);
207		return NULL;
208	}
209
210	ctrl->dest.sin_family = AF_INET;
211	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
212	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
213	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
214		    sizeof(ctrl->dest)) < 0) {
215		perror("connect");
216		close(ctrl->s);
217		os_free(ctrl);
218		return NULL;
219	}
220
221	len = sizeof(buf) - 1;
222	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
223		buf[len] = '\0';
224		ctrl->cookie = os_strdup(buf);
225	}
226
227	return ctrl;
228}
229
230
231void wpa_ctrl_close(struct wpa_ctrl *ctrl)
232{
233	close(ctrl->s);
234	os_free(ctrl->cookie);
235	os_free(ctrl);
236}
237
238#endif /* CONFIG_CTRL_IFACE_UDP */
239
240
241#ifdef CTRL_IFACE_SOCKET
242int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
243		     char *reply, size_t *reply_len,
244		     void (*msg_cb)(char *msg, size_t len))
245{
246	struct timeval tv;
247	int res;
248	fd_set rfds;
249	const char *_cmd;
250	char *cmd_buf = NULL;
251	size_t _cmd_len;
252
253#ifdef CONFIG_CTRL_IFACE_UDP
254	if (ctrl->cookie) {
255		char *pos;
256		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
257		cmd_buf = os_malloc(_cmd_len);
258		if (cmd_buf == NULL)
259			return -1;
260		_cmd = cmd_buf;
261		pos = cmd_buf;
262		os_strlcpy(pos, ctrl->cookie, _cmd_len);
263		pos += os_strlen(ctrl->cookie);
264		*pos++ = ' ';
265		os_memcpy(pos, cmd, cmd_len);
266	} else
267#endif /* CONFIG_CTRL_IFACE_UDP */
268	{
269		_cmd = cmd;
270		_cmd_len = cmd_len;
271	}
272
273	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
274		os_free(cmd_buf);
275		return -1;
276	}
277	os_free(cmd_buf);
278
279	for (;;) {
280		tv.tv_sec = 10;
281		tv.tv_usec = 0;
282		FD_ZERO(&rfds);
283		FD_SET(ctrl->s, &rfds);
284		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
285		if (res < 0)
286			return res;
287		if (FD_ISSET(ctrl->s, &rfds)) {
288			res = recv(ctrl->s, reply, *reply_len, 0);
289			if (res < 0)
290				return res;
291			if (res > 0 && reply[0] == '<') {
292				/* This is an unsolicited message from
293				 * wpa_supplicant, not the reply to the
294				 * request. Use msg_cb to report this to the
295				 * caller. */
296				if (msg_cb) {
297					/* Make sure the message is nul
298					 * terminated. */
299					if ((size_t) res == *reply_len)
300						res = (*reply_len) - 1;
301					reply[res] = '\0';
302					msg_cb(reply, res);
303				}
304				continue;
305			}
306			*reply_len = res;
307			break;
308		} else {
309			return -2;
310		}
311	}
312	return 0;
313}
314#endif /* CTRL_IFACE_SOCKET */
315
316
317static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
318{
319	char buf[10];
320	int ret;
321	size_t len = 10;
322
323	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
324			       buf, &len, NULL);
325	if (ret < 0)
326		return ret;
327	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
328		return 0;
329	return -1;
330}
331
332
333int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
334{
335	return wpa_ctrl_attach_helper(ctrl, 1);
336}
337
338
339int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
340{
341	return wpa_ctrl_attach_helper(ctrl, 0);
342}
343
344
345#ifdef CTRL_IFACE_SOCKET
346
347int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
348{
349	int res;
350
351	res = recv(ctrl->s, reply, *reply_len, 0);
352	if (res < 0)
353		return res;
354	*reply_len = res;
355	return 0;
356}
357
358
359int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
360{
361	struct timeval tv;
362	fd_set rfds;
363	tv.tv_sec = 0;
364	tv.tv_usec = 0;
365	FD_ZERO(&rfds);
366	FD_SET(ctrl->s, &rfds);
367	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
368	return FD_ISSET(ctrl->s, &rfds);
369}
370
371
372int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
373{
374	return ctrl->s;
375}
376
377#endif /* CTRL_IFACE_SOCKET */
378
379
380#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
381
382#ifndef WPA_SUPPLICANT_NAMED_PIPE
383#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
384#endif
385#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
386
387struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
388{
389	struct wpa_ctrl *ctrl;
390	DWORD mode;
391	TCHAR name[256];
392	int i, ret;
393
394	ctrl = os_malloc(sizeof(*ctrl));
395	if (ctrl == NULL)
396		return NULL;
397	os_memset(ctrl, 0, sizeof(*ctrl));
398
399#ifdef UNICODE
400	if (ctrl_path == NULL)
401		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
402	else
403		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
404				 ctrl_path);
405#else /* UNICODE */
406	if (ctrl_path == NULL)
407		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
408	else
409		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
410				  ctrl_path);
411#endif /* UNICODE */
412	if (ret < 0 || ret >= 256) {
413		os_free(ctrl);
414		return NULL;
415	}
416
417	for (i = 0; i < 10; i++) {
418		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
419					NULL, OPEN_EXISTING, 0, NULL);
420		/*
421		 * Current named pipe server side in wpa_supplicant is
422		 * re-opening the pipe for new clients only after the previous
423		 * one is taken into use. This leaves a small window for race
424		 * conditions when two connections are being opened at almost
425		 * the same time. Retry if that was the case.
426		 */
427		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
428		    GetLastError() != ERROR_PIPE_BUSY)
429			break;
430		WaitNamedPipe(name, 1000);
431	}
432	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
433		os_free(ctrl);
434		return NULL;
435	}
436
437	mode = PIPE_READMODE_MESSAGE;
438	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
439		CloseHandle(ctrl->pipe);
440		os_free(ctrl);
441		return NULL;
442	}
443
444	return ctrl;
445}
446
447
448void wpa_ctrl_close(struct wpa_ctrl *ctrl)
449{
450	CloseHandle(ctrl->pipe);
451	os_free(ctrl);
452}
453
454
455int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
456		     char *reply, size_t *reply_len,
457		     void (*msg_cb)(char *msg, size_t len))
458{
459	DWORD written;
460	DWORD readlen = *reply_len;
461
462	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
463		return -1;
464
465	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
466		return -1;
467	*reply_len = readlen;
468
469	return 0;
470}
471
472
473int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
474{
475	DWORD len = *reply_len;
476	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
477		return -1;
478	*reply_len = len;
479	return 0;
480}
481
482
483int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
484{
485	DWORD left;
486
487	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
488		return -1;
489	return left ? 1 : 0;
490}
491
492
493int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
494{
495	return -1;
496}
497
498#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
499
500#endif /* CONFIG_CTRL_IFACE */
501