blob: b2b06832360a4d4065c4bfadf78e0ec8c69ee444 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * wpa_supplicant/hostapd control interface library
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080018#include <dirent.h>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#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
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800173
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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223#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 */