diff options
Diffstat (limited to 'contrib/hostapd/wpa_ctrl.c')
-rw-r--r-- | contrib/hostapd/wpa_ctrl.c | 296 |
1 files changed, 241 insertions, 55 deletions
diff --git a/contrib/hostapd/wpa_ctrl.c b/contrib/hostapd/wpa_ctrl.c index 98e0669..dcec537 100644 --- a/contrib/hostapd/wpa_ctrl.c +++ b/contrib/hostapd/wpa_ctrl.c @@ -1,6 +1,6 @@ /* * wpa_supplicant/hostapd control interface library - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,22 +12,21 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/time.h> -#ifndef CONFIG_NATIVE_WINDOWS -#include <sys/socket.h> -#include <netinet/in.h> +#include "includes.h" + +#ifdef CONFIG_CTRL_IFACE + +#ifdef CONFIG_CTRL_IFACE_UNIX #include <sys/un.h> -#endif /* CONFIG_NATIVE_WINDOWS */ +#endif /* CONFIG_CTRL_IFACE_UNIX */ #include "wpa_ctrl.h" -#ifdef CONFIG_NATIVE_WINDOWS #include "common.h" -#endif /* CONFIG_NATIVE_WINDOWS */ + + +#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) +#define CTRL_IFACE_SOCKET +#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ /** @@ -40,84 +39,121 @@ * the arguments for most of the control interface library functions. */ struct wpa_ctrl { - int s; #ifdef CONFIG_CTRL_IFACE_UDP + int s; struct sockaddr_in local; struct sockaddr_in dest; -#else /* CONFIG_CTRL_IFACE_UDP */ + char *cookie; +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + int s; struct sockaddr_un local; struct sockaddr_un dest; -#endif /* CONFIG_CTRL_IFACE_UDP */ +#endif /* CONFIG_CTRL_IFACE_UNIX */ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + HANDLE pipe; +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ }; +#ifdef CONFIG_CTRL_IFACE_UNIX + struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) { struct wpa_ctrl *ctrl; -#ifndef CONFIG_CTRL_IFACE_UDP static int counter = 0; -#endif /* CONFIG_CTRL_IFACE_UDP */ - ctrl = malloc(sizeof(*ctrl)); + ctrl = os_malloc(sizeof(*ctrl)); if (ctrl == NULL) return NULL; - memset(ctrl, 0, sizeof(*ctrl)); + os_memset(ctrl, 0, sizeof(*ctrl)); -#ifdef CONFIG_CTRL_IFACE_UDP - ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); + ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); if (ctrl->s < 0) { - perror("socket"); - free(ctrl); + os_free(ctrl); return NULL; } - ctrl->local.sin_family = AF_INET; - ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); + ctrl->local.sun_family = AF_UNIX; + os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), + "/tmp/wpa_ctrl_%d-%d", getpid(), counter++); if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { + sizeof(ctrl->local)) < 0) { close(ctrl->s); - free(ctrl); + os_free(ctrl); return NULL; } - ctrl->dest.sin_family = AF_INET; - ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); - ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); + ctrl->dest.sun_family = AF_UNIX; + os_snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s", + ctrl_path); if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { - perror("connect"); close(ctrl->s); - free(ctrl); + unlink(ctrl->local.sun_path); + os_free(ctrl); return NULL; } -#else /* CONFIG_CTRL_IFACE_UDP */ - ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); + + return ctrl; +} + + +void wpa_ctrl_close(struct wpa_ctrl *ctrl) +{ + unlink(ctrl->local.sun_path); + close(ctrl->s); + os_free(ctrl); +} + +#endif /* CONFIG_CTRL_IFACE_UNIX */ + + +#ifdef CONFIG_CTRL_IFACE_UDP + +struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) +{ + struct wpa_ctrl *ctrl; + char buf[128]; + size_t len; + + ctrl = os_malloc(sizeof(*ctrl)); + if (ctrl == NULL) + return NULL; + os_memset(ctrl, 0, sizeof(*ctrl)); + + ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); if (ctrl->s < 0) { - free(ctrl); + perror("socket"); + os_free(ctrl); return NULL; } - ctrl->local.sun_family = AF_UNIX; - snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), - "/tmp/wpa_ctrl_%d-%d", getpid(), counter++); + ctrl->local.sin_family = AF_INET; + ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { + sizeof(ctrl->local)) < 0) { close(ctrl->s); - free(ctrl); + os_free(ctrl); return NULL; } - ctrl->dest.sun_family = AF_UNIX; - snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s", - ctrl_path); + ctrl->dest.sin_family = AF_INET; + ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); + ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { + perror("connect"); close(ctrl->s); - unlink(ctrl->local.sun_path); - free(ctrl); + os_free(ctrl); return NULL; } -#endif /* CONFIG_CTRL_IFACE_UDP */ + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { + buf[len] = '\0'; + ctrl->cookie = strdup(buf); + } return ctrl; } @@ -125,14 +161,15 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) void wpa_ctrl_close(struct wpa_ctrl *ctrl) { -#ifndef CONFIG_CTRL_IFACE_UDP - unlink(ctrl->local.sun_path); -#endif /* CONFIG_CTRL_IFACE_UDP */ close(ctrl->s); - free(ctrl); + os_free(ctrl->cookie); + os_free(ctrl); } +#endif /* CONFIG_CTRL_IFACE_UDP */ + +#ifdef CTRL_IFACE_SOCKET int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)) @@ -140,9 +177,35 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, struct timeval tv; int res; fd_set rfds; + const char *_cmd; + char *cmd_buf = NULL; + size_t _cmd_len; - if (send(ctrl->s, cmd, cmd_len, 0) < 0) +#ifdef CONFIG_CTRL_IFACE_UDP + if (ctrl->cookie) { + char *pos; + _cmd_len = strlen(ctrl->cookie) + 1 + cmd_len; + cmd_buf = os_malloc(_cmd_len ); + if (cmd_buf == NULL) + return -1; + _cmd = cmd_buf; + pos = cmd_buf; + strcpy(pos, ctrl->cookie); + pos += strlen(ctrl->cookie); + *pos++ = ' '; + memcpy(pos, cmd, cmd_len); + } else +#endif /* CONFIG_CTRL_IFACE_UDP */ + { + _cmd = cmd; + _cmd_len = cmd_len; + } + + if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { + os_free(cmd_buf); return -1; + } + os_free(cmd_buf); for (;;) { tv.tv_sec = 2; @@ -177,6 +240,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, } return 0; } +#endif /* CTRL_IFACE_SOCKET */ static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) @@ -189,7 +253,7 @@ static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) buf, &len, NULL); if (ret < 0) return ret; - if (len == 3 && memcmp(buf, "OK\n", 3) == 0) + if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) return 0; return -1; } @@ -207,6 +271,8 @@ int wpa_ctrl_detach(struct wpa_ctrl *ctrl) } +#ifdef CTRL_IFACE_SOCKET + int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) { int res; @@ -222,13 +288,12 @@ int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) int wpa_ctrl_pending(struct wpa_ctrl *ctrl) { struct timeval tv; - int res; fd_set rfds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); - res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); + select(ctrl->s + 1, &rfds, NULL, NULL, &tv); return FD_ISSET(ctrl->s, &rfds); } @@ -237,3 +302,124 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) { return ctrl->s; } + +#endif /* CTRL_IFACE_SOCKET */ + + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + +#ifndef WPA_SUPPLICANT_NAMED_PIPE +#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" +#endif +#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) + +struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) +{ + struct wpa_ctrl *ctrl; + DWORD mode; + TCHAR name[256]; + int i; + + ctrl = os_malloc(sizeof(*ctrl)); + if (ctrl == NULL) + return NULL; + os_memset(ctrl, 0, sizeof(*ctrl)); + +#ifdef UNICODE + if (ctrl_path == NULL) + _snwprintf(name, 256, NAMED_PIPE_PREFIX); + else + _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), + ctrl_path); +#else /* UNICODE */ + if (ctrl_path == NULL) + os_snprintf(name, 256, NAMED_PIPE_PREFIX); + else + os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", + ctrl_path); +#endif /* UNICODE */ + + for (i = 0; i < 10; i++) { + ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, 0, NULL); + /* + * Current named pipe server side in wpa_supplicant is + * re-opening the pipe for new clients only after the previous + * one is taken into use. This leaves a small window for race + * conditions when two connections are being opened at almost + * the same time. Retry if that was the case. + */ + if (ctrl->pipe != INVALID_HANDLE_VALUE || + GetLastError() != ERROR_PIPE_BUSY) + break; + WaitNamedPipe(name, 1000); + } + if (ctrl->pipe == INVALID_HANDLE_VALUE) { + os_free(ctrl); + return NULL; + } + + mode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { + CloseHandle(ctrl->pipe); + os_free(ctrl); + return NULL; + } + + return ctrl; +} + + +void wpa_ctrl_close(struct wpa_ctrl *ctrl) +{ + CloseHandle(ctrl->pipe); + os_free(ctrl); +} + + +int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, + char *reply, size_t *reply_len, + void (*msg_cb)(char *msg, size_t len)) +{ + DWORD written; + DWORD readlen = *reply_len; + + if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) + return -1; + + if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) + return -1; + *reply_len = readlen; + + return 0; +} + + +int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) +{ + DWORD len = *reply_len; + if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) + return -1; + *reply_len = len; + return 0; +} + + +int wpa_ctrl_pending(struct wpa_ctrl *ctrl) +{ + DWORD left; + + if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) + return -1; + return left ? 1 : 0; +} + + +int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) +{ + return -1; +} + +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#endif /* CONFIG_CTRL_IFACE */ |