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