Accumulative patch from commit b618a469c42120e984ab1c85ed6058504d1fca78

  Author: Jouni Malinen <jouni@qca.qualcomm.com>
  Date:   Sat Feb 16 19:54:09 2013 +0200
    Interworking: Select highest priority cred if multiple matches

Interworking: Select highest priority cred if multiple matches
GAS server: Fix a regression in GAS server callback
hostapd: Fix Max SP Length derivation from QoS Info
nl80211: Configure STA Capabilities and Extended Capabilities
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Fix build without CONFIG_WPS_NFC
WPS: Add support for NFC handover select generation with wpa_supplicant
WPS: Update NFC connection handover documentation
WPS: Add support for config token generation with wpa_supplicant
WPS: Allow password token to be written with nfcpy
WPS: Use pre-configured NFC password token instead of overriding it
TDLS: Pass peer's Capability and Ext Capability info during sta_add
TDLS: Pass peer's HT Capability and QOS information during sta_add
nl80211: Add debug prints for STA add/set operations
TDLS: Fix add/set STA operation
Synchronize with wireless-testing.git include/uapi/linux/nl80211.h
WPS: Allow Device Password to be changed from M1 to M2
WPS: Fix wps_reg nfc-pw option
TDLS: Tear down peers when disconnecting from the AP
P2P: Do not use old scan result data for peer discovery
Use more accurate timestamps for scan results
P2P: Postpone P2P-DEVICE-FOUND if config_methods not known
P2P: Do not allow peer update to clear config_methods
WPS: Report NFC connection handover completion differently
P2P: Avoid concurrent scans during all steps of group formation
P2P: Cancel group formation timeout on group removal (on client)
WPS: Change listen time to match nfcpy default (250 ms)
WPS: Report only the carrier record from NFC to wpa_supplicant
WPS: Fetch only the carrier record from wpa_supplicant for NFC
WPS: Update nfcpy script to support AP mode NFC connection handover
WPS: Add command for fetching carrier record for NFC handover
WPS: Clean up debug prints with nfcpy
WPS: Remove 0.5 sec extra wait from NFC handover with nfcpy
WPS: Use alternating poll/listen for NFC peer discovery with nfcpy
WPS: Configure logging to show nfcpy log message
WPS: Add an example python script for NFC operations with hostapd
hostapd: Do not change HT40 capability due to OBSS scan
dbus: Add missing signal description for WPS (7)
EAP peer: Add Session-Id derivation to more EAP methods
EAP peer: Add Session-Id derivation
EAP-IKEV2 server: Fix invalid memory freeing operation
eap_proxy: Add a dummy implementation for compilation testing
eap_proxy: Add mechanism for allowing EAP methods to be offloaded
Android: Allow setgroups to be overridden from build configuration
P2P: Send p2p_stop_find event on failure to start pending p2p_find
P2P: Fix GO Probe Response IEs when Wi-Fi Display is enabled
Capability matching for 60 GHz band
nl80211: Add ctrl_iface message for AP mode connection rejection
P2P: Allow local configuration to use 5 GHz band 40 MHz channels
Fix BSS RANGE command for no exact id match cases

Change-Id: Iac9284bba31db40911aecc3adf2843c9b1576db1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 87a6f91..654b5bc 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -338,3 +338,17 @@
 internal Registrar. This allows station Enrollee from which the password
 token was received to run through WPS protocol to provision the
 credential.
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7b22dfd..e29ae2f 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2627,15 +2627,19 @@
 					   "wps_nfc_dev_pw_id value", line);
 				errors++;
 			}
+			bss->wps_nfc_pw_from_config = 1;
 		} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
 			wpabuf_free(bss->wps_nfc_dh_pubkey);
 			bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+			bss->wps_nfc_pw_from_config = 1;
 		} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
 			wpabuf_free(bss->wps_nfc_dh_privkey);
 			bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+			bss->wps_nfc_pw_from_config = 1;
 		} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
 			wpabuf_free(bss->wps_nfc_dev_pw);
 			bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+			bss->wps_nfc_pw_from_config = 1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P_MANAGER
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 93b740e..f20721b 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -352,6 +352,59 @@
 
 	return -1;
 }
