1f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#!/usr/bin/python
2f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#
3f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt# Example nfcpy to hostapd wrapper for WPS NFC operations
4f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
5f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#
6f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt# This software may be distributed under the terms of the BSD license.
7f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt# See README for more details.
8f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
9f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport os
10f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport sys
11f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport time
12cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtimport argparse
13f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
14f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport nfc
15f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport nfc.ndef
16f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport nfc.llcp
17f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport nfc.handover
18f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
19f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtimport logging
20f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidtimport wpaspy
22f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
23f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtwpas_ctrl = '/var/run/hostapd'
24cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtcontinue_loop = True
2596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtsummary_file = None
2696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtsuccess_file = None
2796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
2896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtdef summary(txt):
2996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    print txt
3096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if summary_file:
3196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        with open(summary_file, 'a') as f:
3296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            f.write(txt + "\n")
3396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
3496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidtdef success_report(txt):
3596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary(txt)
3696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if success_file:
3796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        with open(success_file, 'a') as f:
3896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            f.write(txt + "\n")
39f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
40f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_connect():
41f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    ifaces = []
42f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if os.path.isdir(wpas_ctrl):
43f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        try:
44f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
45f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        except OSError, error:
46f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            print "Could not find hostapd: ", error
47f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            return None
48f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
49f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if len(ifaces) < 1:
50f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print "No hostapd control interface found"
51f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
52f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
53f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    for ctrl in ifaces:
54f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        try:
55700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt            wpas = wpaspy.Ctrl(ctrl)
56f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            return wpas
57700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt        except Exception, e:
58f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            pass
59f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    return None
60f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
61f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
62f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_tag_read(message):
63f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
64f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
6596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return False
66cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
67cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        return False
68cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return True
69f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
70f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
71f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_get_config_token():
72f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
73f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
74f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
7596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
7696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if "FAIL" in ret:
7796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return None
7896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    return ret.rstrip().decode("hex")
79f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
80f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
81f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_get_password_token():
82f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
83f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
84f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
8596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    ret = wpas.request("WPS_NFC_TOKEN NDEF")
8696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if "FAIL" in ret:
8796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return None
8896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    return ret.rstrip().decode("hex")
89f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
90f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
91f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_get_handover_sel():
92f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
93f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
94f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
9596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
9696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if "FAIL" in ret:
9796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return None
9896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    return ret.rstrip().decode("hex")
99f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
100f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
101f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wpas_report_handover(req, sel):
102f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    wpas = wpas_connect()
103f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if (wpas == None):
104f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return None
105f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
106f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                        str(req).encode("hex") + " " +
107f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                        str(sel).encode("hex"))
108f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
109f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
110f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtclass HandoverServer(nfc.handover.HandoverServer):
111cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    def __init__(self, llc):
112cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        super(HandoverServer, self).__init__(llc)
113cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.ho_server_processing = False
114cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.success = False
115f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
11696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    # override to avoid parser error in request/response.pretty() in nfcpy
11796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    # due to new WSC handover format
11896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    def _process_request(self, request):
11996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("received handover request {}".format(request.type))
12096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        response = nfc.ndef.Message("\xd1\x02\x01Hs\x12")
12196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        if not request.type == 'urn:nfc:wkt:Hr':
12296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            summary("not a handover request")
12396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        else:
12496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            try:
12596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                request = nfc.ndef.HandoverRequestMessage(request)
12696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            except nfc.ndef.DecodeError as e:
12796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("error decoding 'Hr' message: {}".format(e))
12896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt            else:
12996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                response = self.process_request(request)
13096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("send handover response {}".format(response.type))
13196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return response
13296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
133f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    def process_request(self, request):
13496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("HandoverServer - request received")
135cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
136cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Parsed handover request: " + request.pretty()
137cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
138cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
139cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print str(request).encode("hex")
140f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
141f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        sel = nfc.ndef.HandoverSelectMessage(version="1.2")
142f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
143f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        for carrier in request.carriers:
144f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            print "Remote carrier type: " + carrier.type
145f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            if carrier.type == "application/vnd.wfa.wsc":
14696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("WPS carrier type match - add WPS carrier record")
147f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                data = wpas_get_handover_sel()
148f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                if data is None:
14996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    summary("Could not get handover select carrier record from hostapd")
150f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                    continue
151f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                print "Handover select carrier record from hostapd:"
152f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                print data.encode("hex")
15396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                if "OK" in wpas_report_handover(carrier.record, data):
15496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    success_report("Handover reported successfully")
15596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                else:
15696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                    summary("Handover report rejected")
157f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
158f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                message = nfc.ndef.Message(data);
159f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                sel.add_carrier(message[0], "active", message[1:])
160f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
161f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print "Handover select:"
162cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
163cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print sel.pretty()
164cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
165cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
166f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        print str(sel).encode("hex")
167f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
16896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Sending handover select")
169cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        self.success = True
170f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return sel
171f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
172f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
173f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef wps_tag_read(tag):
174cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    success = False
175f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    if len(tag.ndef.message):
176cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        for record in tag.ndef.message:
177f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            print "record type " + record.type
178f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            if record.type == "application/vnd.wfa.wsc":
17996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                summary("WPS tag - send to hostapd")
180cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                success = wpas_tag_read(tag.ndef.message)
181f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt                break
182f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    else:
18396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Empty tag")
18496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
18596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if success:
18696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        success_report("Tag read succeeded")
187f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
188cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return success
189f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
190f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
191cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef rdwr_connected_write(tag):
19296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Tag found - writing - " + str(tag))
193cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data
194cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    tag.ndef.message = str(write_data)
19596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    success_report("Tag write succeeded")
196cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "Done - remove tag"
197cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one
198cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if only_one:
199cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global continue_loop
200cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        continue_loop = False
201cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_wait_remove
202cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    while write_wait_remove and tag.is_present:
203cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        time.sleep(0.1)
204cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
205cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef wps_write_config_tag(clf, wait_remove=True):
20696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Write WPS config token")
207cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data, write_wait_remove
208cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_wait_remove = wait_remove
209cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_data = wpas_get_config_token()
210cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if write_data == None:
21196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Could not get WPS config token from hostapd")
212f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
213f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
214f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Touch an NFC tag"
215cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf.connect(rdwr={'on-connect': rdwr_connected_write})
216f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
217f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
218cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef wps_write_password_tag(clf, wait_remove=True):
21996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Write WPS password token")
220cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global write_data, write_wait_remove
221cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_wait_remove = wait_remove
222cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    write_data = wpas_get_password_token()
223cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if write_data == None:
22496be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Could not get WPS password token from hostapd")
225f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        return
226f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
227f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    print "Touch an NFC tag"
228cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    clf.connect(rdwr={'on-connect': rdwr_connected_write})
229f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
230f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
231cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef rdwr_connected(tag):
232cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one, no_wait
23396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    summary("Tag connected: " + str(tag))
234cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
235cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    if tag.ndef:
236cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        print "NDEF tag: " + tag.type
237cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        try:
238cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print tag.ndef.message.pretty()
239cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        except Exception, e:
240cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print e
241cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        success = wps_tag_read(tag)
242cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if only_one and success:
243cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            global continue_loop
244cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            continue_loop = False
245cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    else:
24696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary("Not an NDEF tag - remove tag")
24796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        return True
248f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
249cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return not no_wait
250cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
251cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
252cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef llcp_startup(clf, llc):
253cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "Start LLCP server"
254cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global srv
255cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    srv = HandoverServer(llc)
256cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return llc
257cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
258cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtdef llcp_connected(llc):
259cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    print "P2P LLCP connected"
260cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global wait_connection
261cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    wait_connection = False
262cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global srv
263cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    srv.start()
264cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    return True
265f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
266f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
267f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtdef main():
268f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    clf = nfc.ContactlessFrontend()
269f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
270cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
271cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
272cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        action='store_const', dest='loglevel',
273cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='verbose debug output')
274cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('-q', const=logging.WARNING, action='store_const',
275cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        dest='loglevel', help='be quiet')
276cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--only-one', '-1', action='store_true',
277cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='run only one operation and exit')
278cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('--no-wait', action='store_true',
279cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        help='do not wait for tag to be removed before exiting')
28096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    parser.add_argument('--summary',
28196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                        help='summary file for writing status updates')
28296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    parser.add_argument('--success',
28396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt                        help='success file for writing success update')
284cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    parser.add_argument('command', choices=['write-config',
285cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                            'write-password'],
286cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                        nargs='?')
287cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    args = parser.parse_args()
288cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
289cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global only_one
290cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    only_one = args.only_one
291cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
292cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    global no_wait
293cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    no_wait = args.no_wait
294cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
29596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if args.summary:
29696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        global summary_file
29796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        summary_file = args.summary
29896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
29996be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt    if args.success:
30096be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        global success_file
30196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt        success_file = args.success
30296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
303cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt    logging.basicConfig(level=args.loglevel)
304cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
305f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    try:
306cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if not clf.open("usb"):
307cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Could not open connection with an NFC device"
308f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            raise SystemExit
309f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
310cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if args.command == "write-config":
311cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wps_write_config_tag(clf, wait_remove=not args.no_wait)
312f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt            raise SystemExit
313f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
314cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        if args.command == "write-password":
315cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wps_write_password_tag(clf, wait_remove=not args.no_wait)
316cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            raise SystemExit
317f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
318cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        global continue_loop
319cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        while continue_loop:
320cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            print "Waiting for a tag or peer to be touched"
321cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            wait_connection = True
322cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            try:
323cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                if not clf.connect(rdwr={'on-connect': rdwr_connected},
324cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                   llcp={'on-startup': llcp_startup,
325cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                                         'on-connect': llcp_connected}):
326cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                    break
327cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            except Exception, e:
328cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                print "clf.connect failed"
329cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
330cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            global srv
331cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt            if only_one and srv and srv.success:
332cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt                raise SystemExit
333f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
334f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    except KeyboardInterrupt:
335f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        raise SystemExit
336f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    finally:
337f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt        clf.close()
338f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
339f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    raise SystemExit
340f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
341f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtif __name__ == '__main__':
342f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt    main()
343