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>
This commit is contained in:
Jouni Malinen 2013-04-27 18:50:14 +03:00 committed by Jouni Malinen
parent 9358878055
commit db6ae69e6b
12 changed files with 531 additions and 11 deletions

View file

@ -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 */

View file

@ -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 */

View file

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

View file

@ -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;
};
/**

View file

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

View file

@ -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 */