+
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+						   char *cmd, char *reply,
+						   size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+	char *pos;
+	int ndef;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	if (os_strcmp(pos, "WPS-CR") == 0)
+		buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+	else
+		buf = NULL;
+	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 hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
+						  char *cmd)
+{
+	/*
+	 * Since NFC connection handover provided full WPS Credential, there is
+	 * no need for additional operations within hostapd. Just report this in
+	 * debug log.
+	 */
+	wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
+	return 0;
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -913,6 +966,12 @@
 	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
 		reply_len = hostapd_ctrl_iface_wps_nfc_token(
 			hapd, buf + 14, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+		reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+			hapd, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+		if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+			reply_len = -1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_WNM
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index b693fa0..1537275 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -475,6 +475,29 @@
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+						int argc, char *argv[])
+{
+	char cmd[64];
+	int res;
+
+	if (argc != 2) {
+		printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+		       "are required.\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
 #endif /* CONFIG_WPS_NFC */
 
 
@@ -796,6 +819,7 @@
 	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
 	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
 	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+	{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
 #endif /* CONFIG_WPS_NFC */
 	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
 	{ "wps_config", hostapd_cli_cmd_wps_config },
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
new file mode 100755
index 0000000..32a0214
--- /dev/null
+++ b/hostapd/wps-ap-nfc.py
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+logging.basicConfig()
+
+import wpactrl
+
+wpas_ctrl = '/var/run/hostapd'
+
+def wpas_connect():
+    ifaces = []
+    if os.path.isdir(wpas_ctrl):
+        try:
+            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+        except OSError, error:
+            print "Could not find hostapd: ", error
+            return None
+
+    if len(ifaces) < 1:
+        print "No hostapd control interface found"
+        return None
+
+    for ctrl in ifaces:
+        try:
+            wpas = wpactrl.WPACtrl(ctrl)
+            return wpas
+        except wpactrl.error, error:
+            print "Error: ", error
+            pass
+    return None
+
+
+def wpas_tag_read(message):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return
+    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_config_token():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+    wpas = wpas_connect()
+    if (wpas == None):
+        return None
+    return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+                        str(req).encode("hex") + " " +
+                        str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+    def __init__(self):
+        super(HandoverServer, self).__init__()
+
+    def process_request(self, request):
+        print "HandoverServer - request received"
+        print "Parsed handover request: " + request.pretty()
+
+        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+        for carrier in request.carriers:
+            print "Remote carrier type: " + carrier.type
+            if carrier.type == "application/vnd.wfa.wsc":
+                print "WPS carrier type match - add WPS carrier record"
+                self.received_carrier = carrier.record
+                data = wpas_get_handover_sel()
+                if data is None:
+                    print "Could not get handover select carrier record from hostapd"
+                    continue
+                print "Handover select carrier record from hostapd:"
+                print data.encode("hex")
+                self.sent_carrier = data
+
+                message = nfc.ndef.Message(data);
+                sel.add_carrier(message[0], "active", message[1:])
+
+        print "Handover select:"
+        print sel.pretty()
+        print str(sel).encode("hex")
+
+        print "Sending handover select"
+        return sel
+
+
+def wps_handover_resp(peer):
+    print "Trying to handle WPS handover"
+
+    srv = HandoverServer()
+
+    nfc.llcp.activate(peer);
+
+    try:
+        print "Trying handover";
+        srv.start()
+        print "Wait for disconnect"
+        while nfc.llcp.connected():
+            time.sleep(0.1)
+        print "Disconnected after handover"
+    except nfc.llcp.ConnectRefused:
+        print "Handover connection refused"
+        nfc.llcp.shutdown()
+        return
+
+    if srv.sent_carrier:
+        wpas_report_handover(srv.received_carrier, srv.sent_carrier)
+
+    print "Remove peer"
+    nfc.llcp.shutdown()
+    print "Done with handover"
+
+
+def wps_tag_read(tag):
+    if len(tag.ndef.message):
+        message = nfc.ndef.Message(tag.ndef.message)
+        print "message type " + message.type
+
+        for record in message:
+            print "record type " + record.type
+            if record.type == "application/vnd.wfa.wsc":
+                print "WPS tag - send to hostapd"
+                wpas_tag_read(tag.ndef.message)
+                break
+    else:
+        print "Empty tag"
+
+    print "Remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_config_tag(clf):
+    print "Write WPS config token"
+    data = wpas_get_config_token()
+    if (data == None):
+        print "Could not get WPS config token from hostapd"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+    print "Write WPS password token"
+    data = wpas_get_password_token()
+    if (data == None):
+        print "Could not get WPS password token from hostapd"
+        return
+
+    print "Touch an NFC tag"
+    while True:
+        tag = clf.poll()
+        if tag == None:
+            time.sleep(0.1)
+            continue
+        break
+
+    print "Tag found - writing"
+    tag.ndef.message = data
+    print "Done - remove tag"
+    while tag.is_present:
+        time.sleep(0.1)
+
+
+def find_peer(clf):
+    while True:
+        if nfc.llcp.connected():
+            print "LLCP connected"
+        general_bytes = nfc.llcp.startup({})
+        peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "listen -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        peer = clf.poll(general_bytes)
+        if isinstance(peer, nfc.DEP):
+            print "poll -> DEP";
+            if peer.general_bytes.startswith("Ffm"):
+                print "Found DEP"
+                return peer
+            print "mismatch in general_bytes"
+            print peer.general_bytes
+
+        if peer:
+            print "Found tag"
+            return peer
+
+
+def main():
+    clf = nfc.ContactlessFrontend()
+
+    try:
+        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+            wps_write_config_tag(clf)
+            raise SystemExit
+
+        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+            wps_write_password_tag(clf)
+            raise SystemExit
+
+        while True:
+            print "Waiting for a tag or peer to be touched"
+
+            tag = find_peer(clf)
+            if isinstance(tag, nfc.DEP):
+                wps_handover_resp(tag)
+                continue
+
+            if tag.ndef:
+                wps_tag_read(tag)
+                continue
+
+            print "Not an NDEF tag - remove tag"
+            while tag.is_present:
+                time.sleep(0.1)
+
+    except KeyboardInterrupt:
+        raise SystemExit
+    finally:
+        clf.close()
+
+    raise SystemExit
+
+if __name__ == '__main__':
+    main()