/*
* hostapd / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2010, 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
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
const u8 *ie, size_t ie_len);
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
}
+static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ if (hapd->conf->ap_setup_locked)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+ hapd->wps->ap_setup_locked = 0;
+ wps_registrar_update_ie(hapd->wps->registrar);
+}
+
+
static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
struct wps_event_pwd_auth_fail *data)
{
- FILE *f;
-
if (!data->enrollee || hapd->conf->ap_pin == NULL)
return;
/*
* Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
- * if this happens multiple times.
+ * for some time if this happens multiple times to slow down brute
+ * force attacks.
*/
hapd->ap_pin_failures++;
- if (hapd->ap_pin_failures < 4)
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+ hapd->ap_pin_failures);
+ if (hapd->ap_pin_failures < 3)
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
wps_registrar_update_ie(hapd->wps->registrar);
- if (hapd->conf->wps_cred_processing == 1)
- return;
-
- f = fopen(hapd->iface->config_fname, "a");
- if (f == NULL) {
- wpa_printf(MSG_WARNING, "WPS: Could not append to the current "
- "configuration file");
- return;
+ if (!hapd->conf->ap_setup_locked) {
+ if (hapd->ap_pin_lockout_time == 0)
+ hapd->ap_pin_lockout_time = 60;
+ else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
+ (hapd->ap_pin_failures % 3) == 0)
+ hapd->ap_pin_lockout_time *= 2;
+
+ wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
+ hapd->ap_pin_lockout_time);
+ eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+ eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
+ hostapd_wps_reenable_ap_pin, hapd,
+ NULL);
}
- fprintf(f, "# WPS AP Setup Locked based on possible attack\n");
- fprintf(f, "ap_setup_locked=1\n");
- fclose(f);
-
- /* TODO: dualband AP may need to update multiple configuration files */
-
- wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+ /* TODO: dualband AP may need to update other interfaces */
}
}
+static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
+{
+ const u8 **uuid = ctx;
+ size_t j;
+
+ if (iface == NULL)
+ return 0;
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd = iface->bss[j];
+ if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+ *uuid = hapd->wps->uuid;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static const u8 * get_own_uuid(struct hostapd_iface *iface)
+{
+ const u8 *uuid;
+ if (iface->for_each_interface == NULL)
+ return NULL;
+ uuid = NULL;
+ iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid);
+ return uuid;
+}
+
+
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf)
{
wps->wps_state = hapd->conf->wps_state;
wps->ap_setup_locked = hapd->conf->ap_setup_locked;
if (is_nil_uuid(hapd->conf->uuid)) {
- uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
- wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
- wps->uuid, UUID_LEN);
- } else
+ const u8 *uuid;
+ uuid = get_own_uuid(hapd->iface);
+ if (uuid) {
+ os_memcpy(wps->uuid, uuid, UUID_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
+ "interface", wps->uuid, UUID_LEN);
+ } else {
+ uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+ "address", wps->uuid, UUID_LEN);
+ }
+ } else {
os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
+ wps->uuid, UUID_LEN);
+ }
wps->ssid_len = hapd->conf->ssid.ssid_len;
os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
wps->ap = 1;
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
+ eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
if (hapd->wps == NULL)
return;
#ifdef CONFIG_WPS_UPNP
}
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
- const char *pin, int timeout)
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+ const char *uuid, const char *pin, int timeout)
{
u8 u[UUID_LEN];
int any = 0;
any = 1;
else if (uuid_str2bin(uuid, u))
return -1;
- return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
+ return wps_registrar_add_pin(hapd->wps->registrar, addr,
+ any ? NULL : u,
(const u8 *) pin, os_strlen(pin),
timeout);
}
if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
- hostapd_wps_add_pin(hapd, "any",
+ hostapd_wps_add_pin(hapd, NULL, "any",
wpabuf_head(wps->oob_conf.dev_password), 0) <
0)
goto error;
wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
if (wps_ie == NULL)
return 0;
+ if (wps_validate_probe_req(wps_ie) < 0) {
+ wpabuf_free(wps_ie);
+ return 0;
+ }
if (wpabuf_len(wps_ie) > 0) {
- wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
+ int p2p_wildcard = 0;
+#ifdef CONFIG_P2P
+ if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+ os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+ P2P_WILDCARD_SSID_LEN) == 0)
+ p2p_wildcard = 1;
+#endif /* CONFIG_P2P */
+ wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
+ p2p_wildcard);
#ifdef CONFIG_WPS_UPNP
/* FIX: what exactly should be included in the WLANEvent?
* WPS attributes? Full ProbeReq frame? */
- upnp_wps_device_send_wlan_event(hapd->wps_upnp, addr,
- UPNP_WPS_WLANEVENT_TYPE_PROBE,
- wps_ie);
+ if (!p2p_wildcard)
+ upnp_wps_device_send_wlan_event(
+ hapd->wps_upnp, addr,
+ UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
#endif /* CONFIG_WPS_UPNP */
}
*/
sta = ap_get_sta(hapd, mac_addr);
+#ifndef CONFIG_WPS_STRICT
if (!sta) {
/*
* Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
break;
}
}
+#endif /* CONFIG_WPS_STRICT */
if (!sta) {
wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
return 0;
return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
}
+
+
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+ hostapd_wps_ap_pin_disable(hapd);
+}
+
+
+static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
+{
+ wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+ hapd->ap_pin_failures = 0;
+ hapd->conf->ap_setup_locked = 0;
+ if (hapd->wps->ap_setup_locked) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+ hapd->wps->ap_setup_locked = 0;
+ wps_registrar_update_ie(hapd->wps->registrar);
+ }
+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0,
+ hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = NULL;
+#ifdef CONFIG_WPS_UPNP
+ upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
+#endif /* CONFIG_WPS_UPNP */
+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+ unsigned int pin;
+ char pin_txt[9];
+
+ pin = wps_generate_pin();
+ os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin_txt);
+#ifdef CONFIG_WPS_UPNP
+ upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
+#endif /* CONFIG_WPS_UPNP */
+ hostapd_wps_ap_pin_enable(hapd, timeout);
+ return hapd->conf->ap_pin;
+}
+
+
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
+{
+ return hapd->conf->ap_pin;
+}
+
+
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+ int timeout)
+{
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin);
+ if (hapd->conf->ap_pin == NULL)
+ return -1;
+#ifdef CONFIG_WPS_UPNP
+ upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
+#endif /* CONFIG_WPS_UPNP */
+ hostapd_wps_ap_pin_enable(hapd, timeout);
+ return 0;
+}