+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+ int ndef)
+{
+ struct wpabuf *ret;
+
+ if (hapd->wps == NULL)
+ return NULL;
+
+ ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd),
+ hapd->iconf->channel);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
+{
+ struct wpabuf *ret;
+
+ if (hapd->wps == NULL)
+ return NULL;
+
+ if (hapd->conf->wps_nfc_dh_pubkey == NULL) {
+ struct wps_context *wps = hapd->wps;
+ if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey,
+ &hapd->conf->wps_nfc_dh_privkey) < 0)
+ return NULL;
+ hostapd_wps_nfc_clear(wps);
+ wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
+ wps->ap_nfc_dh_pubkey =
+ wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey =
+ wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
+ hostapd_wps_nfc_clear(wps);
+ return NULL;
+ }
+ }
+
+ ret = wps_build_nfc_handover_sel(hapd->wps,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->own_addr, hapd->iface->freq);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ struct wpabuf *wps;
+ int ret = -1;
+ u16 wsc_len;
+ const u8 *pos;
+ struct wpabuf msg;
+ struct wps_parse_attr attr;
+ u16 dev_pw_id;
+
+ /*
+ * Enrollee/station is always initiator of the NFC connection handover,
+ * so use the request message here to find Enrollee public key hash.
+ */
+ wps = ndef_parse_wifi(req);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
+ if (wpabuf_len(wps) < 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
+ "Message");
+ goto out;
+ }
+ pos = wpabuf_head(wps);
+ wsc_len = WPA_GET_BE16(pos);
+ if (wsc_len > wpabuf_len(wps) - 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
+ "in rt Wi-Fi Handover Request Message", wsc_len);
+ goto out;
+ }
+ pos += 2;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: WSC attributes in Wi-Fi Handover Request Message",
+ pos, wsc_len);
+ if (wsc_len < wpabuf_len(wps) - 2) {
+ wpa_hexdump(MSG_DEBUG,
+ "WPS: Ignore extra data after WSC attributes",
+ pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
+ }
+
+ wpabuf_set(&msg, pos, wsc_len);
+ ret = wps_parse_msg(&msg, &attr);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
+ "Wi-Fi Handover Request Message");
+ goto out;
+ }
+
+ if (attr.oob_dev_password == NULL ||
+ attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
+ wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
+ "included in Wi-Fi Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ if (attr.uuid_e == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
+ "Handover Request Message");
+ ret = -1;
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
+ attr.oob_dev_password, attr.oob_dev_password_len);
+ dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
+ WPS_OOB_PUBKEY_HASH_LEN);
+ if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
+ wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
+ "%u in Wi-Fi Handover Request Message", dev_pw_id);
+ ret = -1;
+ goto out;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
+ attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
+
+ ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar,
+ attr.oob_dev_password,
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ NULL, 0, 1);
+
+out:
+ wpabuf_free(wps);
+ return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+ if (hapd->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ hapd->conf->wps_nfc_dev_pw_id,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->conf->wps_nfc_dev_pw);
+ }
+
+ return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+ &hapd->conf->wps_nfc_dh_pubkey,
+ &hapd->conf->wps_nfc_dh_privkey,
+ &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+ struct wps_context *wps = hapd->wps;
+ struct wpabuf *pw;
+
+ if (wps == NULL)
+ return -1;
+
+ if (!hapd->conf->wps_nfc_dh_pubkey ||
+ !hapd->conf->wps_nfc_dh_privkey ||
+ !hapd->conf->wps_nfc_dev_pw ||
+ !hapd->conf->wps_nfc_dev_pw_id)
+ return -1;
+
+ hostapd_wps_nfc_clear(wps);
+ wpa_printf(MSG_DEBUG,
+ "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
+ hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
+ wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+ wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+ wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+ pw = hapd->conf->wps_nfc_dev_pw;
+ wps->ap_nfc_dev_pw = wpabuf_alloc(
+ wpabuf_len(pw) * 2 + 1);
+ if (wps->ap_nfc_dev_pw) {
+ wpa_snprintf_hex_uppercase(
+ (char *) wpabuf_put(wps->ap_nfc_dev_pw,
+ wpabuf_len(pw) * 2),
+ wpabuf_len(pw) * 2 + 1,
+ wpabuf_head(pw), wpabuf_len(pw));
+ }
+
+ if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+ !wps->ap_nfc_dev_pw) {
+ hostapd_wps_nfc_clear(wps);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+ wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
+ hapd->conf->iface);
+ hostapd_wps_nfc_clear(hapd->wps);
+}
+