diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 0fb2bd415..ae3ba85e6 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -4370,3 +4370,55 @@ void p2p_err(struct p2p_data *p2p, const char *fmt, ...) va_end(ap); p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf); } + + +#ifdef CONFIG_WPS_NFC + +static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p) +{ + struct wpabuf *buf; + u8 op_class, channel; + enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP; + + buf = wpabuf_alloc(1000); + if (buf == NULL) + return NULL; + + op_class = p2p->cfg->reg_class; + channel = p2p->cfg->channel; + + p2p_buf_add_capability(buf, p2p->dev_capab & + ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); + p2p_buf_add_device_info(buf, p2p, NULL); + + if (p2p->num_groups > 0) { + role = P2P_GO_IN_A_GROUP; + p2p_freq_to_channel(p2p_group_get_freq(p2p->groups[0]), + &op_class, &channel); + } + + p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class, + channel, role); + + if (p2p->num_groups > 0) { + /* Limit number of clients to avoid very long message */ + p2p_buf_add_group_info(p2p->groups[0], buf, 5); + p2p_group_buf_add_id(p2p->groups[0], buf); + } + + return buf; +} + + +struct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p) +{ + return p2p_build_nfc_handover(p2p); +} + + +struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p) +{ + return p2p_build_nfc_handover(p2p); +} + +#endif /* CONFIG_WPS_NFC */ diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 247491ea8..1dc71fa3a 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1897,4 +1897,7 @@ int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int, */ 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); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index dddf92c93..3154acc3e 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -419,6 +419,13 @@ void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, } +void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf) +{ + p2p_buf_add_group_id(buf, group->p2p->cfg->dev_addr, group->cfg->ssid, + group->cfg->ssid_len); +} + + static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { struct wpabuf *p2p_subelems, *ie; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 0fa4b70a1..210184105 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -613,6 +613,7 @@ void p2p_group_force_beacon_update_ies(struct p2p_group *group); struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g); void p2p_buf_add_group_info(struct p2p_group *group, struct wpabuf *buf, int max_clients); +void p2p_group_buf_add_id(struct p2p_group *group, struct wpabuf *buf); int p2p_group_get_freq(struct p2p_group *group); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 7ba17db1d..cde9c461e 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -928,6 +928,30 @@ static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_nfc_get_handover_req_p2p(struct wpa_supplicant *wpa_s, + char *reply, size_t max_len, + int ndef) +{ + struct wpabuf *buf; + int res; + + buf = wpas_p2p_nfc_handover_req(wpa_s, ndef); + if (buf == NULL) { + wpa_printf(MSG_DEBUG, "P2P: Could not generate NFC handover request"); + return -1; + } + + res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), + wpabuf_len(buf)); + reply[res++] = '\n'; + reply[res] = '\0'; + + wpabuf_free(buf); + + return res; +} + + static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) @@ -954,6 +978,11 @@ static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s, wpa_s, reply, max_len, ndef); } + if (os_strcmp(pos, "P2P-CR") == 0) { + return wpas_ctrl_nfc_get_handover_req_p2p( + wpa_s, reply, max_len, ndef); + } + return -1; } @@ -980,6 +1009,28 @@ static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s, } +static int wpas_ctrl_nfc_get_handover_sel_p2p(struct wpa_supplicant *wpa_s, + char *reply, size_t max_len, + int ndef, int tag) +{ + struct wpabuf *buf; + int res; + + buf = wpas_p2p_nfc_handover_sel(wpa_s, ndef, tag); + if (buf == NULL) + return -1; + + res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), + wpabuf_len(buf)); + reply[res++] = '\n'; + reply[res] = '\0'; + + wpabuf_free(buf); + + return res; +} + + static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len) @@ -1003,11 +1054,23 @@ static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s, if (pos2) *pos2++ = '\0'; if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) { + if (!ndef) + return -1; return wpas_ctrl_nfc_get_handover_sel_wps( wpa_s, reply, max_len, ndef, os_strcmp(pos, "WPS-CR") == 0, pos2); } + if (os_strcmp(pos, "P2P-CR") == 0) { + return wpas_ctrl_nfc_get_handover_sel_p2p( + wpa_s, reply, max_len, ndef, 0); + } + + if (os_strcmp(pos, "P2P-CR-TAG") == 0) { + return wpas_ctrl_nfc_get_handover_sel_p2p( + wpa_s, reply, max_len, ndef, 1); + } + return -1; } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 8ec70dccd..e61d5ceea 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -6923,3 +6923,106 @@ int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) wpa_s->p2p_last_4way_hs_fail = ssid; return 0; } + + +#ifdef CONFIG_WPS_NFC + +static struct wpabuf * wpas_p2p_nfc_handover(int ndef, struct wpabuf *wsc, + struct wpabuf *p2p) +{ + struct wpabuf *ret; + + if (wsc == NULL) { + wpabuf_free(p2p); + return NULL; + } + + if (p2p == NULL) { + wpabuf_free(wsc); + wpa_printf(MSG_DEBUG, "P2P: No p2p buffer for handover"); + return NULL; + } + + ret = wpabuf_alloc(2 + wpabuf_len(wsc) + 2 + wpabuf_len(p2p)); + if (ret == NULL) { + wpabuf_free(wsc); + wpabuf_free(p2p); + return NULL; + } + + wpabuf_put_be16(ret, wpabuf_len(wsc)); + wpabuf_put_buf(ret, wsc); + wpabuf_put_be16(ret, wpabuf_len(p2p)); + wpabuf_put_buf(ret, p2p); + + wpabuf_free(wsc); + wpabuf_free(p2p); + wpa_hexdump_buf(MSG_DEBUG, + "P2P: Generated NFC connection handover message", ret); + + if (ndef && ret) { + struct wpabuf *tmp; + tmp = ndef_build_p2p(ret); + wpabuf_free(ret); + if (tmp == NULL) { + wpa_printf(MSG_DEBUG, "P2P: Failed to NDEF encapsulate handover request"); + return NULL; + } + ret = tmp; + } + + return ret; +} + + +struct wpabuf * wpas_p2p_nfc_handover_req(struct wpa_supplicant *wpa_s, + int ndef) +{ + struct wpabuf *wsc, *p2p; + + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) { + wpa_printf(MSG_DEBUG, "P2P: P2P disabled - cannot build handover request"); + return NULL; + } + + 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) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No DH key available for handover request"); + return NULL; + } + + wsc = wps_build_nfc_handover_req_p2p(wpa_s->parent->wps, + wpa_s->conf->wps_nfc_dh_pubkey); + p2p = p2p_build_nfc_handover_req(wpa_s->global->p2p); + + return wpas_p2p_nfc_handover(ndef, wsc, p2p); +} + + +struct wpabuf * wpas_p2p_nfc_handover_sel(struct wpa_supplicant *wpa_s, + int ndef, int tag) +{ + struct wpabuf *wsc, *p2p; + + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) + return NULL; + + if (!tag && 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 NULL; + + wsc = wps_build_nfc_handover_sel_p2p(wpa_s->parent->wps, + tag ? + wpa_s->conf->wps_nfc_dev_pw_id : + DEV_PW_NFC_CONNECTION_HANDOVER, + wpa_s->conf->wps_nfc_dh_pubkey, + tag ? wpa_s->conf->wps_nfc_dev_pw : + NULL); + p2p = p2p_build_nfc_handover_sel(wpa_s->global->p2p); + + return wpas_p2p_nfc_handover(ndef, wsc, p2p); +} + +#endif /* CONFIG_WPS_NFC */ diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 7abfb1256..17e7bae58 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -148,6 +148,10 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr, const u8 *psk, size_t psk_len); void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer, int iface_addr); +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); #ifdef CONFIG_P2P int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);