1#!/usr/bin/python
2#
3# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
4# Copyright (c) 2012, Jouni Malinen <j@w1.fi>
5#
6# This software may be distributed under the terms of the BSD license.
7# See README for more details.
8
9import os
10import sys
11import time
12
13import nfc
14import nfc.ndef
15import nfc.llcp
16import nfc.handover
17
18import wpactrl
19
20wpas_ctrl = '/var/run/wpa_supplicant'
21
22def wpas_connect():
23    ifaces = []
24    if os.path.isdir(wpas_ctrl):
25        try:
26            ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
27        except OSError, error:
28            print "Could not find wpa_supplicant: ", error
29            return None
30
31    if len(ifaces) < 1:
32        print "No wpa_supplicant control interface found"
33        return None
34
35    for ctrl in ifaces:
36        try:
37            wpas = wpactrl.WPACtrl(ctrl)
38            return wpas
39        except wpactrl.error, error:
40            print "Error: ", error
41            pass
42    return None
43
44
45def wpas_tag_read(message):
46    wpas = wpas_connect()
47    if (wpas == None):
48        return
49    print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
50
51
52def wpas_get_handover_req():
53    wpas = wpas_connect()
54    if (wpas == None):
55        return None
56    return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS").rstrip().decode("hex")
57
58
59def wpas_put_handover_sel(message):
60    wpas = wpas_connect()
61    if (wpas == None):
62        return
63    print wpas.request("NFC_RX_HANDOVER_SEL " + str(message).encode("hex"))
64
65
66def wps_handover_init(peer):
67    print "Trying to initiate WPS handover"
68
69    data = wpas_get_handover_req()
70    if (data == None):
71        print "Could not get handover request message from wpa_supplicant"
72        return
73    print "Handover request from wpa_supplicant: " + data.encode("hex")
74    message = nfc.ndef.Message(data)
75    print "Parsed handover request: " + message.pretty()
76
77    nfc.llcp.activate(peer);
78    time.sleep(0.5)
79
80    client = nfc.handover.HandoverClient()
81    try:
82        print "Trying handover";
83        client.connect()
84        print "Connected for handover"
85    except nfc.llcp.ConnectRefused:
86        print "Handover connection refused"
87        nfc.llcp.shutdown()
88        client.close()
89        return
90
91    print "Sending handover request"
92
93    if not client.send(message):
94        print "Failed to send handover request"
95
96    print "Receiving handover response"
97    message = client._recv()
98    print "Handover select received"
99    print message.pretty()
100    wpas_put_handover_sel(message)
101
102    print "Remove peer"
103    nfc.llcp.shutdown()
104    client.close()
105    print "Done with handover"
106
107
108def wps_tag_read(tag):
109    if len(tag.ndef.message):
110        message = nfc.ndef.Message(tag.ndef.message)
111        print "message type " + message.type
112
113        for record in message:
114            print "record type " + record.type
115            if record.type == "application/vnd.wfa.wsc":
116                print "WPS tag - send to wpa_supplicant"
117                wpas_tag_read(tag.ndef.message)
118                break
119    else:
120        print "Empty tag"
121
122    print "Remove tag"
123    while tag.is_present:
124        time.sleep(0.1)
125
126
127def main():
128    clf = nfc.ContactlessFrontend()
129
130    try:
131        while True:
132            print "Waiting for a tag or peer to be touched"
133
134            while True:
135                general_bytes = nfc.llcp.startup({})
136                tag = clf.poll(general_bytes)
137                if tag == None:
138                    continue
139
140                if isinstance(tag, nfc.DEP):
141                    wps_handover_init(tag)
142                    break
143
144                if tag.ndef:
145                    wps_tag_read(tag)
146                    break
147
148                if tag:
149                    print "Not an NDEF tag - remove tag"
150                    while tag.is_present:
151                        time.sleep(0.1)
152                    break
153
154    except KeyboardInterrupt:
155        raise SystemExit
156    finally:
157        clf.close()
158
159    raise SystemExit
160
161if __name__ == '__main__':
162    main()
163