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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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