/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
int disabled = wpa_s->current_ssid->disabled;
unsigned int freq = wpa_s->assoc_freq;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = NULL;
+ int use_fast_assoc = 0;
+
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
wpa_s->wps_freq = freq;
wpa_s->normal_scans = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+ "without a new scan can be used");
+ bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+ if (bss) {
+ struct wpabuf *wps;
+ struct wps_parse_attr attr;
+
+ wps = wpa_bss_get_vendor_ie_multi(bss,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_parse_msg(wps, &attr) == 0 &&
+ attr.wps_state &&
+ *attr.wps_state == WPS_STATE_CONFIGURED)
+ use_fast_assoc = 1;
+ wpabuf_free(wps);
+ }
+
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
return 1;
}
struct wpa_ssid *ssid;
struct wpa_bss *bss;
+ wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
if (bssid) {
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss && bss->freq > 0) {
wpa_s->known_wps_freq = 1;
wpa_s->wps_freq = bss->freq;
const char *uuid, const char *pin)
{
u8 u[UUID_LEN];
- int any = 0;
-
- if (os_strcmp(uuid, "any") == 0)
- any = 1;
- else if (uuid_str2bin(uuid, u))
+ const u8 *use_uuid = NULL;
+ u8 addr_buf[ETH_ALEN];
+
+ if (os_strcmp(uuid, "any") == 0) {
+ } else if (uuid_str2bin(uuid, u) == 0) {
+ use_uuid = u;
+ } else if (hwaddr_aton(uuid, addr_buf) == 0) {
+ use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+ if (use_uuid == NULL)
+ return -1;
+ } else
return -1;
return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
- any ? NULL : u,
+ use_uuid,
(const u8 *) pin, os_strlen(pin), 300);
}
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_pbc(wpa_s->wps_er, u);
+ return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
}
int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+ return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
os_strlen(pin));
}
-int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
- int id)
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+ struct wps_credential *cred)
{
- u8 u[UUID_LEN];
- struct wpa_ssid *ssid;
- struct wps_credential cred;
-
- if (uuid_str2bin(uuid, u))
- return -1;
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL || ssid->ssid == NULL)
- return -1;
-
- os_memset(&cred, 0, sizeof(cred));
+ os_memset(cred, 0, sizeof(*cred));
if (ssid->ssid_len > 32)
return -1;
- os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
- cred.ssid_len = ssid->ssid_len;
+ os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
+ cred->ssid_len = ssid->ssid_len;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+ cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- cred.encr_type = WPS_ENCR_AES;
+ cred->encr_type = WPS_ENCR_AES;
else
- cred.encr_type = WPS_ENCR_TKIP;
+ cred->encr_type = WPS_ENCR_TKIP;
if (ssid->passphrase) {
- cred.key_len = os_strlen(ssid->passphrase);
- if (cred.key_len >= 64)
+ cred->key_len = os_strlen(ssid->passphrase);
+ if (cred->key_len >= 64)
return -1;
- os_memcpy(cred.key, ssid->passphrase, cred.key_len);
+ os_memcpy(cred->key, ssid->passphrase, cred->key_len);
} else if (ssid->psk_set) {
- cred.key_len = 32;
- os_memcpy(cred.key, ssid->psk, 32);
+ cred->key_len = 32;
+ os_memcpy(cred->key, ssid->psk, 32);
} else
return -1;
} else {
- cred.auth_type = WPS_AUTH_OPEN;
- cred.encr_type = WPS_ENCR_NONE;
+ cred->auth_type = WPS_AUTH_OPEN;
+ cred->encr_type = WPS_ENCR_NONE;
}
- return wps_er_set_config(wpa_s->wps_er, u, &cred);
+
+ return 0;
+}
+
+
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+ int id)
+{
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+ struct wpa_ssid *ssid;
+ struct wps_credential cred;
+
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return -1;
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL || ssid->ssid == NULL)
+ return -1;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return -1;
+ return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
}
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
struct wps_credential cred;
size_t len;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
if (settings->ssid_hex == NULL || settings->auth == NULL ||
settings->encr == NULL || settings->key_hex == NULL)
else
return -1;
- return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
- os_strlen(pin), &cred);
+ return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+ (const u8 *) pin, os_strlen(pin), &cred);
}
int ndef, const char *uuid)
{
struct wpabuf *ret;
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
if (!wpa_s->wps_er)
return NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return NULL;
- ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
if (ndef && ret) {
struct wpabuf *tmp;
tmp = ndef_build_wifi(ret);
#ifdef CONFIG_WPS_NFC
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *ret;
+ struct wps_credential cred;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return NULL;
+
+ ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+ if (id_str) {
+ int id;
+ char *end = NULL;
+ struct wpa_ssid *ssid;
+
+ id = strtol(id_str, &end, 10);
+ if (end && *end)
+ return NULL;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL)
+ return NULL;
+ return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+ }
+#endif /* CONFIG_WPS_ER */
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface)
+ return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+ return NULL;
+}
+
+
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
{
+ if (wpa_s->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ wpa_s->conf->wps_nfc_dev_pw_id,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ wpa_s->conf->wps_nfc_dev_pw);
+ }
+
return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
&wpa_s->conf->wps_nfc_dh_pubkey,
&wpa_s->conf->wps_nfc_dh_privkey,
return -1;
}
wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
- if (wps->dh_ctx == NULL)
+ if (wps->dh_ctx == NULL) {
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
return -1;
+ }
wpa_snprintf_hex_uppercase(pw, sizeof(pw),
wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
}
-struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr)
{
+ if (cr)
+ return ndef_build_wifi_hc(1);
return ndef_build_wifi_hr();
}
-struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s)
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, const char *uuid)
{
+#ifdef CONFIG_WPS_ER
+ struct wpabuf *ret;
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+
+ if (!wpa_s->wps_er)
+ return NULL;
+
+ if (uuid == NULL)
+ return NULL;
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return NULL;
+
+ /*
+ * Handover Select carrier record for WPS uses the same format as
+ * configuration token.
+ */
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+#else /* CONFIG_WPS_ER */
return NULL;
+#endif /* CONFIG_WPS_ER */
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid)
+{
+ struct wpabuf *ret;
+ if (!cr)
+ return NULL;
+ ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
+ if (ret)
+ return ret;
+ return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
}
return ret;
}
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+ return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
#endif /* CONFIG_WPS_NFC */