From c90fd485141fd5e713684cfb385c557a618fa70d Mon Sep 17 00:00:00 2001 From: Shan Palanisamy Date: Tue, 20 Dec 2011 17:10:47 +0200 Subject: [PATCH] hostapd: Add global control interface Signed-hostap: Jouni Malinen --- hostapd/ctrl_iface.c | 185 +++++++++++++++++++++++++++++++++++++++++++ hostapd/ctrl_iface.h | 13 +++ hostapd/main.c | 37 ++++++++- src/ap/hostapd.h | 3 + 4 files changed, 236 insertions(+), 2 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 77146e3e5..c21c8a017 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1092,6 +1092,191 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) } +static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + char buf[256]; + int res; + struct sockaddr_un from; + socklen_t fromlen = sizeof(from); + char reply[24]; + int reply_len; + + res = recvfrom(sock, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &from, &fromlen); + if (res < 0) { + perror("recvfrom(ctrl_iface)"); + return; + } + buf[res] = '\0'; + + os_memcpy(reply, "OK\n", 3); + reply_len = 3; + + if (os_strcmp(buf, "PING") == 0) { + os_memcpy(reply, "PONG\n", 5); + reply_len = 5; + } else { + wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " + "ignored"); + reply_len = -1; + } + + if (reply_len < 0) { + os_memcpy(reply, "FAIL\n", 5); + reply_len = 5; + } + + sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); +} + + +static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) +{ + char *buf; + size_t len; + + if (interface->global_iface_path == NULL) + return NULL; + + len = os_strlen(interface->global_iface_path) + + os_strlen(interface->global_iface_name) + 2; + buf = os_malloc(len); + if (buf == NULL) + return NULL; + + os_snprintf(buf, len, "%s/%s", interface->global_iface_path, + interface->global_iface_name); + buf[len - 1] = '\0'; + return buf; +} + + +int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) +{ + struct sockaddr_un addr; + int s = -1; + char *fname = NULL; + + if (interface->global_iface_path == NULL) { + wpa_printf(MSG_DEBUG, "ctrl_iface not configured!"); + return 0; + } + + if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) { + if (errno == EEXIST) { + wpa_printf(MSG_DEBUG, "Using existing control " + "interface directory."); + } else { + perror("mkdir[ctrl_interface]"); + goto fail; + } + } + + if (os_strlen(interface->global_iface_path) + 1 + + os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path)) + goto fail; + + s = socket(PF_UNIX, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket(PF_UNIX)"); + goto fail; + } + + os_memset(&addr, 0, sizeof(addr)); +#ifdef __FreeBSD__ + addr.sun_len = sizeof(addr); +#endif /* __FreeBSD__ */ + addr.sun_family = AF_UNIX; + fname = hostapd_global_ctrl_iface_path(interface); + if (fname == NULL) + goto fail; + os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", + strerror(errno)); + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" + " allow connections - assuming it was left" + "over from forced program termination"); + if (unlink(fname) < 0) { + perror("unlink[ctrl_iface]"); + wpa_printf(MSG_ERROR, "Could not unlink " + "existing ctrl_iface socket '%s'", + fname); + goto fail; + } + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < + 0) { + perror("bind(PF_UNIX)"); + goto fail; + } + wpa_printf(MSG_DEBUG, "Successfully replaced leftover " + "ctrl_iface socket '%s'", fname); + } else { + wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " + "be in use - cannot override it"); + wpa_printf(MSG_INFO, "Delete '%s' manually if it is " + "not used anymore", fname); + os_free(fname); + fname = NULL; + goto fail; + } + } + + if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { + perror("chmod[ctrl_interface/ifname]"); + goto fail; + } + os_free(fname); + + interface->global_ctrl_sock = s; + eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, + interface, NULL); + + return 0; + +fail: + if (s >= 0) + close(s); + if (fname) { + unlink(fname); + os_free(fname); + } + return -1; +} + + +void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) +{ + char *fname = NULL; + + if (interfaces->global_ctrl_sock > -1) { + eloop_unregister_read_sock(interfaces->global_ctrl_sock); + close(interfaces->global_ctrl_sock); + interfaces->global_ctrl_sock = -1; + fname = hostapd_global_ctrl_iface_path(interfaces); + if (fname) { + unlink(fname); + os_free(fname); + } + + if (interfaces->global_iface_path && + rmdir(interfaces->global_iface_path) < 0) { + if (errno == ENOTEMPTY) { + wpa_printf(MSG_DEBUG, "Control interface " + "directory not empty - leaving it " + "behind"); + } else { + perror("rmdir[ctrl_interface]"); + } + } + os_free(interfaces->global_iface_path); + interfaces->global_iface_path = NULL; + } +} + + static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, const char *buf, size_t len) { diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h index 64a508039..3341a66bd 100644 --- a/hostapd/ctrl_iface.h +++ b/hostapd/ctrl_iface.h @@ -12,6 +12,8 @@ #ifndef CONFIG_NO_CTRL_IFACE int hostapd_ctrl_iface_init(struct hostapd_data *hapd); void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); +int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface); +void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface); #else /* CONFIG_NO_CTRL_IFACE */ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) { @@ -21,6 +23,17 @@ static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) { } + +static inline int +hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) +{ + return 0; +} + +static inline void +hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface) +{ +} #endif /* CONFIG_NO_CTRL_IFACE */ #endif /* CTRL_IFACE_H */ diff --git a/hostapd/main.c b/hostapd/main.c index d1790a435..94b90beb2 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -494,13 +494,15 @@ static void usage(void) fprintf(stderr, "\n" "usage: hostapd [-hdBKtv] [-P ] [-e ] " - "\n" + "\\\n" + " [-g ] \n" "\n" "options:\n" " -h show this usage\n" " -d show more debug messages (-dd for even more)\n" " -B run daemon in the background\n" " -e entropy file\n" + " -g global control interface path\n" " -P PID file\n" " -K include key data in debug messages\n" #ifdef CONFIG_DEBUG_FILE @@ -522,6 +524,28 @@ static const char * hostapd_msg_ifname_cb(void *ctx) } +static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, + const char *path) +{ + char *pos; + os_free(interfaces->global_iface_path); + interfaces->global_iface_path = os_strdup(path); + if (interfaces->global_iface_path == NULL) + return -1; + pos = os_strrchr(interfaces->global_iface_path, '/'); + if (pos == NULL) { + os_free(interfaces->global_iface_path); + interfaces->global_iface_path = NULL; + return -1; + } + + *pos = '\0'; + interfaces->global_iface_name = pos + 1; + + return 0; +} + + int main(int argc, char *argv[]) { struct hapd_interfaces interfaces; @@ -541,9 +565,12 @@ int main(int argc, char *argv[]) interfaces.for_each_interface = hostapd_for_each_interface; interfaces.ctrl_iface_init = hostapd_ctrl_iface_init; interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit; + interfaces.global_iface_path = NULL; + interfaces.global_iface_name = NULL; + interfaces.global_ctrl_sock = -1; for (;;) { - c = getopt(argc, argv, "Bde:f:hKP:tv"); + c = getopt(argc, argv, "Bde:f:hKP:tvg:"); if (c < 0) break; switch (c) { @@ -578,6 +605,9 @@ int main(int argc, char *argv[]) show_version(); exit(1); break; + case 'g': + hostapd_get_global_ctrl_iface(&interfaces, optarg); + break; default: usage(); @@ -613,12 +643,15 @@ int main(int argc, char *argv[]) goto out; } + hostapd_global_ctrl_iface_init(&interfaces); + if (hostapd_global_run(&interfaces, daemonize, pid_file)) goto out; ret = 0; out: + hostapd_global_ctrl_iface_deinit(&interfaces); /* Deinitialize all interfaces */ for (i = 0; i < interfaces.count; i++) hostapd_interface_deinit_free(interfaces.iface[i]); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 05e349f9b..3b79e1286 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -35,6 +35,9 @@ struct hapd_interfaces { void *ctx), void *ctx); size_t count; + int global_ctrl_sock; + char *global_iface_path; + char *global_iface_name; struct hostapd_iface **iface; };