diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index d6865bb7d..17e4c8082 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1131,9 +1131,32 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) } +static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces, + char *buf) +{ + if (hostapd_add_iface(interfaces, buf) < 0) { + wpa_printf(MSG_ERROR, "Adding interface %s failed", buf); + return -1; + } + return 0; +} + + +static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, + char *buf) +{ + if (hostapd_remove_iface(interfaces, buf) < 0) { + wpa_printf(MSG_ERROR, "Removing interface %s failed", buf); + return -1; + } + return 0; +} + + static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { + void *interfaces = eloop_ctx; char buf[256]; int res; struct sockaddr_un from; @@ -1155,6 +1178,12 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, if (os_strcmp(buf, "PING") == 0) { os_memcpy(reply, "PONG\n", 5); reply_len = 5; + } else if (os_strncmp(buf, "ADD ", 4) == 0) { + if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { + if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) + reply_len = -1; } else { wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " "ignored"); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 35ceb02b6..34292587e 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -39,6 +39,7 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); extern int wpa_debug_level; +extern struct wpa_driver_ops *wpa_drivers[]; int hostapd_for_each_interface(struct hapd_interfaces *interfaces, @@ -1147,6 +1148,190 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface) return 0; } + +static struct hostapd_iface * +hostapd_iface_alloc(struct hapd_interfaces *interfaces) +{ + struct hostapd_iface **iface, *hapd_iface; + + iface = os_realloc_array(interfaces->iface, interfaces->count + 1, + sizeof(struct hostapd_iface *)); + if (iface == NULL) + return NULL; + interfaces->iface = iface; + hapd_iface = interfaces->iface[interfaces->count] = + os_zalloc(sizeof(*hapd_iface)); + if (hapd_iface == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " + "the interface", __func__); + return NULL; + } + interfaces->count++; + hapd_iface->interfaces = interfaces; + + return hapd_iface; +} + + +static struct hostapd_config * +hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname, + const char *ctrl_iface) +{ + struct hostapd_bss_config *bss; + struct hostapd_config *conf; + + /* Allocates memory for bss and conf */ + conf = hostapd_config_defaults(); + if (conf == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for " + "configuration", __func__); + return NULL; + } + + conf->driver = wpa_drivers[0]; + if (conf->driver == NULL) { + wpa_printf(MSG_ERROR, "No driver wrappers registered!"); + hostapd_config_free(conf); + return NULL; + } + + bss = conf->last_bss = conf->bss; + + os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); + bss->ctrl_interface = os_strdup(ctrl_iface); + if (bss->ctrl_interface == NULL) { + hostapd_config_free(conf); + return NULL; + } + + /* Reading configuration file skipped, will be done in SET! + * From reading the configuration till the end has to be done in + * SET + */ + return conf; +} + + +static struct hostapd_iface * hostapd_data_alloc( + struct hapd_interfaces *interfaces, struct hostapd_config *conf) +{ + size_t i; + struct hostapd_iface *hapd_iface = + interfaces->iface[interfaces->count - 1]; + struct hostapd_data *hapd; + + hapd_iface->conf = conf; + hapd_iface->num_bss = conf->num_bss; + + hapd_iface->bss = os_zalloc(conf->num_bss * + sizeof(struct hostapd_data *)); + if (hapd_iface->bss == NULL) + return NULL; + + for (i = 0; i < conf->num_bss; i++) { + hapd = hapd_iface->bss[i] = + hostapd_alloc_bss_data(hapd_iface, conf, + &conf->bss[i]); + if (hapd == NULL) + return NULL; + hapd->msg_ctx = hapd; + } + + hapd_iface->interfaces = interfaces; + + return hapd_iface; +} + + +int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) +{ + struct hostapd_config *conf = NULL; + struct hostapd_iface *hapd_iface = NULL; + char *ptr; + size_t i; + + ptr = os_strchr(buf, ' '); + if (ptr == NULL) + return -1; + *ptr++ = '\0'; + + for (i = 0; i < interfaces->count; i++) { + if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface, + buf)) { + wpa_printf(MSG_INFO, "Cannot add interface - it " + "already exists"); + return -1; + } + } + + hapd_iface = hostapd_iface_alloc(interfaces); + if (hapd_iface == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " + "for interface", __func__); + goto fail; + } + + conf = hostapd_config_alloc(interfaces, buf, ptr); + if (conf == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " + "for configuration", __func__); + goto fail; + } + + hapd_iface = hostapd_data_alloc(interfaces, conf); + if (hapd_iface == NULL) { + wpa_printf(MSG_ERROR, "%s: Failed to allocate memory " + "for hostapd", __func__); + goto fail; + } + + if (hapd_iface->interfaces && + hapd_iface->interfaces->ctrl_iface_init && + hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) { + wpa_printf(MSG_ERROR, "%s: Failed to setup control " + "interface", __func__); + goto fail; + } + wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface); + + return 0; + +fail: + if (conf) + hostapd_config_free(conf); + if (hapd_iface) { + os_free(hapd_iface->bss[interfaces->count]); + os_free(hapd_iface); + } + return -1; +} + + +int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf) +{ + struct hostapd_iface *hapd_iface; + size_t i, k = 0; + + for (i = 0; i < interfaces->count; i++) { + hapd_iface = interfaces->iface[i]; + if (hapd_iface == NULL) + return -1; + if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) { + wpa_printf(MSG_INFO, "Remove interface '%s'", buf); + hostapd_interface_deinit_free(hapd_iface); + k = i; + while (k < (interfaces->count - 1)) { + interfaces->iface[k] = + interfaces->iface[k + 1]; + k++; + } + interfaces->count--; + return 0; + } + } + return -1; +} + #endif /* HOSTAPD */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 2c348322c..71f476c0e 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -274,6 +274,8 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface); int hostapd_enable_iface(struct hostapd_iface *hapd_iface); int hostapd_reload_iface(struct hostapd_iface *hapd_iface); int hostapd_disable_iface(struct hostapd_iface *hapd_iface); +int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf); +int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf); /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd,