WPS: Change listen time to match nfcpy default (250 ms)
[mech_eap.git] / wpa_supplicant / examples / wps-nfc.py
index 0cfc1f6..c328a90 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 # Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
-# Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+# 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.
@@ -9,12 +9,17 @@
 import os
 import sys
 import time
+import random
+import StringIO
 
 import nfc
 import nfc.ndef
 import nfc.llcp
 import nfc.handover
 
+import logging
+logging.basicConfig()
+
 import wpactrl
 
 wpas_ctrl = '/var/run/wpa_supplicant'
@@ -53,7 +58,7 @@ def wpas_get_handover_req():
     wpas = wpas_connect()
     if (wpas == None):
         return None
-    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
+    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
 
 
 def wpas_put_handover_sel(message):
@@ -68,14 +73,24 @@ def wps_handover_init(peer):
 
     data = wpas_get_handover_req()
     if (data == None):
-        print "Could not get handover request message from wpa_supplicant"
+        print "Could not get handover request carrier record from wpa_supplicant"
         return
-    print "Handover request from wpa_supplicant: " + data.encode("hex")
-    message = nfc.ndef.Message(data)
-    print "Parsed handover request: " + message.pretty()
+    print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+    record = nfc.ndef.Record()
+    f = StringIO.StringIO(data)
+    record._read(f)
+    record = nfc.ndef.HandoverCarrierRecord(record)
+    print "Parsed handover request carrier record:"
+    print record.pretty()
+
+    message = nfc.ndef.HandoverRequestMessage(version="1.2")
+    message.nonce = random.randint(0, 0xffff)
+    message.add_carrier(record, "active")
+
+    print "Handover request:"
+    print message.pretty()
 
     nfc.llcp.activate(peer);
-    time.sleep(0.5)
 
     client = nfc.handover.HandoverClient()
     try:
@@ -95,9 +110,30 @@ def wps_handover_init(peer):
 
     print "Receiving handover response"
     message = client._recv()
+    if message is None:
+        print "No response received"
+        nfc.llcp.shutdown()
+        client.close()
+        return
+    if message.type != "urn:nfc:wkt:Hs":
+        print "Response was not Hs - received: " + message.type
+        nfc.llcp.shutdown()
+        client.close()
+        return
+
+    print "Received message"
+    print message.pretty()
+    message = nfc.ndef.HandoverSelectMessage(message)
     print "Handover select received"
     print message.pretty()
-    wpas_put_handover_sel(message)
+
+    for carrier in message.carriers:
+        print "Remote carrier type: " + carrier.type
+        if carrier.type == "application/vnd.wfa.wsc":
+            print "WPS carrier type match - send to wpa_supplicant"
+            wpas_put_handover_sel(carrier.record)
+            wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+            print wifi.pretty()
 
     print "Remove peer"
     nfc.llcp.shutdown()
@@ -124,6 +160,34 @@ def wps_tag_read(tag):
         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()
 
@@ -131,25 +195,18 @@ def main():
         while True:
             print "Waiting for a tag or peer to be touched"
 
-            while True:
-                general_bytes = nfc.llcp.startup({})
-                tag = clf.poll(general_bytes)
-                if tag == None:
-                    continue
-
-                if isinstance(tag, nfc.DEP):
-                    wps_handover_init(tag)
-                    break
-
-                if tag.ndef:
-                    wps_tag_read(tag)
-                    break
-
-                if tag:
-                    print "Not an NDEF tag - remove tag"
-                    while tag.is_present:
-                        time.sleep(0.1)
-                    break
+            tag = find_peer(clf)
+            if isinstance(tag, nfc.DEP):
+                wps_handover_init(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