Cumulative patch from commit 2e988392436227c51002b573ee27a8cee37f70e9

2e98839 P2P: Disable DNS server from dnsmasq
c07f261 P2P NFC: Add script for connection handover with nfcpy
12288d8 WPS NFC: Protect nfcpy pretty print calls against exceptions
c209dd1 WPS NFC: nfcpy script to use new connection handover design
6202500 WPS NFC: Logging level configuration to wps-nfc.py and wps-ap-nfc.py
1f1b5b3 WPS NFC: Clean up nfcpy script no-wait operations
79ede5a WPS NFC: Validate ctrl_iface response before decoding it
ab1db08 WPS NFC: Use argparse in the nfcpy scripts
6f8fa6e WPS NFC: Update wps-nfc.py and wps-ap-nfc.py to use new nfcpy API
b56f6c8 P2P NFC: Add support for freq option in NFC ctrl_iface commands
91a6501 WPS NFC: Use BSSID and AP Channel from handover select
91226e0 WPS: Add testing option to corrupt public key hash
7312776 WPS NFC: add more debug prints for connection handover report
5cd4f66 WPS NFC: Use AP Channel information from credential container
d2f1837 WPS NFC: Add BSSID and AP channel info to Configuration Token
75dbf98 WPS-STRICT: Update valid Device Password ID and Config Error range
5cd4740 P2P NFC: WPA state machine config with driver-based BSS selection
8e9f53c P2P NFC: Static handover with NFC Tag on client
dd87677 P2P NFC: Enable own NFC Tag on GO Registrar
abe44e3 P2P NFC: Add GO info into handover message when in client role
23318be P2P NFC: Optimize join-a-group operation based on NFC information
86e3208 P2P NFC: Copy DH parameters to a separate group interface
d4b4d7f WPS NFC: Update DH keys for ER operations
ac08752 WPS NFC: Use pubkey mismatch config error from Enrollee
59b45d1 P2P NFC: Add processing of P2P client while NFC handover case
74df9ec P2P NFC: Do not try to join peer if both devices are already GO
201b0f5 P2P: Add test option to disable IP address assignment request
25ef852 P2P: Add support for IP address assignment in 4-way handshake
fdd48ff P2P NFC: Optimize GO Negotiation retries
c4f87a7 P2P NFC: Add NFC tag enabling for static handover
dd37a93 P2P NFC: Report handover select from tag for static handover
db6ae69 P2P NFC: Report connection handover as trigger for P2P
9358878 P2P NFC: Build connection handover messages
c00ab85 P2P NFC: Define WPS_NFC config method
0deab08 P2P NFC: Allow separate WPS/P2P IES to be parsed
fca9958 P2P NFC: Pass OOB Dev Password through P2P parser
ab9e344 P2P NFC: Pass OOB Device Password ID to P2P
5154689 P2P NFC: Add WPS attribute building for P2P NFC
01afd8d P2P NFC: Add NDEF helpers for P2P connection handover messages
9e323a2 P2P NFC: Add OOB GO Negotiation Channel attribute
14d8645 WPS NFC: Allow BSSID and channel to be included in handover select
50d1f89 NFC: Update WPS ER to use the new connection handover design
d950793 WPS NFC: Add support for wpa_supplicant AP/GO mode to use handover
fa4c298 WPS NFC: Process new style handover select
068cdb1 WPS NFC: New style connection handover select from AP/Registrar
3189ca0 WPS NFC: Add AP mode connection handover report
41f9ffb WPS NFC: Build new style carrier record for connection handover request
3f1639d WPS NFC: Split DH key generation to a separate function
9754917 WPS NFC: Update NFC connection handover design
34b6795 WPS NFC: Use abbreviated handshake if both PK hashes delivered OOB
57630e6 WPS: Preparations for allowing SSID filtering for provisioning step
5f45455 WPS NFC: Validate peer public key hash on Enrollee
ff40cd6 WPS NFC: Send M2D with config error 20 on pkhash mismatch
e435417 WPS: Remove Version attribute from NFC messages
72403ec WPS: Add builder functions for AP Channel and RF Bands attributes
ea43ad9 P2P: Make group operating channel available
9f7cd9a P2P: Split add-group-info into a helper function
253f2e3 P2P: Apply unsafe frequency rules to available channels
1682c62 Add a header file defining QCA OUI and vendor extensions

