wpa_ctrl.c revision 189251
1189251Ssam/* 2189251Ssam * wpa_supplicant/hostapd control interface library 3189251Ssam * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#ifdef CONFIG_CTRL_IFACE 18189251Ssam 19189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 20189251Ssam#include <sys/un.h> 21189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 22189251Ssam 23189251Ssam#include "wpa_ctrl.h" 24189251Ssam#include "common.h" 25189251Ssam 26189251Ssam 27189251Ssam#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 28189251Ssam#define CTRL_IFACE_SOCKET 29189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 30189251Ssam 31189251Ssam 32189251Ssam/** 33189251Ssam * struct wpa_ctrl - Internal structure for control interface library 34189251Ssam * 35189251Ssam * This structure is used by the wpa_supplicant/hostapd control interface 36189251Ssam * library to store internal data. Programs using the library should not touch 37189251Ssam * this data directly. They can only use the pointer to the data structure as 38189251Ssam * an identifier for the control interface connection and use this as one of 39189251Ssam * the arguments for most of the control interface library functions. 40189251Ssam */ 41189251Ssamstruct wpa_ctrl { 42189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 43189251Ssam int s; 44189251Ssam struct sockaddr_in local; 45189251Ssam struct sockaddr_in dest; 46189251Ssam char *cookie; 47189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 48189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 49189251Ssam int s; 50189251Ssam struct sockaddr_un local; 51189251Ssam struct sockaddr_un dest; 52189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 53189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 54189251Ssam HANDLE pipe; 55189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 56189251Ssam}; 57189251Ssam 58189251Ssam 59189251Ssam#ifdef CONFIG_CTRL_IFACE_UNIX 60189251Ssam 61189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 62189251Ssam{ 63189251Ssam struct wpa_ctrl *ctrl; 64189251Ssam static int counter = 0; 65189251Ssam int ret; 66189251Ssam size_t res; 67189251Ssam int tries = 0; 68189251Ssam 69189251Ssam ctrl = os_malloc(sizeof(*ctrl)); 70189251Ssam if (ctrl == NULL) 71189251Ssam return NULL; 72189251Ssam os_memset(ctrl, 0, sizeof(*ctrl)); 73189251Ssam 74189251Ssam ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 75189251Ssam if (ctrl->s < 0) { 76189251Ssam os_free(ctrl); 77189251Ssam return NULL; 78189251Ssam } 79189251Ssam 80189251Ssam ctrl->local.sun_family = AF_UNIX; 81189251Ssam counter++; 82189251Ssamtry_again: 83189251Ssam ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), 84189251Ssam "/tmp/wpa_ctrl_%d-%d", getpid(), counter); 85189251Ssam if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { 86189251Ssam close(ctrl->s); 87189251Ssam os_free(ctrl); 88189251Ssam return NULL; 89189251Ssam } 90189251Ssam tries++; 91189251Ssam if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 92189251Ssam sizeof(ctrl->local)) < 0) { 93189251Ssam if (errno == EADDRINUSE && tries < 2) { 94189251Ssam /* 95189251Ssam * getpid() returns unique identifier for this instance 96189251Ssam * of wpa_ctrl, so the existing socket file must have 97189251Ssam * been left by unclean termination of an earlier run. 98189251Ssam * Remove the file and try again. 99189251Ssam */ 100189251Ssam unlink(ctrl->local.sun_path); 101189251Ssam goto try_again; 102189251Ssam } 103189251Ssam close(ctrl->s); 104189251Ssam os_free(ctrl); 105189251Ssam return NULL; 106189251Ssam } 107189251Ssam 108189251Ssam ctrl->dest.sun_family = AF_UNIX; 109189251Ssam res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 110189251Ssam sizeof(ctrl->dest.sun_path)); 111189251Ssam if (res >= sizeof(ctrl->dest.sun_path)) { 112189251Ssam close(ctrl->s); 113189251Ssam os_free(ctrl); 114189251Ssam return NULL; 115189251Ssam } 116189251Ssam if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 117189251Ssam sizeof(ctrl->dest)) < 0) { 118189251Ssam close(ctrl->s); 119189251Ssam unlink(ctrl->local.sun_path); 120189251Ssam os_free(ctrl); 121189251Ssam return NULL; 122189251Ssam } 123189251Ssam 124189251Ssam return ctrl; 125189251Ssam} 126189251Ssam 127189251Ssam 128189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 129189251Ssam{ 130189251Ssam unlink(ctrl->local.sun_path); 131189251Ssam close(ctrl->s); 132189251Ssam os_free(ctrl); 133189251Ssam} 134189251Ssam 135189251Ssam#endif /* CONFIG_CTRL_IFACE_UNIX */ 136189251Ssam 137189251Ssam 138189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 139189251Ssam 140189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 141189251Ssam{ 142189251Ssam struct wpa_ctrl *ctrl; 143189251Ssam char buf[128]; 144189251Ssam size_t len; 145189251Ssam 146189251Ssam ctrl = os_malloc(sizeof(*ctrl)); 147189251Ssam if (ctrl == NULL) 148189251Ssam return NULL; 149189251Ssam os_memset(ctrl, 0, sizeof(*ctrl)); 150189251Ssam 151189251Ssam ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 152189251Ssam if (ctrl->s < 0) { 153189251Ssam perror("socket"); 154189251Ssam os_free(ctrl); 155189251Ssam return NULL; 156189251Ssam } 157189251Ssam 158189251Ssam ctrl->local.sin_family = AF_INET; 159189251Ssam ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 160189251Ssam if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 161189251Ssam sizeof(ctrl->local)) < 0) { 162189251Ssam close(ctrl->s); 163189251Ssam os_free(ctrl); 164189251Ssam return NULL; 165189251Ssam } 166189251Ssam 167189251Ssam ctrl->dest.sin_family = AF_INET; 168189251Ssam ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 169189251Ssam ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 170189251Ssam if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 171189251Ssam sizeof(ctrl->dest)) < 0) { 172189251Ssam perror("connect"); 173189251Ssam close(ctrl->s); 174189251Ssam os_free(ctrl); 175189251Ssam return NULL; 176189251Ssam } 177189251Ssam 178189251Ssam len = sizeof(buf) - 1; 179189251Ssam if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 180189251Ssam buf[len] = '\0'; 181189251Ssam ctrl->cookie = os_strdup(buf); 182189251Ssam } 183189251Ssam 184189251Ssam return ctrl; 185189251Ssam} 186189251Ssam 187189251Ssam 188189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 189189251Ssam{ 190189251Ssam close(ctrl->s); 191189251Ssam os_free(ctrl->cookie); 192189251Ssam os_free(ctrl); 193189251Ssam} 194189251Ssam 195189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 196189251Ssam 197189251Ssam 198189251Ssam#ifdef CTRL_IFACE_SOCKET 199189251Ssamint wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 200189251Ssam char *reply, size_t *reply_len, 201189251Ssam void (*msg_cb)(char *msg, size_t len)) 202189251Ssam{ 203189251Ssam struct timeval tv; 204189251Ssam int res; 205189251Ssam fd_set rfds; 206189251Ssam const char *_cmd; 207189251Ssam char *cmd_buf = NULL; 208189251Ssam size_t _cmd_len; 209189251Ssam 210189251Ssam#ifdef CONFIG_CTRL_IFACE_UDP 211189251Ssam if (ctrl->cookie) { 212189251Ssam char *pos; 213189251Ssam _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 214189251Ssam cmd_buf = os_malloc(_cmd_len); 215189251Ssam if (cmd_buf == NULL) 216189251Ssam return -1; 217189251Ssam _cmd = cmd_buf; 218189251Ssam pos = cmd_buf; 219189251Ssam os_strlcpy(pos, ctrl->cookie, _cmd_len); 220189251Ssam pos += os_strlen(ctrl->cookie); 221189251Ssam *pos++ = ' '; 222189251Ssam os_memcpy(pos, cmd, cmd_len); 223189251Ssam } else 224189251Ssam#endif /* CONFIG_CTRL_IFACE_UDP */ 225189251Ssam { 226189251Ssam _cmd = cmd; 227189251Ssam _cmd_len = cmd_len; 228189251Ssam } 229189251Ssam 230189251Ssam if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 231189251Ssam os_free(cmd_buf); 232189251Ssam return -1; 233189251Ssam } 234189251Ssam os_free(cmd_buf); 235189251Ssam 236189251Ssam for (;;) { 237189251Ssam tv.tv_sec = 2; 238189251Ssam tv.tv_usec = 0; 239189251Ssam FD_ZERO(&rfds); 240189251Ssam FD_SET(ctrl->s, &rfds); 241189251Ssam res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 242189251Ssam if (FD_ISSET(ctrl->s, &rfds)) { 243189251Ssam res = recv(ctrl->s, reply, *reply_len, 0); 244189251Ssam if (res < 0) 245189251Ssam return res; 246189251Ssam if (res > 0 && reply[0] == '<') { 247189251Ssam /* This is an unsolicited message from 248189251Ssam * wpa_supplicant, not the reply to the 249189251Ssam * request. Use msg_cb to report this to the 250189251Ssam * caller. */ 251189251Ssam if (msg_cb) { 252189251Ssam /* Make sure the message is nul 253189251Ssam * terminated. */ 254189251Ssam if ((size_t) res == *reply_len) 255189251Ssam res = (*reply_len) - 1; 256189251Ssam reply[res] = '\0'; 257189251Ssam msg_cb(reply, res); 258189251Ssam } 259189251Ssam continue; 260189251Ssam } 261189251Ssam *reply_len = res; 262189251Ssam break; 263189251Ssam } else { 264189251Ssam return -2; 265189251Ssam } 266189251Ssam } 267189251Ssam return 0; 268189251Ssam} 269189251Ssam#endif /* CTRL_IFACE_SOCKET */ 270189251Ssam 271189251Ssam 272189251Ssamstatic int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 273189251Ssam{ 274189251Ssam char buf[10]; 275189251Ssam int ret; 276189251Ssam size_t len = 10; 277189251Ssam 278189251Ssam ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 279189251Ssam buf, &len, NULL); 280189251Ssam if (ret < 0) 281189251Ssam return ret; 282189251Ssam if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 283189251Ssam return 0; 284189251Ssam return -1; 285189251Ssam} 286189251Ssam 287189251Ssam 288189251Ssamint wpa_ctrl_attach(struct wpa_ctrl *ctrl) 289189251Ssam{ 290189251Ssam return wpa_ctrl_attach_helper(ctrl, 1); 291189251Ssam} 292189251Ssam 293189251Ssam 294189251Ssamint wpa_ctrl_detach(struct wpa_ctrl *ctrl) 295189251Ssam{ 296189251Ssam return wpa_ctrl_attach_helper(ctrl, 0); 297189251Ssam} 298189251Ssam 299189251Ssam 300189251Ssam#ifdef CTRL_IFACE_SOCKET 301189251Ssam 302189251Ssamint wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 303189251Ssam{ 304189251Ssam int res; 305189251Ssam 306189251Ssam res = recv(ctrl->s, reply, *reply_len, 0); 307189251Ssam if (res < 0) 308189251Ssam return res; 309189251Ssam *reply_len = res; 310189251Ssam return 0; 311189251Ssam} 312189251Ssam 313189251Ssam 314189251Ssamint wpa_ctrl_pending(struct wpa_ctrl *ctrl) 315189251Ssam{ 316189251Ssam struct timeval tv; 317189251Ssam fd_set rfds; 318189251Ssam tv.tv_sec = 0; 319189251Ssam tv.tv_usec = 0; 320189251Ssam FD_ZERO(&rfds); 321189251Ssam FD_SET(ctrl->s, &rfds); 322189251Ssam select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 323189251Ssam return FD_ISSET(ctrl->s, &rfds); 324189251Ssam} 325189251Ssam 326189251Ssam 327189251Ssamint wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 328189251Ssam{ 329189251Ssam return ctrl->s; 330189251Ssam} 331189251Ssam 332189251Ssam#endif /* CTRL_IFACE_SOCKET */ 333189251Ssam 334189251Ssam 335189251Ssam#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 336189251Ssam 337189251Ssam#ifndef WPA_SUPPLICANT_NAMED_PIPE 338189251Ssam#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 339189251Ssam#endif 340189251Ssam#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 341189251Ssam 342189251Ssamstruct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 343189251Ssam{ 344189251Ssam struct wpa_ctrl *ctrl; 345189251Ssam DWORD mode; 346189251Ssam TCHAR name[256]; 347189251Ssam int i, ret; 348189251Ssam 349189251Ssam ctrl = os_malloc(sizeof(*ctrl)); 350189251Ssam if (ctrl == NULL) 351189251Ssam return NULL; 352189251Ssam os_memset(ctrl, 0, sizeof(*ctrl)); 353189251Ssam 354189251Ssam#ifdef UNICODE 355189251Ssam if (ctrl_path == NULL) 356189251Ssam ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 357189251Ssam else 358189251Ssam ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 359189251Ssam ctrl_path); 360189251Ssam#else /* UNICODE */ 361189251Ssam if (ctrl_path == NULL) 362189251Ssam ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 363189251Ssam else 364189251Ssam ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 365189251Ssam ctrl_path); 366189251Ssam#endif /* UNICODE */ 367189251Ssam if (ret < 0 || ret >= 256) { 368189251Ssam os_free(ctrl); 369189251Ssam return NULL; 370189251Ssam } 371189251Ssam 372189251Ssam for (i = 0; i < 10; i++) { 373189251Ssam ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 374189251Ssam NULL, OPEN_EXISTING, 0, NULL); 375189251Ssam /* 376189251Ssam * Current named pipe server side in wpa_supplicant is 377189251Ssam * re-opening the pipe for new clients only after the previous 378189251Ssam * one is taken into use. This leaves a small window for race 379189251Ssam * conditions when two connections are being opened at almost 380189251Ssam * the same time. Retry if that was the case. 381189251Ssam */ 382189251Ssam if (ctrl->pipe != INVALID_HANDLE_VALUE || 383189251Ssam GetLastError() != ERROR_PIPE_BUSY) 384189251Ssam break; 385189251Ssam WaitNamedPipe(name, 1000); 386189251Ssam } 387189251Ssam if (ctrl->pipe == INVALID_HANDLE_VALUE) { 388189251Ssam os_free(ctrl); 389189251Ssam return NULL; 390189251Ssam } 391189251Ssam 392189251Ssam mode = PIPE_READMODE_MESSAGE; 393189251Ssam if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 394189251Ssam CloseHandle(ctrl->pipe); 395189251Ssam os_free(ctrl); 396189251Ssam return NULL; 397189251Ssam } 398189251Ssam 399189251Ssam return ctrl; 400189251Ssam} 401189251Ssam 402189251Ssam 403189251Ssamvoid wpa_ctrl_close(struct wpa_ctrl *ctrl) 404189251Ssam{ 405189251Ssam CloseHandle(ctrl->pipe); 406189251Ssam os_free(ctrl); 407189251Ssam} 408189251Ssam 409189251Ssam 410189251Ssamint wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 411189251Ssam char *reply, size_t *reply_len, 412189251Ssam void (*msg_cb)(char *msg, size_t len)) 413189251Ssam{ 414189251Ssam DWORD written; 415189251Ssam DWORD readlen = *reply_len; 416189251Ssam 417189251Ssam if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 418189251Ssam return -1; 419189251Ssam 420189251Ssam if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 421189251Ssam return -1; 422189251Ssam *reply_len = readlen; 423189251Ssam 424189251Ssam return 0; 425189251Ssam} 426189251Ssam 427189251Ssam 428189251Ssamint wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 429189251Ssam{ 430189251Ssam DWORD len = *reply_len; 431189251Ssam if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 432189251Ssam return -1; 433189251Ssam *reply_len = len; 434189251Ssam return 0; 435189251Ssam} 436189251Ssam 437189251Ssam 438189251Ssamint wpa_ctrl_pending(struct wpa_ctrl *ctrl) 439189251Ssam{ 440189251Ssam DWORD left; 441189251Ssam 442189251Ssam if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 443189251Ssam return -1; 444189251Ssam return left ? 1 : 0; 445189251Ssam} 446189251Ssam 447189251Ssam 448189251Ssamint wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 449189251Ssam{ 450189251Ssam return -1; 451189251Ssam} 452189251Ssam 453189251Ssam#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 454189251Ssam 455189251Ssam#endif /* CONFIG_CTRL_IFACE */ 456