16d49e1aeSJan Lentfer /* 26d49e1aeSJan Lentfer * wpa_supplicant/hostapd control interface library 36d49e1aeSJan Lentfer * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 46d49e1aeSJan Lentfer * 5*3ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license. 6*3ff40c12SJohn Marino * See README for more details. 76d49e1aeSJan Lentfer */ 86d49e1aeSJan Lentfer 96d49e1aeSJan Lentfer #include "includes.h" 106d49e1aeSJan Lentfer 116d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE 126d49e1aeSJan Lentfer 136d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX 146d49e1aeSJan Lentfer #include <sys/un.h> 15*3ff40c12SJohn Marino #include <unistd.h> 16*3ff40c12SJohn Marino #include <fcntl.h> 176d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */ 18*3ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 19*3ff40c12SJohn Marino #include <netdb.h> 20*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 21*3ff40c12SJohn Marino 22*3ff40c12SJohn Marino #ifdef ANDROID 23*3ff40c12SJohn Marino #include <dirent.h> 24*3ff40c12SJohn Marino #include <cutils/sockets.h> 25*3ff40c12SJohn Marino #include "private/android_filesystem_config.h" 26*3ff40c12SJohn Marino #endif /* ANDROID */ 276d49e1aeSJan Lentfer 286d49e1aeSJan Lentfer #include "wpa_ctrl.h" 296d49e1aeSJan Lentfer #include "common.h" 306d49e1aeSJan Lentfer 316d49e1aeSJan Lentfer 326d49e1aeSJan Lentfer #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 336d49e1aeSJan Lentfer #define CTRL_IFACE_SOCKET 346d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 356d49e1aeSJan Lentfer 366d49e1aeSJan Lentfer 376d49e1aeSJan Lentfer /** 386d49e1aeSJan Lentfer * struct wpa_ctrl - Internal structure for control interface library 396d49e1aeSJan Lentfer * 406d49e1aeSJan Lentfer * This structure is used by the wpa_supplicant/hostapd control interface 416d49e1aeSJan Lentfer * library to store internal data. Programs using the library should not touch 426d49e1aeSJan Lentfer * this data directly. They can only use the pointer to the data structure as 436d49e1aeSJan Lentfer * an identifier for the control interface connection and use this as one of 446d49e1aeSJan Lentfer * the arguments for most of the control interface library functions. 456d49e1aeSJan Lentfer */ 466d49e1aeSJan Lentfer struct wpa_ctrl { 476d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP 486d49e1aeSJan Lentfer int s; 496d49e1aeSJan Lentfer struct sockaddr_in local; 506d49e1aeSJan Lentfer struct sockaddr_in dest; 516d49e1aeSJan Lentfer char *cookie; 52*3ff40c12SJohn Marino char *remote_ifname; 53*3ff40c12SJohn Marino char *remote_ip; 546d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */ 556d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX 566d49e1aeSJan Lentfer int s; 576d49e1aeSJan Lentfer struct sockaddr_un local; 586d49e1aeSJan Lentfer struct sockaddr_un dest; 596d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */ 606d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 616d49e1aeSJan Lentfer HANDLE pipe; 626d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 636d49e1aeSJan Lentfer }; 646d49e1aeSJan Lentfer 656d49e1aeSJan Lentfer 666d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UNIX 676d49e1aeSJan Lentfer 68*3ff40c12SJohn Marino #ifndef CONFIG_CTRL_IFACE_CLIENT_DIR 69*3ff40c12SJohn Marino #define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" 70*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ 71*3ff40c12SJohn Marino #ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX 72*3ff40c12SJohn Marino #define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" 73*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ 74*3ff40c12SJohn Marino 75*3ff40c12SJohn Marino 766d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 776d49e1aeSJan Lentfer { 786d49e1aeSJan Lentfer struct wpa_ctrl *ctrl; 796d49e1aeSJan Lentfer static int counter = 0; 806d49e1aeSJan Lentfer int ret; 816d49e1aeSJan Lentfer size_t res; 826d49e1aeSJan Lentfer int tries = 0; 83*3ff40c12SJohn Marino int flags; 84*3ff40c12SJohn Marino 85*3ff40c12SJohn Marino if (ctrl_path == NULL) 86*3ff40c12SJohn Marino return NULL; 876d49e1aeSJan Lentfer 886d49e1aeSJan Lentfer ctrl = os_malloc(sizeof(*ctrl)); 896d49e1aeSJan Lentfer if (ctrl == NULL) 906d49e1aeSJan Lentfer return NULL; 916d49e1aeSJan Lentfer os_memset(ctrl, 0, sizeof(*ctrl)); 926d49e1aeSJan Lentfer 936d49e1aeSJan Lentfer ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 946d49e1aeSJan Lentfer if (ctrl->s < 0) { 956d49e1aeSJan Lentfer os_free(ctrl); 966d49e1aeSJan Lentfer return NULL; 976d49e1aeSJan Lentfer } 986d49e1aeSJan Lentfer 996d49e1aeSJan Lentfer ctrl->local.sun_family = AF_UNIX; 1006d49e1aeSJan Lentfer counter++; 1016d49e1aeSJan Lentfer try_again: 1026d49e1aeSJan Lentfer ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), 103*3ff40c12SJohn Marino CONFIG_CTRL_IFACE_CLIENT_DIR "/" 104*3ff40c12SJohn Marino CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", 105*3ff40c12SJohn Marino (int) getpid(), counter); 1066d49e1aeSJan Lentfer if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { 1076d49e1aeSJan Lentfer close(ctrl->s); 1086d49e1aeSJan Lentfer os_free(ctrl); 1096d49e1aeSJan Lentfer return NULL; 1106d49e1aeSJan Lentfer } 1116d49e1aeSJan Lentfer tries++; 1126d49e1aeSJan Lentfer if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 1136d49e1aeSJan Lentfer sizeof(ctrl->local)) < 0) { 1146d49e1aeSJan Lentfer if (errno == EADDRINUSE && tries < 2) { 1156d49e1aeSJan Lentfer /* 1166d49e1aeSJan Lentfer * getpid() returns unique identifier for this instance 1176d49e1aeSJan Lentfer * of wpa_ctrl, so the existing socket file must have 1186d49e1aeSJan Lentfer * been left by unclean termination of an earlier run. 1196d49e1aeSJan Lentfer * Remove the file and try again. 1206d49e1aeSJan Lentfer */ 1216d49e1aeSJan Lentfer unlink(ctrl->local.sun_path); 1226d49e1aeSJan Lentfer goto try_again; 1236d49e1aeSJan Lentfer } 1246d49e1aeSJan Lentfer close(ctrl->s); 1256d49e1aeSJan Lentfer os_free(ctrl); 1266d49e1aeSJan Lentfer return NULL; 1276d49e1aeSJan Lentfer } 1286d49e1aeSJan Lentfer 129*3ff40c12SJohn Marino #ifdef ANDROID 130*3ff40c12SJohn Marino chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 131*3ff40c12SJohn Marino chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); 132*3ff40c12SJohn Marino 133*3ff40c12SJohn Marino if (os_strncmp(ctrl_path, "@android:", 9) == 0) { 134*3ff40c12SJohn Marino if (socket_local_client_connect( 135*3ff40c12SJohn Marino ctrl->s, ctrl_path + 9, 136*3ff40c12SJohn Marino ANDROID_SOCKET_NAMESPACE_RESERVED, 137*3ff40c12SJohn Marino SOCK_DGRAM) < 0) { 138*3ff40c12SJohn Marino close(ctrl->s); 139*3ff40c12SJohn Marino unlink(ctrl->local.sun_path); 140*3ff40c12SJohn Marino os_free(ctrl); 141*3ff40c12SJohn Marino return NULL; 142*3ff40c12SJohn Marino } 143*3ff40c12SJohn Marino return ctrl; 144*3ff40c12SJohn Marino } 145*3ff40c12SJohn Marino 146*3ff40c12SJohn Marino /* 147*3ff40c12SJohn Marino * If the ctrl_path isn't an absolute pathname, assume that 148*3ff40c12SJohn Marino * it's the name of a socket in the Android reserved namespace. 149*3ff40c12SJohn Marino * Otherwise, it's a normal UNIX domain socket appearing in the 150*3ff40c12SJohn Marino * filesystem. 151*3ff40c12SJohn Marino */ 152*3ff40c12SJohn Marino if (*ctrl_path != '/') { 153*3ff40c12SJohn Marino char buf[21]; 154*3ff40c12SJohn Marino os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); 155*3ff40c12SJohn Marino if (socket_local_client_connect( 156*3ff40c12SJohn Marino ctrl->s, buf, 157*3ff40c12SJohn Marino ANDROID_SOCKET_NAMESPACE_RESERVED, 158*3ff40c12SJohn Marino SOCK_DGRAM) < 0) { 159*3ff40c12SJohn Marino close(ctrl->s); 160*3ff40c12SJohn Marino unlink(ctrl->local.sun_path); 161*3ff40c12SJohn Marino os_free(ctrl); 162*3ff40c12SJohn Marino return NULL; 163*3ff40c12SJohn Marino } 164*3ff40c12SJohn Marino return ctrl; 165*3ff40c12SJohn Marino } 166*3ff40c12SJohn Marino #endif /* ANDROID */ 167*3ff40c12SJohn Marino 1686d49e1aeSJan Lentfer ctrl->dest.sun_family = AF_UNIX; 169*3ff40c12SJohn Marino if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) { 170*3ff40c12SJohn Marino ctrl->dest.sun_path[0] = '\0'; 171*3ff40c12SJohn Marino os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10, 172*3ff40c12SJohn Marino sizeof(ctrl->dest.sun_path) - 1); 173*3ff40c12SJohn Marino } else { 1746d49e1aeSJan Lentfer res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 1756d49e1aeSJan Lentfer sizeof(ctrl->dest.sun_path)); 1766d49e1aeSJan Lentfer if (res >= sizeof(ctrl->dest.sun_path)) { 1776d49e1aeSJan Lentfer close(ctrl->s); 1786d49e1aeSJan Lentfer os_free(ctrl); 1796d49e1aeSJan Lentfer return NULL; 1806d49e1aeSJan Lentfer } 181*3ff40c12SJohn Marino } 1826d49e1aeSJan Lentfer if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 1836d49e1aeSJan Lentfer sizeof(ctrl->dest)) < 0) { 1846d49e1aeSJan Lentfer close(ctrl->s); 1856d49e1aeSJan Lentfer unlink(ctrl->local.sun_path); 1866d49e1aeSJan Lentfer os_free(ctrl); 1876d49e1aeSJan Lentfer return NULL; 1886d49e1aeSJan Lentfer } 1896d49e1aeSJan Lentfer 190*3ff40c12SJohn Marino /* 191*3ff40c12SJohn Marino * Make socket non-blocking so that we don't hang forever if 192*3ff40c12SJohn Marino * target dies unexpectedly. 193*3ff40c12SJohn Marino */ 194*3ff40c12SJohn Marino flags = fcntl(ctrl->s, F_GETFL); 195*3ff40c12SJohn Marino if (flags >= 0) { 196*3ff40c12SJohn Marino flags |= O_NONBLOCK; 197*3ff40c12SJohn Marino if (fcntl(ctrl->s, F_SETFL, flags) < 0) { 198*3ff40c12SJohn Marino perror("fcntl(ctrl->s, O_NONBLOCK)"); 199*3ff40c12SJohn Marino /* Not fatal, continue on.*/ 200*3ff40c12SJohn Marino } 201*3ff40c12SJohn Marino } 202*3ff40c12SJohn Marino 2036d49e1aeSJan Lentfer return ctrl; 2046d49e1aeSJan Lentfer } 2056d49e1aeSJan Lentfer 2066d49e1aeSJan Lentfer 2076d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl) 2086d49e1aeSJan Lentfer { 209*3ff40c12SJohn Marino if (ctrl == NULL) 210*3ff40c12SJohn Marino return; 2116d49e1aeSJan Lentfer unlink(ctrl->local.sun_path); 212*3ff40c12SJohn Marino if (ctrl->s >= 0) 2136d49e1aeSJan Lentfer close(ctrl->s); 2146d49e1aeSJan Lentfer os_free(ctrl); 2156d49e1aeSJan Lentfer } 2166d49e1aeSJan Lentfer 217*3ff40c12SJohn Marino 218*3ff40c12SJohn Marino #ifdef ANDROID 219*3ff40c12SJohn Marino /** 220*3ff40c12SJohn Marino * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 221*3ff40c12SJohn Marino * may be left over from clients that were previously connected to 222*3ff40c12SJohn Marino * wpa_supplicant. This keeps these files from being orphaned in the 223*3ff40c12SJohn Marino * event of crashes that prevented them from being removed as part 224*3ff40c12SJohn Marino * of the normal orderly shutdown. 225*3ff40c12SJohn Marino */ 226*3ff40c12SJohn Marino void wpa_ctrl_cleanup(void) 227*3ff40c12SJohn Marino { 228*3ff40c12SJohn Marino DIR *dir; 229*3ff40c12SJohn Marino struct dirent entry; 230*3ff40c12SJohn Marino struct dirent *result; 231*3ff40c12SJohn Marino size_t dirnamelen; 232*3ff40c12SJohn Marino size_t maxcopy; 233*3ff40c12SJohn Marino char pathname[PATH_MAX]; 234*3ff40c12SJohn Marino char *namep; 235*3ff40c12SJohn Marino 236*3ff40c12SJohn Marino if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL) 237*3ff40c12SJohn Marino return; 238*3ff40c12SJohn Marino 239*3ff40c12SJohn Marino dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/", 240*3ff40c12SJohn Marino CONFIG_CTRL_IFACE_CLIENT_DIR); 241*3ff40c12SJohn Marino if (dirnamelen >= sizeof(pathname)) { 242*3ff40c12SJohn Marino closedir(dir); 243*3ff40c12SJohn Marino return; 244*3ff40c12SJohn Marino } 245*3ff40c12SJohn Marino namep = pathname + dirnamelen; 246*3ff40c12SJohn Marino maxcopy = PATH_MAX - dirnamelen; 247*3ff40c12SJohn Marino while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 248*3ff40c12SJohn Marino if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) 249*3ff40c12SJohn Marino unlink(pathname); 250*3ff40c12SJohn Marino } 251*3ff40c12SJohn Marino closedir(dir); 252*3ff40c12SJohn Marino } 253*3ff40c12SJohn Marino #endif /* ANDROID */ 254*3ff40c12SJohn Marino 255*3ff40c12SJohn Marino #else /* CONFIG_CTRL_IFACE_UNIX */ 256*3ff40c12SJohn Marino 257*3ff40c12SJohn Marino #ifdef ANDROID 258*3ff40c12SJohn Marino void wpa_ctrl_cleanup(void) 259*3ff40c12SJohn Marino { 260*3ff40c12SJohn Marino } 261*3ff40c12SJohn Marino #endif /* ANDROID */ 262*3ff40c12SJohn Marino 2636d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UNIX */ 2646d49e1aeSJan Lentfer 2656d49e1aeSJan Lentfer 2666d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP 2676d49e1aeSJan Lentfer 2686d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 2696d49e1aeSJan Lentfer { 2706d49e1aeSJan Lentfer struct wpa_ctrl *ctrl; 2716d49e1aeSJan Lentfer char buf[128]; 2726d49e1aeSJan Lentfer size_t len; 273*3ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 274*3ff40c12SJohn Marino struct hostent *h; 275*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 2766d49e1aeSJan Lentfer 2776d49e1aeSJan Lentfer ctrl = os_malloc(sizeof(*ctrl)); 2786d49e1aeSJan Lentfer if (ctrl == NULL) 2796d49e1aeSJan Lentfer return NULL; 2806d49e1aeSJan Lentfer os_memset(ctrl, 0, sizeof(*ctrl)); 2816d49e1aeSJan Lentfer 2826d49e1aeSJan Lentfer ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 2836d49e1aeSJan Lentfer if (ctrl->s < 0) { 2846d49e1aeSJan Lentfer perror("socket"); 2856d49e1aeSJan Lentfer os_free(ctrl); 2866d49e1aeSJan Lentfer return NULL; 2876d49e1aeSJan Lentfer } 2886d49e1aeSJan Lentfer 2896d49e1aeSJan Lentfer ctrl->local.sin_family = AF_INET; 290*3ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 291*3ff40c12SJohn Marino ctrl->local.sin_addr.s_addr = INADDR_ANY; 292*3ff40c12SJohn Marino #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 2936d49e1aeSJan Lentfer ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 294*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 2956d49e1aeSJan Lentfer if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 2966d49e1aeSJan Lentfer sizeof(ctrl->local)) < 0) { 2976d49e1aeSJan Lentfer close(ctrl->s); 2986d49e1aeSJan Lentfer os_free(ctrl); 2996d49e1aeSJan Lentfer return NULL; 3006d49e1aeSJan Lentfer } 3016d49e1aeSJan Lentfer 3026d49e1aeSJan Lentfer ctrl->dest.sin_family = AF_INET; 3036d49e1aeSJan Lentfer ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 3046d49e1aeSJan Lentfer ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 305*3ff40c12SJohn Marino 306*3ff40c12SJohn Marino #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 307*3ff40c12SJohn Marino if (ctrl_path) { 308*3ff40c12SJohn Marino char *port, *name; 309*3ff40c12SJohn Marino int port_id; 310*3ff40c12SJohn Marino 311*3ff40c12SJohn Marino name = os_strdup(ctrl_path); 312*3ff40c12SJohn Marino if (name == NULL) { 313*3ff40c12SJohn Marino close(ctrl->s); 314*3ff40c12SJohn Marino os_free(ctrl); 315*3ff40c12SJohn Marino return NULL; 316*3ff40c12SJohn Marino } 317*3ff40c12SJohn Marino port = os_strchr(name, ':'); 318*3ff40c12SJohn Marino 319*3ff40c12SJohn Marino if (port) { 320*3ff40c12SJohn Marino port_id = atoi(&port[1]); 321*3ff40c12SJohn Marino port[0] = '\0'; 322*3ff40c12SJohn Marino } else 323*3ff40c12SJohn Marino port_id = WPA_CTRL_IFACE_PORT; 324*3ff40c12SJohn Marino 325*3ff40c12SJohn Marino h = gethostbyname(name); 326*3ff40c12SJohn Marino ctrl->remote_ip = os_strdup(name); 327*3ff40c12SJohn Marino os_free(name); 328*3ff40c12SJohn Marino if (h == NULL) { 329*3ff40c12SJohn Marino perror("gethostbyname"); 330*3ff40c12SJohn Marino close(ctrl->s); 331*3ff40c12SJohn Marino os_free(ctrl->remote_ip); 332*3ff40c12SJohn Marino os_free(ctrl); 333*3ff40c12SJohn Marino return NULL; 334*3ff40c12SJohn Marino } 335*3ff40c12SJohn Marino ctrl->dest.sin_port = htons(port_id); 336*3ff40c12SJohn Marino os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr, 337*3ff40c12SJohn Marino h->h_length); 338*3ff40c12SJohn Marino } else 339*3ff40c12SJohn Marino ctrl->remote_ip = os_strdup("localhost"); 340*3ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 341*3ff40c12SJohn Marino 3426d49e1aeSJan Lentfer if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 3436d49e1aeSJan Lentfer sizeof(ctrl->dest)) < 0) { 3446d49e1aeSJan Lentfer perror("connect"); 3456d49e1aeSJan Lentfer close(ctrl->s); 346*3ff40c12SJohn Marino os_free(ctrl->remote_ip); 3476d49e1aeSJan Lentfer os_free(ctrl); 3486d49e1aeSJan Lentfer return NULL; 3496d49e1aeSJan Lentfer } 3506d49e1aeSJan Lentfer 3516d49e1aeSJan Lentfer len = sizeof(buf) - 1; 3526d49e1aeSJan Lentfer if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 3536d49e1aeSJan Lentfer buf[len] = '\0'; 3546d49e1aeSJan Lentfer ctrl->cookie = os_strdup(buf); 3556d49e1aeSJan Lentfer } 3566d49e1aeSJan Lentfer 357*3ff40c12SJohn Marino if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) { 358*3ff40c12SJohn Marino buf[len] = '\0'; 359*3ff40c12SJohn Marino ctrl->remote_ifname = os_strdup(buf); 360*3ff40c12SJohn Marino } 361*3ff40c12SJohn Marino 3626d49e1aeSJan Lentfer return ctrl; 3636d49e1aeSJan Lentfer } 3646d49e1aeSJan Lentfer 3656d49e1aeSJan Lentfer 366*3ff40c12SJohn Marino char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl) 367*3ff40c12SJohn Marino { 368*3ff40c12SJohn Marino #define WPA_CTRL_MAX_PS_NAME 100 369*3ff40c12SJohn Marino static char ps[WPA_CTRL_MAX_PS_NAME] = {}; 370*3ff40c12SJohn Marino os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s", 371*3ff40c12SJohn Marino ctrl->remote_ip, ctrl->remote_ifname); 372*3ff40c12SJohn Marino return ps; 373*3ff40c12SJohn Marino } 374*3ff40c12SJohn Marino 375*3ff40c12SJohn Marino 3766d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl) 3776d49e1aeSJan Lentfer { 3786d49e1aeSJan Lentfer close(ctrl->s); 3796d49e1aeSJan Lentfer os_free(ctrl->cookie); 380*3ff40c12SJohn Marino os_free(ctrl->remote_ifname); 381*3ff40c12SJohn Marino os_free(ctrl->remote_ip); 3826d49e1aeSJan Lentfer os_free(ctrl); 3836d49e1aeSJan Lentfer } 3846d49e1aeSJan Lentfer 3856d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */ 3866d49e1aeSJan Lentfer 3876d49e1aeSJan Lentfer 3886d49e1aeSJan Lentfer #ifdef CTRL_IFACE_SOCKET 3896d49e1aeSJan Lentfer int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 3906d49e1aeSJan Lentfer char *reply, size_t *reply_len, 3916d49e1aeSJan Lentfer void (*msg_cb)(char *msg, size_t len)) 3926d49e1aeSJan Lentfer { 3936d49e1aeSJan Lentfer struct timeval tv; 394*3ff40c12SJohn Marino struct os_reltime started_at; 3956d49e1aeSJan Lentfer int res; 3966d49e1aeSJan Lentfer fd_set rfds; 3976d49e1aeSJan Lentfer const char *_cmd; 3986d49e1aeSJan Lentfer char *cmd_buf = NULL; 3996d49e1aeSJan Lentfer size_t _cmd_len; 4006d49e1aeSJan Lentfer 4016d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_UDP 4026d49e1aeSJan Lentfer if (ctrl->cookie) { 4036d49e1aeSJan Lentfer char *pos; 4046d49e1aeSJan Lentfer _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 4056d49e1aeSJan Lentfer cmd_buf = os_malloc(_cmd_len); 4066d49e1aeSJan Lentfer if (cmd_buf == NULL) 4076d49e1aeSJan Lentfer return -1; 4086d49e1aeSJan Lentfer _cmd = cmd_buf; 4096d49e1aeSJan Lentfer pos = cmd_buf; 4106d49e1aeSJan Lentfer os_strlcpy(pos, ctrl->cookie, _cmd_len); 4116d49e1aeSJan Lentfer pos += os_strlen(ctrl->cookie); 4126d49e1aeSJan Lentfer *pos++ = ' '; 4136d49e1aeSJan Lentfer os_memcpy(pos, cmd, cmd_len); 4146d49e1aeSJan Lentfer } else 4156d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_UDP */ 4166d49e1aeSJan Lentfer { 4176d49e1aeSJan Lentfer _cmd = cmd; 4186d49e1aeSJan Lentfer _cmd_len = cmd_len; 4196d49e1aeSJan Lentfer } 4206d49e1aeSJan Lentfer 421*3ff40c12SJohn Marino errno = 0; 422*3ff40c12SJohn Marino started_at.sec = 0; 423*3ff40c12SJohn Marino started_at.usec = 0; 424*3ff40c12SJohn Marino retry_send: 4256d49e1aeSJan Lentfer if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 426*3ff40c12SJohn Marino if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) 427*3ff40c12SJohn Marino { 428*3ff40c12SJohn Marino /* 429*3ff40c12SJohn Marino * Must be a non-blocking socket... Try for a bit 430*3ff40c12SJohn Marino * longer before giving up. 431*3ff40c12SJohn Marino */ 432*3ff40c12SJohn Marino if (started_at.sec == 0) 433*3ff40c12SJohn Marino os_get_reltime(&started_at); 434*3ff40c12SJohn Marino else { 435*3ff40c12SJohn Marino struct os_reltime n; 436*3ff40c12SJohn Marino os_get_reltime(&n); 437*3ff40c12SJohn Marino /* Try for a few seconds. */ 438*3ff40c12SJohn Marino if (os_reltime_expired(&n, &started_at, 5)) 439*3ff40c12SJohn Marino goto send_err; 440*3ff40c12SJohn Marino } 441*3ff40c12SJohn Marino os_sleep(1, 0); 442*3ff40c12SJohn Marino goto retry_send; 443*3ff40c12SJohn Marino } 444*3ff40c12SJohn Marino send_err: 4456d49e1aeSJan Lentfer os_free(cmd_buf); 4466d49e1aeSJan Lentfer return -1; 4476d49e1aeSJan Lentfer } 4486d49e1aeSJan Lentfer os_free(cmd_buf); 4496d49e1aeSJan Lentfer 4506d49e1aeSJan Lentfer for (;;) { 451*3ff40c12SJohn Marino tv.tv_sec = 10; 4526d49e1aeSJan Lentfer tv.tv_usec = 0; 4536d49e1aeSJan Lentfer FD_ZERO(&rfds); 4546d49e1aeSJan Lentfer FD_SET(ctrl->s, &rfds); 4556d49e1aeSJan Lentfer res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 456*3ff40c12SJohn Marino if (res < 0) 457*3ff40c12SJohn Marino return res; 4586d49e1aeSJan Lentfer if (FD_ISSET(ctrl->s, &rfds)) { 4596d49e1aeSJan Lentfer res = recv(ctrl->s, reply, *reply_len, 0); 4606d49e1aeSJan Lentfer if (res < 0) 4616d49e1aeSJan Lentfer return res; 4626d49e1aeSJan Lentfer if (res > 0 && reply[0] == '<') { 4636d49e1aeSJan Lentfer /* This is an unsolicited message from 4646d49e1aeSJan Lentfer * wpa_supplicant, not the reply to the 4656d49e1aeSJan Lentfer * request. Use msg_cb to report this to the 4666d49e1aeSJan Lentfer * caller. */ 4676d49e1aeSJan Lentfer if (msg_cb) { 4686d49e1aeSJan Lentfer /* Make sure the message is nul 4696d49e1aeSJan Lentfer * terminated. */ 4706d49e1aeSJan Lentfer if ((size_t) res == *reply_len) 4716d49e1aeSJan Lentfer res = (*reply_len) - 1; 4726d49e1aeSJan Lentfer reply[res] = '\0'; 4736d49e1aeSJan Lentfer msg_cb(reply, res); 4746d49e1aeSJan Lentfer } 4756d49e1aeSJan Lentfer continue; 4766d49e1aeSJan Lentfer } 4776d49e1aeSJan Lentfer *reply_len = res; 4786d49e1aeSJan Lentfer break; 4796d49e1aeSJan Lentfer } else { 4806d49e1aeSJan Lentfer return -2; 4816d49e1aeSJan Lentfer } 4826d49e1aeSJan Lentfer } 4836d49e1aeSJan Lentfer return 0; 4846d49e1aeSJan Lentfer } 4856d49e1aeSJan Lentfer #endif /* CTRL_IFACE_SOCKET */ 4866d49e1aeSJan Lentfer 4876d49e1aeSJan Lentfer 4886d49e1aeSJan Lentfer static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 4896d49e1aeSJan Lentfer { 4906d49e1aeSJan Lentfer char buf[10]; 4916d49e1aeSJan Lentfer int ret; 4926d49e1aeSJan Lentfer size_t len = 10; 4936d49e1aeSJan Lentfer 4946d49e1aeSJan Lentfer ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 4956d49e1aeSJan Lentfer buf, &len, NULL); 4966d49e1aeSJan Lentfer if (ret < 0) 4976d49e1aeSJan Lentfer return ret; 4986d49e1aeSJan Lentfer if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 4996d49e1aeSJan Lentfer return 0; 5006d49e1aeSJan Lentfer return -1; 5016d49e1aeSJan Lentfer } 5026d49e1aeSJan Lentfer 5036d49e1aeSJan Lentfer 5046d49e1aeSJan Lentfer int wpa_ctrl_attach(struct wpa_ctrl *ctrl) 5056d49e1aeSJan Lentfer { 5066d49e1aeSJan Lentfer return wpa_ctrl_attach_helper(ctrl, 1); 5076d49e1aeSJan Lentfer } 5086d49e1aeSJan Lentfer 5096d49e1aeSJan Lentfer 5106d49e1aeSJan Lentfer int wpa_ctrl_detach(struct wpa_ctrl *ctrl) 5116d49e1aeSJan Lentfer { 5126d49e1aeSJan Lentfer return wpa_ctrl_attach_helper(ctrl, 0); 5136d49e1aeSJan Lentfer } 5146d49e1aeSJan Lentfer 5156d49e1aeSJan Lentfer 5166d49e1aeSJan Lentfer #ifdef CTRL_IFACE_SOCKET 5176d49e1aeSJan Lentfer 5186d49e1aeSJan Lentfer int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 5196d49e1aeSJan Lentfer { 5206d49e1aeSJan Lentfer int res; 5216d49e1aeSJan Lentfer 5226d49e1aeSJan Lentfer res = recv(ctrl->s, reply, *reply_len, 0); 5236d49e1aeSJan Lentfer if (res < 0) 5246d49e1aeSJan Lentfer return res; 5256d49e1aeSJan Lentfer *reply_len = res; 5266d49e1aeSJan Lentfer return 0; 5276d49e1aeSJan Lentfer } 5286d49e1aeSJan Lentfer 5296d49e1aeSJan Lentfer 5306d49e1aeSJan Lentfer int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 5316d49e1aeSJan Lentfer { 5326d49e1aeSJan Lentfer struct timeval tv; 5336d49e1aeSJan Lentfer fd_set rfds; 5346d49e1aeSJan Lentfer tv.tv_sec = 0; 5356d49e1aeSJan Lentfer tv.tv_usec = 0; 5366d49e1aeSJan Lentfer FD_ZERO(&rfds); 5376d49e1aeSJan Lentfer FD_SET(ctrl->s, &rfds); 5386d49e1aeSJan Lentfer select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 5396d49e1aeSJan Lentfer return FD_ISSET(ctrl->s, &rfds); 5406d49e1aeSJan Lentfer } 5416d49e1aeSJan Lentfer 5426d49e1aeSJan Lentfer 5436d49e1aeSJan Lentfer int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 5446d49e1aeSJan Lentfer { 5456d49e1aeSJan Lentfer return ctrl->s; 5466d49e1aeSJan Lentfer } 5476d49e1aeSJan Lentfer 5486d49e1aeSJan Lentfer #endif /* CTRL_IFACE_SOCKET */ 5496d49e1aeSJan Lentfer 5506d49e1aeSJan Lentfer 5516d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 5526d49e1aeSJan Lentfer 5536d49e1aeSJan Lentfer #ifndef WPA_SUPPLICANT_NAMED_PIPE 5546d49e1aeSJan Lentfer #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 5556d49e1aeSJan Lentfer #endif 5566d49e1aeSJan Lentfer #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 5576d49e1aeSJan Lentfer 5586d49e1aeSJan Lentfer struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 5596d49e1aeSJan Lentfer { 5606d49e1aeSJan Lentfer struct wpa_ctrl *ctrl; 5616d49e1aeSJan Lentfer DWORD mode; 5626d49e1aeSJan Lentfer TCHAR name[256]; 5636d49e1aeSJan Lentfer int i, ret; 5646d49e1aeSJan Lentfer 5656d49e1aeSJan Lentfer ctrl = os_malloc(sizeof(*ctrl)); 5666d49e1aeSJan Lentfer if (ctrl == NULL) 5676d49e1aeSJan Lentfer return NULL; 5686d49e1aeSJan Lentfer os_memset(ctrl, 0, sizeof(*ctrl)); 5696d49e1aeSJan Lentfer 5706d49e1aeSJan Lentfer #ifdef UNICODE 5716d49e1aeSJan Lentfer if (ctrl_path == NULL) 5726d49e1aeSJan Lentfer ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 5736d49e1aeSJan Lentfer else 5746d49e1aeSJan Lentfer ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 5756d49e1aeSJan Lentfer ctrl_path); 5766d49e1aeSJan Lentfer #else /* UNICODE */ 5776d49e1aeSJan Lentfer if (ctrl_path == NULL) 5786d49e1aeSJan Lentfer ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 5796d49e1aeSJan Lentfer else 5806d49e1aeSJan Lentfer ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 5816d49e1aeSJan Lentfer ctrl_path); 5826d49e1aeSJan Lentfer #endif /* UNICODE */ 5836d49e1aeSJan Lentfer if (ret < 0 || ret >= 256) { 5846d49e1aeSJan Lentfer os_free(ctrl); 5856d49e1aeSJan Lentfer return NULL; 5866d49e1aeSJan Lentfer } 5876d49e1aeSJan Lentfer 5886d49e1aeSJan Lentfer for (i = 0; i < 10; i++) { 5896d49e1aeSJan Lentfer ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 5906d49e1aeSJan Lentfer NULL, OPEN_EXISTING, 0, NULL); 5916d49e1aeSJan Lentfer /* 5926d49e1aeSJan Lentfer * Current named pipe server side in wpa_supplicant is 5936d49e1aeSJan Lentfer * re-opening the pipe for new clients only after the previous 5946d49e1aeSJan Lentfer * one is taken into use. This leaves a small window for race 5956d49e1aeSJan Lentfer * conditions when two connections are being opened at almost 5966d49e1aeSJan Lentfer * the same time. Retry if that was the case. 5976d49e1aeSJan Lentfer */ 5986d49e1aeSJan Lentfer if (ctrl->pipe != INVALID_HANDLE_VALUE || 5996d49e1aeSJan Lentfer GetLastError() != ERROR_PIPE_BUSY) 6006d49e1aeSJan Lentfer break; 6016d49e1aeSJan Lentfer WaitNamedPipe(name, 1000); 6026d49e1aeSJan Lentfer } 6036d49e1aeSJan Lentfer if (ctrl->pipe == INVALID_HANDLE_VALUE) { 6046d49e1aeSJan Lentfer os_free(ctrl); 6056d49e1aeSJan Lentfer return NULL; 6066d49e1aeSJan Lentfer } 6076d49e1aeSJan Lentfer 6086d49e1aeSJan Lentfer mode = PIPE_READMODE_MESSAGE; 6096d49e1aeSJan Lentfer if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 6106d49e1aeSJan Lentfer CloseHandle(ctrl->pipe); 6116d49e1aeSJan Lentfer os_free(ctrl); 6126d49e1aeSJan Lentfer return NULL; 6136d49e1aeSJan Lentfer } 6146d49e1aeSJan Lentfer 6156d49e1aeSJan Lentfer return ctrl; 6166d49e1aeSJan Lentfer } 6176d49e1aeSJan Lentfer 6186d49e1aeSJan Lentfer 6196d49e1aeSJan Lentfer void wpa_ctrl_close(struct wpa_ctrl *ctrl) 6206d49e1aeSJan Lentfer { 6216d49e1aeSJan Lentfer CloseHandle(ctrl->pipe); 6226d49e1aeSJan Lentfer os_free(ctrl); 6236d49e1aeSJan Lentfer } 6246d49e1aeSJan Lentfer 6256d49e1aeSJan Lentfer 6266d49e1aeSJan Lentfer int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 6276d49e1aeSJan Lentfer char *reply, size_t *reply_len, 6286d49e1aeSJan Lentfer void (*msg_cb)(char *msg, size_t len)) 6296d49e1aeSJan Lentfer { 6306d49e1aeSJan Lentfer DWORD written; 6316d49e1aeSJan Lentfer DWORD readlen = *reply_len; 6326d49e1aeSJan Lentfer 6336d49e1aeSJan Lentfer if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 6346d49e1aeSJan Lentfer return -1; 6356d49e1aeSJan Lentfer 6366d49e1aeSJan Lentfer if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 6376d49e1aeSJan Lentfer return -1; 6386d49e1aeSJan Lentfer *reply_len = readlen; 6396d49e1aeSJan Lentfer 6406d49e1aeSJan Lentfer return 0; 6416d49e1aeSJan Lentfer } 6426d49e1aeSJan Lentfer 6436d49e1aeSJan Lentfer 6446d49e1aeSJan Lentfer int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 6456d49e1aeSJan Lentfer { 6466d49e1aeSJan Lentfer DWORD len = *reply_len; 6476d49e1aeSJan Lentfer if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 6486d49e1aeSJan Lentfer return -1; 6496d49e1aeSJan Lentfer *reply_len = len; 6506d49e1aeSJan Lentfer return 0; 6516d49e1aeSJan Lentfer } 6526d49e1aeSJan Lentfer 6536d49e1aeSJan Lentfer 6546d49e1aeSJan Lentfer int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 6556d49e1aeSJan Lentfer { 6566d49e1aeSJan Lentfer DWORD left; 6576d49e1aeSJan Lentfer 6586d49e1aeSJan Lentfer if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 6596d49e1aeSJan Lentfer return -1; 6606d49e1aeSJan Lentfer return left ? 1 : 0; 6616d49e1aeSJan Lentfer } 6626d49e1aeSJan Lentfer 6636d49e1aeSJan Lentfer 6646d49e1aeSJan Lentfer int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 6656d49e1aeSJan Lentfer { 6666d49e1aeSJan Lentfer return -1; 6676d49e1aeSJan Lentfer } 6686d49e1aeSJan Lentfer 6696d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 6706d49e1aeSJan Lentfer 6716d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE */ 672