$search
00001 /* 00002 * wpa_supplicant/hostapd control interface library 00003 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #ifdef CONFIG_CTRL_IFACE 00018 00019 #ifdef CONFIG_CTRL_IFACE_UNIX 00020 #include <sys/un.h> 00021 #endif /* CONFIG_CTRL_IFACE_UNIX */ 00022 00023 #include "wpa_ctrl.h" 00024 #include "common.h" 00025 00026 00027 #if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) 00028 #define CTRL_IFACE_SOCKET 00029 #endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ 00030 00031 00041 struct wpa_ctrl { 00042 #ifdef CONFIG_CTRL_IFACE_UDP 00043 int s; 00044 struct sockaddr_in local; 00045 struct sockaddr_in dest; 00046 char *cookie; 00047 #endif /* CONFIG_CTRL_IFACE_UDP */ 00048 #ifdef CONFIG_CTRL_IFACE_UNIX 00049 int s; 00050 struct sockaddr_un local; 00051 struct sockaddr_un dest; 00052 #endif /* CONFIG_CTRL_IFACE_UNIX */ 00053 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 00054 HANDLE pipe; 00055 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 00056 }; 00057 00058 00059 #ifdef CONFIG_CTRL_IFACE_UNIX 00060 00061 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 00062 { 00063 struct wpa_ctrl *ctrl; 00064 static int counter = 0; 00065 int ret; 00066 size_t res; 00067 int tries = 0; 00068 00069 ctrl = os_malloc(sizeof(*ctrl)); 00070 if (ctrl == NULL) 00071 return NULL; 00072 os_memset(ctrl, 0, sizeof(*ctrl)); 00073 00074 ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); 00075 if (ctrl->s < 0) { 00076 os_free(ctrl); 00077 return NULL; 00078 } 00079 00080 ctrl->local.sun_family = AF_UNIX; 00081 counter++; 00082 try_again: 00083 ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), 00084 "/tmp/wpa_ctrl_%d-%d", getpid(), counter); 00085 if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { 00086 close(ctrl->s); 00087 os_free(ctrl); 00088 return NULL; 00089 } 00090 tries++; 00091 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 00092 sizeof(ctrl->local)) < 0) { 00093 if (errno == EADDRINUSE && tries < 2) { 00094 /* 00095 * getpid() returns unique identifier for this instance 00096 * of wpa_ctrl, so the existing socket file must have 00097 * been left by unclean termination of an earlier run. 00098 * Remove the file and try again. 00099 */ 00100 unlink(ctrl->local.sun_path); 00101 goto try_again; 00102 } 00103 close(ctrl->s); 00104 os_free(ctrl); 00105 return NULL; 00106 } 00107 00108 ctrl->dest.sun_family = AF_UNIX; 00109 res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, 00110 sizeof(ctrl->dest.sun_path)); 00111 if (res >= sizeof(ctrl->dest.sun_path)) { 00112 close(ctrl->s); 00113 os_free(ctrl); 00114 return NULL; 00115 } 00116 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 00117 sizeof(ctrl->dest)) < 0) { 00118 close(ctrl->s); 00119 unlink(ctrl->local.sun_path); 00120 os_free(ctrl); 00121 return NULL; 00122 } 00123 00124 return ctrl; 00125 } 00126 00127 00128 void wpa_ctrl_close(struct wpa_ctrl *ctrl) 00129 { 00130 unlink(ctrl->local.sun_path); 00131 close(ctrl->s); 00132 os_free(ctrl); 00133 } 00134 00135 #endif /* CONFIG_CTRL_IFACE_UNIX */ 00136 00137 00138 #ifdef CONFIG_CTRL_IFACE_UDP 00139 00140 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 00141 { 00142 struct wpa_ctrl *ctrl; 00143 char buf[128]; 00144 size_t len; 00145 00146 ctrl = os_malloc(sizeof(*ctrl)); 00147 if (ctrl == NULL) 00148 return NULL; 00149 os_memset(ctrl, 0, sizeof(*ctrl)); 00150 00151 ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); 00152 if (ctrl->s < 0) { 00153 perror("socket"); 00154 os_free(ctrl); 00155 return NULL; 00156 } 00157 00158 ctrl->local.sin_family = AF_INET; 00159 ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); 00160 if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, 00161 sizeof(ctrl->local)) < 0) { 00162 close(ctrl->s); 00163 os_free(ctrl); 00164 return NULL; 00165 } 00166 00167 ctrl->dest.sin_family = AF_INET; 00168 ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); 00169 ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); 00170 if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, 00171 sizeof(ctrl->dest)) < 0) { 00172 perror("connect"); 00173 close(ctrl->s); 00174 os_free(ctrl); 00175 return NULL; 00176 } 00177 00178 len = sizeof(buf) - 1; 00179 if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { 00180 buf[len] = '\0'; 00181 ctrl->cookie = os_strdup(buf); 00182 } 00183 00184 return ctrl; 00185 } 00186 00187 00188 void wpa_ctrl_close(struct wpa_ctrl *ctrl) 00189 { 00190 close(ctrl->s); 00191 os_free(ctrl->cookie); 00192 os_free(ctrl); 00193 } 00194 00195 #endif /* CONFIG_CTRL_IFACE_UDP */ 00196 00197 00198 #ifdef CTRL_IFACE_SOCKET 00199 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 00200 char *reply, size_t *reply_len, 00201 void (*msg_cb)(char *msg, size_t len)) 00202 { 00203 struct timeval tv; 00204 int res; 00205 fd_set rfds; 00206 const char *_cmd; 00207 char *cmd_buf = NULL; 00208 size_t _cmd_len; 00209 00210 #ifdef CONFIG_CTRL_IFACE_UDP 00211 if (ctrl->cookie) { 00212 char *pos; 00213 _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; 00214 cmd_buf = os_malloc(_cmd_len); 00215 if (cmd_buf == NULL) 00216 return -1; 00217 _cmd = cmd_buf; 00218 pos = cmd_buf; 00219 os_strlcpy(pos, ctrl->cookie, _cmd_len); 00220 pos += os_strlen(ctrl->cookie); 00221 *pos++ = ' '; 00222 os_memcpy(pos, cmd, cmd_len); 00223 } else 00224 #endif /* CONFIG_CTRL_IFACE_UDP */ 00225 { 00226 _cmd = cmd; 00227 _cmd_len = cmd_len; 00228 } 00229 00230 if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { 00231 os_free(cmd_buf); 00232 return -1; 00233 } 00234 os_free(cmd_buf); 00235 00236 for (;;) { 00237 tv.tv_sec = 2; 00238 tv.tv_usec = 0; 00239 FD_ZERO(&rfds); 00240 FD_SET(ctrl->s, &rfds); 00241 res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 00242 if (FD_ISSET(ctrl->s, &rfds)) { 00243 res = recv(ctrl->s, reply, *reply_len, 0); 00244 if (res < 0) 00245 return res; 00246 if (res > 0 && reply[0] == '<') { 00247 /* This is an unsolicited message from 00248 * wpa_supplicant, not the reply to the 00249 * request. Use msg_cb to report this to the 00250 * caller. */ 00251 if (msg_cb) { 00252 /* Make sure the message is nul 00253 * terminated. */ 00254 if ((size_t) res == *reply_len) 00255 res = (*reply_len) - 1; 00256 reply[res] = '\0'; 00257 msg_cb(reply, res); 00258 } 00259 continue; 00260 } 00261 *reply_len = res; 00262 break; 00263 } else { 00264 return -2; 00265 } 00266 } 00267 return 0; 00268 } 00269 #endif /* CTRL_IFACE_SOCKET */ 00270 00271 00272 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) 00273 { 00274 char buf[10]; 00275 int ret; 00276 size_t len = 10; 00277 00278 ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, 00279 buf, &len, NULL); 00280 if (ret < 0) 00281 return ret; 00282 if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) 00283 return 0; 00284 return -1; 00285 } 00286 00287 00288 int wpa_ctrl_attach(struct wpa_ctrl *ctrl) 00289 { 00290 return wpa_ctrl_attach_helper(ctrl, 1); 00291 } 00292 00293 00294 int wpa_ctrl_detach(struct wpa_ctrl *ctrl) 00295 { 00296 return wpa_ctrl_attach_helper(ctrl, 0); 00297 } 00298 00299 00300 #ifdef CTRL_IFACE_SOCKET 00301 00302 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 00303 { 00304 int res; 00305 00306 res = recv(ctrl->s, reply, *reply_len, 0); 00307 if (res < 0) 00308 return res; 00309 *reply_len = res; 00310 return 0; 00311 } 00312 00313 00314 int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 00315 { 00316 struct timeval tv; 00317 fd_set rfds; 00318 tv.tv_sec = 0; 00319 tv.tv_usec = 0; 00320 FD_ZERO(&rfds); 00321 FD_SET(ctrl->s, &rfds); 00322 select(ctrl->s + 1, &rfds, NULL, NULL, &tv); 00323 return FD_ISSET(ctrl->s, &rfds); 00324 } 00325 00326 00327 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 00328 { 00329 return ctrl->s; 00330 } 00331 00332 #endif /* CTRL_IFACE_SOCKET */ 00333 00334 00335 #ifdef CONFIG_CTRL_IFACE_NAMED_PIPE 00336 00337 #ifndef WPA_SUPPLICANT_NAMED_PIPE 00338 #define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" 00339 #endif 00340 #define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) 00341 00342 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) 00343 { 00344 struct wpa_ctrl *ctrl; 00345 DWORD mode; 00346 TCHAR name[256]; 00347 int i, ret; 00348 00349 ctrl = os_malloc(sizeof(*ctrl)); 00350 if (ctrl == NULL) 00351 return NULL; 00352 os_memset(ctrl, 0, sizeof(*ctrl)); 00353 00354 #ifdef UNICODE 00355 if (ctrl_path == NULL) 00356 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); 00357 else 00358 ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), 00359 ctrl_path); 00360 #else /* UNICODE */ 00361 if (ctrl_path == NULL) 00362 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); 00363 else 00364 ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", 00365 ctrl_path); 00366 #endif /* UNICODE */ 00367 if (ret < 0 || ret >= 256) { 00368 os_free(ctrl); 00369 return NULL; 00370 } 00371 00372 for (i = 0; i < 10; i++) { 00373 ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, 00374 NULL, OPEN_EXISTING, 0, NULL); 00375 /* 00376 * Current named pipe server side in wpa_supplicant is 00377 * re-opening the pipe for new clients only after the previous 00378 * one is taken into use. This leaves a small window for race 00379 * conditions when two connections are being opened at almost 00380 * the same time. Retry if that was the case. 00381 */ 00382 if (ctrl->pipe != INVALID_HANDLE_VALUE || 00383 GetLastError() != ERROR_PIPE_BUSY) 00384 break; 00385 WaitNamedPipe(name, 1000); 00386 } 00387 if (ctrl->pipe == INVALID_HANDLE_VALUE) { 00388 os_free(ctrl); 00389 return NULL; 00390 } 00391 00392 mode = PIPE_READMODE_MESSAGE; 00393 if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { 00394 CloseHandle(ctrl->pipe); 00395 os_free(ctrl); 00396 return NULL; 00397 } 00398 00399 return ctrl; 00400 } 00401 00402 00403 void wpa_ctrl_close(struct wpa_ctrl *ctrl) 00404 { 00405 CloseHandle(ctrl->pipe); 00406 os_free(ctrl); 00407 } 00408 00409 00410 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, 00411 char *reply, size_t *reply_len, 00412 void (*msg_cb)(char *msg, size_t len)) 00413 { 00414 DWORD written; 00415 DWORD readlen = *reply_len; 00416 00417 if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) 00418 return -1; 00419 00420 if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) 00421 return -1; 00422 *reply_len = readlen; 00423 00424 return 0; 00425 } 00426 00427 00428 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) 00429 { 00430 DWORD len = *reply_len; 00431 if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) 00432 return -1; 00433 *reply_len = len; 00434 return 0; 00435 } 00436 00437 00438 int wpa_ctrl_pending(struct wpa_ctrl *ctrl) 00439 { 00440 DWORD left; 00441 00442 if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) 00443 return -1; 00444 return left ? 1 : 0; 00445 } 00446 00447 00448 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) 00449 { 00450 return -1; 00451 } 00452 00453 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ 00454 00455 #endif /* CONFIG_CTRL_IFACE */