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