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