blob: 9a6da5f974c62eb0cc56ba0d00b4d46f9a4c0958 [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
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080064def wpas_get_er_config_token(uuid):
65 wpas = wpas_connect()
66 if (wpas == None):
67 return None
68 return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
69
70
Dmitry Shmidtf8623282013-02-20 14:34:59 -080071def wpas_get_password_token():
72 wpas = wpas_connect()
73 if (wpas == None):
74 return None
75 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
76
77
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080078def wpas_get_handover_req():
79 wpas = wpas_connect()
80 if (wpas == None):
81 return None
Dmitry Shmidtf8623282013-02-20 14:34:59 -080082 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080083
84
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080085def wpas_get_handover_sel(uuid):
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080086 wpas = wpas_connect()
87 if (wpas == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -080088 return None
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -080089 if uuid is None:
90 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
91 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
92
93
94def wpas_report_handover(req, sel, type):
95 wpas = wpas_connect()
96 if (wpas == None):
97 return None
98 return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
Dmitry Shmidtf8623282013-02-20 14:34:59 -080099 str(req).encode("hex") + " " +
100 str(sel).encode("hex"))
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800101
102
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800103class HandoverServer(nfc.handover.HandoverServer):
104 def __init__(self):
105 super(HandoverServer, self).__init__()
106
107 def process_request(self, request):
108 print "HandoverServer - request received"
109 print "Parsed handover request: " + request.pretty()
110
111 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
112
113 for carrier in request.carriers:
114 print "Remote carrier type: " + carrier.type
115 if carrier.type == "application/vnd.wfa.wsc":
116 print "WPS carrier type match - add WPS carrier record"
117 self.received_carrier = carrier.record
118 data = wpas_get_handover_sel(self.uuid)
119 if data is None:
120 print "Could not get handover select carrier record from wpa_supplicant"
121 continue
122 print "Handover select carrier record from wpa_supplicant:"
123 print data.encode("hex")
124 self.sent_carrier = data
125
126 message = nfc.ndef.Message(data);
127 sel.add_carrier(message[0], "active", message[1:])
128
129 print "Handover select:"
130 print sel.pretty()
131 print str(sel).encode("hex")
132
133 print "Sending handover select"
134 return sel
135
136
137def wps_handover_resp(peer, uuid):
138 if uuid is None:
139 print "Trying to handle WPS handover"
140 else:
141 print "Trying to handle WPS handover with AP " + uuid
142
143 srv = HandoverServer()
144 srv.sent_carrier = None
145 srv.uuid = uuid
146
147 nfc.llcp.activate(peer);
148
149 try:
150 print "Trying handover";
151 srv.start()
152 print "Wait for disconnect"
153 while nfc.llcp.connected():
154 time.sleep(0.1)
155 print "Disconnected after handover"
156 except nfc.llcp.ConnectRefused:
157 print "Handover connection refused"
158 nfc.llcp.shutdown()
159 return
160
161 if srv.sent_carrier:
162 wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
163
164 print "Remove peer"
165 nfc.llcp.shutdown()
166 print "Done with handover"
167 time.sleep(1)
168
169
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800170def wps_handover_init(peer):
171 print "Trying to initiate WPS handover"
172
173 data = wpas_get_handover_req()
174 if (data == None):
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800175 print "Could not get handover request carrier record from wpa_supplicant"
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800176 return
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800177 print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
178 record = nfc.ndef.Record()
179 f = StringIO.StringIO(data)
180 record._read(f)
181 record = nfc.ndef.HandoverCarrierRecord(record)
182 print "Parsed handover request carrier record:"
183 print record.pretty()
184
185 message = nfc.ndef.HandoverRequestMessage(version="1.2")
186 message.nonce = random.randint(0, 0xffff)
187 message.add_carrier(record, "active")
188
189 print "Handover request:"
190 print message.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800191
192 nfc.llcp.activate(peer);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800193
194 client = nfc.handover.HandoverClient()
195 try:
196 print "Trying handover";
197 client.connect()
198 print "Connected for handover"
199 except nfc.llcp.ConnectRefused:
200 print "Handover connection refused"
201 nfc.llcp.shutdown()
202 client.close()
203 return
204
205 print "Sending handover request"
206
207 if not client.send(message):
208 print "Failed to send handover request"
209
210 print "Receiving handover response"
211 message = client._recv()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800212 if message is None:
213 print "No response received"
214 nfc.llcp.shutdown()
215 client.close()
216 return
217 if message.type != "urn:nfc:wkt:Hs":
218 print "Response was not Hs - received: " + message.type
219 nfc.llcp.shutdown()
220 client.close()
221 return
222
223 print "Received message"
224 print message.pretty()
225 message = nfc.ndef.HandoverSelectMessage(message)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800226 print "Handover select received"
227 print message.pretty()
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800228
229 for carrier in message.carriers:
230 print "Remote carrier type: " + carrier.type
231 if carrier.type == "application/vnd.wfa.wsc":
232 print "WPS carrier type match - send to wpa_supplicant"
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800233 wpas_report_handover(data, carrier.record, "INIT")
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800234 wifi = nfc.ndef.WifiConfigRecord(carrier.record)
235 print wifi.pretty()
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800236
237 print "Remove peer"
238 nfc.llcp.shutdown()
239 client.close()
240 print "Done with handover"
241
242
243def wps_tag_read(tag):
244 if len(tag.ndef.message):
245 message = nfc.ndef.Message(tag.ndef.message)
246 print "message type " + message.type
247
248 for record in message:
249 print "record type " + record.type
250 if record.type == "application/vnd.wfa.wsc":
251 print "WPS tag - send to wpa_supplicant"
252 wpas_tag_read(tag.ndef.message)
253 break
254 else:
255 print "Empty tag"
256
257 print "Remove tag"
258 while tag.is_present:
259 time.sleep(0.1)
260
261
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800262def wps_write_config_tag(clf):
263 print "Write WPS config token"
264 data = wpas_get_config_token()
265 if (data == None):
266 print "Could not get WPS config token from wpa_supplicant"
267 return
268
269 print "Touch an NFC tag"
270 while True:
271 tag = clf.poll()
272 if tag == None:
273 time.sleep(0.1)
274 continue
275 break
276
277 print "Tag found - writing"
278 tag.ndef.message = data
279 print "Done - remove tag"
280 while tag.is_present:
281 time.sleep(0.1)
282
283
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800284def wps_write_er_config_tag(clf, uuid):
285 print "Write WPS ER config token"
286 data = wpas_get_er_config_token(uuid)
287 if (data == None):
288 print "Could not get WPS config token from wpa_supplicant"
289 return
290
291 print "Touch an NFC tag"
292 while True:
293 tag = clf.poll()
294 if tag == None:
295 time.sleep(0.1)
296 continue
297 break
298
299 print "Tag found - writing"
300 tag.ndef.message = data
301 print "Done - remove tag"
302 while tag.is_present:
303 time.sleep(0.1)
304
305
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800306def wps_write_password_tag(clf):
307 print "Write WPS password token"
308 data = wpas_get_password_token()
309 if (data == None):
310 print "Could not get WPS password token from wpa_supplicant"
311 return
312
313 print "Touch an NFC tag"
314 while True:
315 tag = clf.poll()
316 if tag == None:
317 time.sleep(0.1)
318 continue
319 break
320
321 print "Tag found - writing"
322 tag.ndef.message = data
323 print "Done - remove tag"
324 while tag.is_present:
325 time.sleep(0.1)
326
327
328def find_peer(clf):
329 while True:
330 if nfc.llcp.connected():
331 print "LLCP connected"
332 general_bytes = nfc.llcp.startup({})
333 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
334 if isinstance(peer, nfc.DEP):
335 print "listen -> DEP";
336 if peer.general_bytes.startswith("Ffm"):
337 print "Found DEP"
338 return peer
339 print "mismatch in general_bytes"
340 print peer.general_bytes
341
342 peer = clf.poll(general_bytes)
343 if isinstance(peer, nfc.DEP):
344 print "poll -> DEP";
345 if peer.general_bytes.startswith("Ffm"):
346 print "Found DEP"
347 return peer
348 print "mismatch in general_bytes"
349 print peer.general_bytes
350
351 if peer:
352 print "Found tag"
353 return peer
354
355
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800356def main():
357 clf = nfc.ContactlessFrontend()
358
359 try:
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800360 arg_uuid = None
361 if len(sys.argv) > 1:
362 arg_uuid = sys.argv[1]
363
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800364 if len(sys.argv) > 1 and sys.argv[1] == "write-config":
365 wps_write_config_tag(clf)
366 raise SystemExit
367
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800368 if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
369 wps_write_er_config_tag(clf, sys.argv[2])
370 raise SystemExit
371
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800372 if len(sys.argv) > 1 and sys.argv[1] == "write-password":
373 wps_write_password_tag(clf)
374 raise SystemExit
375
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800376 while True:
377 print "Waiting for a tag or peer to be touched"
378
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800379 tag = find_peer(clf)
380 if isinstance(tag, nfc.DEP):
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800381 if arg_uuid is None:
382 wps_handover_init(tag)
383 elif arg_uuid is "ap":
384 wps_handover_resp(tag, None)
385 else:
386 wps_handover_resp(tag, arg_uuid)
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800387 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800388
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800389 if tag.ndef:
390 wps_tag_read(tag)
391 continue
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800392
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800393 print "Not an NDEF tag - remove tag"
394 while tag.is_present:
395 time.sleep(0.1)
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800396
397 except KeyboardInterrupt:
398 raise SystemExit
399 finally:
400 clf.close()
401
402 raise SystemExit
403
404if __name__ == '__main__':
405 main()