1d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#!/usr/bin/python
2d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#
3d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
4f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
5d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt#
6d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt# This software may be distributed under the terms of the BSD license.
7d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt# See README for more details.
8d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
9d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport os
10d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport sys
11d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport time
12f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport random
13cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtimport threading
14cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtimport argparse
15d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
16d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport nfc
17d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport nfc.ndef
18d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport nfc.llcp
19d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtimport nfc.handover
20d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
21f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport logging
22f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
23700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidtimport wpaspy
24d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
25d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtwpas_ctrl = '/var/run/wpa_supplicant'
26cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtsrv = None
27cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtcontinue_loop = True
28cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtterminate_now = False
2996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtsummary_file = None
3096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtsuccess_file = None
3196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
3296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtdef summary(txt):
3396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    print txt
3496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if summary_file:
3596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        with open(summary_file, 'a') as f:
3696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            f.write(txt + "\n")
3796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
3896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtdef success_report(txt):
3996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary(txt)
4096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if success_file:
4196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        with open(success_file, 'a') as f:
4296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            f.write(txt + "\n")
43d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
44d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtdef wpas_connect():
45d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    ifaces = []
46d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if os.path.isdir(wpas_ctrl):
47d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        try:
48d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
49d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        except OSError, error:
50d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            print "Could not find wpa_supplicant: ", error
51d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            return None
52d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
53d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if len(ifaces) < 1:
54d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        print "No wpa_supplicant control interface found"
55d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        return None
56d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
57d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    for ctrl in ifaces:
58d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        try:
59700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt            wpas = wpaspy.Ctrl(ctrl)
60d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            return wpas
61700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt        except Exception, e:
62d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            pass
63d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    return None
64d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
65d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
66d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtdef wpas_tag_read(message):
67d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    wpas = wpas_connect()
68d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if (wpas == None):
694b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        return False
70cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
714b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        return False
724b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    return True
73d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
741e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtdef wpas_get_config_token(id=None):
75f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
76f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
77f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
781e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt    if id:
794b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id)
804b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    else:
814b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    if "FAIL" in ret:
834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        return None
844b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    return ret.rstrip().decode("hex")
85f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
86f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
8733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidtdef wpas_get_er_config_token(uuid):
8833e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    wpas = wpas_connect()
8933e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    if (wpas == None):
9033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        return None
91cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid)
92cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if "FAIL" in ret:
93cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        return None
94cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return ret.rstrip().decode("hex")
9533e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
9633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
97f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_get_password_token():
98f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
99f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
100f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
10196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    ret = wpas.request("WPS_NFC_TOKEN NDEF")
10296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if "FAIL" in ret:
10396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return None
10496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    return ret.rstrip().decode("hex")
105f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
106d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtdef wpas_get_handover_req():
107d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    wpas = wpas_connect()
108d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if (wpas == None):
109d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        return None
11096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    ret = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR")
11196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if "FAIL" in ret:
11296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return None
11396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    return ret.rstrip().decode("hex")
114d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
115d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
11633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidtdef wpas_get_handover_sel(uuid):
117d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    wpas = wpas_connect()
118d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if (wpas == None):
119f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
12033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    if uuid is None:
121cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip()
122cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    else:
123cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip()
124cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if "FAIL" in res:
125cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return None
126cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return res.decode("hex")
12733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
12833e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
12933e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidtdef wpas_report_handover(req, sel, type):
13033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    wpas = wpas_connect()
13133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    if (wpas == None):
13233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        return None
13333e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
134f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                        str(req).encode("hex") + " " +
135f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                        str(sel).encode("hex"))
136d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
137d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
13833e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidtclass HandoverServer(nfc.handover.HandoverServer):
139cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    def __init__(self, llc):
140cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        super(HandoverServer, self).__init__(llc)
141cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.sent_carrier = None
142cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.ho_server_processing = False
143cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.success = False
14433e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
14596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    # override to avoid parser error in request/response.pretty() in nfcpy
14696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    # due to new WSC handover format
14796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    def _process_request(self, request):
14896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("received handover request {}".format(request.type))
14996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
15096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        if not request.type == 'urn:nfc:wkt:Hr':
15196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            summary("not a handover request")
15296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        else:
15396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            try:
15496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                request = nfc.ndef.HandoverRequestMessage(request)
15596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            except nfc.ndef.DecodeError as e:
15696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("error decoding 'Hr' message: {}".format(e))
15796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            else:
15896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                response = self.process_request(request)
15996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("send handover response {}".format(response.type))
16096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return response
16196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
16233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    def process_request(self, request):
163cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.ho_server_processing = True
16496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("HandoverServer - request received")
165cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
166cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Parsed handover request: " + request.pretty()
167cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
168cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
16933e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
17033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
17133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
17233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        for carrier in request.carriers:
17333e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt            print "Remote carrier type: " + carrier.type
17433e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt            if carrier.type == "application/vnd.wfa.wsc":
17596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("WPS carrier type match - add WPS carrier record")
17633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                data = wpas_get_handover_sel(self.uuid)
17733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                if data is None:
17896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    summary("Could not get handover select carrier record from wpa_supplicant")
17933e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                    continue
18033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                print "Handover select carrier record from wpa_supplicant:"
18133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                print data.encode("hex")
18233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                self.sent_carrier = data
18396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
18496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    success_report("Handover reported successfully (responder)")
18596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                else:
18696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    summary("Handover report rejected (responder)")
18733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
18833e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                message = nfc.ndef.Message(data);
18933e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt                sel.add_carrier(message[0], "active", message[1:])
19033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
19133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        print "Handover select:"
192cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
193cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print sel.pretty()
194cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
195cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
19633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        print str(sel).encode("hex")
19733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
19896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Sending handover select")
199cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.success = True
20033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        return sel
20133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
20233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
203cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef wps_handover_init(llc):
20496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Trying to initiate WPS handover")
205d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
206d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    data = wpas_get_handover_req()
207d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if (data == None):
20896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Could not get handover request carrier record from wpa_supplicant")
209d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        return
210f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
211f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
212f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    message = nfc.ndef.HandoverRequestMessage(version="1.2")
213f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    message.nonce = random.randint(0, 0xffff)
214cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    datamsg = nfc.ndef.Message(data)
215cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    message.add_carrier(datamsg[0], "active", datamsg[1:])
216f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
217f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Handover request:"
218cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    try:
219cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print message.pretty()
220cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    except Exception, e:
221cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print e
222cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print str(message).encode("hex")
223d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
224cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    client = nfc.handover.HandoverClient(llc)
225d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    try:
22696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Trying to initiate NFC connection handover")
227d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        client.connect()
22896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Connected for handover")
229d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    except nfc.llcp.ConnectRefused:
23096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Handover connection refused")
23196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        client.close()
23296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return
23396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    except Exception, e:
23496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Other exception: " + str(e))
235d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        client.close()
236d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        return
237d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
23896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Sending handover request")
239d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
240d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if not client.send(message):
24196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Failed to send handover request")
24296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        client.close()
24396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return
244d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
24596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Receiving handover response")
246d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    message = client._recv()
247f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if message is None:
24896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("No response received")
249f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        client.close()
250f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
251f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if message.type != "urn:nfc:wkt:Hs":
25296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Response was not Hs - received: " + message.type)
253f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        client.close()
254f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
255f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
256f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Received message"
257cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    try:
258cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print message.pretty()
259cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    except Exception, e:
260cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print e
261cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print str(message).encode("hex")
262f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    message = nfc.ndef.HandoverSelectMessage(message)
26396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Handover select received")
264cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    try:
265cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print message.pretty()
266cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    except Exception, e:
267cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print e
268f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
269f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    for carrier in message.carriers:
270f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print "Remote carrier type: " + carrier.type
271f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        if carrier.type == "application/vnd.wfa.wsc":
272f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            print "WPS carrier type match - send to wpa_supplicant"
27396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
27496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                success_report("Handover reported successfully (initiator)")
27596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            else:
27696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("Handover report rejected (initiator)")
277cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            # nfcpy does not support the new format..
278cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            #wifi = nfc.ndef.WifiConfigRecord(carrier.record)
279cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            #print wifi.pretty()
280d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
281d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    print "Remove peer"
282d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    client.close()
283d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    print "Done with handover"
284cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one
285cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if only_one:
286cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global continue_loop
287cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        continue_loop = False
288d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
289cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global no_wait
290cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if no_wait:
291cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print "Trying to exit.."
292cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global terminate_now
293cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        terminate_now = True
294d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2954b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidtdef wps_tag_read(tag, wait_remove=True):
2964b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    success = False
297d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    if len(tag.ndef.message):
298cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        for record in tag.ndef.message:
299d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            print "record type " + record.type
300d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            if record.type == "application/vnd.wfa.wsc":
30196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("WPS tag - send to wpa_supplicant")
3024b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt                success = wpas_tag_read(tag.ndef.message)
303d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt                break
304d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    else:
30596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Empty tag")
30696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
30796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if success:
30896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        success_report("Tag read succeeded")
309d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
3104b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    if wait_remove:
3114b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        print "Remove tag"
3124b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        while tag.is_present:
3134b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt            time.sleep(0.1)
3144b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
3154b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt    return success
316d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
317d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
318cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef rdwr_connected_write(tag):
31996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Tag found - writing - " + str(tag))
320cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data
321cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    tag.ndef.message = str(write_data)
32296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    success_report("Tag write succeeded")
323cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "Done - remove tag"
324cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one
325cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if only_one:
326cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global continue_loop
327cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        continue_loop = False
328cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_wait_remove
329cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    while write_wait_remove and tag.is_present:
330cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        time.sleep(0.1)
331cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
3324b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidtdef wps_write_config_tag(clf, id=None, wait_remove=True):
333f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Write WPS config token"
334cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data, write_wait_remove
335cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_wait_remove = wait_remove
336cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_data = wpas_get_config_token(id)
337cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if write_data == None:
338f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print "Could not get WPS config token from wpa_supplicant"
3394b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        sys.exit(1)
340f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
341f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Touch an NFC tag"
342cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf.connect(rdwr={'on-connect': rdwr_connected_write})
343f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
344f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
345cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef wps_write_er_config_tag(clf, uuid, wait_remove=True):
34633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    print "Write WPS ER config token"
347cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data, write_wait_remove
348cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_wait_remove = wait_remove
349cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_data = wpas_get_er_config_token(uuid)
350cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if write_data == None:
35133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        print "Could not get WPS config token from wpa_supplicant"
35233e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt        return
35333e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
35433e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt    print "Touch an NFC tag"
355cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf.connect(rdwr={'on-connect': rdwr_connected_write})
35633e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
35733e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
3584b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidtdef wps_write_password_tag(clf, wait_remove=True):
359f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Write WPS password token"
360cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data, write_wait_remove
361cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_wait_remove = wait_remove
362cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_data = wpas_get_password_token()
363cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if write_data == None:
364f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print "Could not get WPS password token from wpa_supplicant"
365f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
366f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
367f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Touch an NFC tag"
368cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf.connect(rdwr={'on-connect': rdwr_connected_write})
369f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
370f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
371cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef rdwr_connected(tag):
372cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one, no_wait
37396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Tag connected: " + str(tag))
374f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
375cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if tag.ndef:
376cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print "NDEF tag: " + tag.type
377cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
378cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print tag.ndef.message.pretty()
379cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
380cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
381cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        success = wps_tag_read(tag, not only_one)
382cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if only_one and success:
383cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            global continue_loop
384cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            continue_loop = False
385cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    else:
38696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Not an NDEF tag - remove tag")
38796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return True
388f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
389cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return not no_wait
390f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
391d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
392cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef llcp_worker(llc):
393cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global arg_uuid
394cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if arg_uuid is None:
395cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        wps_handover_init(llc)
396cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print "Exiting llcp_worker thread"
397cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        return
39833e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
399cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global srv
400cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global wait_connection
401cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    while not wait_connection and srv.sent_carrier is None:
402cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if srv.ho_server_processing:
403cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            time.sleep(0.025)
404cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
405cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef llcp_startup(clf, llc):
406cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global arg_uuid
407cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if arg_uuid:
408cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print "Start LLCP server"
409cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global srv
410cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        srv = HandoverServer(llc)
411cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if arg_uuid is "ap":
412cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Trying to handle WPS handover"
413cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            srv.uuid = None
4144b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt        else:
415cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Trying to handle WPS handover with AP " + arg_uuid
416cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            srv.uuid = arg_uuid
417cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return llc
418cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
419cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef llcp_connected(llc):
420cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "P2P LLCP connected"
421cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global wait_connection
422cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    wait_connection = False
423cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global arg_uuid
424cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if arg_uuid:
425cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global srv
426cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        srv.start()
427cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    else:
428cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        threading.Thread(target=llcp_worker, args=(llc,)).start()
429cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "llcp_connected returning"
430cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return True
4314b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
432f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
433cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef terminate_loop():
434cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global terminate_now
435cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return terminate_now
436cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
437cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef main():
438cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf = nfc.ContactlessFrontend()
439cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
440cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations')
441cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
442cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        action='store_const', dest='loglevel',
443cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='verbose debug output')
444cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('-q', const=logging.WARNING, action='store_const',
445cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        dest='loglevel', help='be quiet')
446cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--only-one', '-1', action='store_true',
447cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='run only one operation and exit')
448cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--no-wait', action='store_true',
449cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='do not wait for tag to be removed before exiting')
450cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--uuid',
451cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='UUID of an AP (used for WPS ER operations)')
452cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--id',
453cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='network id (used for WPS ER operations)')
45496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    parser.add_argument('--summary',
45596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                        help='summary file for writing status updates')
45696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    parser.add_argument('--success',
45796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                        help='success file for writing success update')
458cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('command', choices=['write-config',
459cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                            'write-er-config',
460cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                            'write-password'],
461cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        nargs='?')
462cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    args = parser.parse_args()
463cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
464cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global arg_uuid
465cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    arg_uuid = args.uuid
466cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
467cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one
468cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    only_one = args.only_one
469cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
470cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global no_wait
471cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    no_wait = args.no_wait
472cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
47396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if args.summary:
47496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        global summary_file
47596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary_file = args.summary
47696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
47796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if args.success:
47896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        global success_file
47996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        success_file = args.success
48096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
481cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    logging.basicConfig(level=args.loglevel)
4824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
483cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    try:
484cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if not clf.open("usb"):
485cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Could not open connection with an NFC device"
4861e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt            raise SystemExit
4871e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
488cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if args.command == "write-config":
489cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait)
49033e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt            raise SystemExit
49133e38bfa7159cef089d6ee0d904778e184c72c47Dmitry Shmidt
492cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if args.command == "write-er-config":
493cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait)
494f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            raise SystemExit
495f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
496cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if args.command == "write-password":
497cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wps_write_password_tag(clf, wait_remove=not args.no_wait)
4984b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt            raise SystemExit
4994b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
500cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global continue_loop
501cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        while continue_loop:
502d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt            print "Waiting for a tag or peer to be touched"
503cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wait_connection = True
504cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            try:
505cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                if not clf.connect(rdwr={'on-connect': rdwr_connected},
506cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                   llcp={'on-startup': llcp_startup,
507cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                         'on-connect': llcp_connected},
508cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                   terminate=terminate_loop):
5094b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt                    break
510cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            except Exception, e:
511cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                print "clf.connect failed"
512f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
513cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            global srv
514cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            if only_one and srv and srv.success:
515cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                raise SystemExit
516d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
517d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    except KeyboardInterrupt:
518d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        raise SystemExit
519d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    finally:
520d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt        clf.close()
521d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
522d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    raise SystemExit
523d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
524d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtif __name__ == '__main__':
525d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt    main()
526