blob: 61b5519ace3071e8f9b3b9e05c48c4d4ac060d44 [file] [log] [blame]
Dmitry Shmidtf8623282013-02-20 14:34:59 -08001#!/usr/bin/python
2#
3# Example nfcpy to hostapd wrapper for WPS NFC operations
4# Copyright (c) 2012-2013, 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 logging
19logging.basicConfig()
20
Dmitry Shmidt700a1372013-03-15 14:14:44 -070021import wpaspy
Dmitry Shmidtf8623282013-02-20 14:34:59 -080022
23wpas_ctrl = '/var/run/hostapd'
24
25def wpas_connect():
26 ifaces = []
27 if os.path.isdir(wpas_ctrl):
28 try:
29 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
30 except OSError, error:
31 print "Could not find hostapd: ", error
32 return None
33
34 if len(ifaces) < 1:
35 print "No hostapd control interface found"
36 return None
37
38 for ctrl in ifaces:
39 try:
Dmitry Shmidt700a1372013-03-15 14:14:44 -070040 wpas = wpaspy.Ctrl(ctrl)
Dmitry Shmidtf8623282013-02-20 14:34:59 -080041 return wpas
Dmitry Shmidt700a1372013-03-15 14:14:44 -070042 except Exception, e:
Dmitry Shmidtf8623282013-02-20 14:34:59 -080043 pass
44 return None
45
46
47def wpas_tag_read(message):
48 wpas = wpas_connect()
49 if (wpas == None):
50 return
51 print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
52
53
54def wpas_get_config_token():
55 wpas = wpas_connect()
56 if (wpas == None):
57 return None
58 return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
59
60
61def wpas_get_password_token():
62 wpas = wpas_connect()
63 if (wpas == None):
64 return None
65 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
66
67
68def wpas_get_handover_sel():
69 wpas = wpas_connect()
70 if (wpas == None):
71 return None
72 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
73
74
75def wpas_report_handover(req, sel):
76 wpas = wpas_connect()
77 if (wpas == None):
78 return None
79 return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
80 str(req).encode("hex") + " " +
81 str(sel).encode("hex"))
82
83
84class HandoverServer(nfc.handover.HandoverServer):
85 def __init__(self):
86 super(HandoverServer, self).__init__()
87
88 def process_request(self, request):
89 print "HandoverServer - request received"
90 print "Parsed handover request: " + request.pretty()
91
92 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
93
94 for carrier in request.carriers:
95 print "Remote carrier type: " + carrier.type
96 if carrier.type == "application/vnd.wfa.wsc":
97 print "WPS carrier type match - add WPS carrier record"
98 self.received_carrier = carrier.record
99 data = wpas_get_handover_sel()
100 if data is None:
101 print "Could not get handover select carrier record from hostapd"
102 continue
103 print "Handover select carrier record from hostapd:"
104 print data.encode("hex")
105 self.sent_carrier = data
106
107 message = nfc.ndef.Message(data);
108 sel.add_carrier(message[0], "active", message[1:])
109
110 print "Handover select:"
111 print sel.pretty()
112 print str(sel).encode("hex")
113
114 print "Sending handover select"
115 return sel
116
117
118def wps_handover_resp(peer):
119 print "Trying to handle WPS handover"
120
121 srv = HandoverServer()
Dmitry Shmidt33e38bf2013-02-27 12:56:00 -0800122 srv.sent_carrier = None
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800123
124 nfc.llcp.activate(peer);
125
126 try:
127 print "Trying handover";
128 srv.start()
129 print "Wait for disconnect"
130 while nfc.llcp.connected():
131 time.sleep(0.1)
132 print "Disconnected after handover"
133 except nfc.llcp.ConnectRefused:
134 print "Handover connection refused"
135 nfc.llcp.shutdown()
136 return
137
138 if srv.sent_carrier:
139 wpas_report_handover(srv.received_carrier, srv.sent_carrier)
140
141 print "Remove peer"
142 nfc.llcp.shutdown()
143 print "Done with handover"
144
145
146def wps_tag_read(tag):
147 if len(tag.ndef.message):
148 message = nfc.ndef.Message(tag.ndef.message)
149 print "message type " + message.type
150
151 for record in message:
152 print "record type " + record.type
153 if record.type == "application/vnd.wfa.wsc":
154 print "WPS tag - send to hostapd"
155 wpas_tag_read(tag.ndef.message)
156 break
157 else:
158 print "Empty tag"
159
160 print "Remove tag"
161 while tag.is_present:
162 time.sleep(0.1)
163
164
165def wps_write_config_tag(clf):
166 print "Write WPS config token"
167 data = wpas_get_config_token()
168 if (data == None):
169 print "Could not get WPS config token from hostapd"
170 return
171
172 print "Touch an NFC tag"
173 while True:
174 tag = clf.poll()
175 if tag == None:
176 time.sleep(0.1)
177 continue
178 break
179
180 print "Tag found - writing"
181 tag.ndef.message = data
182 print "Done - remove tag"
183 while tag.is_present:
184 time.sleep(0.1)
185
186
187def wps_write_password_tag(clf):
188 print "Write WPS password token"
189 data = wpas_get_password_token()
190 if (data == None):
191 print "Could not get WPS password token from hostapd"
192 return
193
194 print "Touch an NFC tag"
195 while True:
196 tag = clf.poll()
197 if tag == None:
198 time.sleep(0.1)
199 continue
200 break
201
202 print "Tag found - writing"
203 tag.ndef.message = data
204 print "Done - remove tag"
205 while tag.is_present:
206 time.sleep(0.1)
207
208
209def find_peer(clf):
210 while True:
211 if nfc.llcp.connected():
212 print "LLCP connected"
213 general_bytes = nfc.llcp.startup({})
214 peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
215 if isinstance(peer, nfc.DEP):
216 print "listen -> DEP";
217 if peer.general_bytes.startswith("Ffm"):
218 print "Found DEP"
219 return peer
220 print "mismatch in general_bytes"
221 print peer.general_bytes
222
223 peer = clf.poll(general_bytes)
224 if isinstance(peer, nfc.DEP):
225 print "poll -> DEP";
226 if peer.general_bytes.startswith("Ffm"):
227 print "Found DEP"
228 return peer
229 print "mismatch in general_bytes"
230 print peer.general_bytes
231
232 if peer:
233 print "Found tag"
234 return peer
235
236
237def main():
238 clf = nfc.ContactlessFrontend()
239
240 try:
241 if len(sys.argv) > 1 and sys.argv[1] == "write-config":
242 wps_write_config_tag(clf)
243 raise SystemExit
244
245 if len(sys.argv) > 1 and sys.argv[1] == "write-password":
246 wps_write_password_tag(clf)
247 raise SystemExit
248
249 while True:
250 print "Waiting for a tag or peer to be touched"
251
252 tag = find_peer(clf)
253 if isinstance(tag, nfc.DEP):
254 wps_handover_resp(tag)
255 continue
256
257 if tag.ndef:
258 wps_tag_read(tag)
259 continue
260
261 print "Not an NDEF tag - remove tag"
262 while tag.is_present:
263 time.sleep(0.1)
264
265 except KeyboardInterrupt:
266 raise SystemExit
267 finally:
268 clf.close()
269
270 raise SystemExit
271
272if __name__ == '__main__':
273 main()