Change-Id: Ia7604d018e1ffb25e06bdc01ce258fc4a0569245
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 0bb937e..b4860a0 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -384,6 +384,12 @@
 #define P2P_MANAGE BIT(3)
 #define P2P_ALLOW_CROSS_CONNECTION BIT(4)
 	int p2p;
+#ifdef CONFIG_P2P
+	u8 ip_addr_go[4];
+	u8 ip_addr_mask[4];
+	u8 ip_addr_start[4];
+	u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
 
 	int disassoc_low_ack;
 	int skip_inactivity_poll;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 670b834..24e764d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -908,6 +908,7 @@
 	char buf[100];
 #ifdef CONFIG_P2P
 	u8 addr[ETH_ALEN];
+	u8 ip_addr_buf[4];
 #endif /* CONFIG_P2P */
 
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
@@ -929,12 +930,25 @@
 		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
 
 	if (authorized) {
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s", buf);
+		char ip_addr[100];
+		ip_addr[0] = '\0';
+#ifdef CONFIG_P2P
+		if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
+			os_snprintf(ip_addr, sizeof(ip_addr),
+				    " ip_addr=%u.%u.%u.%u",
+				    ip_addr_buf[0], ip_addr_buf[1],
+				    ip_addr_buf[2], ip_addr_buf[3]);
+		}
+#endif /* CONFIG_P2P */
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
+			buf, ip_addr);
 
 		if (hapd->msg_ctx_parent &&
 		    hapd->msg_ctx_parent != hapd->msg_ctx)
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
-					  AP_STA_CONNECTED "%s", buf);
+					  AP_STA_CONNECTED "%s%s",
+					  buf, ip_addr);
 
 		sta->flags |= WLAN_STA_AUTHORIZED;
 	} else {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 5993edf..707a63f 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/state_machine.h"
+#include "utils/bitfield.h"
 #include "common/ieee802_11_defs.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
@@ -424,6 +425,17 @@
 				       wpa_rekey_gtk, wpa_auth, NULL);
 	}
 
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(conf->ip_addr_start)) {
+		int count = WPA_GET_BE32(conf->ip_addr_end) -
+			WPA_GET_BE32(conf->ip_addr_start) + 1;
+		if (count > 1000)
+			count = 1000;
+		if (count > 0)
+			wpa_auth->ip_pool = bitfield_alloc(count);
+	}
+#endif /* CONFIG_P2P */
+
 	return wpa_auth;
 }
 
@@ -466,6 +478,11 @@
 	wpa_auth->ft_pmk_cache = NULL;
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_P2P
+	bitfield_free(wpa_auth->ip_pool);
+#endif /* CONFIG_P2P */
+
+
 	os_free(wpa_auth->wpa_ie);
 
 	group = wpa_auth->group;
@@ -583,6 +600,19 @@
 
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr)) {
+		u32 start;
+		wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
+			   "address %u.%u.%u.%u from " MACSTR,
+			   sm->ip_addr[0], sm->ip_addr[1],
+			   sm->ip_addr[2], sm->ip_addr[3],
+			   MAC2STR(sm->addr));
+		start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
+		bitfield_clear(sm->wpa_auth->ip_pool,
+			       WPA_GET_BE32(sm->ip_addr) - start);
+	}
+#endif /* CONFIG_P2P */
 	if (sm->GUpdateStationKeys) {
 		sm->group->GKeyDoneStations--;
 		sm->GUpdateStationKeys = FALSE;
@@ -1000,6 +1030,26 @@
 			return;
 		}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+		if (kde.ip_addr_req && kde.ip_addr_req[0] &&
+		    wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
+			int idx;
+			wpa_printf(MSG_DEBUG, "P2P: IP address requested in "
+				   "EAPOL-Key exchange");
+			idx = bitfield_get_first_zero(wpa_auth->ip_pool);
+			if (idx >= 0) {
+				u32 start = WPA_GET_BE32(wpa_auth->conf.
+							 ip_addr_start);
+				bitfield_set(wpa_auth->ip_pool, idx);
+				WPA_PUT_BE32(sm->ip_addr, start + idx);
+				wpa_printf(MSG_DEBUG, "P2P: Assigned IP "
+					   "address %u.%u.%u.%u to " MACSTR,
+					   sm->ip_addr[0], sm->ip_addr[1],
+					   sm->ip_addr[2], sm->ip_addr[3],
+					   MAC2STR(sm->addr));
+			}
+		}
+#endif /* CONFIG_P2P */
 		break;
 	case PAIRWISE_4:
 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1995,6 +2045,10 @@
 		kde_len += 300; /* FTIE + 2 * TIE */
 	}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr) > 0)
