diff options
Diffstat (limited to 'contrib/wpa/src/ap/hostapd.c')
-rw-r--r-- | contrib/wpa/src/ap/hostapd.c | 752 |
1 files changed, 634 insertions, 118 deletions
diff --git a/contrib/wpa/src/ap/hostapd.c b/contrib/wpa/src/ap/hostapd.c index 841f9c5..cef9daf 100644 --- a/contrib/wpa/src/ap/hostapd.c +++ b/contrib/wpa/src/ap/hostapd.c @@ -1,15 +1,9 @@ /* * hostapd / Initialization and configuration - * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2012, 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 - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -18,6 +12,7 @@ #include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "radius/radius_client.h" +#include "radius/radius_das.h" #include "drivers/driver.h" #include "hostapd.h" #include "authsrv.h" @@ -35,57 +30,56 @@ #include "wpa_auth_glue.h" #include "ap_drv_ops.h" #include "ap_config.h" +#include "p2p_hostapd.h" +#include "gas_serv.h" -static int hostapd_flush_old_stations(struct hostapd_data *hapd); +static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); 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_reload_config(struct hostapd_iface *iface) +int hostapd_for_each_interface(struct hapd_interfaces *interfaces, + int (*cb)(struct hostapd_iface *iface, + void *ctx), void *ctx) { - struct hostapd_data *hapd = iface->bss[0]; - struct hostapd_config *newconf, *oldconf; - size_t j; + size_t i; + int ret; - if (iface->config_read_cb == NULL) - return -1; - newconf = iface->config_read_cb(iface->config_fname); - if (newconf == NULL) - return -1; + for (i = 0; i < interfaces->count; i++) { + ret = cb(interfaces->iface[i], ctx); + if (ret) + return ret; + } - /* - * Deauthenticate all stations since the new configuration may not - * allow them to use the BSS anymore. - */ - for (j = 0; j < iface->num_bss; j++) - hostapd_flush_old_stations(iface->bss[j]); + return 0; +} + +static void hostapd_reload_bss(struct hostapd_data *hapd) +{ #ifndef CONFIG_NO_RADIUS - /* TODO: update dynamic data based on changed configuration - * items (e.g., open/close sockets, etc.) */ - radius_client_flush(hapd->radius, 0); + radius_client_reconfig(hapd->radius, hapd->conf->radius); #endif /* CONFIG_NO_RADIUS */ - oldconf = hapd->iconf; - hapd->iconf = newconf; - hapd->conf = &newconf->bss[0]; - iface->conf = newconf; - if (hostapd_setup_wpa_psk(hapd->conf)) { wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " "after reloading configuration"); } if (hapd->conf->ieee802_1x || hapd->conf->wpa) - hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 1); + hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); else - hapd->drv.set_drv_ieee8021x(hapd, hapd->conf->iface, 0); + hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); - if (hapd->conf->wpa && hapd->wpa_auth == NULL) + if (hapd->conf->wpa && hapd->wpa_auth == NULL) { hostapd_setup_wpa(hapd); - else if (hapd->conf->wpa) { + if (hapd->wpa_auth) + wpa_init_keys(hapd->wpa_auth); + } else if (hapd->conf->wpa) { const u8 *wpa_ie; size_t wpa_ie_len; hostapd_reconfig_wpa(hapd); @@ -105,15 +99,56 @@ int hostapd_reload_config(struct hostapd_iface *iface) hostapd_update_wps(hapd); if (hapd->conf->ssid.ssid_set && - hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, + hostapd_set_ssid(hapd, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len)) { wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); /* try to continue */ } + wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); +} + + +int hostapd_reload_config(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + struct hostapd_config *newconf, *oldconf; + size_t j; + + if (iface->interfaces == NULL || + iface->interfaces->config_read_cb == NULL) + return -1; + newconf = iface->interfaces->config_read_cb(iface->config_fname); + if (newconf == NULL) + return -1; + + /* + * Deauthenticate all stations since the new configuration may not + * allow them to use the BSS anymore. + */ + for (j = 0; j < iface->num_bss; j++) { + hostapd_flush_old_stations(iface->bss[j], + WLAN_REASON_PREV_AUTH_NOT_VALID); + hostapd_broadcast_wep_clear(iface->bss[j]); + +#ifndef CONFIG_NO_RADIUS + /* TODO: update dynamic data based on changed configuration + * items (e.g., open/close sockets, etc.) */ + radius_client_flush(iface->bss[j]->radius, 0); +#endif /* CONFIG_NO_RADIUS */ + } + + oldconf = hapd->iconf; + iface->conf = newconf; + + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + hapd->iconf = newconf; + hapd->conf = &newconf->bss[j]; + hostapd_reload_bss(hapd); + } hostapd_config_free(oldconf); - wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); return 0; } @@ -125,8 +160,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, int i; for (i = 0; i < NUM_WEP_KEYS; i++) { - if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, - i == 0 ? 1 : 0, NULL, 0, NULL, 0)) { + if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, + 0, NULL, 0, NULL, 0)) { wpa_printf(MSG_DEBUG, "Failed to clear default " "encryption keys (ifname=%s keyidx=%d)", ifname, i); @@ -135,9 +170,9 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W if (hapd->conf->ieee80211w) { for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { - if (hapd->drv.set_key(ifname, hapd, WPA_ALG_NONE, NULL, - i, i == 0 ? 1 : 0, NULL, 0, - NULL, 0)) { + if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, + NULL, i, 0, NULL, + 0, NULL, 0)) { wpa_printf(MSG_DEBUG, "Failed to clear " "default mgmt encryption keys " "(ifname=%s keyidx=%d)", ifname, i); @@ -162,11 +197,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) idx = ssid->wep.idx; if (ssid->wep.default_len && - hapd->drv.set_key(hapd->conf->iface, - hapd, WPA_ALG_WEP, NULL, idx, - idx == ssid->wep.idx, - NULL, 0, ssid->wep.key[idx], - ssid->wep.len[idx])) { + hostapd_drv_set_key(hapd->conf->iface, + hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, + 1, NULL, 0, ssid->wep.key[idx], + ssid->wep.len[idx])) { wpa_printf(MSG_WARNING, "Could not set WEP encryption."); errors++; } @@ -184,9 +218,10 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) continue; idx = key->idx; - if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, - idx, idx == key->idx, NULL, 0, - key->key[idx], key->len[idx])) { + if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP, + broadcast_ether_addr, idx, 1, + NULL, 0, key->key[idx], + key->len[idx])) { wpa_printf(MSG_WARNING, "Could not set " "dynamic VLAN WEP encryption."); errors++; @@ -197,21 +232,9 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) return errors; } -/** - * hostapd_cleanup - Per-BSS cleanup (deinitialization) - * @hapd: Pointer to BSS data - * - * This function is used to free all per-BSS data structures and resources. - * This gets called in a loop for each BSS between calls to - * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface - * is deinitialized. Most of the modules that are initialized in - * hostapd_setup_bss() are deinitialized here. - */ -static void hostapd_cleanup(struct hostapd_data *hapd) -{ - if (hapd->iface->ctrl_iface_deinit) - hapd->iface->ctrl_iface_deinit(hapd); +static void hostapd_free_hapd_data(struct hostapd_data *hapd) +{ iapp_deinit(hapd->iapp); hapd->iapp = NULL; accounting_deinit(hapd); @@ -221,6 +244,8 @@ static void hostapd_cleanup(struct hostapd_data *hapd) #ifndef CONFIG_NO_RADIUS radius_client_deinit(hapd->radius); hapd->radius = NULL; + radius_das_deinit(hapd->radius_das); + hapd->radius_das = NULL; #endif /* CONFIG_NO_RADIUS */ hostapd_deinit_wps(hapd); @@ -235,6 +260,43 @@ static void hostapd_cleanup(struct hostapd_data *hapd) os_free(hapd->probereq_cb); hapd->probereq_cb = NULL; + +#ifdef CONFIG_P2P + wpabuf_free(hapd->p2p_beacon_ie); + hapd->p2p_beacon_ie = NULL; + wpabuf_free(hapd->p2p_probe_resp_ie); + hapd->p2p_probe_resp_ie = NULL; +#endif /* CONFIG_P2P */ + + wpabuf_free(hapd->time_adv); + +#ifdef CONFIG_INTERWORKING + gas_serv_deinit(hapd); +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_SQLITE + os_free(hapd->tmp_eap_user.identity); + os_free(hapd->tmp_eap_user.password); +#endif /* CONFIG_SQLITE */ +} + + +/** + * hostapd_cleanup - Per-BSS cleanup (deinitialization) + * @hapd: Pointer to BSS data + * + * This function is used to free all per-BSS data structures and resources. + * This gets called in a loop for each BSS between calls to + * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface + * is deinitialized. Most of the modules that are initialized in + * hostapd_setup_bss() are deinitialized here. + */ +static void hostapd_cleanup(struct hostapd_data *hapd) +{ + if (hapd->iface->interfaces && + hapd->iface->interfaces->ctrl_iface_deinit) + hapd->iface->interfaces->ctrl_iface_deinit(hapd); + hostapd_free_hapd_data(hapd); } @@ -250,6 +312,18 @@ static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface) } +static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) +{ + hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); + iface->hw_features = NULL; + os_free(iface->current_rates); + iface->current_rates = NULL; + os_free(iface->basic_rates); + iface->basic_rates = NULL; + ap_list_deinit(iface); +} + + /** * hostapd_cleanup_iface - Complete per-interface cleanup * @iface: Pointer to interface data @@ -259,11 +333,7 @@ static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface) */ static void hostapd_cleanup_iface(struct hostapd_iface *iface) { - hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); - iface->hw_features = NULL; - os_free(iface->current_rates); - iface->current_rates = NULL; - ap_list_deinit(iface); + hostapd_cleanup_iface_partial(iface); hostapd_config_free(iface->conf); iface->conf = NULL; @@ -273,6 +343,15 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface) } +static void hostapd_clear_wep(struct hostapd_data *hapd) +{ + if (hapd->drv_priv) { + hostapd_set_privacy(hapd, 0); + hostapd_broadcast_wep_clear(hapd); + } +} + + static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) { int i; @@ -284,12 +363,18 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) return 0; } + /* + * When IEEE 802.1X is not enabled, the driver may need to know how to + * set authentication algorithms for static WEP. + */ + hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs); + for (i = 0; i < 4; i++) { if (hapd->conf->ssid.wep.key[i] && - hapd->drv.set_key(iface, hapd, WPA_ALG_WEP, NULL, i, - i == hapd->conf->ssid.wep.idx, NULL, 0, - hapd->conf->ssid.wep.key[i], - hapd->conf->ssid.wep.len[i])) { + hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, + i == hapd->conf->ssid.wep.idx, NULL, 0, + hapd->conf->ssid.wep.key[i], + hapd->conf->ssid.wep.len[i])) { wpa_printf(MSG_WARNING, "Could not set WEP " "encryption."); return -1; @@ -303,30 +388,24 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) } -static int hostapd_flush_old_stations(struct hostapd_data *hapd) +static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) { int ret = 0; + u8 addr[ETH_ALEN]; if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) return 0; - wpa_printf(MSG_DEBUG, "Flushing old station entries"); + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries"); if (hostapd_flush(hapd)) { - wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); + wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to " + "kernel driver"); ret = -1; } - wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); - - /* New Prism2.5/3 STA firmware versions seem to have issues with this - * broadcast deauth frame. This gets the firmware in odd state where - * nothing works correctly, so let's skip sending this for the hostap - * driver. */ - if (hapd->driver && os_strcmp(hapd->driver->name, "hostap") != 0) { - u8 addr[ETH_ALEN]; - os_memset(addr, 0xff, ETH_ALEN); - hapd->drv.sta_deauth(hapd, addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations"); + os_memset(addr, 0xff, ETH_ALEN); + hostapd_drv_sta_deauth(hapd, addr, reason); + hostapd_free_stas(hapd); return ret; } @@ -344,7 +423,6 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) u8 mask[ETH_ALEN] = { 0 }; struct hostapd_data *hapd = iface->bss[0]; unsigned int i = iface->conf->num_bss, bits = 0, j; - int res; int auto_addr = 0; if (hostapd_drv_none(hapd)) @@ -408,17 +486,6 @@ skip_mask_ext: wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); - res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); - if (res == 0) - return 0; - - if (res < 0) { - wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " - MACSTR " for start address " MACSTR ".", - MAC2STR(mask), MAC2STR(hapd->own_addr)); - return -1; - } - if (!auto_addr) return 0; @@ -452,6 +519,86 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a) } +#ifndef CONFIG_NO_RADIUS + +static int hostapd_das_nas_mismatch(struct hostapd_data *hapd, + struct radius_das_attrs *attr) +{ + /* TODO */ + return 0; +} + + +static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd, + struct radius_das_attrs *attr) +{ + struct sta_info *sta = NULL; + char buf[128]; + + if (attr->sta_addr) + sta = ap_get_sta(hapd, attr->sta_addr); + + if (sta == NULL && attr->acct_session_id && + attr->acct_session_id_len == 17) { + for (sta = hapd->sta_list; sta; sta = sta->next) { + os_snprintf(buf, sizeof(buf), "%08X-%08X", + sta->acct_session_id_hi, + sta->acct_session_id_lo); + if (os_memcmp(attr->acct_session_id, buf, 17) == 0) + break; + } + } + + if (sta == NULL && attr->cui) { + for (sta = hapd->sta_list; sta; sta = sta->next) { + struct wpabuf *cui; + cui = ieee802_1x_get_radius_cui(sta->eapol_sm); + if (cui && wpabuf_len(cui) == attr->cui_len && + os_memcmp(wpabuf_head(cui), attr->cui, + attr->cui_len) == 0) + break; + } + } + + if (sta == NULL && attr->user_name) { + for (sta = hapd->sta_list; sta; sta = sta->next) { + u8 *identity; + size_t identity_len; + identity = ieee802_1x_get_identity(sta->eapol_sm, + &identity_len); + if (identity && + identity_len == attr->user_name_len && + os_memcmp(identity, attr->user_name, identity_len) + == 0) + break; + } + } + + return sta; +} + + +static enum radius_das_res +hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta; + + if (hostapd_das_nas_mismatch(hapd, attr)) + return RADIUS_DAS_NAS_MISMATCH; + + sta = hostapd_das_find_sta(hapd, attr); + if (sta == NULL) + return RADIUS_DAS_SESSION_NOT_FOUND; + + hostapd_drv_sta_deauth(hapd, sta->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); + + return RADIUS_DAS_SUCCESS; +} + +#endif /* CONFIG_NO_RADIUS */ /** @@ -495,14 +642,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hapd->interface_added = 1; if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, hapd->conf->iface, hapd->own_addr, hapd, - &hapd->drv_priv, force_ifname, if_addr)) { + &hapd->drv_priv, force_ifname, if_addr, + hapd->conf->bridge[0] ? hapd->conf->bridge : + NULL)) { wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" MACSTR ")", MAC2STR(hapd->own_addr)); return -1; } } - hostapd_flush_old_stations(hapd); + if (conf->wmm_enabled < 0) + conf->wmm_enabled = hapd->iconf->ieee80211n; + + hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_set_privacy(hapd, 0); hostapd_broadcast_wep_clear(hapd); @@ -535,14 +687,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) set_ssid = 0; conf->ssid.ssid_len = ssid_len; os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); - conf->ssid.ssid[conf->ssid.ssid_len] = '\0'; } if (!hostapd_drv_none(hapd)) { wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR - " and ssid '%s'", + " and ssid \"%s\"", hapd->conf->iface, MAC2STR(hapd->own_addr), - hapd->conf->ssid.ssid); + wpa_ssid_txt(hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len)); } if (hostapd_setup_wpa_psk(conf)) { @@ -552,7 +704,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) /* Set SSID for the kernel driver (to be used in beacon and probe * response frames) */ - if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid, + if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid, conf->ssid.ssid_len)) { wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); return -1; @@ -566,6 +718,27 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); return -1; } + + if (hapd->conf->radius_das_port) { + struct radius_das_conf das_conf; + os_memset(&das_conf, 0, sizeof(das_conf)); + das_conf.port = hapd->conf->radius_das_port; + das_conf.shared_secret = hapd->conf->radius_das_shared_secret; + das_conf.shared_secret_len = + hapd->conf->radius_das_shared_secret_len; + das_conf.client_addr = &hapd->conf->radius_das_client_addr; + das_conf.time_window = hapd->conf->radius_das_time_window; + das_conf.require_event_timestamp = + hapd->conf->radius_das_require_event_timestamp; + das_conf.ctx = hapd; + das_conf.disconnect = hostapd_das_disconnect; + hapd->radius_das = radius_das_init(&das_conf); + if (hapd->radius_das == NULL) { + wpa_printf(MSG_ERROR, "RADIUS DAS initialization " + "failed."); + return -1; + } + } #endif /* CONFIG_NO_RADIUS */ if (hostapd_acl_init(hapd)) { @@ -598,8 +771,16 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (hapd->iface->ctrl_iface_init && - hapd->iface->ctrl_iface_init(hapd)) { +#ifdef CONFIG_INTERWORKING + if (gas_serv_init(hapd)) { + wpa_printf(MSG_ERROR, "GAS server initialization failed"); + return -1; + } +#endif /* CONFIG_INTERWORKING */ + + if (hapd->iface->interfaces && + hapd->iface->interfaces->ctrl_iface_init && + hapd->iface->interfaces->ctrl_iface_init(hapd)) { wpa_printf(MSG_ERROR, "Failed to setup control interface"); return -1; } @@ -611,6 +792,12 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) ieee802_11_set_beacon(hapd); + if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) + return -1; + + if (hapd->driver && hapd->driver->set_operstate) + hapd->driver->set_operstate(hapd->drv_priv, 1); + return 0; } @@ -624,9 +811,6 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface) for (i = 0; i < NUM_TX_QUEUES; i++) { p = &iface->conf->tx_queue[i]; - if (!p->configured) - continue; - if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, p->cwmax, p->burst)) { wpa_printf(MSG_DEBUG, "Failed to set TX queue " @@ -717,6 +901,17 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) } } + if (iface->current_mode) { + if (hostapd_prepare_rates(iface, iface->current_mode)) { + wpa_printf(MSG_ERROR, "Failed to prepare rates " + "table."); + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "Failed to prepare rates table."); + return -1; + } + } + if (hapd->iconf->rts_threshold > -1 && hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { wpa_printf(MSG_ERROR, "Could not set RTS threshold for " @@ -753,6 +948,20 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) return -1; } + /* + * WPS UPnP module can be initialized only when the "upnp_iface" is up. + * If "interface" and "upnp_iface" are the same (e.g., non-bridge + * mode), the interface is up only after driver_commit, so initialize + * WPS after driver_commit. + */ + for (j = 0; j < iface->num_bss; j++) { + if (hostapd_init_wps_complete(iface->bss[j])) + return -1; + } + + if (hapd->setup_complete_cb) + hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); + wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", iface->bss[0]->conf->iface); @@ -807,12 +1016,12 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, if (hapd == NULL) return NULL; - hostapd_set_driver_ops(&hapd->drv); hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; hapd->iconf = conf; hapd->conf = bss; hapd->iface = hapd_iface; hapd->driver = hapd->iconf->driver; + hapd->ctrl_sock = -1; return hapd; } @@ -829,7 +1038,8 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) for (j = 0; j < iface->num_bss; j++) { struct hostapd_data *hapd = iface->bss[j]; hostapd_free_stas(hapd); - hostapd_flush_old_stations(hapd); + hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); + hostapd_clear_wep(hapd); hostapd_cleanup(hapd); } } @@ -844,6 +1054,293 @@ void hostapd_interface_free(struct hostapd_iface *iface) } +#ifdef HOSTAPD + +void hostapd_interface_deinit_free(struct hostapd_iface *iface) +{ + const struct wpa_driver_ops *driver; + void *drv_priv; + if (iface == NULL) + return; + driver = iface->bss[0]->driver; + drv_priv = iface->bss[0]->drv_priv; + hostapd_interface_deinit(iface); + if (driver && driver->hapd_deinit && drv_priv) + driver->hapd_deinit(drv_priv); + hostapd_interface_free(iface); +} + + +int hostapd_enable_iface(struct hostapd_iface *hapd_iface) +{ + if (hapd_iface->bss[0]->drv_priv != NULL) { + wpa_printf(MSG_ERROR, "Interface %s already enabled", + hapd_iface->conf->bss[0].iface); + return -1; + } + + wpa_printf(MSG_DEBUG, "Enable interface %s", + hapd_iface->conf->bss[0].iface); + + if (hapd_iface->interfaces == NULL || + hapd_iface->interfaces->driver_init == NULL || + hapd_iface->interfaces->driver_init(hapd_iface) || + hostapd_setup_interface(hapd_iface)) { + hostapd_interface_deinit_free(hapd_iface); + return -1; + } + return 0; +} + + +int hostapd_reload_iface(struct hostapd_iface *hapd_iface) +{ + size_t j; + + wpa_printf(MSG_DEBUG, "Reload interface %s", + hapd_iface->conf->bss[0].iface); + for (j = 0; j < hapd_iface->num_bss; j++) { + hostapd_flush_old_stations(hapd_iface->bss[j], + WLAN_REASON_PREV_AUTH_NOT_VALID); + +#ifndef CONFIG_NO_RADIUS + /* TODO: update dynamic data based on changed configuration + * items (e.g., open/close sockets, etc.) */ + radius_client_flush(hapd_iface->bss[j]->radius, 0); +#endif /* CONFIG_NO_RADIUS */ + + hostapd_reload_bss(hapd_iface->bss[j]); + } + return 0; +} + + +int hostapd_disable_iface(struct hostapd_iface *hapd_iface) +{ + size_t j; + struct hostapd_bss_config *bss; + const struct wpa_driver_ops *driver; + void *drv_priv; + + if (hapd_iface == NULL) + return -1; + bss = hapd_iface->bss[0]->conf; + driver = hapd_iface->bss[0]->driver; + drv_priv = hapd_iface->bss[0]->drv_priv; + + /* whatever hostapd_interface_deinit does */ + for (j = 0; j < hapd_iface->num_bss; j++) { + struct hostapd_data *hapd = hapd_iface->bss[j]; + hostapd_free_stas(hapd); + hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); + hostapd_clear_wep(hapd); + hostapd_free_hapd_data(hapd); + } + + if (driver && driver->hapd_deinit && drv_priv) { + driver->hapd_deinit(drv_priv); + hapd_iface->bss[0]->drv_priv = NULL; + } + + /* From hostapd_cleanup_iface: These were initialized in + * hostapd_setup_interface and hostapd_setup_interface_complete + */ + hostapd_cleanup_iface_partial(hapd_iface); + bss->wpa = 0; + bss->wpa_key_mgmt = -1; + bss->wpa_pairwise = -1; + + wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->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 */ + + /** * hostapd_new_assoc_sta - Notify that a new station associated with the AP * @hapd: Pointer to BSS data @@ -859,8 +1356,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, int reassoc) { if (hapd->tkip_countermeasures) { - hapd->drv.sta_deauth(hapd, sta->addr, - WLAN_REASON_MICHAEL_MIC_FAILURE); + hostapd_drv_sta_deauth(hapd, sta->addr, + WLAN_REASON_MICHAEL_MIC_FAILURE); return; } @@ -870,11 +1367,22 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->ieee802_11f) iapp_new_station(hapd->iapp, sta); +#ifdef CONFIG_P2P + if (sta->p2p_ie == NULL && !sta->no_p2p_set) { + sta->no_p2p_set = 1; + hapd->num_sta_no_p2p++; + if (hapd->num_sta_no_p2p == 1) + hostapd_p2p_non_p2p_sta_connected(hapd); + } +#endif /* CONFIG_P2P */ + /* Start accounting here, if IEEE 802.1X and WPA are not used. * IEEE 802.1X/WPA code will start accounting after the station has * been authorized. */ - if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) + if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) { + os_get_time(&sta->connected_time); accounting_sta_start(hapd, sta); + } /* Start IEEE 802.1X authentication process for new stations */ ieee802_1x_new_station(hapd, sta); @@ -884,4 +1392,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); } else wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); + + wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " + "for " MACSTR " (%d seconds - ap_max_inactivity)", + __func__, MAC2STR(sta->addr), + hapd->conf->ap_max_inactivity); + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, + ap_handle_timer, hapd, sta); } |