1281681Srpaulo#!/usr/bin/python
2281681Srpaulo#
3281681Srpaulo# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations
4281681Srpaulo# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
5281681Srpaulo#
6281681Srpaulo# This software may be distributed under the terms of the BSD license.
7281681Srpaulo# See README for more details.
8281681Srpaulo
9281681Srpauloimport os
10281681Srpauloimport sys
11281681Srpauloimport time
12281681Srpauloimport random
13281681Srpauloimport threading
14281681Srpauloimport argparse
15281681Srpaulo
16281681Srpauloimport nfc
17281681Srpauloimport nfc.ndef
18281681Srpauloimport nfc.llcp
19281681Srpauloimport nfc.handover
20281681Srpaulo
21281681Srpauloimport logging
22281681Srpaulo
23281681Srpauloimport wpaspy
24281681Srpaulo
25281681Srpaulowpas_ctrl = '/var/run/wpa_supplicant'
26281681Srpauloifname = None
27281681Srpauloinit_on_touch = False
28281681Srpauloin_raw_mode = False
29281681Srpauloprev_tcgetattr = 0
30281681Srpauloinclude_wps_req = True
31281681Srpauloinclude_p2p_req = True
32281681Srpaulono_input = False
33281681Srpaulosrv = None
34281681Srpaulocontinue_loop = True
35281681Srpauloterminate_now = False
36281681Srpaulosummary_file = None
37281681Srpaulosuccess_file = None
38281681Srpaulo
39281681Srpaulodef summary(txt):
40281681Srpaulo    print txt
41281681Srpaulo    if summary_file:
42281681Srpaulo        with open(summary_file, 'a') as f:
43281681Srpaulo            f.write(txt + "\n")
44281681Srpaulo
45281681Srpaulodef success_report(txt):
46281681Srpaulo    summary(txt)
47281681Srpaulo    if success_file:
48281681Srpaulo        with open(success_file, 'a') as f:
49281681Srpaulo            f.write(txt + "\n")
50281681Srpaulo
51281681Srpaulodef wpas_connect():
52281681Srpaulo    ifaces = []
53281681Srpaulo    if os.path.isdir(wpas_ctrl):
54281681Srpaulo        try:
55281681Srpaulo            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
56281681Srpaulo        except OSError, error:
57281681Srpaulo            print "Could not find wpa_supplicant: ", error
58281681Srpaulo            return None
59281681Srpaulo
60281681Srpaulo    if len(ifaces) < 1:
61281681Srpaulo        print "No wpa_supplicant control interface found"
62281681Srpaulo        return None
63281681Srpaulo
64281681Srpaulo    for ctrl in ifaces:
65281681Srpaulo        if ifname:
66281681Srpaulo            if ifname not in ctrl:
67281681Srpaulo                continue
68281681Srpaulo        try:
69281681Srpaulo            print "Trying to use control interface " + ctrl
70281681Srpaulo            wpas = wpaspy.Ctrl(ctrl)
71281681Srpaulo            return wpas
72281681Srpaulo        except Exception, e:
73281681Srpaulo            pass
74281681Srpaulo    return None
75281681Srpaulo
76281681Srpaulo
77281681Srpaulodef wpas_tag_read(message):
78281681Srpaulo    wpas = wpas_connect()
79281681Srpaulo    if (wpas == None):
80281681Srpaulo        return False
81281681Srpaulo    cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex")
82281681Srpaulo    global force_freq
83281681Srpaulo    if force_freq:
84281681Srpaulo        cmd = cmd + " freq=" + force_freq
85281681Srpaulo    if "FAIL" in wpas.request(cmd):
86281681Srpaulo        return False
87281681Srpaulo    return True
88281681Srpaulo
89281681Srpaulo
90281681Srpaulodef wpas_get_handover_req():
91281681Srpaulo    wpas = wpas_connect()
92281681Srpaulo    if (wpas == None):
93281681Srpaulo        return None
94281681Srpaulo    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
95281681Srpaulo    if "FAIL" in res:
96281681Srpaulo        return None
97281681Srpaulo    return res.decode("hex")
98281681Srpaulo
99281681Srpaulodef wpas_get_handover_req_wps():
100281681Srpaulo    wpas = wpas_connect()
101281681Srpaulo    if (wpas == None):
102281681Srpaulo        return None
103281681Srpaulo    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
104281681Srpaulo    if "FAIL" in res:
105281681Srpaulo        return None
106281681Srpaulo    return res.decode("hex")
107281681Srpaulo
108281681Srpaulo
109281681Srpaulodef wpas_get_handover_sel(tag=False):
110281681Srpaulo    wpas = wpas_connect()
111281681Srpaulo    if (wpas == None):
112281681Srpaulo        return None
113281681Srpaulo    if tag:
114281681Srpaulo        res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
115281681Srpaulo    else:
116281681Srpaulo	res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
117281681Srpaulo    if "FAIL" in res:
118281681Srpaulo        return None
119281681Srpaulo    return res.decode("hex")
120281681Srpaulo
121281681Srpaulo
122281681Srpaulodef wpas_get_handover_sel_wps():
123281681Srpaulo    wpas = wpas_connect()
124281681Srpaulo    if (wpas == None):
125281681Srpaulo        return None
126281681Srpaulo    res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR");
127281681Srpaulo    if "FAIL" in res:
128281681Srpaulo        return None
129281681Srpaulo    return res.rstrip().decode("hex")
130281681Srpaulo
131281681Srpaulo
132281681Srpaulodef wpas_report_handover(req, sel, type):
133281681Srpaulo    wpas = wpas_connect()
134281681Srpaulo    if (wpas == None):
135281681Srpaulo        return None
136281681Srpaulo    cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex")
137281681Srpaulo    global force_freq
138281681Srpaulo    if force_freq:
139281681Srpaulo        cmd = cmd + " freq=" + force_freq
140281681Srpaulo    return wpas.request(cmd)
141281681Srpaulo
142281681Srpaulo
143281681Srpaulodef wpas_report_handover_wsc(req, sel, type):
144281681Srpaulo    wpas = wpas_connect()
145281681Srpaulo    if (wpas == None):
146281681Srpaulo        return None
147281681Srpaulo    cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")
148281681Srpaulo    if force_freq:
149281681Srpaulo        cmd = cmd + " freq=" + force_freq
150281681Srpaulo    return wpas.request(cmd)
151281681Srpaulo
152281681Srpaulo
153281681Srpaulodef p2p_handover_client(llc):
154281681Srpaulo    message = nfc.ndef.HandoverRequestMessage(version="1.2")
155281681Srpaulo    message.nonce = random.randint(0, 0xffff)
156281681Srpaulo
157281681Srpaulo    global include_p2p_req
158281681Srpaulo    if include_p2p_req:
159281681Srpaulo        data = wpas_get_handover_req()
160281681Srpaulo        if (data == None):
161281681Srpaulo            summary("Could not get handover request carrier record from wpa_supplicant")
162281681Srpaulo            return
163281681Srpaulo        print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
164281681Srpaulo        datamsg = nfc.ndef.Message(data)
165281681Srpaulo        message.add_carrier(datamsg[0], "active", datamsg[1:])
166281681Srpaulo
167281681Srpaulo    global include_wps_req
168281681Srpaulo    if include_wps_req:
169281681Srpaulo        print "Handover request (pre-WPS):"
170281681Srpaulo        try:
171281681Srpaulo            print message.pretty()
172281681Srpaulo        except Exception, e:
173281681Srpaulo            print e
174281681Srpaulo
175281681Srpaulo        data = wpas_get_handover_req_wps()
176281681Srpaulo        if data:
177281681Srpaulo            print "Add WPS request in addition to P2P"
178281681Srpaulo            datamsg = nfc.ndef.Message(data)
179281681Srpaulo            message.add_carrier(datamsg[0], "active", datamsg[1:])
180281681Srpaulo
181281681Srpaulo    print "Handover request:"
182281681Srpaulo    try:
183281681Srpaulo        print message.pretty()
184281681Srpaulo    except Exception, e:
185281681Srpaulo        print e
186281681Srpaulo    print str(message).encode("hex")
187281681Srpaulo
188281681Srpaulo    client = nfc.handover.HandoverClient(llc)
189281681Srpaulo    try:
190281681Srpaulo        summary("Trying to initiate NFC connection handover")
191281681Srpaulo        client.connect()
192281681Srpaulo        summary("Connected for handover")
193281681Srpaulo    except nfc.llcp.ConnectRefused:
194281681Srpaulo        summary("Handover connection refused")
195281681Srpaulo        client.close()
196281681Srpaulo        return
197281681Srpaulo    except Exception, e:
198281681Srpaulo        summary("Other exception: " + str(e))
199281681Srpaulo        client.close()
200281681Srpaulo        return
201281681Srpaulo
202281681Srpaulo    summary("Sending handover request")
203281681Srpaulo
204281681Srpaulo    if not client.send(message):
205281681Srpaulo        summary("Failed to send handover request")
206281681Srpaulo        client.close()
207281681Srpaulo        return
208281681Srpaulo
209281681Srpaulo    summary("Receiving handover response")
210281681Srpaulo    message = client._recv()
211281681Srpaulo    if message is None:
212281681Srpaulo        summary("No response received")
213281681Srpaulo        client.close()
214281681Srpaulo        return
215281681Srpaulo    if message.type != "urn:nfc:wkt:Hs":
216281681Srpaulo        summary("Response was not Hs - received: " + message.type)
217281681Srpaulo        client.close()
218281681Srpaulo        return
219281681Srpaulo
220281681Srpaulo    print "Received message"
221281681Srpaulo    try:
222281681Srpaulo        print message.pretty()
223281681Srpaulo    except Exception, e:
224281681Srpaulo        print e
225281681Srpaulo    print str(message).encode("hex")
226281681Srpaulo    message = nfc.ndef.HandoverSelectMessage(message)
227281681Srpaulo    summary("Handover select received")
228281681Srpaulo    try:
229281681Srpaulo        print message.pretty()
230281681Srpaulo    except Exception, e:
231281681Srpaulo        print e
232281681Srpaulo
233281681Srpaulo    for carrier in message.carriers:
234281681Srpaulo        print "Remote carrier type: " + carrier.type
235281681Srpaulo        if carrier.type == "application/vnd.wfa.p2p":
236281681Srpaulo            print "P2P carrier type match - send to wpa_supplicant"
237281681Srpaulo            if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
238281681Srpaulo                success_report("P2P handover reported successfully (initiator)")
239281681Srpaulo            else:
240281681Srpaulo                summary("P2P handover report rejected")
241281681Srpaulo            break
242281681Srpaulo
243281681Srpaulo    print "Remove peer"
244281681Srpaulo    client.close()
245281681Srpaulo    print "Done with handover"
246281681Srpaulo    global only_one
247281681Srpaulo    if only_one:
248281681Srpaulo        print "only_one -> stop loop"
249281681Srpaulo        global continue_loop
250281681Srpaulo        continue_loop = False
251281681Srpaulo
252281681Srpaulo    global no_wait
253281681Srpaulo    if no_wait:
254281681Srpaulo        print "Trying to exit.."
255281681Srpaulo        global terminate_now
256281681Srpaulo        terminate_now = True
257281681Srpaulo
258281681Srpaulo
259281681Srpauloclass HandoverServer(nfc.handover.HandoverServer):
260281681Srpaulo    def __init__(self, llc):
261281681Srpaulo        super(HandoverServer, self).__init__(llc)
262281681Srpaulo        self.sent_carrier = None
263281681Srpaulo        self.ho_server_processing = False
264281681Srpaulo        self.success = False
265281681Srpaulo
266281681Srpaulo    # override to avoid parser error in request/response.pretty() in nfcpy
267281681Srpaulo    # due to new WSC handover format
268281681Srpaulo    def _process_request(self, request):
269281681Srpaulo        summary("received handover request {}".format(request.type))
270281681Srpaulo        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
271281681Srpaulo        if not request.type == 'urn:nfc:wkt:Hr':
272281681Srpaulo            summary("not a handover request")
273281681Srpaulo        else:
274281681Srpaulo            try:
275281681Srpaulo                request = nfc.ndef.HandoverRequestMessage(request)
276281681Srpaulo            except nfc.ndef.DecodeError as e:
277281681Srpaulo                summary("error decoding 'Hr' message: {}".format(e))
278281681Srpaulo            else:
279281681Srpaulo                response = self.process_request(request)
280281681Srpaulo        summary("send handover response {}".format(response.type))
281281681Srpaulo        return response
282281681Srpaulo
283281681Srpaulo    def process_request(self, request):
284281681Srpaulo        self.ho_server_processing = True
285281681Srpaulo        clear_raw_mode()
286281681Srpaulo        print "HandoverServer - request received"
287281681Srpaulo        try:
288281681Srpaulo            print "Parsed handover request: " + request.pretty()
289281681Srpaulo        except Exception, e:
290281681Srpaulo            print e
291281681Srpaulo
292281681Srpaulo        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
293281681Srpaulo
294281681Srpaulo        found = False
295281681Srpaulo
296281681Srpaulo        for carrier in request.carriers:
297281681Srpaulo            print "Remote carrier type: " + carrier.type
298281681Srpaulo            if carrier.type == "application/vnd.wfa.p2p":
299281681Srpaulo                print "P2P carrier type match - add P2P carrier record"
300281681Srpaulo                found = True
301281681Srpaulo                self.received_carrier = carrier.record
302281681Srpaulo                print "Carrier record:"
303281681Srpaulo                try:
304281681Srpaulo                    print carrier.record.pretty()
305281681Srpaulo                except Exception, e:
306281681Srpaulo                    print e
307281681Srpaulo                data = wpas_get_handover_sel()
308281681Srpaulo                if data is None:
309281681Srpaulo                    print "Could not get handover select carrier record from wpa_supplicant"
310281681Srpaulo                    continue
311281681Srpaulo                print "Handover select carrier record from wpa_supplicant:"
312281681Srpaulo                print data.encode("hex")
313281681Srpaulo                self.sent_carrier = data
314281681Srpaulo                if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
315281681Srpaulo                    success_report("P2P handover reported successfully (responder)")
316281681Srpaulo                else:
317281681Srpaulo                    summary("P2P handover report rejected")
318281681Srpaulo                    break
319281681Srpaulo
320281681Srpaulo                message = nfc.ndef.Message(data);
321281681Srpaulo                sel.add_carrier(message[0], "active", message[1:])
322281681Srpaulo                break
323281681Srpaulo
324281681Srpaulo        for carrier in request.carriers:
325281681Srpaulo            if found:
326281681Srpaulo                break
327281681Srpaulo            print "Remote carrier type: " + carrier.type
328281681Srpaulo            if carrier.type == "application/vnd.wfa.wsc":
329281681Srpaulo                print "WSC carrier type match - add WSC carrier record"
330281681Srpaulo                found = True
331281681Srpaulo                self.received_carrier = carrier.record
332281681Srpaulo                print "Carrier record:"
333281681Srpaulo                try:
334281681Srpaulo                    print carrier.record.pretty()
335281681Srpaulo                except Exception, e:
336281681Srpaulo                    print e
337281681Srpaulo                data = wpas_get_handover_sel_wps()
338281681Srpaulo                if data is None:
339281681Srpaulo                    print "Could not get handover select carrier record from wpa_supplicant"
340281681Srpaulo                    continue
341281681Srpaulo                print "Handover select carrier record from wpa_supplicant:"
342281681Srpaulo                print data.encode("hex")
343281681Srpaulo                self.sent_carrier = data
344281681Srpaulo                if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
345281681Srpaulo                    success_report("WSC handover reported successfully")
346281681Srpaulo                else:
347281681Srpaulo                    summary("WSC handover report rejected")
348281681Srpaulo                    break
349281681Srpaulo
350281681Srpaulo                message = nfc.ndef.Message(data);
351281681Srpaulo                sel.add_carrier(message[0], "active", message[1:])
352281681Srpaulo                found = True
353281681Srpaulo                break
354281681Srpaulo
355281681Srpaulo        print "Handover select:"
356281681Srpaulo        try:
357281681Srpaulo            print sel.pretty()
358281681Srpaulo        except Exception, e:
359281681Srpaulo            print e
360281681Srpaulo        print str(sel).encode("hex")
361281681Srpaulo
362281681Srpaulo        summary("Sending handover select")
363281681Srpaulo        self.success = True
364281681Srpaulo        return sel
365281681Srpaulo
366281681Srpaulo
367281681Srpaulodef clear_raw_mode():
368281681Srpaulo    import sys, tty, termios
369281681Srpaulo    global prev_tcgetattr, in_raw_mode
370281681Srpaulo    if not in_raw_mode:
371281681Srpaulo        return
372281681Srpaulo    fd = sys.stdin.fileno()
373281681Srpaulo    termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
374281681Srpaulo    in_raw_mode = False
375281681Srpaulo
376281681Srpaulo
377281681Srpaulodef getch():
378281681Srpaulo    import sys, tty, termios, select
379281681Srpaulo    global prev_tcgetattr, in_raw_mode
380281681Srpaulo    fd = sys.stdin.fileno()
381281681Srpaulo    prev_tcgetattr = termios.tcgetattr(fd)
382281681Srpaulo    ch = None
383281681Srpaulo    try:
384281681Srpaulo        tty.setraw(fd)
385281681Srpaulo        in_raw_mode = True
386281681Srpaulo        [i, o, e] = select.select([fd], [], [], 0.05)
387281681Srpaulo        if i:
388281681Srpaulo            ch = sys.stdin.read(1)
389281681Srpaulo    finally:
390281681Srpaulo        termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
391281681Srpaulo        in_raw_mode = False
392281681Srpaulo    return ch
393281681Srpaulo
394281681Srpaulo
395281681Srpaulodef p2p_tag_read(tag):
396281681Srpaulo    success = False
397281681Srpaulo    if len(tag.ndef.message):
398281681Srpaulo        for record in tag.ndef.message:
399281681Srpaulo            print "record type " + record.type
400281681Srpaulo            if record.type == "application/vnd.wfa.wsc":
401281681Srpaulo                summary("WPS tag - send to wpa_supplicant")
402281681Srpaulo                success = wpas_tag_read(tag.ndef.message)
403281681Srpaulo                break
404281681Srpaulo            if record.type == "application/vnd.wfa.p2p":
405281681Srpaulo                summary("P2P tag - send to wpa_supplicant")
406281681Srpaulo                success = wpas_tag_read(tag.ndef.message)
407281681Srpaulo                break
408281681Srpaulo    else:
409281681Srpaulo        summary("Empty tag")
410281681Srpaulo
411281681Srpaulo    if success:
412281681Srpaulo        success_report("Tag read succeeded")
413281681Srpaulo
414281681Srpaulo    return success
415281681Srpaulo
416281681Srpaulo
417281681Srpaulodef rdwr_connected_p2p_write(tag):
418281681Srpaulo    summary("Tag found - writing - " + str(tag))
419281681Srpaulo    global p2p_sel_data
420281681Srpaulo    tag.ndef.message = str(p2p_sel_data)
421281681Srpaulo    success_report("Tag write succeeded")
422281681Srpaulo    print "Done - remove tag"
423281681Srpaulo    global only_one
424281681Srpaulo    if only_one:
425281681Srpaulo        global continue_loop
426281681Srpaulo        continue_loop = False
427281681Srpaulo    global p2p_sel_wait_remove
428281681Srpaulo    return p2p_sel_wait_remove
429281681Srpaulo
430281681Srpaulodef wps_write_p2p_handover_sel(clf, wait_remove=True):
431281681Srpaulo    print "Write P2P handover select"
432281681Srpaulo    data = wpas_get_handover_sel(tag=True)
433281681Srpaulo    if (data == None):
434281681Srpaulo        summary("Could not get P2P handover select from wpa_supplicant")
435281681Srpaulo        return
436281681Srpaulo
437281681Srpaulo    global p2p_sel_wait_remove
438281681Srpaulo    p2p_sel_wait_remove = wait_remove
439281681Srpaulo    global p2p_sel_data
440281681Srpaulo    p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
441281681Srpaulo    message = nfc.ndef.Message(data);
442281681Srpaulo    p2p_sel_data.add_carrier(message[0], "active", message[1:])
443281681Srpaulo    print "Handover select:"
444281681Srpaulo    try:
445281681Srpaulo        print p2p_sel_data.pretty()
446281681Srpaulo    except Exception, e:
447281681Srpaulo        print e
448281681Srpaulo    print str(p2p_sel_data).encode("hex")
449281681Srpaulo
450281681Srpaulo    print "Touch an NFC tag"
451281681Srpaulo    clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
452281681Srpaulo
453281681Srpaulo
454281681Srpaulodef rdwr_connected(tag):
455281681Srpaulo    global only_one, no_wait
456281681Srpaulo    summary("Tag connected: " + str(tag))
457281681Srpaulo
458281681Srpaulo    if tag.ndef:
459281681Srpaulo        print "NDEF tag: " + tag.type
460281681Srpaulo        try:
461281681Srpaulo            print tag.ndef.message.pretty()
462281681Srpaulo        except Exception, e:
463281681Srpaulo            print e
464281681Srpaulo        success = p2p_tag_read(tag)
465281681Srpaulo        if only_one and success:
466281681Srpaulo            global continue_loop
467281681Srpaulo            continue_loop = False
468281681Srpaulo    else:
469281681Srpaulo        summary("Not an NDEF tag - remove tag")
470281681Srpaulo        return True
471281681Srpaulo
472281681Srpaulo    return not no_wait
473281681Srpaulo
474281681Srpaulo
475281681Srpaulodef llcp_worker(llc):
476281681Srpaulo    global init_on_touch
477281681Srpaulo    if init_on_touch:
478281681Srpaulo            print "Starting handover client"
479281681Srpaulo            p2p_handover_client(llc)
480281681Srpaulo            return
481281681Srpaulo
482281681Srpaulo    global no_input
483281681Srpaulo    if no_input:
484281681Srpaulo        print "Wait for handover to complete"
485281681Srpaulo    else:
486281681Srpaulo        print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
487281681Srpaulo    global srv
488281681Srpaulo    global wait_connection
489281681Srpaulo    while not wait_connection and srv.sent_carrier is None:
490281681Srpaulo        if srv.ho_server_processing:
491281681Srpaulo            time.sleep(0.025)
492281681Srpaulo        elif no_input:
493281681Srpaulo            time.sleep(0.5)
494281681Srpaulo        else:
495281681Srpaulo            global include_wps_req, include_p2p_req
496281681Srpaulo            res = getch()
497281681Srpaulo            if res == 'i':
498281681Srpaulo                include_wps_req = True
499281681Srpaulo                include_p2p_req = True
500281681Srpaulo            elif res == 'p':
501281681Srpaulo                include_wps_req = False
502281681Srpaulo                include_p2p_req = True
503281681Srpaulo            elif res == 'w':
504281681Srpaulo                include_wps_req = True
505281681Srpaulo                include_p2p_req = False
506281681Srpaulo            else:
507281681Srpaulo                continue
508281681Srpaulo            clear_raw_mode()
509281681Srpaulo            print "Starting handover client"
510281681Srpaulo            p2p_handover_client(llc)
511281681Srpaulo            return
512281681Srpaulo
513281681Srpaulo    clear_raw_mode()
514281681Srpaulo    print "Exiting llcp_worker thread"
515281681Srpaulo
516281681Srpaulodef llcp_startup(clf, llc):
517281681Srpaulo    print "Start LLCP server"
518281681Srpaulo    global srv
519281681Srpaulo    srv = HandoverServer(llc)
520281681Srpaulo    return llc
521281681Srpaulo
522281681Srpaulodef llcp_connected(llc):
523281681Srpaulo    print "P2P LLCP connected"
524281681Srpaulo    global wait_connection
525281681Srpaulo    wait_connection = False
526281681Srpaulo    global init_on_touch
527281681Srpaulo    if not init_on_touch:
528281681Srpaulo        global srv
529281681Srpaulo        srv.start()
530281681Srpaulo    if init_on_touch or not no_input:
531281681Srpaulo        threading.Thread(target=llcp_worker, args=(llc,)).start()
532281681Srpaulo    return True
533281681Srpaulo
534281681Srpaulodef terminate_loop():
535281681Srpaulo    global terminate_now
536281681Srpaulo    return terminate_now
537281681Srpaulo
538281681Srpaulodef main():
539281681Srpaulo    clf = nfc.ContactlessFrontend()
540281681Srpaulo
541281681Srpaulo    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations')
542281681Srpaulo    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
543281681Srpaulo                        action='store_const', dest='loglevel',
544281681Srpaulo                        help='verbose debug output')
545281681Srpaulo    parser.add_argument('-q', const=logging.WARNING, action='store_const',
546281681Srpaulo                        dest='loglevel', help='be quiet')
547281681Srpaulo    parser.add_argument('--only-one', '-1', action='store_true',
548281681Srpaulo                        help='run only one operation and exit')
549281681Srpaulo    parser.add_argument('--init-on-touch', '-I', action='store_true',
550281681Srpaulo                        help='initiate handover on touch')
551281681Srpaulo    parser.add_argument('--no-wait', action='store_true',
552281681Srpaulo                        help='do not wait for tag to be removed before exiting')
553281681Srpaulo    parser.add_argument('--ifname', '-i',
554281681Srpaulo                        help='network interface name')
555281681Srpaulo    parser.add_argument('--no-wps-req', '-N', action='store_true',
556281681Srpaulo                        help='do not include WPS carrier record in request')
557281681Srpaulo    parser.add_argument('--no-input', '-a', action='store_true',
558281681Srpaulo                        help='do not use stdout input to initiate handover')
559281681Srpaulo    parser.add_argument('--tag-read-only', '-t', action='store_true',
560281681Srpaulo                        help='tag read only (do not allow connection handover)')
561281681Srpaulo    parser.add_argument('--handover-only', action='store_true',
562281681Srpaulo                        help='connection handover only (do not allow tag read)')
563281681Srpaulo    parser.add_argument('--freq', '-f',
564281681Srpaulo                        help='forced frequency of operating channel in MHz')
565281681Srpaulo    parser.add_argument('--summary',
566281681Srpaulo                        help='summary file for writing status updates')
567281681Srpaulo    parser.add_argument('--success',
568281681Srpaulo                        help='success file for writing success update')
569281681Srpaulo    parser.add_argument('command', choices=['write-p2p-sel'],
570281681Srpaulo                        nargs='?')
571281681Srpaulo    args = parser.parse_args()
572281681Srpaulo
573281681Srpaulo    global only_one
574281681Srpaulo    only_one = args.only_one
575281681Srpaulo
576281681Srpaulo    global no_wait
577281681Srpaulo    no_wait = args.no_wait
578281681Srpaulo
579281681Srpaulo    global force_freq
580281681Srpaulo    force_freq = args.freq
581281681Srpaulo
582281681Srpaulo    logging.basicConfig(level=args.loglevel)
583281681Srpaulo
584281681Srpaulo    global init_on_touch
585281681Srpaulo    init_on_touch = args.init_on_touch
586281681Srpaulo
587281681Srpaulo    if args.ifname:
588281681Srpaulo        global ifname
589281681Srpaulo        ifname = args.ifname
590281681Srpaulo        print "Selected ifname " + ifname
591281681Srpaulo
592281681Srpaulo    if args.no_wps_req:
593281681Srpaulo        global include_wps_req
594281681Srpaulo        include_wps_req = False
595281681Srpaulo
596281681Srpaulo    if args.summary:
597281681Srpaulo        global summary_file
598281681Srpaulo        summary_file = args.summary
599281681Srpaulo
600281681Srpaulo    if args.success:
601281681Srpaulo        global success_file
602281681Srpaulo        success_file = args.success
603281681Srpaulo
604281681Srpaulo    if args.no_input:
605281681Srpaulo        global no_input
606281681Srpaulo        no_input = True
607281681Srpaulo
608281681Srpaulo    clf = nfc.ContactlessFrontend()
609281681Srpaulo    global wait_connection
610281681Srpaulo
611281681Srpaulo    try:
612281681Srpaulo        if not clf.open("usb"):
613281681Srpaulo            print "Could not open connection with an NFC device"
614281681Srpaulo            raise SystemExit
615281681Srpaulo
616281681Srpaulo        if args.command == "write-p2p-sel":
617281681Srpaulo            wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait)
618281681Srpaulo            raise SystemExit
619281681Srpaulo
620281681Srpaulo        global continue_loop
621281681Srpaulo        while continue_loop:
622281681Srpaulo            print "Waiting for a tag or peer to be touched"
623281681Srpaulo            wait_connection = True
624281681Srpaulo            try:
625281681Srpaulo                if args.tag_read_only:
626281681Srpaulo                    if not clf.connect(rdwr={'on-connect': rdwr_connected}):
627281681Srpaulo                        break
628281681Srpaulo                elif args.handover_only:
629281681Srpaulo                    if not clf.connect(llcp={'on-startup': llcp_startup,
630281681Srpaulo                                             'on-connect': llcp_connected},
631281681Srpaulo                                       terminate=terminate_loop):
632281681Srpaulo                        break
633281681Srpaulo                else:
634281681Srpaulo                    if not clf.connect(rdwr={'on-connect': rdwr_connected},
635281681Srpaulo                                       llcp={'on-startup': llcp_startup,
636281681Srpaulo                                             'on-connect': llcp_connected},
637281681Srpaulo                                       terminate=terminate_loop):
638281681Srpaulo                        break
639281681Srpaulo            except Exception, e:
640281681Srpaulo                print "clf.connect failed"
641281681Srpaulo
642281681Srpaulo            global srv
643281681Srpaulo            if only_one and srv and srv.success:
644281681Srpaulo                raise SystemExit
645281681Srpaulo
646281681Srpaulo    except KeyboardInterrupt:
647281681Srpaulo        raise SystemExit
648281681Srpaulo    finally:
649281681Srpaulo        clf.close()
650281681Srpaulo
651281681Srpaulo    raise SystemExit
652281681Srpaulo
653281681Srpauloif __name__ == '__main__':
654281681Srpaulo    main()
655