]> git.ipfire.org Git - thirdparty/hostap.git/blob - wpa_supplicant/examples/wps-nfc.py
WPS NFC: Logging level configuration to wps-nfc.py and wps-ap-nfc.py
[thirdparty/hostap.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 import threading
15 import argparse
16
17 import nfc
18 import nfc.ndef
19 import nfc.llcp
20 import nfc.handover
21
22 import logging
23
24 import wpaspy
25
26 wpas_ctrl = '/var/run/wpa_supplicant'
27 srv = None
28 continue_loop = True
29 terminate_now = False
30
31 def wpas_connect():
32 ifaces = []
33 if os.path.isdir(wpas_ctrl):
34 try:
35 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
36 except OSError, error:
37 print "Could not find wpa_supplicant: ", error
38 return None
39
40 if len(ifaces) < 1:
41 print "No wpa_supplicant control interface found"
42 return None
43
44 for ctrl in ifaces:
45 try:
46 wpas = wpaspy.Ctrl(ctrl)
47 return wpas
48 except Exception, e:
49 pass
50 return None
51
52
53 def wpas_tag_read(message):
54 wpas = wpas_connect()
55 if (wpas == None):
56 return False
57 if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
58 return False
59 return True
60
61 def wpas_get_config_token(id=None):
62 wpas = wpas_connect()
63 if (wpas == None):
64 return None
65 if id:
66 ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
67 else:
68 ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
69 if "FAIL" in ret:
70 return None
71 return ret.rstrip().decode("hex")
72
73
74 def wpas_get_er_config_token(uuid):
75 wpas = wpas_connect()
76 if (wpas == None):
77 return None
78 ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid)
79 if "FAIL" in ret:
80 return None
81 return ret.rstrip().decode("hex")
82
83
84 def wpas_get_password_token():
85 wpas = wpas_connect()
86 if (wpas == None):
87 return None
88 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
89
90
91 def wpas_get_handover_req():
92 wpas = wpas_connect()
93 if (wpas == None):
94 return None
95 return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
96
97
98 def wpas_get_handover_sel(uuid):
99 wpas = wpas_connect()
100 if (wpas == None):
101 return None
102 if uuid is None:
103 res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
104 else:
105 res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip()
106 if "FAIL" in res:
107 return None
108 return res.decode("hex")
109
110
111 def wpas_report_handover(req, sel, type):
112 wpas = wpas_connect()
113 if (wpas == None):
114 return None
115 return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
116 str(req).encode("hex") + " " +
117 str(sel).encode("hex"))
118
119
120 class HandoverServer(nfc.handover.HandoverServer):
121 def __init__(self, llc):
122 super(HandoverServer, self).__init__(llc)
123 self.sent_carrier = None
124 self.ho_server_processing = False
125 self.success = False
126
127 def process_request(self, request):
128 self.ho_server_processing = True
129 print "HandoverServer - request received"
130 print "Parsed handover request: " + request.pretty()
131
132 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
133
134 for carrier in request.carriers:
135 print "Remote carrier type: " + carrier.type
136 if carrier.type == "application/vnd.wfa.wsc":
137 print "WPS carrier type match - add WPS carrier record"
138 data = wpas_get_handover_sel(self.uuid)
139 if data is None:
140 print "Could not get handover select carrier record from wpa_supplicant"
141 continue
142 print "Handover select carrier record from wpa_supplicant:"
143 print data.encode("hex")
144 self.sent_carrier = data
145 wpas_report_handover(carrier.record, self.sent_carrier, "RESP")
146
147 message = nfc.ndef.Message(data);
148 sel.add_carrier(message[0], "active", message[1:])
149
150 print "Handover select:"
151 print sel.pretty()
152 print str(sel).encode("hex")
153
154 print "Sending handover select"
155 self.success = True
156 return sel
157
158
159 def wps_handover_init(llc):
160 print "Trying to initiate WPS handover"
161
162 data = wpas_get_handover_req()
163 if (data == None):
164 print "Could not get handover request carrier record from wpa_supplicant"
165 return
166 print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
167 record = nfc.ndef.Record()
168 f = StringIO.StringIO(data)
169 record._read(f)
170 record = nfc.ndef.HandoverCarrierRecord(record)
171 print "Parsed handover request carrier record:"
172 print record.pretty()
173
174 message = nfc.ndef.HandoverRequestMessage(version="1.2")
175 message.nonce = random.randint(0, 0xffff)
176 message.add_carrier(record, "active")
177
178 print "Handover request:"
179 print message.pretty()
180
181 client = nfc.handover.HandoverClient(llc)
182 try:
183 print "Trying handover";
184 client.connect()
185 print "Connected for handover"
186 except nfc.llcp.ConnectRefused:
187 print "Handover connection refused"
188 client.close()
189 return
190
191 print "Sending handover request"
192
193 if not client.send(message):
194 print "Failed to send handover request"
195
196 print "Receiving handover response"
197 message = client._recv()
198 if message is None:
199 print "No response received"
200 client.close()
201 return
202 if message.type != "urn:nfc:wkt:Hs":
203 print "Response was not Hs - received: " + message.type
204 client.close()
205 return
206
207 print "Received message"
208 print message.pretty()
209 message = nfc.ndef.HandoverSelectMessage(message)
210 print "Handover select received"
211 print message.pretty()
212
213 for carrier in message.carriers:
214 print "Remote carrier type: " + carrier.type
215 if carrier.type == "application/vnd.wfa.wsc":
216 print "WPS carrier type match - send to wpa_supplicant"
217 wpas_report_handover(data, carrier.record, "INIT")
218 wifi = nfc.ndef.WifiConfigRecord(carrier.record)
219 print wifi.pretty()
220
221 print "Remove peer"
222 client.close()
223 print "Done with handover"
224 global only_one
225 if only_one:
226 global continue_loop
227 continue_loop = False
228
229 global no_wait
230 if no_wait:
231 print "Trying to exit.."
232 global terminate_now
233 terminate_now = True
234
235 def wps_tag_read(tag, wait_remove=True):
236 success = False
237 if len(tag.ndef.message):
238 for record in tag.ndef.message:
239 print "record type " + record.type
240 if record.type == "application/vnd.wfa.wsc":
241 print "WPS tag - send to wpa_supplicant"
242 success = wpas_tag_read(tag.ndef.message)
243 break
244 else:
245 print "Empty tag"
246
247 if wait_remove:
248 print "Remove tag"
249 while tag.is_present:
250 time.sleep(0.1)
251
252 return success
253
254
255 def rdwr_connected_write(tag):
256 print "Tag found - writing"
257 global write_data
258 tag.ndef.message = str(write_data)
259 print "Done - remove tag"
260 global only_one
261 if only_one:
262 global continue_loop
263 continue_loop = False
264 global write_wait_remove
265 while write_wait_remove and tag.is_present:
266 time.sleep(0.1)
267
268 def wps_write_config_tag(clf, id=None, wait_remove=True):
269 print "Write WPS config token"
270 global write_data, write_wait_remove
271 write_wait_remove = wait_remove
272 write_data = wpas_get_config_token(id)
273 if write_data == None:
274 print "Could not get WPS config token from wpa_supplicant"
275 sys.exit(1)
276 return
277 print "Touch an NFC tag"
278 clf.connect(rdwr={'on-connect': rdwr_connected_write})
279
280
281 def wps_write_er_config_tag(clf, uuid, wait_remove=True):
282 print "Write WPS ER config token"
283 global write_data, write_wait_remove
284 write_wait_remove = wait_remove
285 write_data = wpas_get_er_config_token(uuid)
286 if write_data == None:
287 print "Could not get WPS config token from wpa_supplicant"
288 return
289
290 print "Touch an NFC tag"
291 clf.connect(rdwr={'on-connect': rdwr_connected_write})
292
293
294 def wps_write_password_tag(clf, wait_remove=True):
295 print "Write WPS password token"
296 global write_data, write_wait_remove
297 write_wait_remove = wait_remove
298 write_data = wpas_get_password_token()
299 if write_data == None:
300 print "Could not get WPS password token from wpa_supplicant"
301 return
302
303 print "Touch an NFC tag"
304 clf.connect(rdwr={'on-connect': rdwr_connected_write})
305
306
307 def rdwr_connected(tag):
308 global only_one, no_wait
309 print "Tag connected: " + str(tag)
310
311 if tag.ndef:
312 print "NDEF tag: " + tag.type
313 try:
314 print tag.ndef.message.pretty()
315 except Exception, e:
316 print e
317 success = wps_tag_read(tag, not only_one)
318 if only_one and success:
319 global continue_loop
320 continue_loop = False
321 else:
322 print "Not an NDEF tag - remove tag"
323
324 return not no_wait
325
326
327 def llcp_worker(llc):
328 global arg_uuid
329 if arg_uuid is None:
330 wps_handover_init(llc)
331 print "Exiting llcp_worker thread"
332 return
333
334 global srv
335 global wait_connection
336 while not wait_connection and srv.sent_carrier is None:
337 if srv.ho_server_processing:
338 time.sleep(0.025)
339
340 def llcp_startup(clf, llc):
341 global arg_uuid
342 if arg_uuid:
343 print "Start LLCP server"
344 global srv
345 srv = HandoverServer(llc)
346 if arg_uuid is "ap":
347 print "Trying to handle WPS handover"
348 srv.uuid = None
349 else:
350 print "Trying to handle WPS handover with AP " + arg_uuid
351 srv.uuid = arg_uuid
352 return llc
353
354 def llcp_connected(llc):
355 print "P2P LLCP connected"
356 global wait_connection
357 wait_connection = False
358 global arg_uuid
359 if arg_uuid:
360 global srv
361 srv.start()
362 else:
363 threading.Thread(target=llcp_worker, args=(llc,)).start()
364 print "llcp_connected returning"
365 return True
366
367
368 def terminate_loop():
369 global terminate_now
370 return terminate_now
371
372 def main():
373 clf = nfc.ContactlessFrontend()
374
375 parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations')
376 parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
377 action='store_const', dest='loglevel',
378 help='verbose debug output')
379 parser.add_argument('-q', const=logging.WARNING, action='store_const',
380 dest='loglevel', help='be quiet')
381 parser.add_argument('--only-one', '-1', action='store_true',
382 help='run only one operation and exit')
383 parser.add_argument('--no-wait', action='store_true',
384 help='do not wait for tag to be removed before exiting')
385 parser.add_argument('--uuid',
386 help='UUID of an AP (used for WPS ER operations)')
387 parser.add_argument('--id',
388 help='network id (used for WPS ER operations)')
389 parser.add_argument('command', choices=['write-config',
390 'write-er-config',
391 'write-password'],
392 nargs='?')
393 args = parser.parse_args()
394
395 global arg_uuid
396 arg_uuid = args.uuid
397
398 global only_one
399 only_one = args.only_one
400
401 global no_wait
402 no_wait = args.no_wait
403
404 logging.basicConfig(level=args.loglevel)
405
406 try:
407 if not clf.open("usb"):
408 print "Could not open connection with an NFC device"
409 raise SystemExit
410
411 if args.command == "write-config":
412 wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait)
413 raise SystemExit
414
415 if args.command == "write-er-config":
416 wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait)
417 raise SystemExit
418
419 if args.command == "write-password":
420 wps_write_password_tag(clf, wait_remove=not args.no_wait)
421 raise SystemExit
422
423 global continue_loop
424 while continue_loop:
425 print "Waiting for a tag or peer to be touched"
426 wait_connection = True
427 try:
428 if not clf.connect(rdwr={'on-connect': rdwr_connected},
429 llcp={'on-startup': llcp_startup,
430 'on-connect': llcp_connected},
431 terminate=terminate_loop):
432 break
433 except Exception, e:
434 print "clf.connect failed"
435
436 global srv
437 if only_one and srv and srv.success:
438 raise SystemExit
439
440 except KeyboardInterrupt:
441 raise SystemExit
442 finally:
443 clf.close()
444
445 raise SystemExit
446
447 if __name__ == '__main__':
448 main()