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