+		kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
+#endif /* CONFIG_P2P */
 	kde = os_malloc(kde_len);
 	if (kde == NULL)
 		return;
@@ -2056,6 +2110,16 @@
 		pos += 4;
 	}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	if (WPA_GET_BE32(sm->ip_addr) > 0) {
+		u8 addr[3 * 4];
+		os_memcpy(addr, sm->ip_addr, 4);
+		os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
+		os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+		pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
+				  addr, sizeof(addr), NULL, 0);
+	}
+#endif /* CONFIG_P2P */
 
 	wpa_send_eapol(sm->wpa_auth, sm,
 		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
@@ -3103,3 +3167,14 @@
 		return 0;
 	return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
 }
+
+
+#ifdef CONFIG_P2P
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
+{
+	if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+		return -1;
+	os_memcpy(addr, sm->ip_addr, 4);
+	return 0;
+}
+#endif /* CONFIG_P2P */
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index da45ae4..bc3dec4 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -163,6 +163,12 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	double corrupt_gtk_rekey_mic_probability;
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+	u8 ip_addr_go[4];
+	u8 ip_addr_mask[4];
+	u8 ip_addr_start[4];
+	u8 ip_addr_end[4];
+#endif /* CONFIG_P2P */
 };
 
 typedef enum {
@@ -297,4 +303,6 @@
 int wpa_auth_uses_sae(struct wpa_state_machine *sm);
 int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
 
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
+
 #endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 4c1d625..5af1495 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -78,6 +78,12 @@
 	wconf->corrupt_gtk_rekey_mic_probability =
 		iconf->corrupt_gtk_rekey_mic_probability;
 #endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_P2P
+	os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
+	os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4);
+	os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4);
+	os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4);
+#endif /* CONFIG_P2P */
 }
 
 
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 9736874..fcd5878 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -121,6 +121,10 @@
 #endif /* CONFIG_IEEE80211R */
 
 	int pending_1_of_4_timeout;
+
+#ifdef CONFIG_P2P
+	u8 ip_addr[4];
+#endif /* CONFIG_P2P */
 };
 
 
@@ -185,6 +189,10 @@
 
 	struct rsn_pmksa_cache *pmksa;
 	struct wpa_ft_pmk_cache *ft_pmk_cache;
+
+#ifdef CONFIG_P2P
+	struct bitfield *ip_pool;
+#endif /* CONFIG_P2P */
 };
 
 
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index cdfcca1..274f4d6 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -708,6 +708,25 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+	if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+		ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+			    ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+
+	if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+	    RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+		ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG,
+			    "WPA: IP Address Allocation in EAPOL-Key",
+			    ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+		return 0;
+	}
+#endif /* CONFIG_P2P */
+
 	return 0;
 }
 
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index 4999139..f945882 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -39,6 +39,10 @@
 	const u8 *ftie;
 	size_t ftie_len;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+	const u8 *ip_addr_req;
+	const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
 };
 
 int wpa_parse_kde_ies(const u8 *buf, size_t len,
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 4c94210..1b1dce4 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1784,7 +1784,8 @@
 	if (hapd->wps == NULL)
 		return NULL;
 
-	ret = wps_get_oob_cred(hapd->wps);
+	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);
@@ -1800,11 +1801,136 @@
 
 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;
+
 	/*
-	 * Handover Select carrier record for WPS uses the same format as
-	 * configuration token.
+	 * Enrollee/station is always initiator of the NFC connection handover,
+	 * so use the request message here to find Enrollee public key hash.
 	 */
-	return hostapd_wps_nfc_config_token(hapd, ndef);
+	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;
 }
 
 
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index a292598..204bd82 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -37,6 +37,9 @@
 struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
 					     int ndef);
 struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
+				    const struct wpabuf *req,
+				    const struct wpabuf *sel);
 struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
 int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
 void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);