139beb93cSSam Leffler /*
239beb93cSSam Leffler * wpa_supplicant/hostapd control interface library
339beb93cSSam Leffler * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE
1239beb93cSSam Leffler
1339beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
144bc52338SCy Schubert #include <sys/stat.h>
154bc52338SCy Schubert #include <fcntl.h>
1639beb93cSSam Leffler #include <sys/un.h>
17f05cddf9SRui Paulo #include <unistd.h>
18f05cddf9SRui Paulo #include <fcntl.h>
1939beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
20f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
21f05cddf9SRui Paulo #include <netdb.h>
22f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
23f05cddf9SRui Paulo
24f05cddf9SRui Paulo #ifdef ANDROID
25f05cddf9SRui Paulo #include <dirent.h>
26325151a3SRui Paulo #include <sys/stat.h>
27f05cddf9SRui Paulo #include <cutils/sockets.h>
28f05cddf9SRui Paulo #include "private/android_filesystem_config.h"
29f05cddf9SRui Paulo #endif /* ANDROID */
3039beb93cSSam Leffler
315b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
325b9c547cSRui Paulo #include <net/if.h>
335b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
345b9c547cSRui Paulo
3539beb93cSSam Leffler #include "wpa_ctrl.h"
3639beb93cSSam Leffler #include "common.h"
3739beb93cSSam Leffler
3839beb93cSSam Leffler
3939beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
4039beb93cSSam Leffler #define CTRL_IFACE_SOCKET
4139beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
4239beb93cSSam Leffler
4339beb93cSSam Leffler
4439beb93cSSam Leffler /**
4539beb93cSSam Leffler * struct wpa_ctrl - Internal structure for control interface library
4639beb93cSSam Leffler *
4739beb93cSSam Leffler * This structure is used by the wpa_supplicant/hostapd control interface
4839beb93cSSam Leffler * library to store internal data. Programs using the library should not touch
4939beb93cSSam Leffler * this data directly. They can only use the pointer to the data structure as
5039beb93cSSam Leffler * an identifier for the control interface connection and use this as one of
5139beb93cSSam Leffler * the arguments for most of the control interface library functions.
5239beb93cSSam Leffler */
5339beb93cSSam Leffler struct wpa_ctrl {
5439beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
5539beb93cSSam Leffler int s;
565b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
575b9c547cSRui Paulo struct sockaddr_in6 local;
585b9c547cSRui Paulo struct sockaddr_in6 dest;
595b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6039beb93cSSam Leffler struct sockaddr_in local;
6139beb93cSSam Leffler struct sockaddr_in dest;
625b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
6339beb93cSSam Leffler char *cookie;
64f05cddf9SRui Paulo char *remote_ifname;
65f05cddf9SRui Paulo char *remote_ip;
6639beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
6739beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
6839beb93cSSam Leffler int s;
6939beb93cSSam Leffler struct sockaddr_un local;
7039beb93cSSam Leffler struct sockaddr_un dest;
7139beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
7239beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
7339beb93cSSam Leffler HANDLE pipe;
7439beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
7539beb93cSSam Leffler };
7639beb93cSSam Leffler
7739beb93cSSam Leffler
7839beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UNIX
7939beb93cSSam Leffler
80f05cddf9SRui Paulo #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
81f05cddf9SRui Paulo #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
82f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
83f05cddf9SRui Paulo #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
84f05cddf9SRui Paulo #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
85f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
86f05cddf9SRui Paulo
87f05cddf9SRui Paulo
wpa_ctrl_open(const char * ctrl_path)8839beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
8939beb93cSSam Leffler {
90325151a3SRui Paulo return wpa_ctrl_open2(ctrl_path, NULL);
91325151a3SRui Paulo }
92325151a3SRui Paulo
93325151a3SRui Paulo
wpa_ctrl_open2(const char * ctrl_path,const char * cli_path)94325151a3SRui Paulo struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
95325151a3SRui Paulo const char *cli_path)
96325151a3SRui Paulo {
9739beb93cSSam Leffler struct wpa_ctrl *ctrl;
9839beb93cSSam Leffler static int counter = 0;
9939beb93cSSam Leffler int ret;
10039beb93cSSam Leffler size_t res;
10139beb93cSSam Leffler int tries = 0;
102f05cddf9SRui Paulo int flags;
10339beb93cSSam Leffler
1045b9c547cSRui Paulo if (ctrl_path == NULL)
1055b9c547cSRui Paulo return NULL;
1065b9c547cSRui Paulo
1075b9c547cSRui Paulo ctrl = os_zalloc(sizeof(*ctrl));
10839beb93cSSam Leffler if (ctrl == NULL)
10939beb93cSSam Leffler return NULL;
11039beb93cSSam Leffler
11139beb93cSSam Leffler ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
11239beb93cSSam Leffler if (ctrl->s < 0) {
11339beb93cSSam Leffler os_free(ctrl);
11439beb93cSSam Leffler return NULL;
11539beb93cSSam Leffler }
11639beb93cSSam Leffler
11739beb93cSSam Leffler ctrl->local.sun_family = AF_UNIX;
11839beb93cSSam Leffler counter++;
11939beb93cSSam Leffler try_again:
120325151a3SRui Paulo if (cli_path && cli_path[0] == '/') {
121325151a3SRui Paulo ret = os_snprintf(ctrl->local.sun_path,
122325151a3SRui Paulo sizeof(ctrl->local.sun_path),
123325151a3SRui Paulo "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
124325151a3SRui Paulo cli_path, (int) getpid(), counter);
125325151a3SRui Paulo } else {
126325151a3SRui Paulo ret = os_snprintf(ctrl->local.sun_path,
127325151a3SRui Paulo sizeof(ctrl->local.sun_path),
128f05cddf9SRui Paulo CONFIG_CTRL_IFACE_CLIENT_DIR "/"
129f05cddf9SRui Paulo CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
130f05cddf9SRui Paulo (int) getpid(), counter);
131325151a3SRui Paulo }
1325b9c547cSRui Paulo if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
13339beb93cSSam Leffler close(ctrl->s);
13439beb93cSSam Leffler os_free(ctrl);
13539beb93cSSam Leffler return NULL;
13639beb93cSSam Leffler }
13739beb93cSSam Leffler tries++;
1384bc52338SCy Schubert #ifdef ANDROID
1394bc52338SCy Schubert /* Set client socket file permissions so that bind() creates the client
1404bc52338SCy Schubert * socket with these permissions and there is no need to try to change
1414bc52338SCy Schubert * them with chmod() after bind() which would have potential issues with
1424bc52338SCy Schubert * race conditions. These permissions are needed to make sure the server
1434bc52338SCy Schubert * side (wpa_supplicant or hostapd) can reply to the control interface
1444bc52338SCy Schubert * messages.
1454bc52338SCy Schubert *
1464bc52338SCy Schubert * The lchown() calls below after bind() are also part of the needed
1474bc52338SCy Schubert * operations to allow the response to go through. Those are using the
1484bc52338SCy Schubert * no-deference-symlinks version to avoid races. */
1494bc52338SCy Schubert fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
1504bc52338SCy Schubert #endif /* ANDROID */
15139beb93cSSam Leffler if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
15239beb93cSSam Leffler sizeof(ctrl->local)) < 0) {
15339beb93cSSam Leffler if (errno == EADDRINUSE && tries < 2) {
15439beb93cSSam Leffler /*
15539beb93cSSam Leffler * getpid() returns unique identifier for this instance
15639beb93cSSam Leffler * of wpa_ctrl, so the existing socket file must have
15739beb93cSSam Leffler * been left by unclean termination of an earlier run.
15839beb93cSSam Leffler * Remove the file and try again.
15939beb93cSSam Leffler */
16039beb93cSSam Leffler unlink(ctrl->local.sun_path);
16139beb93cSSam Leffler goto try_again;
16239beb93cSSam Leffler }
16339beb93cSSam Leffler close(ctrl->s);
16439beb93cSSam Leffler os_free(ctrl);
16539beb93cSSam Leffler return NULL;
16639beb93cSSam Leffler }
16739beb93cSSam Leffler
168f05cddf9SRui Paulo #ifdef ANDROID
169325151a3SRui Paulo /* Set group even if we do not have privileges to change owner */
1704bc52338SCy Schubert lchown(ctrl->local.sun_path, -1, AID_WIFI);
1714bc52338SCy Schubert lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
1725b9c547cSRui Paulo
1735b9c547cSRui Paulo if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
1745b9c547cSRui Paulo if (socket_local_client_connect(
1755b9c547cSRui Paulo ctrl->s, ctrl_path + 9,
1765b9c547cSRui Paulo ANDROID_SOCKET_NAMESPACE_RESERVED,
1775b9c547cSRui Paulo SOCK_DGRAM) < 0) {
1785b9c547cSRui Paulo close(ctrl->s);
1795b9c547cSRui Paulo unlink(ctrl->local.sun_path);
1805b9c547cSRui Paulo os_free(ctrl);
1815b9c547cSRui Paulo return NULL;
1825b9c547cSRui Paulo }
1835b9c547cSRui Paulo return ctrl;
1845b9c547cSRui Paulo }
1855b9c547cSRui Paulo
186f05cddf9SRui Paulo /*
187f05cddf9SRui Paulo * If the ctrl_path isn't an absolute pathname, assume that
188f05cddf9SRui Paulo * it's the name of a socket in the Android reserved namespace.
189f05cddf9SRui Paulo * Otherwise, it's a normal UNIX domain socket appearing in the
190f05cddf9SRui Paulo * filesystem.
191f05cddf9SRui Paulo */
1925b9c547cSRui Paulo if (*ctrl_path != '/') {
193f05cddf9SRui Paulo char buf[21];
194f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
195f05cddf9SRui Paulo if (socket_local_client_connect(
196f05cddf9SRui Paulo ctrl->s, buf,
197f05cddf9SRui Paulo ANDROID_SOCKET_NAMESPACE_RESERVED,
198f05cddf9SRui Paulo SOCK_DGRAM) < 0) {
199f05cddf9SRui Paulo close(ctrl->s);
200f05cddf9SRui Paulo unlink(ctrl->local.sun_path);
201f05cddf9SRui Paulo os_free(ctrl);
202f05cddf9SRui Paulo return NULL;
203f05cddf9SRui Paulo }
204f05cddf9SRui Paulo return ctrl;
205f05cddf9SRui Paulo }
206f05cddf9SRui Paulo #endif /* ANDROID */
207f05cddf9SRui Paulo
20839beb93cSSam Leffler ctrl->dest.sun_family = AF_UNIX;
2095b9c547cSRui Paulo if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
2105b9c547cSRui Paulo ctrl->dest.sun_path[0] = '\0';
2115b9c547cSRui Paulo os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
2125b9c547cSRui Paulo sizeof(ctrl->dest.sun_path) - 1);
2135b9c547cSRui Paulo } else {
21439beb93cSSam Leffler res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
21539beb93cSSam Leffler sizeof(ctrl->dest.sun_path));
21639beb93cSSam Leffler if (res >= sizeof(ctrl->dest.sun_path)) {
21739beb93cSSam Leffler close(ctrl->s);
21839beb93cSSam Leffler os_free(ctrl);
21939beb93cSSam Leffler return NULL;
22039beb93cSSam Leffler }
2215b9c547cSRui Paulo }
22239beb93cSSam Leffler if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
22339beb93cSSam Leffler sizeof(ctrl->dest)) < 0) {
22439beb93cSSam Leffler close(ctrl->s);
22539beb93cSSam Leffler unlink(ctrl->local.sun_path);
22639beb93cSSam Leffler os_free(ctrl);
22739beb93cSSam Leffler return NULL;
22839beb93cSSam Leffler }
22939beb93cSSam Leffler
230f05cddf9SRui Paulo /*
231f05cddf9SRui Paulo * Make socket non-blocking so that we don't hang forever if
232f05cddf9SRui Paulo * target dies unexpectedly.
233f05cddf9SRui Paulo */
234f05cddf9SRui Paulo flags = fcntl(ctrl->s, F_GETFL);
235f05cddf9SRui Paulo if (flags >= 0) {
236f05cddf9SRui Paulo flags |= O_NONBLOCK;
237f05cddf9SRui Paulo if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
238f05cddf9SRui Paulo perror("fcntl(ctrl->s, O_NONBLOCK)");
239f05cddf9SRui Paulo /* Not fatal, continue on.*/
240f05cddf9SRui Paulo }
241f05cddf9SRui Paulo }
242f05cddf9SRui Paulo
24339beb93cSSam Leffler return ctrl;
24439beb93cSSam Leffler }
24539beb93cSSam Leffler
24639beb93cSSam Leffler
wpa_ctrl_close(struct wpa_ctrl * ctrl)24739beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
24839beb93cSSam Leffler {
249f05cddf9SRui Paulo if (ctrl == NULL)
250f05cddf9SRui Paulo return;
25139beb93cSSam Leffler unlink(ctrl->local.sun_path);
252f05cddf9SRui Paulo if (ctrl->s >= 0)
25339beb93cSSam Leffler close(ctrl->s);
25439beb93cSSam Leffler os_free(ctrl);
25539beb93cSSam Leffler }
25639beb93cSSam Leffler
257f05cddf9SRui Paulo
258f05cddf9SRui Paulo #ifdef ANDROID
259f05cddf9SRui Paulo /**
260f05cddf9SRui Paulo * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
261f05cddf9SRui Paulo * may be left over from clients that were previously connected to
262f05cddf9SRui Paulo * wpa_supplicant. This keeps these files from being orphaned in the
263f05cddf9SRui Paulo * event of crashes that prevented them from being removed as part
264f05cddf9SRui Paulo * of the normal orderly shutdown.
265f05cddf9SRui Paulo */
wpa_ctrl_cleanup(void)266f05cddf9SRui Paulo void wpa_ctrl_cleanup(void)
267f05cddf9SRui Paulo {
268f05cddf9SRui Paulo DIR *dir;
269f05cddf9SRui Paulo struct dirent *result;
270f05cddf9SRui Paulo size_t dirnamelen;
271f05cddf9SRui Paulo size_t maxcopy;
272f05cddf9SRui Paulo char pathname[PATH_MAX];
273f05cddf9SRui Paulo char *namep;
274f05cddf9SRui Paulo
275f05cddf9SRui Paulo if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
276f05cddf9SRui Paulo return;
277f05cddf9SRui Paulo
278f05cddf9SRui Paulo dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
279f05cddf9SRui Paulo CONFIG_CTRL_IFACE_CLIENT_DIR);
280f05cddf9SRui Paulo if (dirnamelen >= sizeof(pathname)) {
281f05cddf9SRui Paulo closedir(dir);
282f05cddf9SRui Paulo return;
283f05cddf9SRui Paulo }
284f05cddf9SRui Paulo namep = pathname + dirnamelen;
285f05cddf9SRui Paulo maxcopy = PATH_MAX - dirnamelen;
286c1d255d3SCy Schubert while ((result = readdir(dir)) != NULL) {
287c1d255d3SCy Schubert if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
288f05cddf9SRui Paulo unlink(pathname);
289f05cddf9SRui Paulo }
290f05cddf9SRui Paulo closedir(dir);
291f05cddf9SRui Paulo }
292f05cddf9SRui Paulo #endif /* ANDROID */
293f05cddf9SRui Paulo
294f05cddf9SRui Paulo #else /* CONFIG_CTRL_IFACE_UNIX */
295f05cddf9SRui Paulo
296f05cddf9SRui Paulo #ifdef ANDROID
wpa_ctrl_cleanup(void)297f05cddf9SRui Paulo void wpa_ctrl_cleanup(void)
298f05cddf9SRui Paulo {
299f05cddf9SRui Paulo }
300f05cddf9SRui Paulo #endif /* ANDROID */
301f05cddf9SRui Paulo
30239beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UNIX */
30339beb93cSSam Leffler
30439beb93cSSam Leffler
30539beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
30639beb93cSSam Leffler
wpa_ctrl_open(const char * ctrl_path)30739beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
30839beb93cSSam Leffler {
30939beb93cSSam Leffler struct wpa_ctrl *ctrl;
31039beb93cSSam Leffler char buf[128];
31139beb93cSSam Leffler size_t len;
312f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
313f05cddf9SRui Paulo struct hostent *h;
314f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
31539beb93cSSam Leffler
3165b9c547cSRui Paulo ctrl = os_zalloc(sizeof(*ctrl));
31739beb93cSSam Leffler if (ctrl == NULL)
31839beb93cSSam Leffler return NULL;
31939beb93cSSam Leffler
3205b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3215b9c547cSRui Paulo ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
3225b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
32339beb93cSSam Leffler ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
3245b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
32539beb93cSSam Leffler if (ctrl->s < 0) {
32639beb93cSSam Leffler perror("socket");
32739beb93cSSam Leffler os_free(ctrl);
32839beb93cSSam Leffler return NULL;
32939beb93cSSam Leffler }
33039beb93cSSam Leffler
3315b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3325b9c547cSRui Paulo ctrl->local.sin6_family = AF_INET6;
3335b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
3345b9c547cSRui Paulo ctrl->local.sin6_addr = in6addr_any;
3355b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3365b9c547cSRui Paulo inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
3375b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3385b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
33939beb93cSSam Leffler ctrl->local.sin_family = AF_INET;
340f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
341f05cddf9SRui Paulo ctrl->local.sin_addr.s_addr = INADDR_ANY;
342f05cddf9SRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
34339beb93cSSam Leffler ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
344f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
3455b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
3465b9c547cSRui Paulo
34739beb93cSSam Leffler if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
34839beb93cSSam Leffler sizeof(ctrl->local)) < 0) {
34939beb93cSSam Leffler close(ctrl->s);
35039beb93cSSam Leffler os_free(ctrl);
35139beb93cSSam Leffler return NULL;
35239beb93cSSam Leffler }
35339beb93cSSam Leffler
3545b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3555b9c547cSRui Paulo ctrl->dest.sin6_family = AF_INET6;
3565b9c547cSRui Paulo inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
3575b9c547cSRui Paulo ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
3585b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
35939beb93cSSam Leffler ctrl->dest.sin_family = AF_INET;
36039beb93cSSam Leffler ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
36139beb93cSSam Leffler ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
3625b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
363f05cddf9SRui Paulo
364f05cddf9SRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
365f05cddf9SRui Paulo if (ctrl_path) {
366f05cddf9SRui Paulo char *port, *name;
367f05cddf9SRui Paulo int port_id;
3685b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3695b9c547cSRui Paulo char *scope;
3705b9c547cSRui Paulo int scope_id = 0;
3715b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
372f05cddf9SRui Paulo
373f05cddf9SRui Paulo name = os_strdup(ctrl_path);
374f05cddf9SRui Paulo if (name == NULL) {
375f05cddf9SRui Paulo close(ctrl->s);
376f05cddf9SRui Paulo os_free(ctrl);
377f05cddf9SRui Paulo return NULL;
378f05cddf9SRui Paulo }
3795b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3805b9c547cSRui Paulo port = os_strchr(name, ',');
3815b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
382f05cddf9SRui Paulo port = os_strchr(name, ':');
3835b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
384f05cddf9SRui Paulo
385f05cddf9SRui Paulo if (port) {
386f05cddf9SRui Paulo port_id = atoi(&port[1]);
387f05cddf9SRui Paulo port[0] = '\0';
388f05cddf9SRui Paulo } else
389f05cddf9SRui Paulo port_id = WPA_CTRL_IFACE_PORT;
390f05cddf9SRui Paulo
3915b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
3925b9c547cSRui Paulo scope = os_strchr(name, '%');
3935b9c547cSRui Paulo if (scope) {
3945b9c547cSRui Paulo scope_id = if_nametoindex(&scope[1]);
3955b9c547cSRui Paulo scope[0] = '\0';
3965b9c547cSRui Paulo }
3975b9c547cSRui Paulo h = gethostbyname2(name, AF_INET6);
3985b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
399f05cddf9SRui Paulo h = gethostbyname(name);
4005b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
401f05cddf9SRui Paulo ctrl->remote_ip = os_strdup(name);
402f05cddf9SRui Paulo os_free(name);
403f05cddf9SRui Paulo if (h == NULL) {
404f05cddf9SRui Paulo perror("gethostbyname");
405f05cddf9SRui Paulo close(ctrl->s);
406f05cddf9SRui Paulo os_free(ctrl->remote_ip);
407f05cddf9SRui Paulo os_free(ctrl);
408f05cddf9SRui Paulo return NULL;
409f05cddf9SRui Paulo }
4105b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4115b9c547cSRui Paulo ctrl->dest.sin6_scope_id = scope_id;
4125b9c547cSRui Paulo ctrl->dest.sin6_port = htons(port_id);
4135b9c547cSRui Paulo os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
4145b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
415f05cddf9SRui Paulo ctrl->dest.sin_port = htons(port_id);
4165b9c547cSRui Paulo os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
4175b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
418f05cddf9SRui Paulo } else
419f05cddf9SRui Paulo ctrl->remote_ip = os_strdup("localhost");
420f05cddf9SRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
421f05cddf9SRui Paulo
42239beb93cSSam Leffler if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
42339beb93cSSam Leffler sizeof(ctrl->dest)) < 0) {
4245b9c547cSRui Paulo #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
4255b9c547cSRui Paulo char addr[INET6_ADDRSTRLEN];
4265b9c547cSRui Paulo wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
4275b9c547cSRui Paulo inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
4285b9c547cSRui Paulo sizeof(ctrl->dest)),
4295b9c547cSRui Paulo ntohs(ctrl->dest.sin6_port),
4305b9c547cSRui Paulo strerror(errno));
4315b9c547cSRui Paulo #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
4325b9c547cSRui Paulo wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
4335b9c547cSRui Paulo inet_ntoa(ctrl->dest.sin_addr),
4345b9c547cSRui Paulo ntohs(ctrl->dest.sin_port),
4355b9c547cSRui Paulo strerror(errno));
4365b9c547cSRui Paulo #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
43739beb93cSSam Leffler close(ctrl->s);
438f05cddf9SRui Paulo os_free(ctrl->remote_ip);
43939beb93cSSam Leffler os_free(ctrl);
44039beb93cSSam Leffler return NULL;
44139beb93cSSam Leffler }
44239beb93cSSam Leffler
44339beb93cSSam Leffler len = sizeof(buf) - 1;
44439beb93cSSam Leffler if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
44539beb93cSSam Leffler buf[len] = '\0';
44639beb93cSSam Leffler ctrl->cookie = os_strdup(buf);
44739beb93cSSam Leffler }
44839beb93cSSam Leffler
449f05cddf9SRui Paulo if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
450f05cddf9SRui Paulo buf[len] = '\0';
451f05cddf9SRui Paulo ctrl->remote_ifname = os_strdup(buf);
452f05cddf9SRui Paulo }
453f05cddf9SRui Paulo
45439beb93cSSam Leffler return ctrl;
45539beb93cSSam Leffler }
45639beb93cSSam Leffler
45739beb93cSSam Leffler
wpa_ctrl_get_remote_ifname(struct wpa_ctrl * ctrl)458f05cddf9SRui Paulo char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
459f05cddf9SRui Paulo {
460f05cddf9SRui Paulo #define WPA_CTRL_MAX_PS_NAME 100
461f05cddf9SRui Paulo static char ps[WPA_CTRL_MAX_PS_NAME] = {};
462f05cddf9SRui Paulo os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
463f05cddf9SRui Paulo ctrl->remote_ip, ctrl->remote_ifname);
464f05cddf9SRui Paulo return ps;
465f05cddf9SRui Paulo }
466f05cddf9SRui Paulo
467f05cddf9SRui Paulo
wpa_ctrl_close(struct wpa_ctrl * ctrl)46839beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
46939beb93cSSam Leffler {
47039beb93cSSam Leffler close(ctrl->s);
47139beb93cSSam Leffler os_free(ctrl->cookie);
472f05cddf9SRui Paulo os_free(ctrl->remote_ifname);
473f05cddf9SRui Paulo os_free(ctrl->remote_ip);
47439beb93cSSam Leffler os_free(ctrl);
47539beb93cSSam Leffler }
47639beb93cSSam Leffler
47739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
47839beb93cSSam Leffler
47939beb93cSSam Leffler
48039beb93cSSam Leffler #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))48139beb93cSSam Leffler int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
48239beb93cSSam Leffler char *reply, size_t *reply_len,
48339beb93cSSam Leffler void (*msg_cb)(char *msg, size_t len))
48439beb93cSSam Leffler {
48539beb93cSSam Leffler struct timeval tv;
486*a90b9d01SCy Schubert struct os_reltime started_at, ending_at;
48739beb93cSSam Leffler int res;
48839beb93cSSam Leffler fd_set rfds;
48939beb93cSSam Leffler const char *_cmd;
49039beb93cSSam Leffler char *cmd_buf = NULL;
49139beb93cSSam Leffler size_t _cmd_len;
49239beb93cSSam Leffler
49339beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_UDP
49439beb93cSSam Leffler if (ctrl->cookie) {
49539beb93cSSam Leffler char *pos;
49639beb93cSSam Leffler _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
49739beb93cSSam Leffler cmd_buf = os_malloc(_cmd_len);
49839beb93cSSam Leffler if (cmd_buf == NULL)
49939beb93cSSam Leffler return -1;
50039beb93cSSam Leffler _cmd = cmd_buf;
50139beb93cSSam Leffler pos = cmd_buf;
50239beb93cSSam Leffler os_strlcpy(pos, ctrl->cookie, _cmd_len);
50339beb93cSSam Leffler pos += os_strlen(ctrl->cookie);
50439beb93cSSam Leffler *pos++ = ' ';
50539beb93cSSam Leffler os_memcpy(pos, cmd, cmd_len);
50639beb93cSSam Leffler } else
50739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_UDP */
50839beb93cSSam Leffler {
50939beb93cSSam Leffler _cmd = cmd;
51039beb93cSSam Leffler _cmd_len = cmd_len;
51139beb93cSSam Leffler }
51239beb93cSSam Leffler
513f05cddf9SRui Paulo errno = 0;
514f05cddf9SRui Paulo started_at.sec = 0;
515f05cddf9SRui Paulo started_at.usec = 0;
516f05cddf9SRui Paulo retry_send:
51739beb93cSSam Leffler if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
518f05cddf9SRui Paulo if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
519f05cddf9SRui Paulo {
520f05cddf9SRui Paulo /*
521f05cddf9SRui Paulo * Must be a non-blocking socket... Try for a bit
522f05cddf9SRui Paulo * longer before giving up.
523f05cddf9SRui Paulo */
524f05cddf9SRui Paulo if (started_at.sec == 0)
5255b9c547cSRui Paulo os_get_reltime(&started_at);
526f05cddf9SRui Paulo else {
5275b9c547cSRui Paulo struct os_reltime n;
5285b9c547cSRui Paulo os_get_reltime(&n);
529f05cddf9SRui Paulo /* Try for a few seconds. */
5305b9c547cSRui Paulo if (os_reltime_expired(&n, &started_at, 5))
531f05cddf9SRui Paulo goto send_err;
532f05cddf9SRui Paulo }
533f05cddf9SRui Paulo os_sleep(1, 0);
534f05cddf9SRui Paulo goto retry_send;
535f05cddf9SRui Paulo }
536f05cddf9SRui Paulo send_err:
53739beb93cSSam Leffler os_free(cmd_buf);
53839beb93cSSam Leffler return -1;
53939beb93cSSam Leffler }
54039beb93cSSam Leffler os_free(cmd_buf);
54139beb93cSSam Leffler
542*a90b9d01SCy Schubert os_get_reltime(&ending_at);
543*a90b9d01SCy Schubert ending_at.sec += 10;
544*a90b9d01SCy Schubert
54539beb93cSSam Leffler for (;;) {
546*a90b9d01SCy Schubert struct os_reltime diff;
547*a90b9d01SCy Schubert
548*a90b9d01SCy Schubert os_get_reltime(&started_at);
549*a90b9d01SCy Schubert if (os_reltime_before(&ending_at, &started_at))
550*a90b9d01SCy Schubert return -2;
551*a90b9d01SCy Schubert os_reltime_sub(&ending_at, &started_at, &diff);
552*a90b9d01SCy Schubert tv.tv_sec = diff.sec;
553*a90b9d01SCy Schubert tv.tv_usec = diff.usec;
554*a90b9d01SCy Schubert
55539beb93cSSam Leffler FD_ZERO(&rfds);
55639beb93cSSam Leffler FD_SET(ctrl->s, &rfds);
55739beb93cSSam Leffler res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
558780fb4a2SCy Schubert if (res < 0 && errno == EINTR)
559780fb4a2SCy Schubert continue;
560f05cddf9SRui Paulo if (res < 0)
561f05cddf9SRui Paulo return res;
56239beb93cSSam Leffler if (FD_ISSET(ctrl->s, &rfds)) {
56339beb93cSSam Leffler res = recv(ctrl->s, reply, *reply_len, 0);
56439beb93cSSam Leffler if (res < 0)
56539beb93cSSam Leffler return res;
5664bc52338SCy Schubert if ((res > 0 && reply[0] == '<') ||
5674bc52338SCy Schubert (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
56839beb93cSSam Leffler /* This is an unsolicited message from
56939beb93cSSam Leffler * wpa_supplicant, not the reply to the
57039beb93cSSam Leffler * request. Use msg_cb to report this to the
57139beb93cSSam Leffler * caller. */
57239beb93cSSam Leffler if (msg_cb) {
57339beb93cSSam Leffler /* Make sure the message is nul
57439beb93cSSam Leffler * terminated. */
57539beb93cSSam Leffler if ((size_t) res == *reply_len)
57639beb93cSSam Leffler res = (*reply_len) - 1;
57739beb93cSSam Leffler reply[res] = '\0';
57839beb93cSSam Leffler msg_cb(reply, res);
57939beb93cSSam Leffler }
58039beb93cSSam Leffler continue;
58139beb93cSSam Leffler }
58239beb93cSSam Leffler *reply_len = res;
58339beb93cSSam Leffler break;
58439beb93cSSam Leffler } else {
58539beb93cSSam Leffler return -2;
58639beb93cSSam Leffler }
58739beb93cSSam Leffler }
58839beb93cSSam Leffler return 0;
58939beb93cSSam Leffler }
59039beb93cSSam Leffler #endif /* CTRL_IFACE_SOCKET */
59139beb93cSSam Leffler
59239beb93cSSam Leffler
wpa_ctrl_attach_helper(struct wpa_ctrl * ctrl,int attach)59339beb93cSSam Leffler static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
59439beb93cSSam Leffler {
59539beb93cSSam Leffler char buf[10];
59639beb93cSSam Leffler int ret;
59739beb93cSSam Leffler size_t len = 10;
59839beb93cSSam Leffler
59939beb93cSSam Leffler ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
60039beb93cSSam Leffler buf, &len, NULL);
60139beb93cSSam Leffler if (ret < 0)
60239beb93cSSam Leffler return ret;
60339beb93cSSam Leffler if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
60439beb93cSSam Leffler return 0;
60539beb93cSSam Leffler return -1;
60639beb93cSSam Leffler }
60739beb93cSSam Leffler
60839beb93cSSam Leffler
wpa_ctrl_attach(struct wpa_ctrl * ctrl)60939beb93cSSam Leffler int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
61039beb93cSSam Leffler {
61139beb93cSSam Leffler return wpa_ctrl_attach_helper(ctrl, 1);
61239beb93cSSam Leffler }
61339beb93cSSam Leffler
61439beb93cSSam Leffler
wpa_ctrl_detach(struct wpa_ctrl * ctrl)61539beb93cSSam Leffler int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
61639beb93cSSam Leffler {
61739beb93cSSam Leffler return wpa_ctrl_attach_helper(ctrl, 0);
61839beb93cSSam Leffler }
61939beb93cSSam Leffler
62039beb93cSSam Leffler
62139beb93cSSam Leffler #ifdef CTRL_IFACE_SOCKET
62239beb93cSSam Leffler
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)62339beb93cSSam Leffler int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
62439beb93cSSam Leffler {
62539beb93cSSam Leffler int res;
62639beb93cSSam Leffler
62739beb93cSSam Leffler res = recv(ctrl->s, reply, *reply_len, 0);
62839beb93cSSam Leffler if (res < 0)
62939beb93cSSam Leffler return res;
63039beb93cSSam Leffler *reply_len = res;
63139beb93cSSam Leffler return 0;
63239beb93cSSam Leffler }
63339beb93cSSam Leffler
63439beb93cSSam Leffler
wpa_ctrl_pending(struct wpa_ctrl * ctrl)63539beb93cSSam Leffler int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
63639beb93cSSam Leffler {
63739beb93cSSam Leffler struct timeval tv;
63839beb93cSSam Leffler fd_set rfds;
63939beb93cSSam Leffler tv.tv_sec = 0;
64039beb93cSSam Leffler tv.tv_usec = 0;
64139beb93cSSam Leffler FD_ZERO(&rfds);
64239beb93cSSam Leffler FD_SET(ctrl->s, &rfds);
64339beb93cSSam Leffler select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
64439beb93cSSam Leffler return FD_ISSET(ctrl->s, &rfds);
64539beb93cSSam Leffler }
64639beb93cSSam Leffler
64739beb93cSSam Leffler
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)64839beb93cSSam Leffler int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
64939beb93cSSam Leffler {
65039beb93cSSam Leffler return ctrl->s;
65139beb93cSSam Leffler }
65239beb93cSSam Leffler
65339beb93cSSam Leffler #endif /* CTRL_IFACE_SOCKET */
65439beb93cSSam Leffler
65539beb93cSSam Leffler
65639beb93cSSam Leffler #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
65739beb93cSSam Leffler
65839beb93cSSam Leffler #ifndef WPA_SUPPLICANT_NAMED_PIPE
65939beb93cSSam Leffler #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
66039beb93cSSam Leffler #endif
66139beb93cSSam Leffler #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
66239beb93cSSam Leffler
wpa_ctrl_open(const char * ctrl_path)66339beb93cSSam Leffler struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
66439beb93cSSam Leffler {
66539beb93cSSam Leffler struct wpa_ctrl *ctrl;
66639beb93cSSam Leffler DWORD mode;
66739beb93cSSam Leffler TCHAR name[256];
66839beb93cSSam Leffler int i, ret;
66939beb93cSSam Leffler
67039beb93cSSam Leffler ctrl = os_malloc(sizeof(*ctrl));
67139beb93cSSam Leffler if (ctrl == NULL)
67239beb93cSSam Leffler return NULL;
67339beb93cSSam Leffler os_memset(ctrl, 0, sizeof(*ctrl));
67439beb93cSSam Leffler
67539beb93cSSam Leffler #ifdef UNICODE
67639beb93cSSam Leffler if (ctrl_path == NULL)
67739beb93cSSam Leffler ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
67839beb93cSSam Leffler else
67939beb93cSSam Leffler ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
68039beb93cSSam Leffler ctrl_path);
68139beb93cSSam Leffler #else /* UNICODE */
68239beb93cSSam Leffler if (ctrl_path == NULL)
68339beb93cSSam Leffler ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
68439beb93cSSam Leffler else
68539beb93cSSam Leffler ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
68639beb93cSSam Leffler ctrl_path);
68739beb93cSSam Leffler #endif /* UNICODE */
6885b9c547cSRui Paulo if (os_snprintf_error(256, ret)) {
68939beb93cSSam Leffler os_free(ctrl);
69039beb93cSSam Leffler return NULL;
69139beb93cSSam Leffler }
69239beb93cSSam Leffler
69339beb93cSSam Leffler for (i = 0; i < 10; i++) {
69439beb93cSSam Leffler ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
69539beb93cSSam Leffler NULL, OPEN_EXISTING, 0, NULL);
69639beb93cSSam Leffler /*
69739beb93cSSam Leffler * Current named pipe server side in wpa_supplicant is
69839beb93cSSam Leffler * re-opening the pipe for new clients only after the previous
69939beb93cSSam Leffler * one is taken into use. This leaves a small window for race
70039beb93cSSam Leffler * conditions when two connections are being opened at almost
70139beb93cSSam Leffler * the same time. Retry if that was the case.
70239beb93cSSam Leffler */
70339beb93cSSam Leffler if (ctrl->pipe != INVALID_HANDLE_VALUE ||
70439beb93cSSam Leffler GetLastError() != ERROR_PIPE_BUSY)
70539beb93cSSam Leffler break;
70639beb93cSSam Leffler WaitNamedPipe(name, 1000);
70739beb93cSSam Leffler }
70839beb93cSSam Leffler if (ctrl->pipe == INVALID_HANDLE_VALUE) {
70939beb93cSSam Leffler os_free(ctrl);
71039beb93cSSam Leffler return NULL;
71139beb93cSSam Leffler }
71239beb93cSSam Leffler
71339beb93cSSam Leffler mode = PIPE_READMODE_MESSAGE;
71439beb93cSSam Leffler if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
71539beb93cSSam Leffler CloseHandle(ctrl->pipe);
71639beb93cSSam Leffler os_free(ctrl);
71739beb93cSSam Leffler return NULL;
71839beb93cSSam Leffler }
71939beb93cSSam Leffler
72039beb93cSSam Leffler return ctrl;
72139beb93cSSam Leffler }
72239beb93cSSam Leffler
72339beb93cSSam Leffler
wpa_ctrl_close(struct wpa_ctrl * ctrl)72439beb93cSSam Leffler void wpa_ctrl_close(struct wpa_ctrl *ctrl)
72539beb93cSSam Leffler {
72639beb93cSSam Leffler CloseHandle(ctrl->pipe);
72739beb93cSSam Leffler os_free(ctrl);
72839beb93cSSam Leffler }
72939beb93cSSam Leffler
73039beb93cSSam Leffler
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))73139beb93cSSam Leffler int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
73239beb93cSSam Leffler char *reply, size_t *reply_len,
73339beb93cSSam Leffler void (*msg_cb)(char *msg, size_t len))
73439beb93cSSam Leffler {
73539beb93cSSam Leffler DWORD written;
73639beb93cSSam Leffler DWORD readlen = *reply_len;
73739beb93cSSam Leffler
73839beb93cSSam Leffler if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
73939beb93cSSam Leffler return -1;
74039beb93cSSam Leffler
74139beb93cSSam Leffler if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
74239beb93cSSam Leffler return -1;
74339beb93cSSam Leffler *reply_len = readlen;
74439beb93cSSam Leffler
74539beb93cSSam Leffler return 0;
74639beb93cSSam Leffler }
74739beb93cSSam Leffler
74839beb93cSSam Leffler
wpa_ctrl_recv(struct wpa_ctrl * ctrl,char * reply,size_t * reply_len)74939beb93cSSam Leffler int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
75039beb93cSSam Leffler {
75139beb93cSSam Leffler DWORD len = *reply_len;
75239beb93cSSam Leffler if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
75339beb93cSSam Leffler return -1;
75439beb93cSSam Leffler *reply_len = len;
75539beb93cSSam Leffler return 0;
75639beb93cSSam Leffler }
75739beb93cSSam Leffler
75839beb93cSSam Leffler
wpa_ctrl_pending(struct wpa_ctrl * ctrl)75939beb93cSSam Leffler int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
76039beb93cSSam Leffler {
76139beb93cSSam Leffler DWORD left;
76239beb93cSSam Leffler
76339beb93cSSam Leffler if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
76439beb93cSSam Leffler return -1;
76539beb93cSSam Leffler return left ? 1 : 0;
76639beb93cSSam Leffler }
76739beb93cSSam Leffler
76839beb93cSSam Leffler
wpa_ctrl_get_fd(struct wpa_ctrl * ctrl)76939beb93cSSam Leffler int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
77039beb93cSSam Leffler {
77139beb93cSSam Leffler return -1;
77239beb93cSSam Leffler }
77339beb93cSSam Leffler
77439beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
77539beb93cSSam Leffler
77639beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE */
777