aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2013-04-27 15:50:14 (GMT)
committerJouni Malinen <j@w1.fi>2014-01-27 19:10:56 (GMT)
commitdb6ae69e6b71d34bb03c8e75f78c6dc74985cda5 (patch)
tree626f3d701eb9dc8f49f2baf44da8e0b2af796861
parent93588780558074279f1603b2155d93bc76d71407 (diff)
downloadhostap-db6ae69e6b71d34bb03c8e75f78c6dc74985cda5.zip
hostap-db6ae69e6b71d34bb03c8e75f78c6dc74985cda5.tar.gz
hostap-db6ae69e6b71d34bb03c8e75f78c6dc74985cda5.tar.bz2
P2P NFC: Report connection handover as trigger for P2P
"NFC_REPORT_HANDOVER {INIT,RESP} P2P <req> <sel>" can now be used to report completed NFC negotiated connection handover in which the P2P alternative carrier was selected. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
-rw-r--r--src/p2p/p2p.c102
-rw-r--r--src/p2p/p2p.h21
-rw-r--r--src/p2p/p2p_go_neg.c41
-rw-r--r--src/p2p/p2p_i.h3
-rw-r--r--src/wps/wps.c1
-rw-r--r--src/wps/wps_registrar.c30
-rw-r--r--wpa_supplicant/ap.c46
-rw-r--r--wpa_supplicant/ap.h2
-rw-r--r--wpa_supplicant/ctrl_iface.c6
-rw-r--r--wpa_supplicant/p2p_supplicant.c280
-rw-r--r--wpa_supplicant/p2p_supplicant.h3
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h7
12 files changed, 531 insertions, 11 deletions
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index ae3ba85..67bd859 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4421,4 +4421,106 @@ struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p)
return p2p_build_nfc_handover(p2p);
}
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params)
+{
+ struct p2p_message msg;
+ struct p2p_device *dev;
+ const u8 *p2p_dev_addr;
+ int peer_go = 0;
+
+ params->next_step = NO_ACTION;
+
+ if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len,
+ params->p2p_attr, params->p2p_len, &msg)) {
+ p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.p2p_device_addr)
+ p2p_dev_addr = msg.p2p_device_addr;
+ else if (msg.device_id)
+ p2p_dev_addr = msg.device_id;
+ else {
+ p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.oob_dev_password) {
+ os_memcpy(params->oob_dev_pw, msg.oob_dev_password,
+ msg.oob_dev_password_len);
+ params->oob_dev_pw_len = msg.oob_dev_password_len;
+ }
+
+ dev = p2p_create_device(p2p, p2p_dev_addr);
+ if (dev == NULL) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ params->peer = &dev->info;
+
+ os_get_reltime(&dev->last_seen);
+ dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+ p2p_copy_wps_info(p2p, dev, 0, &msg);
+
+ if (msg.oob_go_neg_channel) {
+ int freq;
+ if (msg.oob_go_neg_channel[3] == 0 &&
+ msg.oob_go_neg_channel[4] == 0)
+ freq = 0;
+ else
+ freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3],
+ msg.oob_go_neg_channel[4]);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+ } else {
+ p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
+ dev->oob_go_neg_freq = freq;
+ }
+
+ if (!params->sel) {
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Own listen channel not known");
+ return -1;
+ }
+ p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz",
+ freq);
+ dev->oob_go_neg_freq = freq;
+ }
+
+ if (msg.oob_go_neg_channel[5] == P2P_GO_IN_A_GROUP)
+ peer_go = 1;
+ }
+
+ p2p_parse_free(&msg);
+
+ if (dev->flags & P2P_DEV_USER_REJECTED) {
+ p2p_dbg(p2p, "Do not report rejected device");
+ return 0;
+ }
+
+ if (!(dev->flags & P2P_DEV_REPORTED)) {
+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info,
+ !(dev->flags & P2P_DEV_REPORTED_ONCE));
+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
+ }
+
+ if (peer_go)
+ params->next_step = JOIN_GROUP;
+ else if (p2p->num_groups > 0)
+ params->next_step = AUTH_JOIN;
+ else if (params->sel)
+ params->next_step = INIT_GO_NEG;
+ else
+ params->next_step = RESP_GO_NEG;
+
+ return 0;
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 1dc71fa..2a64ca5 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -9,6 +9,8 @@
#ifndef P2P_H
#define P2P_H
+#include "wps/wps_defs.h"
+
/**
* P2P_MAX_REG_CLASSES - Maximum number of regulatory classes
*/
@@ -1900,4 +1902,23 @@ const char * p2p_get_state_txt(struct p2p_data *p2p);
struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p);
struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p);
+struct p2p_nfc_params {
+ int sel;
+ const u8 *wsc_attr;
+ size_t wsc_len;
+ const u8 *p2p_attr;
+ size_t p2p_len;
+
+ enum {
+ NO_ACTION, JOIN_GROUP, AUTH_JOIN, INIT_GO_NEG, RESP_GO_NEG
+ } next_step;
+ struct p2p_peer_info *peer;
+ u8 oob_dev_pw[WPS_OOB_PUBKEY_HASH_LEN + 2 +
+ WPS_OOB_DEVICE_PASSWORD_LEN];
+ size_t oob_dev_pw_len;
+};
+
+int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
+ struct p2p_nfc_params *params);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f23cff6..76436f5 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -217,6 +217,8 @@ int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev)
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (dev->oob_go_neg_freq > 0)
+ freq = dev->oob_go_neg_freq;
if (freq <= 0) {
p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
MACSTR " to send GO Negotiation Request",
@@ -614,7 +616,11 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
- } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) {
+ } else if (dev == NULL ||
+ (dev->wps_method == WPS_NOT_READY &&
+ (p2p->authorized_oob_dev_pw_id == 0 ||
+ p2p->authorized_oob_dev_pw_id !=
+ msg.dev_password_id))) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
@@ -701,6 +707,28 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
}
break;
default:
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(
+ dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
+#ifdef CONFIG_WPS_NFC
+ if (p2p->authorized_oob_dev_pw_id &&
+ msg.dev_password_id ==
+ p2p->authorized_oob_dev_pw_id) {
+ p2p_dbg(p2p, "Using static handover with our device password from NFC Tag");
+ dev->wps_method = WPS_NFC;
+ dev->oob_pw_id = p2p->authorized_oob_dev_pw_id;
+ break;
+ }
+#endif /* CONFIG_WPS_NFC */
p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
@@ -1026,6 +1054,17 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
}
break;
default:
+ if (msg.dev_password_id &&
+ msg.dev_password_id == dev->oob_pw_id) {
+ p2p_dbg(p2p, "Peer using NFC");
+ if (dev->wps_method != WPS_NFC) {
+ p2p_dbg(p2p, "We have wps_method=%s -> incompatible",
+ p2p_wps_method_str(dev->wps_method));
+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
+ goto fail;
+ }
+ break;
+ }
p2p_dbg(p2p, "Unsupported Device Password ID %d",
msg.dev_password_id);
status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 2101841..1150d40 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -27,6 +27,7 @@ struct p2p_device {
struct dl_list list;
struct os_reltime last_seen;
int listen_freq;
+ int oob_go_neg_freq;
enum p2p_wps_method wps_method;
u16 oob_pw_id;
@@ -465,6 +466,8 @@ struct p2p_data {
struct wpabuf *wfd_assoc_bssid;
struct wpabuf *wfd_coupled_sink_info;
#endif /* CONFIG_WIFI_DISPLAY */
+
+ u16 authorized_oob_dev_pw_id;
};
/**
diff --git a/src/wps/wps.c b/src/wps/wps.c
index a38a6db..b40a68a 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -178,7 +178,6 @@ void wps_deinit(struct wps_data *data)
wps_device_data_free(&data->peer_dev);
os_free(data->new_ap_settings);
dh5_free(data->dh_ctx);
- os_free(data->nfc_pw_token);
os_free(data);
}
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index f8f2ae1..56b8e23 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -31,6 +31,7 @@
struct wps_nfc_pw_token {
struct dl_list list;
u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
+ unsigned int peer_pk_hash_known:1;
u16 pw_id;
u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1];
size_t dev_pw_len;
@@ -1822,7 +1823,8 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
}
#ifdef CONFIG_WPS_NFC
- if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob) {
+ if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob &&
+ wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
/*
* Use abbreviated handshake since public key hash allowed
* Enrollee to validate our public key similarly to how Enrollee
@@ -2585,7 +2587,7 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
wps->dev_pw_id, wps->wps, wps->wps->registrar);
token = wps_get_nfc_pw_token(
&wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
- if (token) {
+ if (token && token->peer_pk_hash_known) {
wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
"Password Token");
dl_list_del(&token->list);
@@ -2602,6 +2604,10 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
return WPS_CONTINUE;
}
+ } else if (token) {
+ wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
+ "Password Token (no peer PK hash)");
+ wps->nfc_pw_token = token;
}
}
#endif /* CONFIG_WPS_NFC */
@@ -3543,13 +3549,23 @@ int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
return -1;
+ if (pw_id == DEV_PW_NFC_CONNECTION_HANDOVER &&
+ (pubkey_hash == NULL || !pk_hash_provided_oob)) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected NFC Password Token "
+ "addition - missing public key hash");
+ return -1;
+ }
+
wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, pw_id);
token = os_zalloc(sizeof(*token));
if (token == NULL)
return -1;
- os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
+ token->peer_pk_hash_known = pubkey_hash != NULL;
+ if (pubkey_hash)
+ os_memcpy(token->pubkey_hash, pubkey_hash,
+ WPS_OOB_PUBKEY_HASH_LEN);
token->pw_id = pw_id;
token->pk_hash_provided_oob = pk_hash_provided_oob;
if (dev_pw) {
@@ -3615,6 +3631,14 @@ void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
wps_registrar_remove_authorized_mac(reg,
(u8 *) "\xff\xff\xff\xff\xff\xff");
wps_registrar_selected_registrar_changed(reg, 0);
+
+ /*
+ * Free the NFC password token if it was used only for a single protocol
+ * run. The static handover case uses the same password token multiple
+ * times, so do not free that case here.
+ */
+ if (token->peer_pk_hash_known)
+ os_free(token);
}
#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 0f80249..9a09e3e 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "crypto/dh_group5.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
@@ -1152,3 +1153,48 @@ int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
return 0;
}
+
+
+#ifdef CONFIG_WPS_NFC
+int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
+ const struct wpabuf *pw, const u8 *pubkey_hash)
+{
+ struct hostapd_data *hapd;
+ struct wps_context *wps;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ wps = hapd->wps;
+
+ if (wpa_s->parent->conf->wps_nfc_dh_pubkey == NULL ||
+ wpa_s->parent->conf->wps_nfc_dh_privkey == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC DH key known");
+ return -1;
+ }
+
+ dh5_free(wps->dh_ctx);
+ wpabuf_free(wps->dh_pubkey);
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_privkey);
+ wps->dh_pubkey = wpabuf_dup(
+ wpa_s->parent->conf->wps_nfc_dh_pubkey);
+ if (wps->dh_privkey == NULL || wps->dh_pubkey == NULL) {
+ wps->dh_ctx = NULL;
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
+ return -1;
+ }
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
+ if (wps->dh_ctx == NULL)
+ return -1;
+
+ return wps_registrar_add_nfc_pw_token(hapd->wps->registrar, pubkey_hash,
+ pw_id,
+ pw ? wpabuf_head(pw) : NULL,
+ pw ? wpabuf_len(pw) : 0, 1);
+}
+#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 9138717..8aa5ffa 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -72,5 +72,7 @@ wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
int wpas_ap_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
const struct wpabuf *req,
const struct wpabuf *sel);
+int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
+ const struct wpabuf *pw, const u8 *pubkey_hash);
#endif /* AP_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index cde9c46..3bfcc90 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1193,6 +1193,12 @@ static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
ret = wpas_ap_wps_nfc_report_handover(wpa_s, req, sel);
if (ret < 0)
ret = wpas_er_wps_nfc_report_handover(wpa_s, req, sel);
+ } else if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 1, req, sel);
+ } else if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "P2P") == 0)
+ {
+ ret = wpas_p2p_nfc_report_handover(wpa_s, 0, req, sel);
} else {
wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
"reported: role=%s type=%s", role, type);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index e61d5ce..4e9dcc3 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1107,9 +1107,20 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
res->ssid, res->ssid_len);
wpa_supplicant_ap_deinit(wpa_s);
wpas_copy_go_neg_results(wpa_s, res);
- if (res->wps_method == WPS_PBC)
+ if (res->wps_method == WPS_PBC) {
wpas_wps_start_pbc(wpa_s, res->peer_interface_addr, 1);
- else {
+#ifdef CONFIG_WPS_NFC
+ } else if (res->wps_method == WPS_NFC) {
+ wpas_wps_start_nfc(wpa_s, res->peer_interface_addr,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_oob_dev_pw_id, 1,
+ wpa_s->parent->p2p_oob_dev_pw_id ==
+ DEV_PW_NFC_CONNECTION_HANDOVER ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash :
+ NULL,
+ NULL, 0);
+#endif /* CONFIG_WPS_NFC */
+ } else {
u16 dev_pw_id = DEV_PW_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
@@ -1233,10 +1244,24 @@ static void p2p_go_configured(void *ctx, void *data)
"filtering");
return;
}
- if (params->wps_method == WPS_PBC)
+ if (params->wps_method == WPS_PBC) {
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
params->peer_device_addr);
- else if (wpa_s->p2p_pin[0])
+#ifdef CONFIG_WPS_NFC
+ } else if (params->wps_method == WPS_NFC) {
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->p2p_oob_dev_pw) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+ return;
+ }
+ wpas_ap_wps_add_nfc_pw(
+ wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+#endif /* CONFIG_WPS_NFC */
+ } else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
@@ -3848,6 +3873,9 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
}
eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
}
@@ -3942,7 +3970,9 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0,
- wpa_s->p2p_pd_before_go_neg, pref_freq, 0);
+ wpa_s->p2p_pd_before_go_neg, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -3959,7 +3989,9 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s,
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0, pref_freq, 0);
+ ssid ? ssid->ssid_len : 0, pref_freq,
+ wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
+ 0);
}
@@ -7025,4 +7057,240 @@ struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
return wpas_p2p_nfc_handover(ndef, wsc, p2p);
}
+
+static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate join-group based on NFC "
+ "connection handover");
+ return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
+ 0, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Authorize join-group based on NFC "
+ "connection handover");
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (ssid == NULL)
+ continue;
+ if (ssid->mode != WPAS_MODE_P2P_GO)
+ continue;
+ if (wpa_s->ap_iface == NULL)
+ continue;
+ break;
+ }
+ if (wpa_s == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not find GO interface");
+ return -1;
+ }
+
+ if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ DEV_PW_NFC_CONNECTION_HANDOVER &&
+ !wpa_s->parent->p2p_oob_dev_pw) {
+ wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
+ return -1;
+ }
+ return wpas_ap_wps_add_nfc_pw(
+ wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
+ wpa_s->parent->p2p_oob_dev_pw,
+ wpa_s->parent->p2p_peer_oob_pk_hash_known ?
+ wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+}
+
+
+static int wpas_p2p_nfc_init_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Initiate GO Negotiation based on NFC "
+ "connection handover");
+ return wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
+ 0, -1, 0, 1, 1);
+}
+
+
+static int wpas_p2p_nfc_resp_go_neg(struct wpa_supplicant *wpa_s,
+ struct p2p_nfc_params *params)
+{
+ int res;
+
+ wpa_printf(MSG_DEBUG, "P2P: Authorize GO Negotiation based on NFC "
+ "connection handover");
+ res = wpas_p2p_connect(wpa_s, params->peer->p2p_device_addr, NULL,
+ WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
+ 0, -1, 0, 1, 1);
+ if (res)
+ return res;
+
+ res = wpas_p2p_listen(wpa_s, 60);
+ if (res) {
+ p2p_unauthorize(wpa_s->global->p2p,
+ params->peer->p2p_device_addr);
+ }
+
+ return res;
+}
+
+
+static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data,
+ int sel, int tag)
+{
+ const u8 *pos, *end;
+ u16 len, id;
+ struct p2p_nfc_params params;
+ int res;
+
+ os_memset(&params, 0, sizeof(params));
+ params.sel = sel;
+
+ wpa_hexdump_buf(MSG_DEBUG, "P2P: Received NFC tag payload", data);
+
+ pos = wpabuf_head(data);
+ end = pos + wpabuf_len(data);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of WSC "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
+ "attributes");
+ return -1;
+ }
+ params.wsc_attr = pos;
+ params.wsc_len = len;
+ pos += len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for Length of P2P "
+ "attributes");
+ return -1;
+ }
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
+ "attributes");
+ return -1;
+ }
+ params.p2p_attr = pos;
+ params.p2p_len = len;
+ pos += len;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: WSC attributes",
+ params.wsc_attr, params.wsc_len);
+ wpa_hexdump(MSG_DEBUG, "P2P: P2P attributes",
+ params.p2p_attr, params.p2p_len);
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "P2P: Ignored extra data after P2P attributes",
+ pos, end - pos);
+ }
+
+ res = p2p_process_nfc_connection_handover(wpa_s->global->p2p, &params);
+ if (res)
+ return res;
+
+ wpabuf_free(wpa_s->p2p_oob_dev_pw);
+ wpa_s->p2p_oob_dev_pw = NULL;
+
+ if (params.oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "P2P: No peer OOB Dev Pw "
+ "received");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_printf(MSG_DEBUG, "P2P: Peer OOB Dev Pw %u", id);
+ wpa_hexdump(MSG_DEBUG, "P2P: Peer OOB Public Key hash",
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ os_memcpy(wpa_s->p2p_peer_oob_pubkey_hash,
+ params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
+ wpa_s->p2p_peer_oob_pk_hash_known = 1;
+
+ if (tag) {
+ if (id < 0x10) {
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
+ "peer OOB Device Password Id %u", id);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Static handover - use peer OOB "
+ "Device Password Id %u", id);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: Peer OOB Device Password",
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ wpa_s->p2p_oob_dev_pw_id = id;
+ wpa_s->p2p_oob_dev_pw = wpabuf_alloc_copy(
+ params.oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN + 2,
+ params.oob_dev_pw_len -
+ WPS_OOB_PUBKEY_HASH_LEN - 2);
+ if (wpa_s->p2p_oob_dev_pw == NULL)
+ return -1;
+
+ if (wpa_s->conf->wps_nfc_dh_pubkey == NULL &&
+ wps_nfc_gen_dh(&wpa_s->conf->wps_nfc_dh_pubkey,
+ &wpa_s->conf->wps_nfc_dh_privkey) < 0)
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Using abbreviated WPS handshake "
+ "without Device Password");
+ wpa_s->p2p_oob_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ }
+
+ switch (params.next_step) {
+ case NO_ACTION:
+ return 0;
+ case JOIN_GROUP:
+ return wpas_p2p_nfc_join_group(wpa_s, &params);
+ case AUTH_JOIN:
+ return wpas_p2p_nfc_auth_join(wpa_s, &params);
+ case INIT_GO_NEG:
+ return wpas_p2p_nfc_init_go_neg(wpa_s, &params);
+ case RESP_GO_NEG:
+ /* TODO: use own OOB Dev Pw */
+ return wpas_p2p_nfc_resp_go_neg(wpa_s, &params);
+ }
+
+ return -1;
+}
+
+
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct wpabuf *tmp;
+ int ret;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "NFC: P2P connection handover reported");
+
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Req",
+ wpabuf_head(req), wpabuf_len(req));
+ wpa_hexdump_ascii(MSG_DEBUG, "NFC: Sel",
+ wpabuf_head(sel), wpabuf_len(sel));
+ tmp = ndef_parse_p2p(init ? sel : req);
+ if (tmp == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Could not parse NDEF");
+ return -1;
+ }
+
+ ret = wpas_p2p_nfc_connection_handover(wpa_s, tmp, init, 0);
+ wpabuf_free(tmp);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 17e7bae..0f09d17 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -152,6 +152,9 @@ struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s,
int ndef);
struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s,
int ndef, int tag);
+int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
#ifdef CONFIG_P2P
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 68995fc..df07f46 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -12,6 +12,7 @@
#include "utils/list.h"
#include "common/defs.h"
#include "common/sae.h"
+#include "wps/wps_defs.h"
#include "config_ssid.h"
extern const char *wpa_supplicant_version;
@@ -713,6 +714,7 @@ struct wpa_supplicant {
unsigned int p2p_go_group_formation_completed:1;
unsigned int waiting_presence_resp;
int p2p_first_connection_timeout;
+ unsigned int p2p_peer_oob_pk_hash_known:1;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -722,6 +724,11 @@ struct wpa_supplicant {
struct wpa_radio_work *p2p_scan_work;
struct wpa_radio_work *p2p_listen_work;
struct wpa_radio_work *p2p_send_action_work;
+
+ u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
+ struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group
+ * formation */
+ u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;