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/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 72faeae..4a9da5f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -399,13 +399,70 @@
 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;
+	size_t len;
+	struct wpabuf *req, *sel;
+	int ret;
+	char *pos, *role, *type, *pos2;
+
+	role = cmd;
+	pos = os_strchr(role, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	type = pos;
+	pos = os_strchr(type, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL)
+		return -1;
+	*pos2++ = '\0';
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	req = wpabuf_alloc(len);
+	if (req == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+		wpabuf_free(req);
+		return -1;
+	}
+
+	len = os_strlen(pos2);
+	if (len & 0x01) {
+		wpabuf_free(req);
+		return -1;
+	}
+	len /= 2;
+
+	sel = wpabuf_alloc(len);
+	if (sel == NULL) {
+		wpabuf_free(req);
+		return -1;
+	}
+	if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+		wpabuf_free(req);
+		wpabuf_free(sel);
+		return -1;
+	}
+
+	if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) {
+		ret = hostapd_wps_nfc_report_handover(hapd, req, sel);
+	} else {
+		wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+			   "reported: role=%s type=%s", role, type);
+		ret = -1;
+	}
+	wpabuf_free(req);
+	wpabuf_free(sel);
+
+	return ret;
 }
 
 #endif /* CONFIG_WPS_NFC */
@@ -908,6 +965,10 @@
 		wps_testing_dummy_cred = atoi(value);
 		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
 			   wps_testing_dummy_cred);
+	} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
+		wps_corrupt_pkhash = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
+			   wps_corrupt_pkhash);
 #endif /* CONFIG_WPS_TESTING */
 #ifdef CONFIG_INTERWORKING
 	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
@@ -1101,7 +1162,7 @@
 				       void *sock_ctx)
 {
 	struct hostapd_data *hapd = eloop_ctx;
-	char buf[256];
+	char buf[4096];
 	int res;
 	struct sockaddr_un from;
 	socklen_t fromlen = sizeof(from);
@@ -1542,6 +1603,16 @@
 }
 
 
+static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
+{
+#ifdef CONFIG_WPS_TESTING
+	wps_version_number = 0x20;
+	wps_testing_dummy_cred = 0;
+	wps_corrupt_pkhash = 0;
+#endif /* CONFIG_WPS_TESTING */
+}
+
+
 static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
 					      void *sock_ctx)
 {
@@ -1571,6 +1642,8 @@
 	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
 		if (wpa_debug_reopen_file() < 0)
 			reply_len = -1;
+	} else if (os_strcmp(buf, "FLUSH") == 0) {
+		hostapd_ctrl_iface_flush(interfaces);
 	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
 		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
 			reply_len = -1;
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
index 61b5519..58e538a 100755
--- a/hostapd/wps-ap-nfc.py
+++ b/hostapd/wps-ap-nfc.py
@@ -9,6 +9,7 @@
 import os
 import sys
 import time
+import argparse
 
 import nfc
 import nfc.ndef
@@ -16,11 +17,11 @@
 import nfc.handover
 
 import logging
-logging.basicConfig()
 
 import wpaspy
 
 wpas_ctrl = '/var/run/hostapd'
+continue_loop = True
 
 def wpas_connect():
     ifaces = []
@@ -48,7 +49,9 @@
     wpas = wpas_connect()
     if (wpas == None):
         return
-    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
+        return False
+    return True
 
 
 def wpas_get_config_token():
@@ -82,12 +85,18 @@
 
 
 class HandoverServer(nfc.handover.HandoverServer):
-    def __init__(self):
-        super(HandoverServer, self).__init__()
+    def __init__(self, llc):
+        super(HandoverServer, self).__init__(llc)
+        self.ho_server_processing = False
+        self.success = False
 
     def process_request(self, request):
         print "HandoverServer - request received"
-        print "Parsed handover request: " + request.pretty()
+        try:
+            print "Parsed handover request: " + request.pretty()
+        except Exception, e:
+            print e
+        print str(request).encode("hex")
 
         sel = nfc.ndef.HandoverSelectMessage(version="1.2")
 
@@ -95,172 +104,172 @@
             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
+                wpas_report_handover(carrier.record, data)
 
                 message = nfc.ndef.Message(data);
                 sel.add_carrier(message[0], "active", message[1:])
 
         print "Handover select:"
-        print sel.pretty()
+        try:
+            print sel.pretty()
+        except Exception, e:
+            print e
         print str(sel).encode("hex")
 
         print "Sending handover select"
+        self.success = True
         return sel
 
 
-def wps_handover_resp(peer):
-    print "Trying to handle WPS handover"
-
-    srv = HandoverServer()
-    srv.sent_carrier = None
-
-    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):
+    success = False
     if len(tag.ndef.message):
