diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index c553e238c..ca347e7b6 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 3d8ee1f99..08e7176c1 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 1150d4051..6ebaa846d 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 2734386e3..98cfb3303 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 bc548e8d4..d6144a0eb 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 b1e25ad07..7920276ba 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: