From 8e9f53c367bc9500afbf7db6470d09790b4f740b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 8 Sep 2013 09:45:04 -0700 Subject: [PATCH] P2P NFC: Static handover with NFC Tag on client This adds a new P2P Invitation mechanism to invite a P2P Device with an NFC Tag to an already operating group when the GO with NFC Device reads the NFC Tag. The P2P Device with the NFC Tag will then accept invitation and connect to the group automatically using its OOB Device Password. Signed-hostap: Jouni Malinen --- src/p2p/p2p.c | 5 ++-- src/p2p/p2p.h | 9 ++++-- src/p2p/p2p_i.h | 4 ++- src/p2p/p2p_invitation.c | 29 ++++++++++++++----- src/p2p/p2p_parse.c | 1 + wpa_supplicant/p2p_supplicant.c | 64 +++++++++++++++++++++++++++++++++++------ 6 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index c553e23..ca347e7 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1762,7 +1762,8 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx) if (p2p->invite_peer == NULL) return; p2p->cfg->stop_listen(p2p->cfg->cb_ctx); - p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr); + p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr, + p2p->invite_dev_pw_id); } @@ -3277,7 +3278,7 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p) if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) { p2p_set_state(p2p, P2P_INVITE); p2p_invite_send(p2p, p2p->invite_peer, - p2p->invite_go_dev_addr); + p2p->invite_go_dev_addr, p2p->invite_dev_pw_id); } else { if (p2p->invite_peer) { p2p_dbg(p2p, "Invitation Request retry limit reached"); diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 3d8ee1f..08e7176 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -708,6 +708,8 @@ struct p2p_config { * persistent group (instead of invitation to join an active * group) * @channels: Available operating channels for the group + * @dev_pw_id: Device Password ID for NFC static handover or -1 if not + * used * Returns: Status code (P2P_SC_*) * * This optional callback can be used to implement persistent reconnect @@ -729,7 +731,8 @@ struct p2p_config { const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, int *force_freq, int persistent_group, - const struct p2p_channels *channels); + const struct p2p_channels *channels, + int dev_pw_id); /** * invitation_received - Callback on Invitation Request RX @@ -1104,12 +1107,14 @@ enum p2p_invite_role { * @persistent_group: Whether this is to reinvoke a persistent group * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if * force_freq == 0) + * @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover + * case or -1 if not used * Returns: 0 on success, -1 on failure */ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, const u8 *bssid, const u8 *ssid, size_t ssid_len, unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq); + int persistent_group, unsigned int pref_freq, int dev_pw_id); /** * p2p_presence_req - Request GO presence diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 1150d40..6ebaa84 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -243,6 +243,7 @@ struct p2p_data { const u8 *invite_go_dev_addr; u8 invite_go_dev_addr_buf[ETH_ALEN]; + int invite_dev_pw_id; /** * sd_peer - Pointer to Service Discovery peer @@ -522,6 +523,7 @@ struct p2p_message { /* WPS IE */ u16 dev_password_id; + int dev_password_id_present; u16 wps_config_methods; const u8 *wps_pri_dev_type; const u8 *wps_sec_dev_type_list; @@ -699,7 +701,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len); int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, - const u8 *go_dev_addr); + const u8 *go_dev_addr, int dev_pw_id); void p2p_invitation_req_cb(struct p2p_data *p2p, int success); void p2p_invitation_resp_cb(struct p2p_data *p2p, int success); diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index 2734386..98cfb33 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -16,7 +16,8 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, struct p2p_device *peer, - const u8 *go_dev_addr) + const u8 *go_dev_addr, + int dev_pw_id) { struct wpabuf *buf; u8 *len; @@ -85,6 +86,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (dev_pw_id >= 0) { + /* WSC IE in Invitation Request for NFC static handover */ + p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); + } + return buf; } @@ -228,7 +234,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, status = p2p->cfg->invitation_process( p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id, msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN, - &go, group_bssid, &op_freq, persistent, &intersection); + &go, group_bssid, &op_freq, persistent, &intersection, + msg.dev_password_id_present ? msg.dev_password_id : -1); } if (op_freq) { @@ -450,12 +457,14 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, - const u8 *go_dev_addr) + const u8 *go_dev_addr, int dev_pw_id) { struct wpabuf *req; int freq; freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; + if (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 Invitation Request", @@ -463,7 +472,7 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, return -1; } - req = p2p_build_invitation_req(p2p, dev, go_dev_addr); + req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id); if (req == NULL) return -1; if (p2p->state != P2P_IDLE) @@ -528,7 +537,7 @@ void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, const u8 *bssid, const u8 *ssid, size_t ssid_len, unsigned int force_freq, const u8 *go_dev_addr, - int persistent_group, unsigned int pref_freq) + int persistent_group, unsigned int pref_freq, int dev_pw_id) { struct p2p_device *dev; @@ -546,9 +555,15 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, p2p->invite_go_dev_addr = NULL; wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID", ssid, ssid_len); + if (dev_pw_id >= 0) { + p2p_dbg(p2p, "Invitation to use Device Password ID %d", + dev_pw_id); + } + p2p->invite_dev_pw_id = dev_pw_id; dev = p2p_get_device(p2p, peer); - if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) { + if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 && + dev->oob_go_neg_freq <= 0)) { p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR, MAC2STR(peer)); return -1; @@ -586,5 +601,5 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, os_memcpy(p2p->inv_ssid, ssid, ssid_len); p2p->inv_ssid_len = ssid_len; p2p->inv_persistent = persistent_group; - return p2p_invite_send(p2p, dev, go_dev_addr); + return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id); } diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index bc548e8..d6144a0 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -353,6 +353,7 @@ static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg) msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id); wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d", msg->dev_password_id); + msg->dev_password_id_present = 1; } if (attr.primary_dev_type) { char devtype[WPS_DEV_TYPE_BUFSIZE]; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index b1e25ad..7920276 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1109,9 +1109,9 @@ static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s, struct p2p_go_neg_results *res) { wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR - " dev_addr " MACSTR, + " dev_addr " MACSTR " wps_method %d", MAC2STR(res->peer_interface_addr), - MAC2STR(res->peer_device_addr)); + MAC2STR(res->peer_device_addr), res->wps_method); wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start WPS Enrollee for SSID", res->ssid, res->ssid_len); wpa_supplicant_ap_deinit(wpa_s); @@ -2901,7 +2901,8 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, int *force_freq, int persistent_group, - const struct p2p_channels *channels) + const struct p2p_channels *channels, + int dev_pw_id) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; @@ -2920,6 +2921,21 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, "authorized invitation"); goto accept_inv; } + +#ifdef CONFIG_WPS_NFC + if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled && + dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) { + wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag"); + wpa_s->parent->p2p_wps_method = WPS_NFC; + wpa_s->parent->pending_join_wps_method = WPS_NFC; + os_memcpy(wpa_s->parent->pending_join_dev_addr, + go_dev_addr, ETH_ALEN); + os_memcpy(wpa_s->parent->pending_join_iface_addr, + bssid, ETH_ALEN); + goto accept_inv; + } +#endif /* CONFIG_WPS_NFC */ + /* * Do not accept the invitation automatically; notify user and * request approval. @@ -5722,7 +5738,7 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, - 1, pref_freq); + 1, pref_freq, -1); } @@ -5796,7 +5812,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq, - go_dev_addr, persistent, pref_freq); + go_dev_addr, persistent, pref_freq, -1); } @@ -7158,12 +7174,15 @@ static int wpas_p2p_nfc_join_group(struct wpa_supplicant *wpa_s, static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, - struct p2p_nfc_params *params) + struct p2p_nfc_params *params, int tag) { + int res, persistent; + struct wpa_ssid *ssid; + 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; + ssid = wpa_s->current_ssid; if (ssid == NULL) continue; if (ssid->mode != WPAS_MODE_P2P_GO) @@ -7183,11 +7202,38 @@ static int wpas_p2p_nfc_auth_join(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known"); return -1; } - return wpas_ap_wps_add_nfc_pw( + res = 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); + if (res) + return res; + + if (!tag) { + wpa_printf(MSG_DEBUG, "P2P: Negotiated handover - wait for peer to join without invitation"); + return 0; + } + + if (!params->peer || + !(params->peer->dev_capab & P2P_DEV_CAPAB_INVITATION_PROCEDURE)) + return 0; + + wpa_printf(MSG_DEBUG, "P2P: Static handover - invite peer " MACSTR + " to join", MAC2STR(params->peer->p2p_device_addr)); + + wpa_s->global->p2p_invite_group = wpa_s; + persistent = ssid->p2p_persistent_group && + wpas_p2p_get_persistent(wpa_s->parent, + params->peer->p2p_device_addr, + ssid->ssid, ssid->ssid_len); + wpa_s->parent->pending_invite_ssid_id = -1; + + return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr, + P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr, + ssid->ssid, ssid->ssid_len, ssid->frequency, + wpa_s->global->p2p_dev_addr, persistent, 0, + wpa_s->parent->p2p_oob_dev_pw_id); } @@ -7378,7 +7424,7 @@ static int wpas_p2p_nfc_connection_handover(struct wpa_supplicant *wpa_s, case JOIN_GROUP: return wpas_p2p_nfc_join_group(wpa_s, ¶ms); case AUTH_JOIN: - return wpas_p2p_nfc_auth_join(wpa_s, ¶ms); + return wpas_p2p_nfc_auth_join(wpa_s, ¶ms, tag); case INIT_GO_NEG: return wpas_p2p_nfc_init_go_neg(wpa_s, ¶ms); case RESP_GO_NEG: -- 2.1.4