1189251Ssam/* 2189251Ssam * wpa_supplicant/hostapd control interface library 3189251Ssam * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#ifdef CONFIG_CTRL_IFACE 12189251Ssam 13189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 14346981Scy#include <sys/stat.h> 15346981Scy#include <fcntl.h> 16189251Ssam#include <sys/un.h> 17252726Srpaulo#include <unistd.h> 18252726Srpaulo#include <fcntl.h> 19189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 20252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 21252726Srpaulo#include <netdb.h> 22252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 23189251Ssam 24252726Srpaulo#ifdef ANDROID 25252726Srpaulo#include <dirent.h> 26289549Srpaulo#include <sys/stat.h> 27252726Srpaulo#include <cutils/sockets.h> 28252726Srpaulo#include "private/android_filesystem_config.h" 29252726Srpaulo#endif /* ANDROID */ 30252726Srpaulo 31281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 32281806Srpaulo#include <net/if.h> 33281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 34281806Srpaulo 35189251Ssam#include "wpa_ctrl.h" 36189251Ssam#include "common.h" 37189251Ssam 38189251Ssam 39189251Ssam#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 40189251Ssam#define CTRL_IFACE_SOCKET 41189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 42189251Ssam 43189251Ssam 44189251Ssam/** 45189251Ssam * struct wpa_ctrl - Internal structure for control interface library 46189251Ssam * 47189251Ssam * This structure is used by the wpa_supplicant/hostapd control interface 48189251Ssam * library to store internal data. Programs using the library should not touch 49189251Ssam * this data directly. They can only use the pointer to the data structure as 50189251Ssam * an identifier for the control interface connection and use this as one of 51189251Ssam * the arguments for most of the control interface library functions. 52189251Ssam */ 53189251Ssamstruct wpa_ctrl { 54189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 55189251Ssam int s; 56281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 57281806Srpaulo struct sockaddr_in6 local; 58281806Srpaulo struct sockaddr_in6 dest; 59281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 60189251Ssam struct sockaddr_in local; 61189251Ssam struct sockaddr_in dest; 62281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 63189251Ssam char *cookie; 64252726Srpaulo char *remote_ifname; 65252726Srpaulo char *remote_ip; 66189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 67189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 68189251Ssam int s; 69189251Ssam struct sockaddr_un local; 70189251Ssam struct sockaddr_un dest; 71189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 72189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 73189251Ssam HANDLE pipe; 74189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 75189251Ssam}; 76189251Ssam 77189251Ssam 78189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 79189251Ssam 80252726Srpaulo#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR 81252726Srpaulo#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" 82252726Srpaulo#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ 83252726Srpaulo#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX 84252726Srpaulo#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" 85252726Srpaulo#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ 86252726Srpaulo 87252726Srpaulo 88189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 89189251Ssam{ 90289549Srpaulo return wpa_ctrl_open2(ctrl_path, NULL); 91289549Srpaulo} 92289549Srpaulo 93289549Srpaulo 94289549Srpaulostruct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path, 95289549Srpaulo const char *cli_path) 96289549Srpaulo{ 97189251Ssam struct wpa_ctrl *ctrl; 98189251Ssam static int counter = 0; 99189251Ssam int ret; 100189251Ssam size_t res; 101189251Ssam int tries = 0; 102252726Srpaulo int flags; 103189251Ssam 104281806Srpaulo if (ctrl_path == NULL) 105281806Srpaulo return NULL; 106281806Srpaulo 107281806Srpaulo ctrl = os_zalloc(sizeof(*ctrl)); 108189251Ssam if (ctrl == NULL) 109189251Ssam return NULL; 110189251Ssam 111189251Ssam ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 112189251Ssam if (ctrl->s < 0) { 113189251Ssam os_free(ctrl); 114189251Ssam return NULL; 115189251Ssam } 116189251Ssam 117189251Ssam ctrl->local.sun_family = AF_UNIX; 118189251Ssam counter++; 119189251Ssamtry_again: 120289549Srpaulo if (cli_path && cli_path[0] == '/') { 121289549Srpaulo ret = os_snprintf(ctrl->local.sun_path, 122289549Srpaulo sizeof(ctrl->local.sun_path), 123289549Srpaulo "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 124289549Srpaulo cli_path, (int) getpid(), counter); 125289549Srpaulo } else { 126289549Srpaulo ret = os_snprintf(ctrl->local.sun_path, 127289549Srpaulo sizeof(ctrl->local.sun_path), 128289549Srpaulo CONFIG_CTRL_IFACE_CLIENT_DIR "/" 129289549Srpaulo CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 130289549Srpaulo (int) getpid(), counter); 131289549Srpaulo } 132281806Srpaulo if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) { 133189251Ssam close(ctrl->s); 134189251Ssam os_free(ctrl); 135189251Ssam return NULL; 136189251Ssam } 137189251Ssam tries++; 138346981Scy#ifdef ANDROID 139346981Scy /* Set client socket file permissions so that bind() creates the client 140346981Scy * socket with these permissions and there is no need to try to change 141346981Scy * them with chmod() after bind() which would have potential issues with 142346981Scy * race conditions. These permissions are needed to make sure the server 143346981Scy * side (wpa_supplicant or hostapd) can reply to the control interface 144346981Scy * messages. 145346981Scy * 146346981Scy * The lchown() calls below after bind() are also part of the needed 147346981Scy * operations to allow the response to go through. Those are using the 148346981Scy * no-deference-symlinks version to avoid races. */ 149346981Scy fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 150346981Scy#endif /* ANDROID */ 151189251Ssam if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 152189251Ssam sizeof(ctrl->local)) < 0) { 153189251Ssam if (errno == EADDRINUSE && tries < 2) { 154189251Ssam /* 155189251Ssam * getpid() returns unique identifier for this instance 156189251Ssam * of wpa_ctrl, so the existing socket file must have 157189251Ssam * been left by unclean termination of an earlier run. 158189251Ssam * Remove the file and try again. 159189251Ssam */ 160189251Ssam unlink(ctrl->local.sun_path); 161189251Ssam goto try_again; 162189251Ssam } 163189251Ssam close(ctrl->s); 164189251Ssam os_free(ctrl); 165189251Ssam return NULL; 166189251Ssam } 167189251Ssam 168252726Srpaulo#ifdef ANDROID 169289549Srpaulo /* Set group even if we do not have privileges to change owner */ 170346981Scy lchown(ctrl->local.sun_path, -1, AID_WIFI); 171346981Scy lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); 172281806Srpaulo 173281806Srpaulo if (os_strncmp(ctrl_path, "@android:", 9) == 0) { 174281806Srpaulo if (socket_local_client_connect( 175281806Srpaulo ctrl->s, ctrl_path + 9, 176281806Srpaulo ANDROID_SOCKET_NAMESPACE_RESERVED, 177281806Srpaulo SOCK_DGRAM) < 0) { 178281806Srpaulo close(ctrl->s); 179281806Srpaulo unlink(ctrl->local.sun_path); 180281806Srpaulo os_free(ctrl); 181281806Srpaulo return NULL; 182281806Srpaulo } 183281806Srpaulo return ctrl; 184281806Srpaulo } 185281806Srpaulo 186252726Srpaulo /* 187252726Srpaulo * If the ctrl_path isn't an absolute pathname, assume that 188252726Srpaulo * it's the name of a socket in the Android reserved namespace. 189252726Srpaulo * Otherwise, it's a normal UNIX domain socket appearing in the 190252726Srpaulo * filesystem. 191252726Srpaulo */ 192281806Srpaulo if (*ctrl_path != '/') { 193252726Srpaulo char buf[21]; 194252726Srpaulo os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); 195252726Srpaulo if (socket_local_client_connect( 196252726Srpaulo ctrl->s, buf, 197252726Srpaulo ANDROID_SOCKET_NAMESPACE_RESERVED, 198252726Srpaulo SOCK_DGRAM) < 0) { 199252726Srpaulo close(ctrl->s); 200252726Srpaulo unlink(ctrl->local.sun_path); 201252726Srpaulo os_free(ctrl); 202252726Srpaulo return NULL; 203252726Srpaulo } 204252726Srpaulo return ctrl; 205252726Srpaulo } 206252726Srpaulo#endif /* ANDROID */ 207252726Srpaulo 208189251Ssam ctrl->dest.sun_family = AF_UNIX; 209281806Srpaulo if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) { 210281806Srpaulo ctrl->dest.sun_path[0] = '\0'; 211281806Srpaulo os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10, 212281806Srpaulo sizeof(ctrl->dest.sun_path) - 1); 213281806Srpaulo } else { 214281806Srpaulo res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 215281806Srpaulo sizeof(ctrl->dest.sun_path)); 216281806Srpaulo if (res >= sizeof(ctrl->dest.sun_path)) { 217281806Srpaulo close(ctrl->s); 218281806Srpaulo os_free(ctrl); 219281806Srpaulo return NULL; 220281806Srpaulo } 221189251Ssam } 222189251Ssam if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 223189251Ssam sizeof(ctrl->dest)) < 0) { 224189251Ssam close(ctrl->s); 225189251Ssam unlink(ctrl->local.sun_path); 226189251Ssam os_free(ctrl); 227189251Ssam return NULL; 228189251Ssam } 229189251Ssam 230252726Srpaulo /* 231252726Srpaulo * Make socket non-blocking so that we don't hang forever if 232252726Srpaulo * target dies unexpectedly. 233252726Srpaulo */ 234252726Srpaulo flags = fcntl(ctrl->s, F_GETFL); 235252726Srpaulo if (flags >= 0) { 236252726Srpaulo flags |= O_NONBLOCK; 237252726Srpaulo if (fcntl(ctrl->s, F_SETFL, flags) < 0) { 238252726Srpaulo perror("fcntl(ctrl->s, O_NONBLOCK)"); 239252726Srpaulo /* Not fatal, continue on.*/ 240252726Srpaulo } 241252726Srpaulo } 242252726Srpaulo 243189251Ssam return ctrl; 244189251Ssam} 245189251Ssam 246189251Ssam 247189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 248189251Ssam{ 249252726Srpaulo if (ctrl == NULL) 250252726Srpaulo return; 251189251Ssam unlink(ctrl->local.sun_path); 252252726Srpaulo if (ctrl->s >= 0) 253252726Srpaulo close(ctrl->s); 254189251Ssam os_free(ctrl); 255189251Ssam} 256189251Ssam 257252726Srpaulo 258252726Srpaulo#ifdef ANDROID 259252726Srpaulo/** 260252726Srpaulo * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 261252726Srpaulo * may be left over from clients that were previously connected to 262252726Srpaulo * wpa_supplicant. This keeps these files from being orphaned in the 263252726Srpaulo * event of crashes that prevented them from being removed as part 264252726Srpaulo * of the normal orderly shutdown. 265252726Srpaulo */ 266252726Srpaulovoid wpa_ctrl_cleanup(void) 267252726Srpaulo{ 268252726Srpaulo DIR *dir; 269252726Srpaulo struct dirent entry; 270252726Srpaulo struct dirent *result; 271252726Srpaulo size_t dirnamelen; 272252726Srpaulo size_t maxcopy; 273252726Srpaulo char pathname[PATH_MAX]; 274252726Srpaulo char *namep; 275252726Srpaulo 276252726Srpaulo if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL) 277252726Srpaulo return; 278252726Srpaulo 279252726Srpaulo dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/", 280252726Srpaulo CONFIG_CTRL_IFACE_CLIENT_DIR); 281252726Srpaulo if (dirnamelen >= sizeof(pathname)) { 282252726Srpaulo closedir(dir); 283252726Srpaulo return; 284252726Srpaulo } 285252726Srpaulo namep = pathname + dirnamelen; 286252726Srpaulo maxcopy = PATH_MAX - dirnamelen; 287252726Srpaulo while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 288281806Srpaulo if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) 289281806Srpaulo unlink(pathname); 290252726Srpaulo } 291252726Srpaulo closedir(dir); 292252726Srpaulo} 293252726Srpaulo#endif /* ANDROID */ 294252726Srpaulo 295252726Srpaulo#else /* CONFIG_CTRL_IFACE_UNIX */ 296252726Srpaulo 297252726Srpaulo#ifdef ANDROID 298252726Srpaulovoid wpa_ctrl_cleanup(void) 299252726Srpaulo{ 300252726Srpaulo} 301252726Srpaulo#endif /* ANDROID */ 302252726Srpaulo 303189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 304189251Ssam 305189251Ssam 306189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 307189251Ssam 308189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 309189251Ssam{ 310189251Ssam struct wpa_ctrl *ctrl; 311189251Ssam char buf[128]; 312189251Ssam size_t len; 313252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 314252726Srpaulo struct hostent *h; 315252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 316189251Ssam 317281806Srpaulo ctrl = os_zalloc(sizeof(*ctrl)); 318189251Ssam if (ctrl == NULL) 319189251Ssam return NULL; 320189251Ssam 321281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 322281806Srpaulo ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0); 323281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 324189251Ssam ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 325281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 326189251Ssam if (ctrl->s < 0) { 327189251Ssam perror("socket"); 328189251Ssam os_free(ctrl); 329189251Ssam return NULL; 330189251Ssam } 331189251Ssam 332281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 333281806Srpaulo ctrl->local.sin6_family = AF_INET6; 334281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 335281806Srpaulo ctrl->local.sin6_addr = in6addr_any; 336281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 337281806Srpaulo inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr); 338281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 339281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 340189251Ssam ctrl->local.sin_family = AF_INET; 341252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 342252726Srpaulo ctrl->local.sin_addr.s_addr = INADDR_ANY; 343252726Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 344189251Ssam ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 345252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 346281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 347281806Srpaulo 348189251Ssam if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 349189251Ssam sizeof(ctrl->local)) < 0) { 350189251Ssam close(ctrl->s); 351189251Ssam os_free(ctrl); 352189251Ssam return NULL; 353189251Ssam } 354189251Ssam 355281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 356281806Srpaulo ctrl->dest.sin6_family = AF_INET6; 357281806Srpaulo inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr); 358281806Srpaulo ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT); 359281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 360189251Ssam ctrl->dest.sin_family = AF_INET; 361189251Ssam ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 362189251Ssam ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 363281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 364252726Srpaulo 365252726Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 366252726Srpaulo if (ctrl_path) { 367252726Srpaulo char *port, *name; 368252726Srpaulo int port_id; 369281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 370281806Srpaulo char *scope; 371281806Srpaulo int scope_id = 0; 372281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 373252726Srpaulo 374252726Srpaulo name = os_strdup(ctrl_path); 375252726Srpaulo if (name == NULL) { 376252726Srpaulo close(ctrl->s); 377252726Srpaulo os_free(ctrl); 378252726Srpaulo return NULL; 379252726Srpaulo } 380281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 381281806Srpaulo port = os_strchr(name, ','); 382281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 383252726Srpaulo port = os_strchr(name, ':'); 384281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 385252726Srpaulo 386252726Srpaulo if (port) { 387252726Srpaulo port_id = atoi(&port[1]); 388252726Srpaulo port[0] = '\0'; 389252726Srpaulo } else 390252726Srpaulo port_id = WPA_CTRL_IFACE_PORT; 391252726Srpaulo 392281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 393281806Srpaulo scope = os_strchr(name, '%'); 394281806Srpaulo if (scope) { 395281806Srpaulo scope_id = if_nametoindex(&scope[1]); 396281806Srpaulo scope[0] = '\0'; 397281806Srpaulo } 398281806Srpaulo h = gethostbyname2(name, AF_INET6); 399281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 400252726Srpaulo h = gethostbyname(name); 401281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 402252726Srpaulo ctrl->remote_ip = os_strdup(name); 403252726Srpaulo os_free(name); 404252726Srpaulo if (h == NULL) { 405252726Srpaulo perror("gethostbyname"); 406252726Srpaulo close(ctrl->s); 407252726Srpaulo os_free(ctrl->remote_ip); 408252726Srpaulo os_free(ctrl); 409252726Srpaulo return NULL; 410252726Srpaulo } 411281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 412281806Srpaulo ctrl->dest.sin6_scope_id = scope_id; 413281806Srpaulo ctrl->dest.sin6_port = htons(port_id); 414281806Srpaulo os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length); 415281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 416252726Srpaulo ctrl->dest.sin_port = htons(port_id); 417281806Srpaulo os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length); 418281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 419252726Srpaulo } else 420252726Srpaulo ctrl->remote_ip = os_strdup("localhost"); 421252726Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 422252726Srpaulo 423189251Ssam if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 424189251Ssam sizeof(ctrl->dest)) < 0) { 425281806Srpaulo#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 426281806Srpaulo char addr[INET6_ADDRSTRLEN]; 427281806Srpaulo wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", 428281806Srpaulo inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr, 429281806Srpaulo sizeof(ctrl->dest)), 430281806Srpaulo ntohs(ctrl->dest.sin6_port), 431281806Srpaulo strerror(errno)); 432281806Srpaulo#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 433281806Srpaulo wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", 434281806Srpaulo inet_ntoa(ctrl->dest.sin_addr), 435281806Srpaulo ntohs(ctrl->dest.sin_port), 436281806Srpaulo strerror(errno)); 437281806Srpaulo#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ 438189251Ssam close(ctrl->s); 439252726Srpaulo os_free(ctrl->remote_ip); 440189251Ssam os_free(ctrl); 441189251Ssam return NULL; 442189251Ssam } 443189251Ssam 444189251Ssam len = sizeof(buf) - 1; 445189251Ssam if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 446189251Ssam buf[len] = '\0'; 447189251Ssam ctrl->cookie = os_strdup(buf); 448189251Ssam } 449189251Ssam 450252726Srpaulo if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) { 451252726Srpaulo buf[len] = '\0'; 452252726Srpaulo ctrl->remote_ifname = os_strdup(buf); 453252726Srpaulo } 454252726Srpaulo 455189251Ssam return ctrl; 456189251Ssam} 457189251Ssam 458189251Ssam 459252726Srpaulochar * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl) 460252726Srpaulo{ 461252726Srpaulo#define WPA_CTRL_MAX_PS_NAME 100 462252726Srpaulo static char ps[WPA_CTRL_MAX_PS_NAME] = {}; 463252726Srpaulo os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s", 464252726Srpaulo ctrl->remote_ip, ctrl->remote_ifname); 465252726Srpaulo return ps; 466252726Srpaulo} 467252726Srpaulo 468252726Srpaulo 469189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 470189251Ssam{ 471189251Ssam close(ctrl->s); 472189251Ssam os_free(ctrl->cookie); 473252726Srpaulo os_free(ctrl->remote_ifname); 474252726Srpaulo os_free(ctrl->remote_ip); 475189251Ssam os_free(ctrl); 476189251Ssam} 477189251Ssam 478189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 479189251Ssam 480189251Ssam 481189251Ssam#ifdef CTRL_IFACE_SOCKET 482189251Ssamint wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 483189251Ssam char *reply, size_t *reply_len, 484189251Ssam void (*msg_cb)(char *msg, size_t len)) 485189251Ssam{ 486189251Ssam struct timeval tv; 487281806Srpaulo struct os_reltime started_at; 488189251Ssam int res; 489189251Ssam fd_set rfds; 490189251Ssam const char *_cmd; 491189251Ssam char *cmd_buf = NULL; 492189251Ssam size_t _cmd_len; 493189251Ssam 494189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 495189251Ssam if (ctrl->cookie) { 496189251Ssam char *pos; 497189251Ssam _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 498189251Ssam cmd_buf = os_malloc(_cmd_len); 499189251Ssam if (cmd_buf == NULL) 500189251Ssam return -1; 501189251Ssam _cmd = cmd_buf; 502189251Ssam pos = cmd_buf; 503189251Ssam os_strlcpy(pos, ctrl->cookie, _cmd_len); 504189251Ssam pos += os_strlen(ctrl->cookie); 505189251Ssam *pos++ = ' '; 506189251Ssam os_memcpy(pos, cmd, cmd_len); 507189251Ssam } else 508189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 509189251Ssam { 510189251Ssam _cmd = cmd; 511189251Ssam _cmd_len = cmd_len; 512189251Ssam } 513189251Ssam 514252726Srpaulo errno = 0; 515252726Srpaulo started_at.sec = 0; 516252726Srpaulo started_at.usec = 0; 517252726Srpauloretry_send: 518189251Ssam if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 519252726Srpaulo if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) 520252726Srpaulo { 521252726Srpaulo /* 522252726Srpaulo * Must be a non-blocking socket... Try for a bit 523252726Srpaulo * longer before giving up. 524252726Srpaulo */ 525252726Srpaulo if (started_at.sec == 0) 526281806Srpaulo os_get_reltime(&started_at); 527252726Srpaulo else { 528281806Srpaulo struct os_reltime n; 529281806Srpaulo os_get_reltime(&n); 530252726Srpaulo /* Try for a few seconds. */ 531281806Srpaulo if (os_reltime_expired(&n, &started_at, 5)) 532252726Srpaulo goto send_err; 533252726Srpaulo } 534252726Srpaulo os_sleep(1, 0); 535252726Srpaulo goto retry_send; 536252726Srpaulo } 537252726Srpaulo send_err: 538189251Ssam os_free(cmd_buf); 539189251Ssam return -1; 540189251Ssam } 541189251Ssam os_free(cmd_buf); 542189251Ssam 543189251Ssam for (;;) { 544252726Srpaulo tv.tv_sec = 10; 545189251Ssam tv.tv_usec = 0; 546189251Ssam FD_ZERO(&rfds); 547189251Ssam FD_SET(ctrl->s, &rfds); 548189251Ssam res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 549337817Scy if (res < 0 && errno == EINTR) 550337817Scy continue; 551252726Srpaulo if (res < 0) 552252726Srpaulo return res; 553189251Ssam if (FD_ISSET(ctrl->s, &rfds)) { 554189251Ssam res = recv(ctrl->s, reply, *reply_len, 0); 555189251Ssam if (res < 0) 556189251Ssam return res; 557346981Scy if ((res > 0 && reply[0] == '<') || 558346981Scy (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) { 559189251Ssam /* This is an unsolicited message from 560189251Ssam * wpa_supplicant, not the reply to the 561189251Ssam * request. Use msg_cb to report this to the 562189251Ssam * caller. */ 563189251Ssam if (msg_cb) { 564189251Ssam /* Make sure the message is nul 565189251Ssam * terminated. */ 566189251Ssam if ((size_t) res == *reply_len) 567189251Ssam res = (*reply_len) - 1; 568189251Ssam reply[res] = '\0'; 569189251Ssam msg_cb(reply, res); 570189251Ssam } 571189251Ssam continue; 572189251Ssam } 573189251Ssam *reply_len = res; 574189251Ssam break; 575189251Ssam } else { 576189251Ssam return -2; 577189251Ssam } 578189251Ssam } 579189251Ssam return 0; 580189251Ssam} 581189251Ssam#endif /* CTRL_IFACE_SOCKET */ 582189251Ssam 583189251Ssam 584189251Ssamstatic int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 585189251Ssam{ 586189251Ssam char buf[10]; 587189251Ssam int ret; 588189251Ssam size_t len = 10; 589189251Ssam 590189251Ssam ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 591189251Ssam buf, &len, NULL); 592189251Ssam if (ret < 0) 593189251Ssam return ret; 594189251Ssam if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 595189251Ssam return 0; 596189251Ssam return -1; 597189251Ssam} 598189251Ssam 599189251Ssam 600189251Ssamint wpa_ctrl_attach(struct wpa_ctrl *ctrl) 601189251Ssam{ 602189251Ssam return wpa_ctrl_attach_helper(ctrl, 1); 603189251Ssam} 604189251Ssam 605189251Ssam 606189251Ssamint wpa_ctrl_detach(struct wpa_ctrl *ctrl) 607189251Ssam{ 608189251Ssam return wpa_ctrl_attach_helper(ctrl, 0); 609189251Ssam} 610189251Ssam 611189251Ssam 612189251Ssam#ifdef CTRL_IFACE_SOCKET 613189251Ssam 614189251Ssamint wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 615189251Ssam{ 616189251Ssam int res; 617189251Ssam 618189251Ssam res = recv(ctrl->s, reply, *reply_len, 0); 619189251Ssam if (res < 0) 620189251Ssam return res; 621189251Ssam *reply_len = res; 622189251Ssam return 0; 623189251Ssam} 624189251Ssam 625189251Ssam 626189251Ssamint wpa_ctrl_pending(struct wpa_ctrl *ctrl) 627189251Ssam{ 628189251Ssam struct timeval tv; 629189251Ssam fd_set rfds; 630189251Ssam tv.tv_sec = 0; 631189251Ssam tv.tv_usec = 0; 632189251Ssam FD_ZERO(&rfds); 633189251Ssam FD_SET(ctrl->s, &rfds); 634189251Ssam select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 635189251Ssam return FD_ISSET(ctrl->s, &rfds); 636189251Ssam} 637189251Ssam 638189251Ssam 639189251Ssamint wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 640189251Ssam{ 641189251Ssam return ctrl->s; 642189251Ssam} 643189251Ssam 644189251Ssam#endif /* CTRL_IFACE_SOCKET */ 645189251Ssam 646189251Ssam 647189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 648189251Ssam 649189251Ssam#ifndef WPA_SUPPLICANT_NAMED_PIPE 650189251Ssam#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 651189251Ssam#endif 652189251Ssam#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 653189251Ssam 654189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 655189251Ssam{ 656189251Ssam struct wpa_ctrl *ctrl; 657189251Ssam DWORD mode; 658189251Ssam TCHAR name[256]; 659189251Ssam int i, ret; 660189251Ssam 661189251Ssam ctrl = os_malloc(sizeof(*ctrl)); 662189251Ssam if (ctrl == NULL) 663189251Ssam return NULL; 664189251Ssam os_memset(ctrl, 0, sizeof(*ctrl)); 665189251Ssam 666189251Ssam#ifdef UNICODE 667189251Ssam if (ctrl_path == NULL) 668189251Ssam ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 669189251Ssam else 670189251Ssam ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 671189251Ssam ctrl_path); 672189251Ssam#else /* UNICODE */ 673189251Ssam if (ctrl_path == NULL) 674189251Ssam ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 675189251Ssam else 676189251Ssam ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 677189251Ssam ctrl_path); 678189251Ssam#endif /* UNICODE */ 679281806Srpaulo if (os_snprintf_error(256, ret)) { 680189251Ssam os_free(ctrl); 681189251Ssam return NULL; 682189251Ssam } 683189251Ssam 684189251Ssam for (i = 0; i < 10; i++) { 685189251Ssam ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 686189251Ssam NULL, OPEN_EXISTING, 0, NULL); 687189251Ssam /* 688189251Ssam * Current named pipe server side in wpa_supplicant is 689189251Ssam * re-opening the pipe for new clients only after the previous 690189251Ssam * one is taken into use. This leaves a small window for race 691189251Ssam * conditions when two connections are being opened at almost 692189251Ssam * the same time. Retry if that was the case. 693189251Ssam */ 694189251Ssam if (ctrl->pipe != INVALID_HANDLE_VALUE || 695189251Ssam GetLastError() != ERROR_PIPE_BUSY) 696189251Ssam break; 697189251Ssam WaitNamedPipe(name, 1000); 698189251Ssam } 699189251Ssam if (ctrl->pipe == INVALID_HANDLE_VALUE) { 700189251Ssam os_free(ctrl); 701189251Ssam return NULL; 702189251Ssam } 703189251Ssam 704189251Ssam mode = PIPE_READMODE_MESSAGE; 705189251Ssam if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 706189251Ssam CloseHandle(ctrl->pipe); 707189251Ssam os_free(ctrl); 708189251Ssam return NULL; 709189251Ssam } 710189251Ssam 711189251Ssam return ctrl; 712189251Ssam} 713189251Ssam 714189251Ssam 715189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 716189251Ssam{ 717189251Ssam CloseHandle(ctrl->pipe); 718189251Ssam os_free(ctrl); 719189251Ssam} 720189251Ssam 721189251Ssam 722189251Ssamint wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 723189251Ssam char *reply, size_t *reply_len, 724189251Ssam void (*msg_cb)(char *msg, size_t len)) 725189251Ssam{ 726189251Ssam DWORD written; 727189251Ssam DWORD readlen = *reply_len; 728189251Ssam 729189251Ssam if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 730189251Ssam return -1; 731189251Ssam 732189251Ssam if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 733189251Ssam return -1; 734189251Ssam *reply_len = readlen; 735189251Ssam 736189251Ssam return 0; 737189251Ssam} 738189251Ssam 739189251Ssam 740189251Ssamint wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 741189251Ssam{ 742189251Ssam DWORD len = *reply_len; 743189251Ssam if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 744189251Ssam return -1; 745189251Ssam *reply_len = len; 746189251Ssam return 0; 747189251Ssam} 748189251Ssam 749189251Ssam 750189251Ssamint wpa_ctrl_pending(struct wpa_ctrl *ctrl) 751189251Ssam{ 752189251Ssam DWORD left; 753189251Ssam 754189251Ssam if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 755189251Ssam return -1; 756189251Ssam return left ? 1 : 0; 757189251Ssam} 758189251Ssam 759189251Ssam 760189251Ssamint wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 761189251Ssam{ 762189251Ssam return -1; 763189251Ssam} 764189251Ssam 765189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 766189251Ssam 767189251Ssam#endif /* CONFIG_CTRL_IFACE */ 768