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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2013-03-31 11:26:29 +03:00
parent 8970bae806
commit ccdff94035
2 changed files with 135 additions and 11 deletions

View file

@ -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;

View file

@ -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)