WPS AP: Add support for reconfiguration with in-memory config
authorJouni Malinen <j@w1.fi>
Sun, 31 Mar 2013 08:26:29 +0000 (11:26 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 31 Mar 2013 09:34:35 +0000 (12:34 +0300)
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>

src/ap/hostapd.c
src/ap/wps_hostapd.c

index 92fda56..a0ac38c 100644 (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;
index e017972..b6d9c20 100644 (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)