WPS: Fetch only the carrier record from wpa_supplicant for NFC
[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 import random
13 import StringIO
14
15 import nfc
16 import nfc.ndef
17 import nfc.llcp
18 import nfc.handover
19
20 import logging
21 logging.basicConfig()
22
23 import wpactrl
24
25 wpas_ctrl = '/var/run/wpa_supplicant'
26
27 def wpas_connect():
28     ifaces = []
29     if os.path.isdir(wpas_ctrl):
30         try:
31             ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
32         except OSError, error:
33             print "Could not find wpa_supplicant: ", error
34             return None
35
36     if len(ifaces) < 1:
37         print "No wpa_supplicant control interface found"
38         return None
39
40     for ctrl in ifaces:
41         try:
42             wpas = wpactrl.WPACtrl(ctrl)
43             return wpas
44         except wpactrl.error, error:
45             print "Error: ", error
46             pass
47     return None
48
49
50 def wpas_tag_read(message):
51     wpas = wpas_connect()
52     if (wpas == None):
53         return
54     print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
55
56
57 def wpas_get_handover_req():
58     wpas = wpas_connect()
59     if (wpas == None):
60         return None
61     return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
62
63
64 def wpas_put_handover_sel(message):
65     wpas = wpas_connect()
66     if (wpas == None):
67         return
68     print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
69
70
71 def wps_handover_init(peer):
72     print "Trying to initiate WPS handover"
73
74     data = wpas_get_handover_req()
75     if (data == None):
76         print "Could not get handover request carrier record from wpa_supplicant"
77         return
78     print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
79     record = nfc.ndef.Record()
80     f = StringIO.StringIO(data)
81     record._read(f)
82     record = nfc.ndef.HandoverCarrierRecord(record)
83     print "Parsed handover request carrier record:"
84     print record.pretty()
85
86     message = nfc.ndef.HandoverRequestMessage(version="1.2")
87     message.nonce = random.randint(0, 0xffff)
88     message.add_carrier(record, "active")
89
90     print "Handover request:"
91     print message.pretty()
92
93     nfc.llcp.activate(peer);
94
95     client = nfc.handover.HandoverClient()
96     try:
97         print "Trying handover";
98         client.connect()
99         print "Connected for handover"
100     except nfc.llcp.ConnectRefused:
101         print "Handover connection refused"
102         nfc.llcp.shutdown()
103         client.close()
104         return
105
106     print "Sending handover request"
107
108     if not client.send(message):
109         print "Failed to send handover request"
110
111     print "Receiving handover response"
112     message = client._recv()
113     if message is None:
114         print "No response received"
115         nfc.llcp.shutdown()
116         client.close()
117         return
118
119     print "Handover select received"
120     print message.pretty()
121     wpas_put_handover_sel(message)
122
123     print "Remove peer"
124     nfc.llcp.shutdown()
125     client.close()
126     print "Done with handover"
127
128
129 def wps_tag_read(tag):
130     if len(tag.ndef.message):
131         message = nfc.ndef.Message(tag.ndef.message)
132         print "message type " + message.type
133
134         for record in message:
135             print "record type " + record.type
136             if record.type == "application/vnd.wfa.wsc":
137                 print "WPS tag - send to wpa_supplicant"
138                 wpas_tag_read(tag.ndef.message)
139                 break
140     else:
141         print "Empty tag"
142
143     print "Remove tag"
144     while tag.is_present:
145         time.sleep(0.1)
146
147
148 def find_peer(clf):
149     while True:
150         if nfc.llcp.connected():
151             print "LLCP connected"
152         general_bytes = nfc.llcp.startup({})
153         peer = clf.listen(ord(os.urandom(1)) + 200, general_bytes)
154         if isinstance(peer, nfc.DEP):
155             print "listen -> DEP";
156             if peer.general_bytes.startswith("Ffm"):
157                 print "Found DEP"
158                 return peer
159             print "mismatch in general_bytes"
160             print peer.general_bytes
161
162         peer = clf.poll(general_bytes)
163         if isinstance(peer, nfc.DEP):
164             print "poll -> DEP";
165             if peer.general_bytes.startswith("Ffm"):
166                 print "Found DEP"
167                 return peer
168             print "mismatch in general_bytes"
169             print peer.general_bytes
170
171         if peer:
172             print "Found tag"
173             return peer
174
175
176 def main():
177     clf = nfc.ContactlessFrontend()
178
179     try:
180         while True:
181             print "Waiting for a tag or peer to be touched"
182
183             tag = find_peer(clf)
184             if isinstance(tag, nfc.DEP):
185                 wps_handover_init(tag)
186                 continue
187
188             if tag.ndef:
189                 wps_tag_read(tag)
190                 continue
191
192             print "Not an NDEF tag - remove tag"
193             while tag.is_present:
194                 time.sleep(0.1)
195
196     except KeyboardInterrupt:
197         raise SystemExit
198     finally:
199         clf.close()
200
201     raise SystemExit
202
203 if __name__ == '__main__':
204     main()