WPS: Use alternating poll/listen for NFC peer discovery with nfcpy
[mech_eap.git] / wpa_supplicant / examples / wps-nfc.py
1 #!/usr/bin/python
2 #
3 # Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
4 # Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
5 #
6 # This software may be distributed under the terms of the BSD license.
7 # See README for more details.
8
9 import os
10 import sys
11 import time
12
13 import nfc
14 import nfc.ndef
15 import nfc.llcp
16 import nfc.handover
17
18 import logging
19 logging.basicConfig()
20
21 import wpactrl
22
23 wpas_ctrl = '/var/run/wpa_supplicant'
24
25 def wpas_connect():
26     ifaces = []
27     if os.path.isdir(wpas_ctrl):
28         try:
29             ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
30         except OSError, error:
31             print "Could not find wpa_supplicant: ", error
32             return None
33
34     if len(ifaces) < 1:
35         print "No wpa_supplicant control interface found"
36         return None
37
38     for ctrl in ifaces:
39         try:
40             wpas = wpactrl.WPACtrl(ctrl)
41             return wpas
42         except wpactrl.error, error:
43             print "Error: ", error
44             pass
45     return None
46
47
48 def wpas_tag_read(message):
49     wpas = wpas_connect()
50     if (wpas == None):
51         return
52     print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
53
54
55 def wpas_get_handover_req():
56     wpas = wpas_connect()
57     if (wpas == None):
58         return None
59     return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
60
61
62 def wpas_put_handover_sel(message):
63     wpas = wpas_connect()
64     if (wpas == None):
65         return
66     print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
67
68
69 def wps_handover_init(peer):
70     print "Trying to initiate WPS handover"
71
72     data = wpas_get_handover_req()
73     if (data == None):
74         print "Could not get handover request message from wpa_supplicant"
75         return
76     print "Handover request from wpa_supplicant: " + data.encode("hex")
77     message = nfc.ndef.Message(data)
78     print "Parsed handover request: " + message.pretty()
79
80     nfc.llcp.activate(peer);
81     time.sleep(0.5)
82
83     client = nfc.handover.HandoverClient()
84     try:
85         print "Trying handover";
86         client.connect()
87         print "Connected for handover"
88     except nfc.llcp.ConnectRefused:
89         print "Handover connection refused"
90         nfc.llcp.shutdown()
91         client.close()
92         return
93
94     print "Sending handover request"
95
96     if not client.send(message):
97         print "Failed to send handover request"
98
99     print "Receiving handover response"
100     message = client._recv()
101     print "Handover select received"
102     print message.pretty()
103     wpas_put_handover_sel(message)
104
105     print "Remove peer"
106     nfc.llcp.shutdown()
107     client.close()
108     print "Done with handover"
109
110
111 def wps_tag_read(tag):
112     if len(tag.ndef.message):
113         message = nfc.ndef.Message(tag.ndef.message)
114         print "message type " + message.type
115
116         for record in message:
117             print "record type " + record.type
118             if record.type == "application/vnd.wfa.wsc":
119                 print "WPS tag - send to wpa_supplicant"
120                 wpas_tag_read(tag.ndef.message)
121                 break
122     else:
123         print "Empty tag"
124
125     print "Remove tag"
126     while tag.is_present:
127         time.sleep(0.1)
128
129
130 def find_peer(clf):
131     while True:
132         if nfc.llcp.connected():
133             print "LLCP connected"
134         general_bytes = nfc.llcp.startup({})
135         peer = clf.listen(ord(os.urandom(1)) + 200, general_bytes)
136         if isinstance(peer, nfc.DEP):
137             print "listen -> DEP";
138             if peer.general_bytes.startswith("Ffm"):
139                 print "Found DEP"
140                 return peer
141             print "mismatch in general_bytes"
142             print peer.general_bytes
143
144         peer = clf.poll(general_bytes)
145         if isinstance(peer, nfc.DEP):
146             print "poll -> DEP";
147             if peer.general_bytes.startswith("Ffm"):
148                 print "Found DEP"
149                 return peer
150             print "mismatch in general_bytes"
151             print peer.general_bytes
152
153         if peer:
154             print "Found tag"
155             return peer
156
157
158 def main():
159     clf = nfc.ContactlessFrontend()
160
161     try:
162         while True:
163             print "Waiting for a tag or peer to be touched"
164
165             tag = find_peer(clf)
166             if isinstance(tag, nfc.DEP):
167                 wps_handover_init(tag)
168                 continue
169
170             if tag.ndef:
171                 wps_tag_read(tag)
172                 continue
173
174             print "Not an NDEF tag - remove tag"
175             while tag.is_present:
176                 time.sleep(0.1)
177
178     except KeyboardInterrupt:
179         raise SystemExit
180     finally:
181         clf.close()
182
183     raise SystemExit
184
185 if __name__ == '__main__':
186     main()