3 # Example nfcpy to hostapd wrapper for WPS NFC operations
4 # Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
6 # This software may be distributed under the terms of the BSD license.
7 # See README for more details.
23 wpas_ctrl = '/var/run/hostapd'
31 with open(summary_file, 'a') as f:
34 def success_report(txt):
37 with open(success_file, 'a') as f:
42 if os.path.isdir(wpas_ctrl):
44 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
45 except OSError, error:
46 print "Could not find hostapd: ", error
50 print "No hostapd control interface found"
55 wpas = wpaspy.Ctrl(ctrl)
62 def wpas_tag_read(message):
66 if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")):
71 def wpas_get_config_token():
75 ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF")
78 return ret.rstrip().decode("hex")
81 def wpas_get_password_token():
85 ret = wpas.request("WPS_NFC_TOKEN NDEF")
88 return ret.rstrip().decode("hex")
91 def wpas_get_handover_sel():
95 ret = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR")
98 return ret.rstrip().decode("hex")
101 def wpas_report_handover(req, sel):
102 wpas = wpas_connect()
105 return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
106 str(req).encode("hex") + " " +
107 str(sel).encode("hex"))
110 class HandoverServer(nfc.handover.HandoverServer):
111 def __init__(self, llc):
112 super(HandoverServer, self).__init__(llc)
113 self.ho_server_processing = False
116 def process_request(self, request):
117 summary("HandoverServer - request received")
119 print "Parsed handover request: " + request.pretty()
122 print str(request).encode("hex")
124 sel = nfc.ndef.HandoverSelectMessage(version="1.2")
126 for carrier in request.carriers:
127 print "Remote carrier type: " + carrier.type
128 if carrier.type == "application/vnd.wfa.wsc":
129 summary("WPS carrier type match - add WPS carrier record")
130 data = wpas_get_handover_sel()
132 summary("Could not get handover select carrier record from hostapd")
134 print "Handover select carrier record from hostapd:"
135 print data.encode("hex")
136 if "OK" in wpas_report_handover(carrier.record, data):
137 success_report("Handover reported successfully")
139 summary("Handover report rejected")
141 message = nfc.ndef.Message(data);
142 sel.add_carrier(message[0], "active", message[1:])
144 print "Handover select:"
149 print str(sel).encode("hex")
151 summary("Sending handover select")
156 def wps_tag_read(tag):
158 if len(tag.ndef.message):
159 for record in tag.ndef.message:
160 print "record type " + record.type
161 if record.type == "application/vnd.wfa.wsc":
162 summary("WPS tag - send to hostapd")
163 success = wpas_tag_read(tag.ndef.message)
169 success_report("Tag read succeeded")
174 def rdwr_connected_write(tag):
175 summary("Tag found - writing - " + str(tag))
177 tag.ndef.message = str(write_data)
178 success_report("Tag write succeeded")
179 print "Done - remove tag"
183 continue_loop = False
184 global write_wait_remove
185 while write_wait_remove and tag.is_present:
188 def wps_write_config_tag(clf, wait_remove=True):
189 summary("Write WPS config token")
190 global write_data, write_wait_remove
191 write_wait_remove = wait_remove
192 write_data = wpas_get_config_token()
193 if write_data == None:
194 summary("Could not get WPS config token from hostapd")
197 print "Touch an NFC tag"
198 clf.connect(rdwr={'on-connect': rdwr_connected_write})
201 def wps_write_password_tag(clf, wait_remove=True):
202 summary("Write WPS password token")
203 global write_data, write_wait_remove
204 write_wait_remove = wait_remove
205 write_data = wpas_get_password_token()
206 if write_data == None:
207 summary("Could not get WPS password token from hostapd")
210 print "Touch an NFC tag"
211 clf.connect(rdwr={'on-connect': rdwr_connected_write})
214 def rdwr_connected(tag):
215 global only_one, no_wait
216 summary("Tag connected: " + str(tag))
219 print "NDEF tag: " + tag.type
221 print tag.ndef.message.pretty()
224 success = wps_tag_read(tag)
225 if only_one and success:
227 continue_loop = False
229 summary("Not an NDEF tag - remove tag")
235 def llcp_startup(clf, llc):
236 print "Start LLCP server"
238 srv = HandoverServer(llc)
241 def llcp_connected(llc):
242 print "P2P LLCP connected"
243 global wait_connection
244 wait_connection = False
251 clf = nfc.ContactlessFrontend()
253 parser = argparse.ArgumentParser(description='nfcpy to hostapd integration for WPS NFC operations')
254 parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
255 action='store_const', dest='loglevel',
256 help='verbose debug output')
257 parser.add_argument('-q', const=logging.WARNING, action='store_const',
258 dest='loglevel', help='be quiet')
259 parser.add_argument('--only-one', '-1', action='store_true',
260 help='run only one operation and exit')
261 parser.add_argument('--no-wait', action='store_true',
262 help='do not wait for tag to be removed before exiting')
263 parser.add_argument('--summary',
264 help='summary file for writing status updates')
265 parser.add_argument('--success',
266 help='success file for writing success update')
267 parser.add_argument('command', choices=['write-config',
270 args = parser.parse_args()
273 only_one = args.only_one
276 no_wait = args.no_wait
280 summary_file = args.summary
284 success_file = args.success
286 logging.basicConfig(level=args.loglevel)
289 if not clf.open("usb"):
290 print "Could not open connection with an NFC device"
293 if args.command == "write-config":
294 wps_write_config_tag(clf, wait_remove=not args.no_wait)
297 if args.command == "write-password":
298 wps_write_password_tag(clf, wait_remove=not args.no_wait)
303 print "Waiting for a tag or peer to be touched"
304 wait_connection = True
306 if not clf.connect(rdwr={'on-connect': rdwr_connected},
307 llcp={'on-startup': llcp_startup,
308 'on-connect': llcp_connected}):
311 print "clf.connect failed"
314 if only_one and srv and srv.success:
317 except KeyboardInterrupt:
324 if __name__ == '__main__':