xref: /freebsd-src/contrib/wpa/wpa_supplicant/examples/p2p-nfc.py (revision 7648bc9fee8dec6cb3c4941e0165a930fbe8dcb0)
15b9c547cSRui Paulo#!/usr/bin/python
25b9c547cSRui Paulo#
35b9c547cSRui Paulo# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations
45b9c547cSRui Paulo# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
55b9c547cSRui Paulo#
65b9c547cSRui Paulo# This software may be distributed under the terms of the BSD license.
75b9c547cSRui Paulo# See README for more details.
85b9c547cSRui Paulo
95b9c547cSRui Pauloimport os
105b9c547cSRui Pauloimport sys
115b9c547cSRui Pauloimport time
125b9c547cSRui Pauloimport random
135b9c547cSRui Pauloimport threading
145b9c547cSRui Pauloimport argparse
155b9c547cSRui Paulo
165b9c547cSRui Pauloimport nfc
175b9c547cSRui Pauloimport nfc.ndef
185b9c547cSRui Pauloimport nfc.llcp
195b9c547cSRui Pauloimport nfc.handover
205b9c547cSRui Paulo
215b9c547cSRui Pauloimport logging
225b9c547cSRui Paulo
235b9c547cSRui Pauloimport wpaspy
245b9c547cSRui Paulo
255b9c547cSRui Paulowpas_ctrl = '/var/run/wpa_supplicant'
265b9c547cSRui Pauloifname = None
275b9c547cSRui Pauloinit_on_touch = False
285b9c547cSRui Pauloin_raw_mode = False
295b9c547cSRui Pauloprev_tcgetattr = 0
305b9c547cSRui Pauloinclude_wps_req = True
315b9c547cSRui Pauloinclude_p2p_req = True
325b9c547cSRui Paulono_input = False
335b9c547cSRui Paulosrv = None
345b9c547cSRui Paulocontinue_loop = True
355b9c547cSRui Pauloterminate_now = False
365b9c547cSRui Paulosummary_file = None
375b9c547cSRui Paulosuccess_file = None
385b9c547cSRui Paulo
395b9c547cSRui Paulodef summary(txt):
40*4bc52338SCy Schubert    print(txt)
415b9c547cSRui Paulo    if summary_file:
425b9c547cSRui Paulo        with open(summary_file, 'a') as f:
435b9c547cSRui Paulo            f.write(txt + "\n")
445b9c547cSRui Paulo
455b9c547cSRui Paulodef success_report(txt):
465b9c547cSRui Paulo    summary(txt)
475b9c547cSRui Paulo    if success_file:
485b9c547cSRui Paulo        with open(success_file, 'a') as f:
495b9c547cSRui Paulo            f.write(txt + "\n")
505b9c547cSRui Paulo
515b9c547cSRui Paulodef wpas_connect():
525b9c547cSRui Paulo    ifaces = []
535b9c547cSRui Paulo    if os.path.isdir(wpas_ctrl):
545b9c547cSRui Paulo        try:
555b9c547cSRui Paulo            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
56*4bc52338SCy Schubert        except OSError as error:
57*4bc52338SCy Schubert            print("Could not find wpa_supplicant: ", error)
585b9c547cSRui Paulo            return None
595b9c547cSRui Paulo
605b9c547cSRui Paulo    if len(ifaces) < 1:
61*4bc52338SCy Schubert        print("No wpa_supplicant control interface found")
625b9c547cSRui Paulo        return None
635b9c547cSRui Paulo
645b9c547cSRui Paulo    for ctrl in ifaces:
655b9c547cSRui Paulo        if ifname:
665b9c547cSRui Paulo            if ifname not in ctrl:
675b9c547cSRui Paulo                continue
685b9c547cSRui Paulo        try:
69*4bc52338SCy Schubert            print("Trying to use control interface " + ctrl)
705b9c547cSRui Paulo            wpas = wpaspy.Ctrl(ctrl)
715b9c547cSRui Paulo            return wpas
72*4bc52338SCy Schubert        except Exception as e:
735b9c547cSRui Paulo            pass
745b9c547cSRui Paulo    return None
755b9c547cSRui Paulo
765b9c547cSRui Paulo
775b9c547cSRui Paulodef wpas_tag_read(message):
785b9c547cSRui Paulo    wpas = wpas_connect()
795b9c547cSRui Paulo    if (wpas == None):
805b9c547cSRui Paulo        return False
815b9c547cSRui Paulo    cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex")
825b9c547cSRui Paulo    global force_freq
835b9c547cSRui Paulo    if force_freq:
845b9c547cSRui Paulo        cmd = cmd + " freq=" + force_freq
855b9c547cSRui Paulo    if "FAIL" in wpas.request(cmd):
865b9c547cSRui Paulo        return False
875b9c547cSRui Paulo    return True
885b9c547cSRui Paulo
895b9c547cSRui Paulo
905b9c547cSRui Paulodef wpas_get_handover_req():
915b9c547cSRui Paulo    wpas = wpas_connect()
925b9c547cSRui Paulo    if (wpas == None):
935b9c547cSRui Paulo        return None
945b9c547cSRui Paulo    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
955b9c547cSRui Paulo    if "FAIL" in res:
965b9c547cSRui Paulo        return None
975b9c547cSRui Paulo    return res.decode("hex")
985b9c547cSRui Paulo
995b9c547cSRui Paulodef wpas_get_handover_req_wps():
1005b9c547cSRui Paulo    wpas = wpas_connect()
1015b9c547cSRui Paulo    if (wpas == None):
1025b9c547cSRui Paulo        return None
1035b9c547cSRui Paulo    res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip()
1045b9c547cSRui Paulo    if "FAIL" in res:
1055b9c547cSRui Paulo        return None
1065b9c547cSRui Paulo    return res.decode("hex")
1075b9c547cSRui Paulo
1085b9c547cSRui Paulo
1095b9c547cSRui Paulodef wpas_get_handover_sel(tag=False):
1105b9c547cSRui Paulo    wpas = wpas_connect()
1115b9c547cSRui Paulo    if (wpas == None):
1125b9c547cSRui Paulo        return None
1135b9c547cSRui Paulo    if tag:
1145b9c547cSRui Paulo        res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip()
1155b9c547cSRui Paulo    else:
1165b9c547cSRui Paulo	res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
1175b9c547cSRui Paulo    if "FAIL" in res:
1185b9c547cSRui Paulo        return None
1195b9c547cSRui Paulo    return res.decode("hex")
1205b9c547cSRui Paulo
1215b9c547cSRui Paulo
1225b9c547cSRui Paulodef wpas_get_handover_sel_wps():
1235b9c547cSRui Paulo    wpas = wpas_connect()
1245b9c547cSRui Paulo    if (wpas == None):
1255b9c547cSRui Paulo        return None
1265b9c547cSRui Paulo    res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR");
1275b9c547cSRui Paulo    if "FAIL" in res:
1285b9c547cSRui Paulo        return None
1295b9c547cSRui Paulo    return res.rstrip().decode("hex")
1305b9c547cSRui Paulo
1315b9c547cSRui Paulo
1325b9c547cSRui Paulodef wpas_report_handover(req, sel, type):
1335b9c547cSRui Paulo    wpas = wpas_connect()
1345b9c547cSRui Paulo    if (wpas == None):
1355b9c547cSRui Paulo        return None
1365b9c547cSRui Paulo    cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex")
1375b9c547cSRui Paulo    global force_freq
1385b9c547cSRui Paulo    if force_freq:
1395b9c547cSRui Paulo        cmd = cmd + " freq=" + force_freq
1405b9c547cSRui Paulo    return wpas.request(cmd)
1415b9c547cSRui Paulo
1425b9c547cSRui Paulo
1435b9c547cSRui Paulodef wpas_report_handover_wsc(req, sel, type):
1445b9c547cSRui Paulo    wpas = wpas_connect()
1455b9c547cSRui Paulo    if (wpas == None):
1465b9c547cSRui Paulo        return None
1475b9c547cSRui Paulo    cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex")
1485b9c547cSRui Paulo    if force_freq:
1495b9c547cSRui Paulo        cmd = cmd + " freq=" + force_freq
1505b9c547cSRui Paulo    return wpas.request(cmd)
1515b9c547cSRui Paulo
1525b9c547cSRui Paulo
1535b9c547cSRui Paulodef p2p_handover_client(llc):
1545b9c547cSRui Paulo    message = nfc.ndef.HandoverRequestMessage(version="1.2")
1555b9c547cSRui Paulo    message.nonce = random.randint(0, 0xffff)
1565b9c547cSRui Paulo
1575b9c547cSRui Paulo    global include_p2p_req
1585b9c547cSRui Paulo    if include_p2p_req:
1595b9c547cSRui Paulo        data = wpas_get_handover_req()
1605b9c547cSRui Paulo        if (data == None):
1615b9c547cSRui Paulo            summary("Could not get handover request carrier record from wpa_supplicant")
1625b9c547cSRui Paulo            return
163*4bc52338SCy Schubert        print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
1645b9c547cSRui Paulo        datamsg = nfc.ndef.Message(data)
1655b9c547cSRui Paulo        message.add_carrier(datamsg[0], "active", datamsg[1:])
1665b9c547cSRui Paulo
1675b9c547cSRui Paulo    global include_wps_req
1685b9c547cSRui Paulo    if include_wps_req:
169*4bc52338SCy Schubert        print("Handover request (pre-WPS):")
1705b9c547cSRui Paulo        try:
171*4bc52338SCy Schubert            print(message.pretty())
172*4bc52338SCy Schubert        except Exception as e:
173*4bc52338SCy Schubert            print(e)
1745b9c547cSRui Paulo
1755b9c547cSRui Paulo        data = wpas_get_handover_req_wps()
1765b9c547cSRui Paulo        if data:
177*4bc52338SCy Schubert            print("Add WPS request in addition to P2P")
1785b9c547cSRui Paulo            datamsg = nfc.ndef.Message(data)
1795b9c547cSRui Paulo            message.add_carrier(datamsg[0], "active", datamsg[1:])
1805b9c547cSRui Paulo
181*4bc52338SCy Schubert    print("Handover request:")
1825b9c547cSRui Paulo    try:
183*4bc52338SCy Schubert        print(message.pretty())
184*4bc52338SCy Schubert    except Exception as e:
185*4bc52338SCy Schubert        print(e)
186*4bc52338SCy Schubert    print(str(message).encode("hex"))
1875b9c547cSRui Paulo
1885b9c547cSRui Paulo    client = nfc.handover.HandoverClient(llc)
1895b9c547cSRui Paulo    try:
1905b9c547cSRui Paulo        summary("Trying to initiate NFC connection handover")
1915b9c547cSRui Paulo        client.connect()
1925b9c547cSRui Paulo        summary("Connected for handover")
1935b9c547cSRui Paulo    except nfc.llcp.ConnectRefused:
1945b9c547cSRui Paulo        summary("Handover connection refused")
1955b9c547cSRui Paulo        client.close()
1965b9c547cSRui Paulo        return
197*4bc52338SCy Schubert    except Exception as e:
1985b9c547cSRui Paulo        summary("Other exception: " + str(e))
1995b9c547cSRui Paulo        client.close()
2005b9c547cSRui Paulo        return
2015b9c547cSRui Paulo
2025b9c547cSRui Paulo    summary("Sending handover request")
2035b9c547cSRui Paulo
2045b9c547cSRui Paulo    if not client.send(message):
2055b9c547cSRui Paulo        summary("Failed to send handover request")
2065b9c547cSRui Paulo        client.close()
2075b9c547cSRui Paulo        return
2085b9c547cSRui Paulo
2095b9c547cSRui Paulo    summary("Receiving handover response")
2105b9c547cSRui Paulo    message = client._recv()
2115b9c547cSRui Paulo    if message is None:
2125b9c547cSRui Paulo        summary("No response received")
2135b9c547cSRui Paulo        client.close()
2145b9c547cSRui Paulo        return
2155b9c547cSRui Paulo    if message.type != "urn:nfc:wkt:Hs":
2165b9c547cSRui Paulo        summary("Response was not Hs - received: " + message.type)
2175b9c547cSRui Paulo        client.close()
2185b9c547cSRui Paulo        return
2195b9c547cSRui Paulo
220*4bc52338SCy Schubert    print("Received message")
2215b9c547cSRui Paulo    try:
222*4bc52338SCy Schubert        print(message.pretty())
223*4bc52338SCy Schubert    except Exception as e:
224*4bc52338SCy Schubert        print(e)
225*4bc52338SCy Schubert    print(str(message).encode("hex"))
2265b9c547cSRui Paulo    message = nfc.ndef.HandoverSelectMessage(message)
2275b9c547cSRui Paulo    summary("Handover select received")
2285b9c547cSRui Paulo    try:
229*4bc52338SCy Schubert        print(message.pretty())
230*4bc52338SCy Schubert    except Exception as e:
231*4bc52338SCy Schubert        print(e)
2325b9c547cSRui Paulo
2335b9c547cSRui Paulo    for carrier in message.carriers:
234*4bc52338SCy Schubert        print("Remote carrier type: " + carrier.type)
2355b9c547cSRui Paulo        if carrier.type == "application/vnd.wfa.p2p":
236*4bc52338SCy Schubert            print("P2P carrier type match - send to wpa_supplicant")
2375b9c547cSRui Paulo            if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
2385b9c547cSRui Paulo                success_report("P2P handover reported successfully (initiator)")
2395b9c547cSRui Paulo            else:
2405b9c547cSRui Paulo                summary("P2P handover report rejected")
2415b9c547cSRui Paulo            break
2425b9c547cSRui Paulo
243*4bc52338SCy Schubert    print("Remove peer")
2445b9c547cSRui Paulo    client.close()
245*4bc52338SCy Schubert    print("Done with handover")
2465b9c547cSRui Paulo    global only_one
2475b9c547cSRui Paulo    if only_one:
248*4bc52338SCy Schubert        print("only_one -> stop loop")
2495b9c547cSRui Paulo        global continue_loop
2505b9c547cSRui Paulo        continue_loop = False
2515b9c547cSRui Paulo
2525b9c547cSRui Paulo    global no_wait
2535b9c547cSRui Paulo    if no_wait:
254*4bc52338SCy Schubert        print("Trying to exit..")
2555b9c547cSRui Paulo        global terminate_now
2565b9c547cSRui Paulo        terminate_now = True
2575b9c547cSRui Paulo
2585b9c547cSRui Paulo
2595b9c547cSRui Pauloclass HandoverServer(nfc.handover.HandoverServer):
2605b9c547cSRui Paulo    def __init__(self, llc):
2615b9c547cSRui Paulo        super(HandoverServer, self).__init__(llc)
2625b9c547cSRui Paulo        self.sent_carrier = None
2635b9c547cSRui Paulo        self.ho_server_processing = False
2645b9c547cSRui Paulo        self.success = False
2655b9c547cSRui Paulo
2665b9c547cSRui Paulo    # override to avoid parser error in request/response.pretty() in nfcpy
2675b9c547cSRui Paulo    # due to new WSC handover format
2685b9c547cSRui Paulo    def _process_request(self, request):
2695b9c547cSRui Paulo        summary("received handover request {}".format(request.type))
2705b9c547cSRui Paulo        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
2715b9c547cSRui Paulo        if not request.type == 'urn:nfc:wkt:Hr':
2725b9c547cSRui Paulo            summary("not a handover request")
2735b9c547cSRui Paulo        else:
2745b9c547cSRui Paulo            try:
2755b9c547cSRui Paulo                request = nfc.ndef.HandoverRequestMessage(request)
2765b9c547cSRui Paulo            except nfc.ndef.DecodeError as e:
2775b9c547cSRui Paulo                summary("error decoding 'Hr' message: {}".format(e))
2785b9c547cSRui Paulo            else:
2795b9c547cSRui Paulo                response = self.process_request(request)
2805b9c547cSRui Paulo        summary("send handover response {}".format(response.type))
2815b9c547cSRui Paulo        return response
2825b9c547cSRui Paulo
2835b9c547cSRui Paulo    def process_request(self, request):
2845b9c547cSRui Paulo        self.ho_server_processing = True
2855b9c547cSRui Paulo        clear_raw_mode()
286*4bc52338SCy Schubert        print("HandoverServer - request received")
2875b9c547cSRui Paulo        try:
288*4bc52338SCy Schubert            print("Parsed handover request: " + request.pretty())
289*4bc52338SCy Schubert        except Exception as e:
290*4bc52338SCy Schubert            print(e)
2915b9c547cSRui Paulo
2925b9c547cSRui Paulo        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
2935b9c547cSRui Paulo
2945b9c547cSRui Paulo        found = False
2955b9c547cSRui Paulo
2965b9c547cSRui Paulo        for carrier in request.carriers:
297*4bc52338SCy Schubert            print("Remote carrier type: " + carrier.type)
2985b9c547cSRui Paulo            if carrier.type == "application/vnd.wfa.p2p":
299*4bc52338SCy Schubert                print("P2P carrier type match - add P2P carrier record")
3005b9c547cSRui Paulo                found = True
3015b9c547cSRui Paulo                self.received_carrier = carrier.record
302*4bc52338SCy Schubert                print("Carrier record:")
3035b9c547cSRui Paulo                try:
304*4bc52338SCy Schubert                    print(carrier.record.pretty())
305*4bc52338SCy Schubert                except Exception as e:
306*4bc52338SCy Schubert                    print(e)
3075b9c547cSRui Paulo                data = wpas_get_handover_sel()
3085b9c547cSRui Paulo                if data is None:
309*4bc52338SCy Schubert                    print("Could not get handover select carrier record from wpa_supplicant")
3105b9c547cSRui Paulo                    continue
311*4bc52338SCy Schubert                print("Handover select carrier record from wpa_supplicant:")
312*4bc52338SCy Schubert                print(data.encode("hex"))
3135b9c547cSRui Paulo                self.sent_carrier = data
3145b9c547cSRui Paulo                if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
3155b9c547cSRui Paulo                    success_report("P2P handover reported successfully (responder)")
3165b9c547cSRui Paulo                else:
3175b9c547cSRui Paulo                    summary("P2P handover report rejected")
3185b9c547cSRui Paulo                    break
3195b9c547cSRui Paulo
3205b9c547cSRui Paulo                message = nfc.ndef.Message(data);
3215b9c547cSRui Paulo                sel.add_carrier(message[0], "active", message[1:])
3225b9c547cSRui Paulo                break
3235b9c547cSRui Paulo
3245b9c547cSRui Paulo        for carrier in request.carriers:
3255b9c547cSRui Paulo            if found:
3265b9c547cSRui Paulo                break
327*4bc52338SCy Schubert            print("Remote carrier type: " + carrier.type)
3285b9c547cSRui Paulo            if carrier.type == "application/vnd.wfa.wsc":
329*4bc52338SCy Schubert                print("WSC carrier type match - add WSC carrier record")
3305b9c547cSRui Paulo                found = True
3315b9c547cSRui Paulo                self.received_carrier = carrier.record
332*4bc52338SCy Schubert                print("Carrier record:")
3335b9c547cSRui Paulo                try:
334*4bc52338SCy Schubert                    print(carrier.record.pretty())
335*4bc52338SCy Schubert                except Exception as e:
336*4bc52338SCy Schubert                    print(e)
3375b9c547cSRui Paulo                data = wpas_get_handover_sel_wps()
3385b9c547cSRui Paulo                if data is None:
339*4bc52338SCy Schubert                    print("Could not get handover select carrier record from wpa_supplicant")
3405b9c547cSRui Paulo                    continue
341*4bc52338SCy Schubert                print("Handover select carrier record from wpa_supplicant:")
342*4bc52338SCy Schubert                print(data.encode("hex"))
3435b9c547cSRui Paulo                self.sent_carrier = data
3445b9c547cSRui Paulo                if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
3455b9c547cSRui Paulo                    success_report("WSC handover reported successfully")
3465b9c547cSRui Paulo                else:
3475b9c547cSRui Paulo                    summary("WSC handover report rejected")
3485b9c547cSRui Paulo                    break
3495b9c547cSRui Paulo
3505b9c547cSRui Paulo                message = nfc.ndef.Message(data);
3515b9c547cSRui Paulo                sel.add_carrier(message[0], "active", message[1:])
3525b9c547cSRui Paulo                found = True
3535b9c547cSRui Paulo                break
3545b9c547cSRui Paulo
355*4bc52338SCy Schubert        print("Handover select:")
3565b9c547cSRui Paulo        try:
357*4bc52338SCy Schubert            print(sel.pretty())
358*4bc52338SCy Schubert        except Exception as e:
359*4bc52338SCy Schubert            print(e)
360*4bc52338SCy Schubert        print(str(sel).encode("hex"))
3615b9c547cSRui Paulo
3625b9c547cSRui Paulo        summary("Sending handover select")
3635b9c547cSRui Paulo        self.success = True
3645b9c547cSRui Paulo        return sel
3655b9c547cSRui Paulo
3665b9c547cSRui Paulo
3675b9c547cSRui Paulodef clear_raw_mode():
3685b9c547cSRui Paulo    import sys, tty, termios
3695b9c547cSRui Paulo    global prev_tcgetattr, in_raw_mode
3705b9c547cSRui Paulo    if not in_raw_mode:
3715b9c547cSRui Paulo        return
3725b9c547cSRui Paulo    fd = sys.stdin.fileno()
3735b9c547cSRui Paulo    termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
3745b9c547cSRui Paulo    in_raw_mode = False
3755b9c547cSRui Paulo
3765b9c547cSRui Paulo
3775b9c547cSRui Paulodef getch():
3785b9c547cSRui Paulo    import sys, tty, termios, select
3795b9c547cSRui Paulo    global prev_tcgetattr, in_raw_mode
3805b9c547cSRui Paulo    fd = sys.stdin.fileno()
3815b9c547cSRui Paulo    prev_tcgetattr = termios.tcgetattr(fd)
3825b9c547cSRui Paulo    ch = None
3835b9c547cSRui Paulo    try:
3845b9c547cSRui Paulo        tty.setraw(fd)
3855b9c547cSRui Paulo        in_raw_mode = True
3865b9c547cSRui Paulo        [i, o, e] = select.select([fd], [], [], 0.05)
3875b9c547cSRui Paulo        if i:
3885b9c547cSRui Paulo            ch = sys.stdin.read(1)
3895b9c547cSRui Paulo    finally:
3905b9c547cSRui Paulo        termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
3915b9c547cSRui Paulo        in_raw_mode = False
3925b9c547cSRui Paulo    return ch
3935b9c547cSRui Paulo
3945b9c547cSRui Paulo
3955b9c547cSRui Paulodef p2p_tag_read(tag):
3965b9c547cSRui Paulo    success = False
3975b9c547cSRui Paulo    if len(tag.ndef.message):
3985b9c547cSRui Paulo        for record in tag.ndef.message:
399*4bc52338SCy Schubert            print("record type " + record.type)
4005b9c547cSRui Paulo            if record.type == "application/vnd.wfa.wsc":
4015b9c547cSRui Paulo                summary("WPS tag - send to wpa_supplicant")
4025b9c547cSRui Paulo                success = wpas_tag_read(tag.ndef.message)
4035b9c547cSRui Paulo                break
4045b9c547cSRui Paulo            if record.type == "application/vnd.wfa.p2p":
4055b9c547cSRui Paulo                summary("P2P tag - send to wpa_supplicant")
4065b9c547cSRui Paulo                success = wpas_tag_read(tag.ndef.message)
4075b9c547cSRui Paulo                break
4085b9c547cSRui Paulo    else:
4095b9c547cSRui Paulo        summary("Empty tag")
4105b9c547cSRui Paulo
4115b9c547cSRui Paulo    if success:
4125b9c547cSRui Paulo        success_report("Tag read succeeded")
4135b9c547cSRui Paulo
4145b9c547cSRui Paulo    return success
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo
4175b9c547cSRui Paulodef rdwr_connected_p2p_write(tag):
4185b9c547cSRui Paulo    summary("Tag found - writing - " + str(tag))
4195b9c547cSRui Paulo    global p2p_sel_data
4205b9c547cSRui Paulo    tag.ndef.message = str(p2p_sel_data)
4215b9c547cSRui Paulo    success_report("Tag write succeeded")
422*4bc52338SCy Schubert    print("Done - remove tag")
4235b9c547cSRui Paulo    global only_one
4245b9c547cSRui Paulo    if only_one:
4255b9c547cSRui Paulo        global continue_loop
4265b9c547cSRui Paulo        continue_loop = False
4275b9c547cSRui Paulo    global p2p_sel_wait_remove
4285b9c547cSRui Paulo    return p2p_sel_wait_remove
4295b9c547cSRui Paulo
4305b9c547cSRui Paulodef wps_write_p2p_handover_sel(clf, wait_remove=True):
431*4bc52338SCy Schubert    print("Write P2P handover select")
4325b9c547cSRui Paulo    data = wpas_get_handover_sel(tag=True)
4335b9c547cSRui Paulo    if (data == None):
4345b9c547cSRui Paulo        summary("Could not get P2P handover select from wpa_supplicant")
4355b9c547cSRui Paulo        return
4365b9c547cSRui Paulo
4375b9c547cSRui Paulo    global p2p_sel_wait_remove
4385b9c547cSRui Paulo    p2p_sel_wait_remove = wait_remove
4395b9c547cSRui Paulo    global p2p_sel_data
4405b9c547cSRui Paulo    p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
4415b9c547cSRui Paulo    message = nfc.ndef.Message(data);
4425b9c547cSRui Paulo    p2p_sel_data.add_carrier(message[0], "active", message[1:])
443*4bc52338SCy Schubert    print("Handover select:")
4445b9c547cSRui Paulo    try:
445*4bc52338SCy Schubert        print(p2p_sel_data.pretty())
446*4bc52338SCy Schubert    except Exception as e:
447*4bc52338SCy Schubert        print(e)
448*4bc52338SCy Schubert    print(str(p2p_sel_data).encode("hex"))
4495b9c547cSRui Paulo
450*4bc52338SCy Schubert    print("Touch an NFC tag")
4515b9c547cSRui Paulo    clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
4525b9c547cSRui Paulo
4535b9c547cSRui Paulo
4545b9c547cSRui Paulodef rdwr_connected(tag):
4555b9c547cSRui Paulo    global only_one, no_wait
4565b9c547cSRui Paulo    summary("Tag connected: " + str(tag))
4575b9c547cSRui Paulo
4585b9c547cSRui Paulo    if tag.ndef:
459*4bc52338SCy Schubert        print("NDEF tag: " + tag.type)
4605b9c547cSRui Paulo        try:
461*4bc52338SCy Schubert            print(tag.ndef.message.pretty())
462*4bc52338SCy Schubert        except Exception as e:
463*4bc52338SCy Schubert            print(e)
4645b9c547cSRui Paulo        success = p2p_tag_read(tag)
4655b9c547cSRui Paulo        if only_one and success:
4665b9c547cSRui Paulo            global continue_loop
4675b9c547cSRui Paulo            continue_loop = False
4685b9c547cSRui Paulo    else:
4695b9c547cSRui Paulo        summary("Not an NDEF tag - remove tag")
4705b9c547cSRui Paulo        return True
4715b9c547cSRui Paulo
4725b9c547cSRui Paulo    return not no_wait
4735b9c547cSRui Paulo
4745b9c547cSRui Paulo
4755b9c547cSRui Paulodef llcp_worker(llc):
4765b9c547cSRui Paulo    global init_on_touch
4775b9c547cSRui Paulo    if init_on_touch:
478*4bc52338SCy Schubert            print("Starting handover client")
4795b9c547cSRui Paulo            p2p_handover_client(llc)
4805b9c547cSRui Paulo            return
4815b9c547cSRui Paulo
4825b9c547cSRui Paulo    global no_input
4835b9c547cSRui Paulo    if no_input:
484*4bc52338SCy Schubert        print("Wait for handover to complete")
4855b9c547cSRui Paulo    else:
486*4bc52338SCy Schubert        print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)")
4875b9c547cSRui Paulo    global srv
4885b9c547cSRui Paulo    global wait_connection
4895b9c547cSRui Paulo    while not wait_connection and srv.sent_carrier is None:
4905b9c547cSRui Paulo        if srv.ho_server_processing:
4915b9c547cSRui Paulo            time.sleep(0.025)
4925b9c547cSRui Paulo        elif no_input:
4935b9c547cSRui Paulo            time.sleep(0.5)
4945b9c547cSRui Paulo        else:
4955b9c547cSRui Paulo            global include_wps_req, include_p2p_req
4965b9c547cSRui Paulo            res = getch()
4975b9c547cSRui Paulo            if res == 'i':
4985b9c547cSRui Paulo                include_wps_req = True
4995b9c547cSRui Paulo                include_p2p_req = True
5005b9c547cSRui Paulo            elif res == 'p':
5015b9c547cSRui Paulo                include_wps_req = False
5025b9c547cSRui Paulo                include_p2p_req = True
5035b9c547cSRui Paulo            elif res == 'w':
5045b9c547cSRui Paulo                include_wps_req = True
5055b9c547cSRui Paulo                include_p2p_req = False
5065b9c547cSRui Paulo            else:
5075b9c547cSRui Paulo                continue
5085b9c547cSRui Paulo            clear_raw_mode()
509*4bc52338SCy Schubert            print("Starting handover client")
5105b9c547cSRui Paulo            p2p_handover_client(llc)
5115b9c547cSRui Paulo            return
5125b9c547cSRui Paulo
5135b9c547cSRui Paulo    clear_raw_mode()
514*4bc52338SCy Schubert    print("Exiting llcp_worker thread")
5155b9c547cSRui Paulo
5165b9c547cSRui Paulodef llcp_startup(clf, llc):
517*4bc52338SCy Schubert    print("Start LLCP server")
5185b9c547cSRui Paulo    global srv
5195b9c547cSRui Paulo    srv = HandoverServer(llc)
5205b9c547cSRui Paulo    return llc
5215b9c547cSRui Paulo
5225b9c547cSRui Paulodef llcp_connected(llc):
523*4bc52338SCy Schubert    print("P2P LLCP connected")
5245b9c547cSRui Paulo    global wait_connection
5255b9c547cSRui Paulo    wait_connection = False
5265b9c547cSRui Paulo    global init_on_touch
5275b9c547cSRui Paulo    if not init_on_touch:
5285b9c547cSRui Paulo        global srv
5295b9c547cSRui Paulo        srv.start()
5305b9c547cSRui Paulo    if init_on_touch or not no_input:
5315b9c547cSRui Paulo        threading.Thread(target=llcp_worker, args=(llc,)).start()
5325b9c547cSRui Paulo    return True
5335b9c547cSRui Paulo
5345b9c547cSRui Paulodef terminate_loop():
5355b9c547cSRui Paulo    global terminate_now
5365b9c547cSRui Paulo    return terminate_now
5375b9c547cSRui Paulo
5385b9c547cSRui Paulodef main():
5395b9c547cSRui Paulo    clf = nfc.ContactlessFrontend()
5405b9c547cSRui Paulo
5415b9c547cSRui Paulo    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations')
5425b9c547cSRui Paulo    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
5435b9c547cSRui Paulo                        action='store_const', dest='loglevel',
5445b9c547cSRui Paulo                        help='verbose debug output')
5455b9c547cSRui Paulo    parser.add_argument('-q', const=logging.WARNING, action='store_const',
5465b9c547cSRui Paulo                        dest='loglevel', help='be quiet')
5475b9c547cSRui Paulo    parser.add_argument('--only-one', '-1', action='store_true',
5485b9c547cSRui Paulo                        help='run only one operation and exit')
5495b9c547cSRui Paulo    parser.add_argument('--init-on-touch', '-I', action='store_true',
5505b9c547cSRui Paulo                        help='initiate handover on touch')
5515b9c547cSRui Paulo    parser.add_argument('--no-wait', action='store_true',
5525b9c547cSRui Paulo                        help='do not wait for tag to be removed before exiting')
5535b9c547cSRui Paulo    parser.add_argument('--ifname', '-i',
5545b9c547cSRui Paulo                        help='network interface name')
5555b9c547cSRui Paulo    parser.add_argument('--no-wps-req', '-N', action='store_true',
5565b9c547cSRui Paulo                        help='do not include WPS carrier record in request')
5575b9c547cSRui Paulo    parser.add_argument('--no-input', '-a', action='store_true',
5585b9c547cSRui Paulo                        help='do not use stdout input to initiate handover')
5595b9c547cSRui Paulo    parser.add_argument('--tag-read-only', '-t', action='store_true',
5605b9c547cSRui Paulo                        help='tag read only (do not allow connection handover)')
5615b9c547cSRui Paulo    parser.add_argument('--handover-only', action='store_true',
5625b9c547cSRui Paulo                        help='connection handover only (do not allow tag read)')
5635b9c547cSRui Paulo    parser.add_argument('--freq', '-f',
5645b9c547cSRui Paulo                        help='forced frequency of operating channel in MHz')
5655b9c547cSRui Paulo    parser.add_argument('--summary',
5665b9c547cSRui Paulo                        help='summary file for writing status updates')
5675b9c547cSRui Paulo    parser.add_argument('--success',
5685b9c547cSRui Paulo                        help='success file for writing success update')
5695b9c547cSRui Paulo    parser.add_argument('command', choices=['write-p2p-sel'],
5705b9c547cSRui Paulo                        nargs='?')
5715b9c547cSRui Paulo    args = parser.parse_args()
5725b9c547cSRui Paulo
5735b9c547cSRui Paulo    global only_one
5745b9c547cSRui Paulo    only_one = args.only_one
5755b9c547cSRui Paulo
5765b9c547cSRui Paulo    global no_wait
5775b9c547cSRui Paulo    no_wait = args.no_wait
5785b9c547cSRui Paulo
5795b9c547cSRui Paulo    global force_freq
5805b9c547cSRui Paulo    force_freq = args.freq
5815b9c547cSRui Paulo
5825b9c547cSRui Paulo    logging.basicConfig(level=args.loglevel)
5835b9c547cSRui Paulo
5845b9c547cSRui Paulo    global init_on_touch
5855b9c547cSRui Paulo    init_on_touch = args.init_on_touch
5865b9c547cSRui Paulo
5875b9c547cSRui Paulo    if args.ifname:
5885b9c547cSRui Paulo        global ifname
5895b9c547cSRui Paulo        ifname = args.ifname
590*4bc52338SCy Schubert        print("Selected ifname " + ifname)
5915b9c547cSRui Paulo
5925b9c547cSRui Paulo    if args.no_wps_req:
5935b9c547cSRui Paulo        global include_wps_req
5945b9c547cSRui Paulo        include_wps_req = False
5955b9c547cSRui Paulo
5965b9c547cSRui Paulo    if args.summary:
5975b9c547cSRui Paulo        global summary_file
5985b9c547cSRui Paulo        summary_file = args.summary
5995b9c547cSRui Paulo
6005b9c547cSRui Paulo    if args.success:
6015b9c547cSRui Paulo        global success_file
6025b9c547cSRui Paulo        success_file = args.success
6035b9c547cSRui Paulo
6045b9c547cSRui Paulo    if args.no_input:
6055b9c547cSRui Paulo        global no_input
6065b9c547cSRui Paulo        no_input = True
6075b9c547cSRui Paulo
6085b9c547cSRui Paulo    clf = nfc.ContactlessFrontend()
6095b9c547cSRui Paulo    global wait_connection
6105b9c547cSRui Paulo
6115b9c547cSRui Paulo    try:
6125b9c547cSRui Paulo        if not clf.open("usb"):
613*4bc52338SCy Schubert            print("Could not open connection with an NFC device")
6145b9c547cSRui Paulo            raise SystemExit
6155b9c547cSRui Paulo
6165b9c547cSRui Paulo        if args.command == "write-p2p-sel":
6175b9c547cSRui Paulo            wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait)
6185b9c547cSRui Paulo            raise SystemExit
6195b9c547cSRui Paulo
6205b9c547cSRui Paulo        global continue_loop
6215b9c547cSRui Paulo        while continue_loop:
622*4bc52338SCy Schubert            print("Waiting for a tag or peer to be touched")
6235b9c547cSRui Paulo            wait_connection = True
6245b9c547cSRui Paulo            try:
6255b9c547cSRui Paulo                if args.tag_read_only:
6265b9c547cSRui Paulo                    if not clf.connect(rdwr={'on-connect': rdwr_connected}):
6275b9c547cSRui Paulo                        break
6285b9c547cSRui Paulo                elif args.handover_only:
6295b9c547cSRui Paulo                    if not clf.connect(llcp={'on-startup': llcp_startup,
6305b9c547cSRui Paulo                                             'on-connect': llcp_connected},
6315b9c547cSRui Paulo                                       terminate=terminate_loop):
6325b9c547cSRui Paulo                        break
6335b9c547cSRui Paulo                else:
6345b9c547cSRui Paulo                    if not clf.connect(rdwr={'on-connect': rdwr_connected},
6355b9c547cSRui Paulo                                       llcp={'on-startup': llcp_startup,
6365b9c547cSRui Paulo                                             'on-connect': llcp_connected},
6375b9c547cSRui Paulo                                       terminate=terminate_loop):
6385b9c547cSRui Paulo                        break
639*4bc52338SCy Schubert            except Exception as e:
640*4bc52338SCy Schubert                print("clf.connect failed")
6415b9c547cSRui Paulo
6425b9c547cSRui Paulo            global srv
6435b9c547cSRui Paulo            if only_one and srv and srv.success:
6445b9c547cSRui Paulo                raise SystemExit
6455b9c547cSRui Paulo
6465b9c547cSRui Paulo    except KeyboardInterrupt:
6475b9c547cSRui Paulo        raise SystemExit
6485b9c547cSRui Paulo    finally:
6495b9c547cSRui Paulo        clf.close()
6505b9c547cSRui Paulo
6515b9c547cSRui Paulo    raise SystemExit
6525b9c547cSRui Paulo
6535b9c547cSRui Pauloif __name__ == '__main__':
6545b9c547cSRui Paulo    main()
655