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