blob: 14acc5b26d785d6b82b8487ccb3acd3688bb907e [file] [log] [blame]
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001#!/usr/bin/python
2#
3# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
Dmitry Shmidtf8623282013-02-20 14:34:59 -08004# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08005#
6# This software may be distributed under the terms of the BSD license.
7# See README for more details.
8
9import os
10import sys
11import time
Dmitry Shmidtf8623282013-02-20 14:34:59 -080012import random
13import StringIO
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080014
15import nfc
16import nfc.ndef
17import nfc.llcp
18import nfc.handover
19
Dmitry Shmidtf8623282013-02-20 14:34:59 -080020import logging
21logging.basicConfig()
22
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080023import wpactrl
24
25wpas_ctrl = '/var/run/wpa_supplicant'
26
27def 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
50def 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
Dmitry Shmidtf8623282013-02-20 14:34:59 -080057def wpas_get_config_token():
58 wpas = wpas_connect()
59 if (wpas == None):
60 return None
61 return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
62
63
64def wpas_get_password_token():
65 wpas = wpas_connect()
66 if (wpas == None):
67 return None
68 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
69
70
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080071def wpas_get_handover_req():
72 wpas = wpas_connect()
73 if (wpas == None):
74 return None
Dmitry Shmidtf8623282013-02-20 14:34:59 -080075 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080076
77
Dmitry Shmidtf8623282013-02-20 14:34:59 -080078def wpas_report_handover(req, sel):
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080079 wpas = wpas_connect()
80 if (wpas == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080081 return None
82 return wpas.request("NFC_REPORT_HANDOVER INIT WPS " +
83 str(req).encode("hex") + " " +
84 str(sel).encode("hex"))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080085
86
87def wps_handover_init(peer):
88 print "Trying to initiate WPS handover"
89
90 data = wpas_get_handover_req()
91 if (data == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080092 print "Could not get handover request carrier record from wpa_supplicant"
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080093 return
Dmitry Shmidtf8623282013-02-20 14:34:59 -080094 print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
95 record = nfc.ndef.Record()
96 f = StringIO.StringIO(data)
97 record._read(f)
98 record = nfc.ndef.HandoverCarrierRecord(record)
99 print "Parsed handover request carrier record:"
100 print record.pretty()
101
102 message = nfc.ndef.HandoverRequestMessage(version="1.2")
103 message.nonce = random.randint(0, 0xffff)
104 message.add_carrier(record, "active")
105
106 print "Handover request:"
107 print message.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800108
109 nfc.llcp.activate(peer);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800110
111 client = nfc.handover.HandoverClient()
112 try:
113 print "Trying handover";
114 client.connect()
115 print "Connected for handover"
116 except nfc.llcp.ConnectRefused:
117 print "Handover connection refused"
118 nfc.llcp.shutdown()
119 client.close()
120 return
121
122 print "Sending handover request"
123
124 if not client.send(message):
125 print "Failed to send handover request"
126
127 print "Receiving handover response"
128 message = client._recv()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800129 if message is None:
130 print "No response received"
131 nfc.llcp.shutdown()
132 client.close()
133 return
134 if message.type != "urn:nfc:wkt:Hs":
135 print "Response was not Hs - received: " + message.type
136 nfc.llcp.shutdown()
137 client.close()
138 return
139
140 print "Received message"
141 print message.pretty()
142 message = nfc.ndef.HandoverSelectMessage(message)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800143 print "Handover select received"
144 print message.pretty()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800145
146 for carrier in message.carriers:
147 print "Remote carrier type: " + carrier.type
148 if carrier.type == "application/vnd.wfa.wsc":
149 print "WPS carrier type match - send to wpa_supplicant"
150 wpas_report_handover(data, carrier.record)
151 wifi = nfc.ndef.WifiConfigRecord(carrier.record)
152 print wifi.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800153
154 print "Remove peer"
155 nfc.llcp.shutdown()
156 client.close()
157 print "Done with handover"
158
159
160def wps_tag_read(tag):
161 if len(tag.ndef.message):
162 message = nfc.ndef.Message(tag.ndef.message)
163 print "message type " + message.type
164
165 for record in message:
166 print "record type " + record.type
167 if record.type == "application/vnd.wfa.wsc":
168 print "WPS tag - send to wpa_supplicant"
169 wpas_tag_read(tag.ndef.message)
170 break
171 else:
172 print "Empty tag"
173
174 print "Remove tag"
175 while tag.is_present:
176 time.sleep(0.1)
177
178
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800179def wps_write_config_tag(clf):
180 print "Write WPS config token"
181 data = wpas_get_config_token()
182 if (data == None):
183 print "Could not get WPS config token from wpa_supplicant"
184 return
185
186 print "Touch an NFC tag"
187 while True:
188 tag = clf.poll()
189 if tag == None:
190 time.sleep(0.1)
191 continue
192 break
193
194 print "Tag found - writing"
195 tag.ndef.message = data
196 print "Done - remove tag"
197 while tag.is_present:
198 time.sleep(0.1)
199
200
201def wps_write_password_tag(clf):
202 print "Write WPS password token"
203 data = wpas_get_password_token()
204 if (data == None):
205 print "Could not get WPS password token from wpa_supplicant"
206 return
207
208 print "Touch an NFC tag"
209 while True:
210 tag = clf.poll()
211 if tag == None:
212 time.sleep(0.1)
213 continue
214 break
215
216 print "Tag found - writing"
217 tag.ndef.message = data
218 print "Done - remove tag"
219 while tag.is_present:
220 time.sleep(0.1)
221
222
223def find_peer(clf):
224 while True:
225 if nfc.llcp.connected():
226 print "LLCP connected"
227 general_bytes = nfc.llcp.startup({})
228 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
229 if isinstance(peer, nfc.DEP):
230 print "listen -> DEP";
231 if peer.general_bytes.startswith("Ffm"):
232 print "Found DEP"
233 return peer
234 print "mismatch in general_bytes"
235 print peer.general_bytes
236
237 peer = clf.poll(general_bytes)
238 if isinstance(peer, nfc.DEP):
239 print "poll -> DEP";
240 if peer.general_bytes.startswith("Ffm"):
241 print "Found DEP"
242 return peer
243 print "mismatch in general_bytes"
244 print peer.general_bytes
245
246 if peer:
247 print "Found tag"
248 return peer
249
250
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800251def main():
252 clf = nfc.ContactlessFrontend()
253
254 try:
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800255 if len(sys.argv) > 1 and sys.argv[1] == "write-config":
256 wps_write_config_tag(clf)
257 raise SystemExit
258
259 if len(sys.argv) > 1 and sys.argv[1] == "write-password":
260 wps_write_password_tag(clf)
261 raise SystemExit
262
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800263 while True:
264 print "Waiting for a tag or peer to be touched"
265
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800266 tag = find_peer(clf)
267 if isinstance(tag, nfc.DEP):
268 wps_handover_init(tag)
269 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800270
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800271 if tag.ndef:
272 wps_tag_read(tag)
273 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800274
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800275 print "Not an NDEF tag - remove tag"
276 while tag.is_present:
277 time.sleep(0.1)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800278
279 except KeyboardInterrupt:
280 raise SystemExit
281 finally:
282 clf.close()
283
284 raise SystemExit
285
286if __name__ == '__main__':
287 main()