]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/wps-ap-nfc.py
WPS NFC: Clean up nfcpy script no-wait operations
[thirdparty/hostap.git] / hostapd / wps-ap-nfc.py
CommitLineData
68f51f9a
JM
1#!/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
ab1db08c 12import argparse
68f51f9a
JM
13
14import nfc
15import nfc.ndef
16import nfc.llcp
17import nfc.handover
18
8140ae96
JM
19import logging
20logging.basicConfig()
21
c3aa4da9 22import wpaspy
68f51f9a
JM
23
24wpas_ctrl = '/var/run/hostapd'
6f8fa6e5 25continue_loop = True
68f51f9a
JM
26
27def wpas_connect():
28 ifaces = []
29 if os.path.isdir(wpas_ctrl):
30 try:
31 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
32 except OSError, error:
33 print "Could not find hostapd: ", error
34 return None
35
36 if len(ifaces) < 1:
37 print "No hostapd control interface found"
38 return None
39
40 for ctrl in ifaces:
41 try:
c3aa4da9 42 wpas = wpaspy.Ctrl(ctrl)
68f51f9a 43 return wpas
c3aa4da9 44 except Exception, e:
68f51f9a
JM
45 pass
46 return None
47
48
49def wpas_tag_read(message):
50 wpas = wpas_connect()
51 if (wpas == None):
52 return
6f8fa6e5
JM
53 if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
54 return False
55 return True
68f51f9a
JM
56
57
58def wpas_get_config_token():
59 wpas = wpas_connect()
60 if (wpas == None):
61 return None
62 return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
63
64
65def wpas_get_password_token():
66 wpas = wpas_connect()
67 if (wpas == None):
68 return None
69 return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
70
71
51e985dd 72def wpas_get_handover_sel():
68f51f9a
JM
73 wpas = wpas_connect()
74 if (wpas == None):
75 return None
51e985dd 76 return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
68f51f9a
JM
77
78
e4758827 79def wpas_report_handover(req, sel):
68f51f9a
JM
80 wpas = wpas_connect()
81 if (wpas == None):
e4758827
JM
82 return None
83 return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
84 str(req).encode("hex") + " " +
85 str(sel).encode("hex"))
68f51f9a
JM
86
87
51e985dd 88class HandoverServer(nfc.handover.HandoverServer):
6f8fa6e5
JM
89 def __init__(self, llc):
90 super(HandoverServer, self).__init__(llc)
91 self.ho_server_processing = False
92 self.success = False
68f51f9a 93
51e985dd
JM
94 def process_request(self, request):
95 print "HandoverServer - request received"
96 print "Parsed handover request: " + request.pretty()
97
98 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
99
100 for carrier in request.carriers:
101 print "Remote carrier type: " + carrier.type
102 if carrier.type == "application/vnd.wfa.wsc":
103 print "WPS carrier type match - add WPS carrier record"
104 data = wpas_get_handover_sel()
105 if data is None:
106 print "Could not get handover select carrier record from hostapd"
107 continue
108 print "Handover select carrier record from hostapd:"
109 print data.encode("hex")
6f8fa6e5 110 wpas_report_handover(carrier.record, data)
51e985dd
JM
111
112 message = nfc.ndef.Message(data);
113 sel.add_carrier(message[0], "active", message[1:])
114
115 print "Handover select:"
116 print sel.pretty()
117 print str(sel).encode("hex")
118
119 print "Sending handover select"
6f8fa6e5 120 self.success = True
51e985dd
JM
121 return sel
122
123
68f51f9a 124def wps_tag_read(tag):
6f8fa6e5 125 success = False
68f51f9a 126 if len(tag.ndef.message):
6f8fa6e5 127 for record in tag.ndef.message:
68f51f9a
JM
128 print "record type " + record.type
129 if record.type == "application/vnd.wfa.wsc":
130 print "WPS tag - send to hostapd"
6f8fa6e5 131 success = wpas_tag_read(tag.ndef.message)
68f51f9a
JM
132 break
133 else:
134 print "Empty tag"
135
6f8fa6e5 136 return success
68f51f9a
JM
137
138
6f8fa6e5
JM
139def rdwr_connected_write(tag):
140 print "Tag found - writing"
141 global write_data
142 tag.ndef.message = str(write_data)
143 print "Done - remove tag"
144 global only_one
145 if only_one:
146 global continue_loop
147 continue_loop = False
148 global write_wait_remove
149 while write_wait_remove and tag.is_present:
150 time.sleep(0.1)
151
1f1b5b31 152def wps_write_config_tag(clf, wait_remove=True):
68f51f9a 153 print "Write WPS config token"
6f8fa6e5 154 global write_data, write_wait_remove
1f1b5b31 155 write_wait_remove = wait_remove
6f8fa6e5
JM
156 write_data = wpas_get_config_token()
157 if write_data == None:
68f51f9a
JM
158 print "Could not get WPS config token from hostapd"
159 return
160
161 print "Touch an NFC tag"
6f8fa6e5 162 clf.connect(rdwr={'on-connect': rdwr_connected_write})
68f51f9a
JM
163
164
1f1b5b31 165def wps_write_password_tag(clf, wait_remove=True):
68f51f9a 166 print "Write WPS password token"
6f8fa6e5 167 global write_data, write_wait_remove
1f1b5b31 168 write_wait_remove = wait_remove
6f8fa6e5
JM
169 write_data = wpas_get_password_token()
170 if write_data == None:
68f51f9a
JM
171 print "Could not get WPS password token from hostapd"
172 return
173
174 print "Touch an NFC tag"
6f8fa6e5
JM
175 clf.connect(rdwr={'on-connect': rdwr_connected_write})
176
177
178def rdwr_connected(tag):
1f1b5b31 179 global only_one, no_wait
6f8fa6e5
JM
180 print "Tag connected: " + str(tag)
181
182 if tag.ndef:
183 print "NDEF tag: " + tag.type
184 try:
185 print tag.ndef.message.pretty()
186 except Exception, e:
187 print e
188 success = wps_tag_read(tag)
189 if only_one and success:
190 global continue_loop
191 continue_loop = False
192 else:
193 print "Not an NDEF tag - remove tag"
68f51f9a 194
6f8fa6e5
JM
195 return not no_wait
196
68f51f9a 197
6f8fa6e5
JM
198def llcp_startup(clf, llc):
199 print "Start LLCP server"
200 global srv
201 srv = HandoverServer(llc)
202 return llc
68f51f9a 203
6f8fa6e5
JM
204def llcp_connected(llc):
205 print "P2P LLCP connected"
206 global wait_connection
207 wait_connection = False
208 global srv
209 srv.start()
210 return True
dc6bda11
JM
211
212
68f51f9a
JM
213def main():
214 clf = nfc.ContactlessFrontend()
215
ab1db08c
JM
216 parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
217 parser.add_argument('--only-one', '-1', action='store_true',
218 help='run only one operation and exit')
1f1b5b31
JM
219 parser.add_argument('--no-wait', action='store_true',
220 help='do not wait for tag to be removed before exiting')
ab1db08c
JM
221 parser.add_argument('command', choices=['write-config',
222 'write-password'],
223 nargs='?')
224 args = parser.parse_args()
225
226 global only_one
227 only_one = args.only_one
228
1f1b5b31
JM
229 global no_wait
230 no_wait = args.no_wait
231
68f51f9a 232 try:
6f8fa6e5
JM
233 if not clf.open("usb"):
234 print "Could not open connection with an NFC device"
235 raise SystemExit
236
ab1db08c 237 if args.command == "write-config":
1f1b5b31 238 wps_write_config_tag(clf, wait_remove=not args.no_wait)
68f51f9a
JM
239 raise SystemExit
240
ab1db08c 241 if args.command == "write-password":
1f1b5b31 242 wps_write_password_tag(clf, wait_remove=not args.no_wait)
68f51f9a
JM
243 raise SystemExit
244
6f8fa6e5
JM
245 global continue_loop
246 while continue_loop:
68f51f9a 247 print "Waiting for a tag or peer to be touched"
6f8fa6e5
JM
248 wait_connection = True
249 try:
250 if not clf.connect(rdwr={'on-connect': rdwr_connected},
251 llcp={'on-startup': llcp_startup,
252 'on-connect': llcp_connected}):
253 break
254 except Exception, e:
255 print "clf.connect failed"
256
257 global srv
258 if only_one and srv and srv.success:
259 raise SystemExit
68f51f9a
JM
260
261 except KeyboardInterrupt:
262 raise SystemExit
263 finally:
264 clf.close()
265
266 raise SystemExit
267
268if __name__ == '__main__':
269 main()