From ccdff940359a7123190cb7c50fdc01d60df0b0a0 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 31 Mar 2013 11:26:29 +0300 Subject: [PATCH] WPS AP: Add support for reconfiguration with in-memory config This allows WPS to update AP configuration in the case no hostapd configuration file is used (i.e., dynamic configuration through the control interface). Signed-hostap: Jouni Malinen --- src/ap/hostapd.c | 36 ++++++++++---- src/ap/wps_hostapd.c | 110 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 11 deletions(-) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 92fda5693..a0ac38c4c 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -108,19 +108,10 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) } -int hostapd_reload_config(struct hostapd_iface *iface) +static void hostapd_clear_old(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. @@ -136,6 +127,31 @@ int hostapd_reload_config(struct hostapd_iface *iface) radius_client_flush(iface->bss[j]->radius, 0); #endif /* CONFIG_NO_RADIUS */ } +} + + +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->config_fname == NULL) { + /* Only in-memory config in use - assume it has been updated */ + hostapd_clear_old(iface); + for (j = 0; j < iface->num_bss; j++) + hostapd_reload_bss(iface->bss[j]); + return 0; + } + + 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; + + hostapd_clear_old(iface); oldconf = hapd->iconf; iface->conf = newconf; diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index e017972de..b6d9c20bc 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -277,6 +277,114 @@ static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr, } +static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd, + const struct wps_credential *cred) +{ + struct hostapd_bss_config *bss = hapd->conf; + + wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration"); + + bss->wps_state = 2; + if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) { + os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len); + bss->ssid.ssid_len = cred->ssid_len; + bss->ssid.ssid_set = 1; + } + + if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && + (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) + bss->wpa = 3; + else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) + bss->wpa = 2; + else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) + bss->wpa = 1; + else + bss->wpa = 0; + + if (bss->wpa) { + if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) + bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; + if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) + bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; + + bss->wpa_pairwise = 0; + if (cred->encr_type & WPS_ENCR_AES) + bss->wpa_pairwise |= WPA_CIPHER_CCMP; + if (cred->encr_type & WPS_ENCR_TKIP) + bss->wpa_pairwise |= WPA_CIPHER_TKIP; + bss->rsn_pairwise = bss->wpa_pairwise; + bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, + bss->wpa_pairwise, + bss->rsn_pairwise); + + if (cred->key_len >= 8 && cred->key_len < 64) { + os_free(bss->ssid.wpa_passphrase); + bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1); + if (bss->ssid.wpa_passphrase) + os_memcpy(bss->ssid.wpa_passphrase, cred->key, + cred->key_len); + os_free(bss->ssid.wpa_psk); + bss->ssid.wpa_psk = NULL; + } else if (cred->key_len == 64) { + os_free(bss->ssid.wpa_psk); + bss->ssid.wpa_psk = + os_zalloc(sizeof(struct hostapd_wpa_psk)); + if (bss->ssid.wpa_psk && + hexstr2bin((const char *) cred->key, + bss->ssid.wpa_psk->psk, PMK_LEN) == 0) { + bss->ssid.wpa_psk->group = 1; + os_free(bss->ssid.wpa_passphrase); + bss->ssid.wpa_passphrase = NULL; + } + } + bss->auth_algs = 1; + } else { + if ((cred->auth_type & WPS_AUTH_OPEN) && + (cred->auth_type & WPS_AUTH_SHARED)) + bss->auth_algs = 3; + else if (cred->auth_type & WPS_AUTH_SHARED) + bss->auth_algs = 2; + else + bss->auth_algs = 1; + if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 && + cred->key_idx <= 4) { + struct hostapd_wep_keys *wep = &bss->ssid.wep; + int idx = cred->key_idx; + if (idx) + idx--; + wep->idx = idx; + if (cred->key_len == 10 || cred->key_len == 26) { + os_free(wep->key[idx]); + wep->key[idx] = os_malloc(cred->key_len / 2); + if (wep->key[idx] == NULL || + hexstr2bin((const char *) cred->key, + wep->key[idx], + cred->key_len / 2)) + return -1; + wep->len[idx] = cred->key_len / 2; + } else { + os_free(wep->key[idx]); + wep->key[idx] = os_malloc(cred->key_len); + if (wep->key[idx] == NULL) + return -1; + os_memcpy(wep->key[idx], cred->key, + cred->key_len); + wep->len[idx] = cred->key_len; + } + wep->keys_set = 1; + } + } + + /* Schedule configuration reload after short period of time to allow + * EAP-WSC to be finished. + */ + eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, + NULL); + + return 0; +} + + static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) { const struct wps_credential *cred = ctx; @@ -344,7 +452,7 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) hapd->wps->wps_state = WPS_STATE_CONFIGURED; if (hapd->iface->config_fname == NULL) - return 0; + return hapd_wps_reconfig_in_memory(hapd, cred); len = os_strlen(hapd->iface->config_fname) + 5; tmp_fname = os_malloc(len); if (tmp_fname == NULL)