-        message = nfc.ndef.Message(tag.ndef.message)
-        print "message type " + message.type
-
-        for record in message:
+        for record in tag.ndef.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)
+                success = wpas_tag_read(tag.ndef.message)
                 break
     else:
         print "Empty tag"
 
-    print "Remove tag"
-    while tag.is_present:
+    return success
+
+
+def rdwr_connected_write(tag):
+    print "Tag found - writing"
+    global write_data
+    tag.ndef.message = str(write_data)
+    print "Done - remove tag"
+    global only_one
+    if only_one:
+        global continue_loop
+        continue_loop = False
+    global write_wait_remove
+    while write_wait_remove and tag.is_present:
         time.sleep(0.1)
 
-
-def wps_write_config_tag(clf):
+def wps_write_config_tag(clf, wait_remove=True):
     print "Write WPS config token"
-    data = wpas_get_config_token()
-    if (data == None):
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_config_token()
+    if write_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)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-def wps_write_password_tag(clf):
+def wps_write_password_tag(clf, wait_remove=True):
     print "Write WPS password token"
-    data = wpas_get_password_token()
-    if (data == None):
+    global write_data, write_wait_remove
+    write_wait_remove = wait_remove
+    write_data = wpas_get_password_token()
+    if write_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)
+    clf.connect(rdwr={'on-connect': rdwr_connected_write})
 
 
-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
+def rdwr_connected(tag):
+    global only_one, no_wait
+    print "Tag connected: " + str(tag)
 
-        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 tag.ndef:
+        print "NDEF tag: " + tag.type
+        try:
+            print tag.ndef.message.pretty()
+        except Exception, e:
+            print e
+        success = wps_tag_read(tag)
+        if only_one and success:
+            global continue_loop
+            continue_loop = False
+    else:
+        print "Not an NDEF tag - remove tag"
 
-        if peer:
-            print "Found tag"
-            return peer
+    return not no_wait
+
+
+def llcp_startup(clf, llc):
+    print "Start LLCP server"
+    global srv
+    srv = HandoverServer(llc)
+    return llc
+
+def llcp_connected(llc):
+    print "P2P LLCP connected"
+    global wait_connection
+    wait_connection = False
+    global srv
+    srv.start()
+    return True
 
 
 def main():
     clf = nfc.ContactlessFrontend()
 
+    parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
+    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
+                        action='store_const', dest='loglevel',
+                        help='verbose debug output')
+    parser.add_argument('-q', const=logging.WARNING, action='store_const',
+                        dest='loglevel', help='be quiet')
+    parser.add_argument('--only-one', '-1', action='store_true',
+                        help='run only one operation and exit')
+    parser.add_argument('--no-wait', action='store_true',
+                        help='do not wait for tag to be removed before exiting')
+    parser.add_argument('command', choices=['write-config',
+                                            'write-password'],
+                        nargs='?')
+    args = parser.parse_args()
+
+    global only_one
+    only_one = args.only_one
+
+    global no_wait
+    no_wait = args.no_wait
+
+    logging.basicConfig(level=args.loglevel)
+
     try:
-        if len(sys.argv) > 1 and sys.argv[1] == "write-config":
-            wps_write_config_tag(clf)
+        if not clf.open("usb"):
+            print "Could not open connection with an NFC device"
             raise SystemExit
 
-        if len(sys.argv) > 1 and sys.argv[1] == "write-password":
-            wps_write_password_tag(clf)
+        if args.command == "write-config":
+            wps_write_config_tag(clf, wait_remove=not args.no_wait)
             raise SystemExit
 
-        while True:
+        if args.command == "write-password":
+            wps_write_password_tag(clf, wait_remove=not args.no_wait)
+            raise SystemExit
+
+        global continue_loop
+        while continue_loop:
             print "Waiting for a tag or peer to be touched"
+            wait_connection = True
+            try:
+                if not clf.connect(rdwr={'on-connect': rdwr_connected},
+                                   llcp={'on-startup': llcp_startup,
+                                         'on-connect': llcp_connected}):
+                    break
+            except Exception, e:
+                print "clf.connect failed"
 
-            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)
+            global srv
+            if only_one and srv and srv.success:
+                raise SystemExit
 
     except KeyboardInterrupt:
         raise SystemExit