blob: 8e865f3fcd33818e363773888fbfa8fb665f25c6 [file] [log] [blame]
Hai Shalomfdcde762020-04-02 11:19:20 -07001#!/usr/bin/python3
2#
3# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations
4# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
5# Copyright (c) 2019-2020, The Linux Foundation
6#
7# This software may be distributed under the terms of the BSD license.
8# See README for more details.
9
Hai Shalom899fcc72020-10-19 14:38:18 -070010import binascii
11import errno
Hai Shalomfdcde762020-04-02 11:19:20 -070012import os
Hai Shalom4fbc08f2020-05-18 12:37:00 -070013import struct
Hai Shalomfdcde762020-04-02 11:19:20 -070014import sys
15import time
16import threading
17import argparse
18
19import nfc
20import ndef
21
22import logging
23
Hai Shalom4fbc08f2020-05-18 12:37:00 -070024scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__))
Hai Shalomfdcde762020-04-02 11:19:20 -070025sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy'))
26import wpaspy
27
28wpas_ctrl = '/var/run/wpa_supplicant'
29ifname = None
30init_on_touch = False
31in_raw_mode = False
32prev_tcgetattr = 0
33no_input = False
Hai Shalomfdcde762020-04-02 11:19:20 -070034continue_loop = True
35terminate_now = False
36summary_file = None
37success_file = None
Hai Shalom899fcc72020-10-19 14:38:18 -070038netrole = None
39operation_success = False
Hai Shalom4fbc08f2020-05-18 12:37:00 -070040mutex = threading.Lock()
Hai Shalomfdcde762020-04-02 11:19:20 -070041
Hai Shalom899fcc72020-10-19 14:38:18 -070042C_NORMAL = '\033[0m'
43C_RED = '\033[91m'
44C_GREEN = '\033[92m'
45C_YELLOW = '\033[93m'
46C_BLUE = '\033[94m'
47C_MAGENTA = '\033[95m'
48C_CYAN = '\033[96m'
49
50def summary(txt, color=None):
Hai Shalom4fbc08f2020-05-18 12:37:00 -070051 with mutex:
Hai Shalom899fcc72020-10-19 14:38:18 -070052 if color:
53 print(color + txt + C_NORMAL)
54 else:
55 print(txt)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070056 if summary_file:
57 with open(summary_file, 'a') as f:
58 f.write(txt + "\n")
Hai Shalomfdcde762020-04-02 11:19:20 -070059
60def success_report(txt):
61 summary(txt)
62 if success_file:
63 with open(success_file, 'a') as f:
64 f.write(txt + "\n")
65
66def wpas_connect():
67 ifaces = []
68 if os.path.isdir(wpas_ctrl):
69 try:
70 ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
71 except OSError as error:
Hai Shalom4fbc08f2020-05-18 12:37:00 -070072 summary("Could not find wpa_supplicant: %s", str(error))
Hai Shalomfdcde762020-04-02 11:19:20 -070073 return None
74
75 if len(ifaces) < 1:
Hai Shalom4fbc08f2020-05-18 12:37:00 -070076 summary("No wpa_supplicant control interface found")
Hai Shalomfdcde762020-04-02 11:19:20 -070077 return None
78
79 for ctrl in ifaces:
Hai Shalom899fcc72020-10-19 14:38:18 -070080 if ifname and ifname not in ctrl:
81 continue
82 if os.path.basename(ctrl).startswith("p2p-dev-"):
83 # skip P2P management interface
84 continue
Hai Shalomfdcde762020-04-02 11:19:20 -070085 try:
Hai Shalom4fbc08f2020-05-18 12:37:00 -070086 summary("Trying to use control interface " + ctrl)
Hai Shalomfdcde762020-04-02 11:19:20 -070087 wpas = wpaspy.Ctrl(ctrl)
88 return wpas
89 except Exception as e:
90 pass
Hai Shalom899fcc72020-10-19 14:38:18 -070091 summary("Could not connect to wpa_supplicant")
Hai Shalomfdcde762020-04-02 11:19:20 -070092 return None
93
94def dpp_nfc_uri_process(uri):
95 wpas = wpas_connect()
96 if wpas is None:
97 return False
98 peer_id = wpas.request("DPP_NFC_URI " + uri)
99 if "FAIL" in peer_id:
Hai Shalom899fcc72020-10-19 14:38:18 -0700100 summary("Could not parse DPP URI from NFC URI record", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700101 return False
102 peer_id = int(peer_id)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700103 summary("peer_id=%d for URI from NFC Tag: %s" % (peer_id, uri))
Hai Shalomfdcde762020-04-02 11:19:20 -0700104 cmd = "DPP_AUTH_INIT peer=%d" % peer_id
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700105 global enrollee_only, configurator_only, config_params
106 if enrollee_only:
107 cmd += " role=enrollee"
108 elif configurator_only:
109 cmd += " role=configurator"
110 if config_params:
111 cmd += " " + config_params
112 summary("Initiate DPP authentication: " + cmd)
Hai Shalomfdcde762020-04-02 11:19:20 -0700113 res = wpas.request(cmd)
114 if "OK" not in res:
Hai Shalom899fcc72020-10-19 14:38:18 -0700115 summary("Failed to initiate DPP Authentication", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700116 return False
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700117 summary("DPP Authentication initiated")
Hai Shalomfdcde762020-04-02 11:19:20 -0700118 return True
119
120def dpp_hs_tag_read(record):
121 wpas = wpas_connect()
122 if wpas is None:
123 return False
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700124 summary(record)
Hai Shalomfdcde762020-04-02 11:19:20 -0700125 if len(record.data) < 5:
Hai Shalom899fcc72020-10-19 14:38:18 -0700126 summary("Too short DPP HS", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700127 return False
128 if record.data[0] != 0:
Hai Shalom899fcc72020-10-19 14:38:18 -0700129 summary("Unexpected URI Identifier Code", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700130 return False
131 uribuf = record.data[1:]
132 try:
133 uri = uribuf.decode()
134 except:
Hai Shalom899fcc72020-10-19 14:38:18 -0700135 summary("Invalid URI payload", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700136 return False
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700137 summary("URI: " + uri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700138 if not uri.startswith("DPP:"):
Hai Shalom899fcc72020-10-19 14:38:18 -0700139 summary("Not a DPP URI", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700140 return False
141 return dpp_nfc_uri_process(uri)
142
143def get_status(wpas, extra=None):
144 if extra:
145 extra = "-" + extra
146 else:
147 extra = ""
148 res = wpas.request("STATUS" + extra)
149 lines = res.splitlines()
150 vals = dict()
151 for l in lines:
152 try:
153 [name, value] = l.split('=', 1)
154 except ValueError:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700155 summary("Ignore unexpected status line: %s" % l)
Hai Shalomfdcde762020-04-02 11:19:20 -0700156 continue
157 vals[name] = value
158 return vals
159
160def get_status_field(wpas, field, extra=None):
161 vals = get_status(wpas, extra)
162 if field in vals:
163 return vals[field]
164 return None
165
166def own_addr(wpas):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700167 addr = get_status_field(wpas, "address")
168 if addr is None:
169 addr = get_status_field(wpas, "bssid[0]")
170 return addr
Hai Shalomfdcde762020-04-02 11:19:20 -0700171
172def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None,
173 curve=None, key=None):
174 cmd = "DPP_BOOTSTRAP_GEN type=" + type
175 if chan:
176 cmd += " chan=" + chan
177 if mac:
178 if mac is True:
179 mac = own_addr(wpas)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700180 if mac is None:
181 summary("Could not determine local MAC address for bootstrap info")
182 else:
183 cmd += " mac=" + mac.replace(':', '')
Hai Shalomfdcde762020-04-02 11:19:20 -0700184 if info:
185 cmd += " info=" + info
186 if curve:
187 cmd += " curve=" + curve
188 if key:
189 cmd += " key=" + key
190 res = wpas.request(cmd)
191 if "FAIL" in res:
192 raise Exception("Failed to generate bootstrapping info")
193 return int(res)
194
Hai Shalom899fcc72020-10-19 14:38:18 -0700195def dpp_start_listen(wpas, freq):
196 if get_status_field(wpas, "bssid[0]"):
197 summary("Own AP freq: %s MHz" % str(get_status_field(wpas, "freq")))
198 if get_status_field(wpas, "beacon_set", extra="DRIVER") is None:
199 summary("Enable beaconing to have radio ready for RX")
200 wpas.request("DISABLE")
201 wpas.request("SET start_disabled 0")
202 wpas.request("ENABLE")
203 cmd = "DPP_LISTEN %d" % freq
204 global enrollee_only
205 global configurator_only
206 if enrollee_only:
207 cmd += " role=enrollee"
208 elif configurator_only:
209 cmd += " role=configurator"
210 global netrole
211 if netrole:
212 cmd += " netrole=" + netrole
213 summary(cmd)
214 res = wpas.request(cmd)
215 if "OK" not in res:
216 summary("Failed to start DPP listen", color=C_RED)
217 return False
218 return True
219
220def wpas_get_nfc_uri(start_listen=True, pick_channel=False, chan_override=None):
221 listen_freq = 2412
Hai Shalomfdcde762020-04-02 11:19:20 -0700222 wpas = wpas_connect()
223 if wpas is None:
224 return None
225 global own_id, chanlist
Hai Shalom899fcc72020-10-19 14:38:18 -0700226 if chan_override:
227 chan = chan_override
228 else:
229 chan = chanlist
230 if chan and chan.startswith("81/"):
231 listen_freq = int(chan[3:].split(',')[0]) * 5 + 2407
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700232 if chan is None and get_status_field(wpas, "bssid[0]"):
233 freq = get_status_field(wpas, "freq")
234 if freq:
235 freq = int(freq)
236 if freq >= 2412 and freq <= 2462:
237 chan = "81/%d" % ((freq - 2407) / 5)
238 summary("Use current AP operating channel (%d MHz) as the URI channel list (%s)" % (freq, chan))
Hai Shalom899fcc72020-10-19 14:38:18 -0700239 listen_freq = freq
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700240 if chan is None and pick_channel:
241 chan = "81/6"
242 summary("Use channel 2437 MHz since no other preference provided")
Hai Shalom899fcc72020-10-19 14:38:18 -0700243 listen_freq = 2437
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700244 own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chan, mac=True)
Hai Shalomfdcde762020-04-02 11:19:20 -0700245 res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
246 if "FAIL" in res:
247 return None
248 if start_listen:
Hai Shalom899fcc72020-10-19 14:38:18 -0700249 if not dpp_start_listen(wpas, listen_freq):
250 raise Exception("Failed to start listen operation on %d MHz" % listen_freq)
Hai Shalomfdcde762020-04-02 11:19:20 -0700251 return res
252
253def wpas_report_handover_req(uri):
254 wpas = wpas_connect()
255 if wpas is None:
256 return None
257 global own_id
258 cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri)
259 return wpas.request(cmd)
260
261def wpas_report_handover_sel(uri):
262 wpas = wpas_connect()
263 if wpas is None:
264 return None
265 global own_id
266 cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri)
267 return wpas.request(cmd)
268
Hai Shalom899fcc72020-10-19 14:38:18 -0700269def dpp_handover_client(handover, alt=False):
270 summary("About to start run_dpp_handover_client (alt=%s)" % str(alt))
271 if alt:
272 handover.i_m_selector = False
273 run_dpp_handover_client(handover, alt)
274 summary("Done run_dpp_handover_client (alt=%s)" % str(alt))
275
276def run_client_alt(handover, alt):
277 if handover.start_client_alt and not alt:
278 handover.start_client_alt = False
279 summary("Try to send alternative handover request")
280 dpp_handover_client(handover, alt=True)
281
282class HandoverClient(nfc.handover.HandoverClient):
283 def __init__(self, handover, llc):
284 super(HandoverClient, self).__init__(llc)
285 self.handover = handover
286
287 def recv_records(self, timeout=None):
288 msg = self.recv_octets(timeout)
289 if msg is None:
290 return None
291 records = list(ndef.message_decoder(msg, 'relax'))
292 if records and records[0].type == 'urn:nfc:wkt:Hs':
293 summary("Handover client received message '{0}'".format(records[0].type))
294 return list(ndef.message_decoder(msg, 'relax'))
295 summary("Handover client received invalid message: %s" + binascii.hexlify(msg))
296 return None
297
298 def recv_octets(self, timeout=None):
299 start = time.time()
300 msg = bytearray()
301 while True:
302 poll_timeout = 0.1 if timeout is None or timeout > 0.1 else timeout
303 if not self.socket.poll('recv', poll_timeout):
304 if timeout:
305 timeout -= time.time() - start
306 if timeout <= 0:
307 return None
308 start = time.time()
309 continue
310 try:
311 r = self.socket.recv()
312 if r is None:
313 return None
314 msg += r
315 except TypeError:
316 return b''
317 try:
318 list(ndef.message_decoder(msg, 'strict', {}))
319 return bytes(msg)
320 except ndef.DecodeError:
321 if timeout:
322 timeout -= time.time() - start
323 if timeout <= 0:
324 return None
325 start = time.time()
326 continue
327 return None
328
329def run_dpp_handover_client(handover, alt=False):
330 chan_override = None
331 if alt:
332 chan_override = handover.altchanlist
333 handover.alt_proposal_used = True
334 global test_uri, test_alt_uri
335 if test_uri:
336 summary("TEST MODE: Using specified URI (alt=%s)" % str(alt))
337 uri = test_alt_uri if alt else test_uri
338 else:
339 uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700340 if uri is None:
Hai Shalom899fcc72020-10-19 14:38:18 -0700341 summary("Cannot start handover client - no bootstrap URI available",
342 color=C_RED)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700343 return
Hai Shalom899fcc72020-10-19 14:38:18 -0700344 handover.my_uri = uri
Hai Shalomfdcde762020-04-02 11:19:20 -0700345 uri = ndef.UriRecord(uri)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700346 summary("NFC URI record for DPP: " + str(uri))
Hai Shalomfdcde762020-04-02 11:19:20 -0700347 carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
Hai Shalom899fcc72020-10-19 14:38:18 -0700348 global test_crn
349 if test_crn:
350 prev, = struct.unpack('>H', test_crn)
351 summary("TEST MODE: Use specified crn %d" % prev)
352 crn = test_crn
353 test_crn = struct.pack('>H', prev + 0x10)
354 else:
355 crn = os.urandom(2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700356 hr = ndef.HandoverRequestRecord(version="1.4", crn=crn)
Hai Shalomfdcde762020-04-02 11:19:20 -0700357 hr.add_alternative_carrier('active', carrier.name)
358 message = [hr, carrier]
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700359 summary("NFC Handover Request message for DPP: " + str(message))
Hai Shalomfdcde762020-04-02 11:19:20 -0700360
Hai Shalom899fcc72020-10-19 14:38:18 -0700361 if handover.peer_crn is not None and not alt:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700362 summary("NFC handover request from peer was already received - do not send own")
363 return
Hai Shalom899fcc72020-10-19 14:38:18 -0700364 if handover.client:
365 summary("Use already started handover client")
366 client = handover.client
367 else:
368 summary("Start handover client")
369 client = HandoverClient(handover, handover.llc)
370 try:
371 summary("Trying to initiate NFC connection handover")
372 client.connect()
373 summary("Connected for handover")
374 except nfc.llcp.ConnectRefused:
375 summary("Handover connection refused")
376 client.close()
377 return
378 except Exception as e:
379 summary("Other exception: " + str(e))
380 client.close()
381 return
382 handover.client = client
Hai Shalomfdcde762020-04-02 11:19:20 -0700383
Hai Shalom899fcc72020-10-19 14:38:18 -0700384 if handover.peer_crn is not None and not alt:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700385 summary("NFC handover request from peer was already received - do not send own")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700386 return
387
Hai Shalomfdcde762020-04-02 11:19:20 -0700388 summary("Sending handover request")
389
Hai Shalom899fcc72020-10-19 14:38:18 -0700390 handover.my_crn_ready = True
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700391
Hai Shalomfdcde762020-04-02 11:19:20 -0700392 if not client.send_records(message):
Hai Shalom899fcc72020-10-19 14:38:18 -0700393 handover.my_crn_ready = False
394 summary("Failed to send handover request", color=C_RED)
395 run_client_alt(handover, alt)
Hai Shalomfdcde762020-04-02 11:19:20 -0700396 return
397
Hai Shalom899fcc72020-10-19 14:38:18 -0700398 handover.my_crn, = struct.unpack('>H', crn)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700399
Hai Shalomfdcde762020-04-02 11:19:20 -0700400 summary("Receiving handover response")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700401 try:
Hai Shalom899fcc72020-10-19 14:38:18 -0700402 start = time.time()
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700403 message = client.recv_records(timeout=3.0)
Hai Shalom899fcc72020-10-19 14:38:18 -0700404 end = time.time()
405 summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700406 except Exception as e:
407 # This is fine if we are the handover selector
Hai Shalom899fcc72020-10-19 14:38:18 -0700408 if handover.hs_sent:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700409 summary("Client receive failed as expected since I'm the handover server: %s" % str(e))
Hai Shalom899fcc72020-10-19 14:38:18 -0700410 elif handover.alt_proposal_used and not alt:
411 summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e))
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700412 else:
Hai Shalom899fcc72020-10-19 14:38:18 -0700413 summary("Client receive failed: %s" % str(e), color=C_RED)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700414 message = None
Hai Shalomfdcde762020-04-02 11:19:20 -0700415 if message is None:
Hai Shalom899fcc72020-10-19 14:38:18 -0700416 if handover.hs_sent:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700417 summary("No response received as expected since I'm the handover server")
Hai Shalom899fcc72020-10-19 14:38:18 -0700418 elif handover.alt_proposal_used and not alt:
419 summary("No response received for initial proposal as expected since alternative proposal was also used")
420 elif handover.try_own and not alt:
421 summary("No response received for initial proposal as expected since alternative proposal will also be sent")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700422 else:
Hai Shalom899fcc72020-10-19 14:38:18 -0700423 summary("No response received", color=C_RED)
424 run_client_alt(handover, alt)
Hai Shalomfdcde762020-04-02 11:19:20 -0700425 return
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700426 summary("Received message: " + str(message))
Hai Shalomfdcde762020-04-02 11:19:20 -0700427 if len(message) < 1 or \
428 not isinstance(message[0], ndef.HandoverSelectRecord):
429 summary("Response was not Hs - received: " + message.type)
Hai Shalomfdcde762020-04-02 11:19:20 -0700430 return
431
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700432 summary("Received handover select message")
433 summary("alternative carriers: " + str(message[0].alternative_carriers))
Hai Shalom899fcc72020-10-19 14:38:18 -0700434 if handover.i_m_selector:
435 summary("Ignore the received select since I'm the handover selector")
436 run_client_alt(handover, alt)
437 return
438
439 if handover.alt_proposal_used and not alt:
440 summary("Ignore received handover select for the initial proposal since alternative proposal was sent")
441 client.close()
442 return
Hai Shalomfdcde762020-04-02 11:19:20 -0700443
444 dpp_found = False
445 for carrier in message:
446 if isinstance(carrier, ndef.HandoverSelectRecord):
447 continue
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700448 summary("Remote carrier type: " + carrier.type)
Hai Shalomfdcde762020-04-02 11:19:20 -0700449 if carrier.type == "application/vnd.wfa.dpp":
450 if len(carrier.data) == 0 or carrier.data[0] != 0:
Hai Shalom899fcc72020-10-19 14:38:18 -0700451 summary("URI Identifier Code 'None' not seen", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700452 continue
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700453 summary("DPP carrier type match - send to wpa_supplicant")
Hai Shalomfdcde762020-04-02 11:19:20 -0700454 dpp_found = True
455 uri = carrier.data[1:].decode("utf-8")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700456 summary("DPP URI: " + uri)
Hai Shalom899fcc72020-10-19 14:38:18 -0700457 handover.peer_uri = uri
458 if test_uri:
459 summary("TEST MODE: Fake processing")
460 break
Hai Shalomfdcde762020-04-02 11:19:20 -0700461 res = wpas_report_handover_sel(uri)
462 if res is None or "FAIL" in res:
Hai Shalom899fcc72020-10-19 14:38:18 -0700463 summary("DPP handover report rejected", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700464 break
465
466 success_report("DPP handover reported successfully (initiator)")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700467 summary("peer_id=" + res)
Hai Shalomfdcde762020-04-02 11:19:20 -0700468 peer_id = int(res)
Hai Shalomfdcde762020-04-02 11:19:20 -0700469 wpas = wpas_connect()
470 if wpas is None:
471 break
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700472
473 global enrollee_only
474 global config_params
475 if enrollee_only:
476 extra = " role=enrollee"
477 elif config_params:
478 extra = " role=configurator " + config_params
479 else:
480 # TODO: Single Configurator instance
481 res = wpas.request("DPP_CONFIGURATOR_ADD")
482 if "FAIL" in res:
Hai Shalom899fcc72020-10-19 14:38:18 -0700483 summary("Failed to initiate Configurator", color=C_RED)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700484 break
485 conf_id = int(res)
486 extra = " conf=sta-dpp configurator=%d" % conf_id
Hai Shalomfdcde762020-04-02 11:19:20 -0700487 global own_id
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700488 summary("Initiate DPP authentication")
489 cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id)
490 cmd += extra
Hai Shalomfdcde762020-04-02 11:19:20 -0700491 res = wpas.request(cmd)
492 if "FAIL" in res:
Hai Shalom899fcc72020-10-19 14:38:18 -0700493 summary("Failed to initiate DPP authentication", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700494 break
495
Hai Shalom899fcc72020-10-19 14:38:18 -0700496 if not dpp_found and handover.no_alt_proposal:
497 summary("DPP carrier not seen in response - do not allow alternative proposal anymore")
498 elif not dpp_found:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700499 summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters")
Hai Shalom899fcc72020-10-19 14:38:18 -0700500 handover.alt_proposal = True
501 handover.my_crn_ready = False
502 handover.my_crn = None
503 handover.peer_crn = None
504 handover.hs_sent = False
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700505 summary("Returning from dpp_handover_client")
Hai Shalomfdcde762020-04-02 11:19:20 -0700506 return
507
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700508 summary("Remove peer")
Hai Shalom899fcc72020-10-19 14:38:18 -0700509 handover.close()
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700510 summary("Done with handover")
Hai Shalomfdcde762020-04-02 11:19:20 -0700511 global only_one
512 if only_one:
513 print("only_one -> stop loop")
514 global continue_loop
515 continue_loop = False
516
517 global no_wait
Hai Shalom899fcc72020-10-19 14:38:18 -0700518 if no_wait or only_one:
519 summary("Trying to exit..")
Hai Shalomfdcde762020-04-02 11:19:20 -0700520 global terminate_now
521 terminate_now = True
522
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700523 summary("Returning from dpp_handover_client")
Hai Shalomfdcde762020-04-02 11:19:20 -0700524
525class HandoverServer(nfc.handover.HandoverServer):
Hai Shalom899fcc72020-10-19 14:38:18 -0700526 def __init__(self, handover, llc):
Hai Shalomfdcde762020-04-02 11:19:20 -0700527 super(HandoverServer, self).__init__(llc)
528 self.sent_carrier = None
529 self.ho_server_processing = False
530 self.success = False
Hai Shalom899fcc72020-10-19 14:38:18 -0700531 self.llc = llc
532 self.handover = handover
533
534 def serve(self, socket):
535 peer_sap = socket.getpeername()
536 summary("Serving handover client on remote sap {0}".format(peer_sap))
537 send_miu = socket.getsockopt(nfc.llcp.SO_SNDMIU)
538 try:
539 while socket.poll("recv"):
540 req = bytearray()
541 while socket.poll("recv"):
542 r = socket.recv()
543 if r is None:
544 return None
545 summary("Received %d octets" % len(r))
546 req += r
547 if len(req) == 0:
548 continue
549 try:
550 list(ndef.message_decoder(req, 'strict', {}))
551 except ndef.DecodeError:
552 continue
553 summary("Full message received")
554 resp = self._process_request_data(req)
555 if resp is None or len(resp) == 0:
556 summary("No handover select to send out - wait for a possible alternative handover request")
557 handover.alt_proposal = True
558 req = bytearray()
559 continue
560
561 for offset in range(0, len(resp), send_miu):
562 if not socket.send(resp[offset:offset + send_miu]):
563 summary("Failed to send handover select - connection closed")
564 return
565 summary("Sent out full handover select")
566 if handover.terminate_on_hs_send_completion:
567 handover.delayed_exit()
568
569 except nfc.llcp.Error as e:
570 global terminate_now
571 summary("HandoverServer exception: %s" % e,
572 color=None if e.errno == errno.EPIPE or terminate_now else C_RED)
573 finally:
574 socket.close()
575 summary("Handover serve thread exiting")
Hai Shalomfdcde762020-04-02 11:19:20 -0700576
577 def process_handover_request_message(self, records):
Hai Shalom899fcc72020-10-19 14:38:18 -0700578 handover = self.handover
Hai Shalomfdcde762020-04-02 11:19:20 -0700579 self.ho_server_processing = True
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700580 global in_raw_mode
581 was_in_raw_mode = in_raw_mode
Hai Shalomfdcde762020-04-02 11:19:20 -0700582 clear_raw_mode()
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700583 if was_in_raw_mode:
584 print("\n")
585 summary("HandoverServer - request received: " + str(records))
Hai Shalomfdcde762020-04-02 11:19:20 -0700586
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700587 for carrier in records:
588 if not isinstance(carrier, ndef.HandoverRequestRecord):
589 continue
590 if carrier.collision_resolution_number:
Hai Shalom899fcc72020-10-19 14:38:18 -0700591 handover.peer_crn = carrier.collision_resolution_number
592 summary("peer_crn: %d" % handover.peer_crn)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700593
Hai Shalom899fcc72020-10-19 14:38:18 -0700594 if handover.my_crn is None and handover.my_crn_ready:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700595 summary("Still trying to send own handover request - wait a moment to see if that succeeds before checking crn values")
596 for i in range(10):
Hai Shalom899fcc72020-10-19 14:38:18 -0700597 if handover.my_crn is not None:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700598 break
599 time.sleep(0.01)
Hai Shalom899fcc72020-10-19 14:38:18 -0700600 if handover.my_crn is not None:
601 summary("my_crn: %d" % handover.my_crn)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700602
Hai Shalom899fcc72020-10-19 14:38:18 -0700603 if handover.my_crn is not None and handover.peer_crn is not None:
604 if handover.my_crn == handover.peer_crn:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700605 summary("Same crn used - automatic collision resolution failed")
606 # TODO: Should generate a new Handover Request message
607 return ''
Hai Shalom899fcc72020-10-19 14:38:18 -0700608 if ((handover.my_crn & 1) == (handover.peer_crn & 1) and \
609 handover.my_crn > handover.peer_crn) or \
610 ((handover.my_crn & 1) != (handover.peer_crn & 1) and \
611 handover.my_crn < handover.peer_crn):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700612 summary("I'm the Handover Selector Device")
Hai Shalom899fcc72020-10-19 14:38:18 -0700613 handover.i_m_selector = True
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700614 else:
615 summary("Peer is the Handover Selector device")
616 summary("Ignore the received request.")
617 return ''
618
Hai Shalomfdcde762020-04-02 11:19:20 -0700619 hs = ndef.HandoverSelectRecord('1.4')
620 sel = [hs]
621
622 found = False
623
624 for carrier in records:
625 if isinstance(carrier, ndef.HandoverRequestRecord):
626 continue
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700627 summary("Remote carrier type: " + carrier.type)
Hai Shalomfdcde762020-04-02 11:19:20 -0700628 if carrier.type == "application/vnd.wfa.dpp":
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700629 summary("DPP carrier type match - add DPP carrier record")
Hai Shalomfdcde762020-04-02 11:19:20 -0700630 if len(carrier.data) == 0 or carrier.data[0] != 0:
Hai Shalom899fcc72020-10-19 14:38:18 -0700631 summary("URI Identifier Code 'None' not seen", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700632 continue
633 uri = carrier.data[1:].decode("utf-8")
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700634 summary("Received DPP URI: " + uri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700635
Hai Shalom899fcc72020-10-19 14:38:18 -0700636 global test_uri, test_alt_uri
637 if test_uri:
638 summary("TEST MODE: Using specified URI")
639 data = test_sel_uri if test_sel_uri else test_uri
640 elif handover.alt_proposal and handover.altchanlist:
641 summary("Use alternative channel list while processing alternative proposal from peer")
642 data = wpas_get_nfc_uri(start_listen=False,
643 chan_override=handover.altchanlist,
644 pick_channel=True)
645 else:
646 data = wpas_get_nfc_uri(start_listen=False,
647 pick_channel=True)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700648 summary("Own URI (pre-processing): %s" % data)
Hai Shalomfdcde762020-04-02 11:19:20 -0700649
Hai Shalom899fcc72020-10-19 14:38:18 -0700650 if test_uri:
651 summary("TEST MODE: Fake processing")
652 res = "OK"
653 data += " [%s]" % uri
654 else:
655 res = wpas_report_handover_req(uri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700656 if res is None or "FAIL" in res:
Hai Shalom899fcc72020-10-19 14:38:18 -0700657 summary("DPP handover request processing failed",
658 color=C_RED)
659 if handover.altchanlist:
660 data = wpas_get_nfc_uri(start_listen=False,
661 chan_override=handover.altchanlist)
662 summary("Own URI (try another channel list): %s" % data)
663 continue
664
665 if test_alt_uri:
666 summary("TEST MODE: Reject initial proposal")
Hai Shalomfdcde762020-04-02 11:19:20 -0700667 continue
668
669 found = True
Hai Shalomfdcde762020-04-02 11:19:20 -0700670
Hai Shalom899fcc72020-10-19 14:38:18 -0700671 if not test_uri:
672 wpas = wpas_connect()
673 if wpas is None:
674 continue
675 global own_id
676 data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip()
677 if "FAIL" in data:
678 continue
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700679 summary("Own URI (post-processing): %s" % data)
Hai Shalom899fcc72020-10-19 14:38:18 -0700680 handover.my_uri = data
681 handover.peer_uri = uri
Hai Shalomfdcde762020-04-02 11:19:20 -0700682 uri = ndef.UriRecord(data)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700683 summary("Own bootstrapping NFC URI record: " + str(uri))
Hai Shalomfdcde762020-04-02 11:19:20 -0700684
Hai Shalom899fcc72020-10-19 14:38:18 -0700685 if not test_uri:
686 info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id)
687 freq = None
688 for line in info.splitlines():
689 if line.startswith("use_freq="):
690 freq = int(line.split('=')[1])
691 if freq is None or freq == 0:
692 summary("No channel negotiated over NFC - use channel 6")
693 freq = 2437
694 else:
695 summary("Negotiated channel: %d MHz" % freq)
696 if not dpp_start_listen(wpas, freq):
697 break
Hai Shalomfdcde762020-04-02 11:19:20 -0700698
699 carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700700 summary("Own DPP carrier record: " + str(carrier))
Hai Shalomfdcde762020-04-02 11:19:20 -0700701 hs.add_alternative_carrier('active', carrier.name)
702 sel = [hs, carrier]
703 break
704
705 summary("Sending handover select: " + str(sel))
706 if found:
Hai Shalom899fcc72020-10-19 14:38:18 -0700707 summary("Handover completed successfully")
708 handover.terminate_on_hs_send_completion = True
Hai Shalomfdcde762020-04-02 11:19:20 -0700709 self.success = True
Hai Shalom899fcc72020-10-19 14:38:18 -0700710 handover.hs_sent = True
711 handover.i_m_selector = True
712 elif handover.no_alt_proposal:
713 summary("Do not try alternative proposal anymore - handover failed",
714 color=C_RED)
715 handover.hs_sent = True
Hai Shalomfdcde762020-04-02 11:19:20 -0700716 else:
Hai Shalom899fcc72020-10-19 14:38:18 -0700717 summary("Try to initiate with alternative parameters")
718 handover.try_own = True
719 handover.hs_sent = False
720 handover.no_alt_proposal = True
721 if handover.client_thread:
722 handover.start_client_alt = True
723 else:
724 handover.client_thread = threading.Thread(target=llcp_worker,
725 args=(self.llc, True))
726 handover.client_thread.start()
Hai Shalomfdcde762020-04-02 11:19:20 -0700727 return sel
728
729def clear_raw_mode():
730 import sys, tty, termios
731 global prev_tcgetattr, in_raw_mode
732 if not in_raw_mode:
733 return
734 fd = sys.stdin.fileno()
735 termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
736 in_raw_mode = False
737
738def getch():
739 import sys, tty, termios, select
740 global prev_tcgetattr, in_raw_mode
741 fd = sys.stdin.fileno()
742 prev_tcgetattr = termios.tcgetattr(fd)
743 ch = None
744 try:
745 tty.setraw(fd)
746 in_raw_mode = True
747 [i, o, e] = select.select([fd], [], [], 0.05)
748 if i:
749 ch = sys.stdin.read(1)
750 finally:
751 termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr)
752 in_raw_mode = False
753 return ch
754
755def dpp_tag_read(tag):
756 success = False
757 for record in tag.ndef.records:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700758 summary(record)
759 summary("record type " + record.type)
Hai Shalomfdcde762020-04-02 11:19:20 -0700760 if record.type == "application/vnd.wfa.dpp":
761 summary("DPP HS tag - send to wpa_supplicant")
762 success = dpp_hs_tag_read(record)
763 break
764 if isinstance(record, ndef.UriRecord):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700765 summary("URI record: uri=" + record.uri)
766 summary("URI record: iri=" + record.iri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700767 if record.iri.startswith("DPP:"):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700768 summary("DPP URI")
Hai Shalomfdcde762020-04-02 11:19:20 -0700769 if not dpp_nfc_uri_process(record.iri):
770 break
771 success = True
772 else:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700773 summary("Ignore unknown URI")
Hai Shalomfdcde762020-04-02 11:19:20 -0700774 break
775
776 if success:
777 success_report("Tag read succeeded")
778
779 return success
780
781def rdwr_connected_write_tag(tag):
782 summary("Tag found - writing - " + str(tag))
Hai Shalom899fcc72020-10-19 14:38:18 -0700783 if not tag.ndef:
784 summary("Not a formatted NDEF tag", color=C_RED)
785 return
Hai Shalomfdcde762020-04-02 11:19:20 -0700786 if not tag.ndef.is_writeable:
Hai Shalom899fcc72020-10-19 14:38:18 -0700787 summary("Not a writable tag", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700788 return
789 global dpp_tag_data
790 if tag.ndef.capacity < len(dpp_tag_data):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700791 summary("Not enough room for the message")
Hai Shalomfdcde762020-04-02 11:19:20 -0700792 return
Hai Shalom899fcc72020-10-19 14:38:18 -0700793 try:
794 tag.ndef.records = dpp_tag_data
795 except ValueError as e:
796 summary("Writing the tag failed: %s" % str(e), color=C_RED)
797 return
Hai Shalomfdcde762020-04-02 11:19:20 -0700798 success_report("Tag write succeeded")
Hai Shalom899fcc72020-10-19 14:38:18 -0700799 summary("Tag writing completed - remove tag", color=C_GREEN)
800 global only_one, operation_success
801 operation_success = True
Hai Shalomfdcde762020-04-02 11:19:20 -0700802 if only_one:
803 global continue_loop
804 continue_loop = False
805 global dpp_sel_wait_remove
806 return dpp_sel_wait_remove
807
808def write_nfc_uri(clf, wait_remove=True):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700809 summary("Write NFC URI record")
Hai Shalomfdcde762020-04-02 11:19:20 -0700810 data = wpas_get_nfc_uri()
811 if data is None:
Hai Shalom899fcc72020-10-19 14:38:18 -0700812 summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700813 return
814
815 global dpp_sel_wait_remove
816 dpp_sel_wait_remove = wait_remove
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700817 summary("URI: %s" % data)
Hai Shalomfdcde762020-04-02 11:19:20 -0700818 uri = ndef.UriRecord(data)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700819 summary(uri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700820
Hai Shalom899fcc72020-10-19 14:38:18 -0700821 summary("Touch an NFC tag to write URI record", color=C_CYAN)
Hai Shalomfdcde762020-04-02 11:19:20 -0700822 global dpp_tag_data
823 dpp_tag_data = [uri]
824 clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
825
826def write_nfc_hs(clf, wait_remove=True):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700827 summary("Write NFC Handover Select record on a tag")
Hai Shalomfdcde762020-04-02 11:19:20 -0700828 data = wpas_get_nfc_uri()
829 if data is None:
Hai Shalom899fcc72020-10-19 14:38:18 -0700830 summary("Could not get NFC URI from wpa_supplicant", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700831 return
832
833 global dpp_sel_wait_remove
834 dpp_sel_wait_remove = wait_remove
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700835 summary("URI: %s" % data)
Hai Shalomfdcde762020-04-02 11:19:20 -0700836 uri = ndef.UriRecord(data)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700837 summary(uri)
Hai Shalomfdcde762020-04-02 11:19:20 -0700838 carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data)
839 hs = ndef.HandoverSelectRecord('1.4')
840 hs.add_alternative_carrier('active', carrier.name)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700841 summary(hs)
842 summary(carrier)
Hai Shalomfdcde762020-04-02 11:19:20 -0700843
Hai Shalom899fcc72020-10-19 14:38:18 -0700844 summary("Touch an NFC tag to write HS record", color=C_CYAN)
Hai Shalomfdcde762020-04-02 11:19:20 -0700845 global dpp_tag_data
846 dpp_tag_data = [hs, carrier]
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700847 summary(dpp_tag_data)
Hai Shalomfdcde762020-04-02 11:19:20 -0700848 clf.connect(rdwr={'on-connect': rdwr_connected_write_tag})
849
850def rdwr_connected(tag):
851 global only_one, no_wait
852 summary("Tag connected: " + str(tag))
853
854 if tag.ndef:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700855 summary("NDEF tag: " + tag.type)
856 summary(tag.ndef.records)
Hai Shalomfdcde762020-04-02 11:19:20 -0700857 success = dpp_tag_read(tag)
858 if only_one and success:
859 global continue_loop
860 continue_loop = False
861 else:
Hai Shalom899fcc72020-10-19 14:38:18 -0700862 summary("Not an NDEF tag - remove tag", color=C_RED)
Hai Shalomfdcde762020-04-02 11:19:20 -0700863 return True
864
865 return not no_wait
866
Hai Shalom899fcc72020-10-19 14:38:18 -0700867def llcp_worker(llc, try_alt):
868 global handover
869 print("Start of llcp_worker()")
870 if try_alt:
871 summary("Starting handover client (try_alt)")
872 dpp_handover_client(handover, alt=True)
873 summary("Exiting llcp_worker thread (try_alt)")
874 return
Hai Shalomfdcde762020-04-02 11:19:20 -0700875 global init_on_touch
876 if init_on_touch:
Hai Shalom899fcc72020-10-19 14:38:18 -0700877 summary("Starting handover client (init_on_touch)")
878 dpp_handover_client(handover)
879 summary("Exiting llcp_worker thread (init_on_touch)")
Hai Shalomfdcde762020-04-02 11:19:20 -0700880 return
881
882 global no_input
883 if no_input:
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700884 summary("Wait for handover to complete")
Hai Shalomfdcde762020-04-02 11:19:20 -0700885 else:
886 print("Wait for handover to complete - press 'i' to initiate")
Hai Shalom899fcc72020-10-19 14:38:18 -0700887 while not handover.wait_connection and handover.srv.sent_carrier is None:
888 if handover.try_own:
889 handover.try_own = False
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700890 summary("Try to initiate another handover with own parameters")
Hai Shalom899fcc72020-10-19 14:38:18 -0700891 handover.my_crn_ready = False
892 handover.my_crn = None
893 handover.peer_crn = None
894 handover.hs_sent = False
895 dpp_handover_client(handover, alt=True)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700896 summary("Exiting llcp_worker thread (retry with own parameters)")
Hai Shalomfdcde762020-04-02 11:19:20 -0700897 return
Hai Shalom899fcc72020-10-19 14:38:18 -0700898 if handover.srv.ho_server_processing:
Hai Shalomfdcde762020-04-02 11:19:20 -0700899 time.sleep(0.025)
900 elif no_input:
901 time.sleep(0.5)
902 else:
903 res = getch()
904 if res != 'i':
905 continue
906 clear_raw_mode()
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700907 summary("Starting handover client")
Hai Shalom899fcc72020-10-19 14:38:18 -0700908 dpp_handover_client(handover)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700909 summary("Exiting llcp_worker thread (manual init)")
Hai Shalomfdcde762020-04-02 11:19:20 -0700910 return
911
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700912 global in_raw_mode
913 was_in_raw_mode = in_raw_mode
Hai Shalomfdcde762020-04-02 11:19:20 -0700914 clear_raw_mode()
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700915 if was_in_raw_mode:
916 print("\r")
917 summary("Exiting llcp_worker thread")
Hai Shalomfdcde762020-04-02 11:19:20 -0700918
Hai Shalom899fcc72020-10-19 14:38:18 -0700919class ConnectionHandover():
920 def __init__(self):
921 self.client = None
922 self.client_thread = None
923 self.reset()
924 self.exit_thread = None
925
926 def reset(self):
927 self.wait_connection = False
928 self.my_crn_ready = False
929 self.my_crn = None
930 self.peer_crn = None
931 self.hs_sent = False
932 self.no_alt_proposal = False
933 self.alt_proposal_used = False
934 self.i_m_selector = False
935 self.start_client_alt = False
936 self.terminate_on_hs_send_completion = False
937 self.try_own = False
938 self.my_uri = None
939 self.peer_uri = None
940 self.connected = False
941 self.alt_proposal = False
942
943 def start_handover_server(self, llc):
944 summary("Start handover server")
945 self.llc = llc
946 self.srv = HandoverServer(self, llc)
947
948 def close(self):
949 if self.client:
950 self.client.close()
951 self.client = None
952
953 def run_delayed_exit(self):
954 summary("Trying to exit (delayed)..")
955 time.sleep(0.25)
956 summary("Trying to exit (after wait)..")
957 global terminate_now
958 terminate_now = True
959
960 def delayed_exit(self):
961 global only_one
962 if only_one:
963 self.exit_thread = threading.Thread(target=self.run_delayed_exit)
964 self.exit_thread.start()
965
Hai Shalomfdcde762020-04-02 11:19:20 -0700966def llcp_startup(llc):
Hai Shalom899fcc72020-10-19 14:38:18 -0700967 global handover
968 handover.start_handover_server(llc)
Hai Shalomfdcde762020-04-02 11:19:20 -0700969 return llc
970
971def llcp_connected(llc):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700972 summary("P2P LLCP connected")
Hai Shalom899fcc72020-10-19 14:38:18 -0700973 global handover
974 handover.connected = True
975 handover.srv.start()
Hai Shalomfdcde762020-04-02 11:19:20 -0700976 if init_on_touch or not no_input:
Hai Shalom899fcc72020-10-19 14:38:18 -0700977 handover.client_thread = threading.Thread(target=llcp_worker,
978 args=(llc, False))
979 handover.client_thread.start()
Hai Shalomfdcde762020-04-02 11:19:20 -0700980 return True
981
982def llcp_release(llc):
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700983 summary("LLCP release")
Hai Shalom899fcc72020-10-19 14:38:18 -0700984 global handover
985 handover.close()
Hai Shalomfdcde762020-04-02 11:19:20 -0700986 return True
987
988def terminate_loop():
989 global terminate_now
990 return terminate_now
991
992def main():
993 clf = nfc.ContactlessFrontend()
994
995 parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations')
996 parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO,
997 action='store_const', dest='loglevel',
998 help='verbose debug output')
999 parser.add_argument('-q', const=logging.WARNING, action='store_const',
1000 dest='loglevel', help='be quiet')
1001 parser.add_argument('--only-one', '-1', action='store_true',
1002 help='run only one operation and exit')
1003 parser.add_argument('--init-on-touch', '-I', action='store_true',
1004 help='initiate handover on touch')
1005 parser.add_argument('--no-wait', action='store_true',
1006 help='do not wait for tag to be removed before exiting')
1007 parser.add_argument('--ifname', '-i',
1008 help='network interface name')
1009 parser.add_argument('--no-input', '-a', action='store_true',
1010 help='do not use stdout input to initiate handover')
1011 parser.add_argument('--tag-read-only', '-t', action='store_true',
1012 help='tag read only (do not allow connection handover)')
1013 parser.add_argument('--handover-only', action='store_true',
1014 help='connection handover only (do not allow tag read)')
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001015 parser.add_argument('--enrollee', action='store_true',
1016 help='run as Enrollee-only')
1017 parser.add_argument('--configurator', action='store_true',
1018 help='run as Configurator-only')
1019 parser.add_argument('--config-params', default='',
1020 help='configurator parameters')
1021 parser.add_argument('--ctrl', default='/var/run/wpa_supplicant',
1022 help='wpa_supplicant/hostapd control interface')
Hai Shalomfdcde762020-04-02 11:19:20 -07001023 parser.add_argument('--summary',
1024 help='summary file for writing status updates')
1025 parser.add_argument('--success',
1026 help='success file for writing success update')
1027 parser.add_argument('--device', default='usb', help='NFC device to open')
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001028 parser.add_argument('--chan', default=None, help='channel list')
Hai Shalom899fcc72020-10-19 14:38:18 -07001029 parser.add_argument('--altchan', default=None, help='alternative channel list')
1030 parser.add_argument('--netrole', default=None, help='netrole for Enrollee')
1031 parser.add_argument('--test-uri', default=None,
1032 help='test mode: initial URI')
1033 parser.add_argument('--test-alt-uri', default=None,
1034 help='test mode: alternative URI')
1035 parser.add_argument('--test-sel-uri', default=None,
1036 help='test mode: handover select URI')
1037 parser.add_argument('--test-crn', default=None,
1038 help='test mode: hardcoded crn')
Hai Shalomfdcde762020-04-02 11:19:20 -07001039 parser.add_argument('command', choices=['write-nfc-uri',
1040 'write-nfc-hs'],
1041 nargs='?')
1042 args = parser.parse_args()
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001043 summary(args)
Hai Shalomfdcde762020-04-02 11:19:20 -07001044
Hai Shalom899fcc72020-10-19 14:38:18 -07001045 global handover
1046 handover = ConnectionHandover()
1047
Hai Shalomfdcde762020-04-02 11:19:20 -07001048 global only_one
1049 only_one = args.only_one
1050
1051 global no_wait
1052 no_wait = args.no_wait
1053
Hai Shalom899fcc72020-10-19 14:38:18 -07001054 global chanlist, netrole, test_uri, test_alt_uri, test_sel_uri
1055 global test_crn
Hai Shalomfdcde762020-04-02 11:19:20 -07001056 chanlist = args.chan
Hai Shalom899fcc72020-10-19 14:38:18 -07001057 handover.altchanlist = args.altchan
1058 netrole = args.netrole
1059 test_uri = args.test_uri
1060 test_alt_uri = args.test_alt_uri
1061 test_sel_uri = args.test_sel_uri
1062 if args.test_crn:
1063 test_crn = struct.pack('>H', int(args.test_crn))
1064 else:
1065 test_crn = None
Hai Shalomfdcde762020-04-02 11:19:20 -07001066
1067 logging.basicConfig(level=args.loglevel)
Hai Shalom899fcc72020-10-19 14:38:18 -07001068 for l in ['nfc.clf.rcs380',
1069 'nfc.clf.transport',
1070 'nfc.clf.device',
1071 'nfc.clf.__init__',
1072 'nfc.llcp',
1073 'nfc.handover']:
1074 log = logging.getLogger(l)
1075 log.setLevel(args.loglevel)
Hai Shalomfdcde762020-04-02 11:19:20 -07001076
1077 global init_on_touch
1078 init_on_touch = args.init_on_touch
1079
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001080 global enrollee_only
1081 enrollee_only = args.enrollee
1082
1083 global configurator_only
1084 configurator_only = args.configurator
1085
1086 global config_params
1087 config_params = args.config_params
1088
Hai Shalomfdcde762020-04-02 11:19:20 -07001089 if args.ifname:
1090 global ifname
1091 ifname = args.ifname
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001092 summary("Selected ifname " + ifname)
1093
1094 if args.ctrl:
1095 global wpas_ctrl
1096 wpas_ctrl = args.ctrl
Hai Shalomfdcde762020-04-02 11:19:20 -07001097
1098 if args.summary:
1099 global summary_file
1100 summary_file = args.summary
1101
1102 if args.success:
1103 global success_file
1104 success_file = args.success
1105
1106 if args.no_input:
1107 global no_input
1108 no_input = True
1109
1110 clf = nfc.ContactlessFrontend()
Hai Shalomfdcde762020-04-02 11:19:20 -07001111
1112 try:
1113 if not clf.open(args.device):
Hai Shalom899fcc72020-10-19 14:38:18 -07001114 summary("Could not open connection with an NFC device", color=C_RED)
1115 raise SystemExit(1)
Hai Shalomfdcde762020-04-02 11:19:20 -07001116
1117 if args.command == "write-nfc-uri":
1118 write_nfc_uri(clf, wait_remove=not args.no_wait)
Hai Shalom899fcc72020-10-19 14:38:18 -07001119 if not operation_success:
1120 raise SystemExit(1)
Hai Shalomfdcde762020-04-02 11:19:20 -07001121 raise SystemExit
1122
1123 if args.command == "write-nfc-hs":
1124 write_nfc_hs(clf, wait_remove=not args.no_wait)
Hai Shalom899fcc72020-10-19 14:38:18 -07001125 if not operation_success:
1126 raise SystemExit(1)
Hai Shalomfdcde762020-04-02 11:19:20 -07001127 raise SystemExit
1128
1129 global continue_loop
1130 while continue_loop:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001131 global in_raw_mode
1132 was_in_raw_mode = in_raw_mode
Hai Shalomfdcde762020-04-02 11:19:20 -07001133 clear_raw_mode()
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001134 if was_in_raw_mode:
1135 print("\r")
Hai Shalom899fcc72020-10-19 14:38:18 -07001136 if args.handover_only:
1137 summary("Waiting a peer to be touched", color=C_MAGENTA)
1138 elif args.tag_read_only:
1139 summary("Waiting for a tag to be touched", color=C_BLUE)
1140 else:
1141 summary("Waiting for a tag or peer to be touched",
1142 color=C_GREEN)
1143 handover.wait_connection = True
Hai Shalomfdcde762020-04-02 11:19:20 -07001144 try:
1145 if args.tag_read_only:
1146 if not clf.connect(rdwr={'on-connect': rdwr_connected}):
1147 break
1148 elif args.handover_only:
1149 if not clf.connect(llcp={'on-startup': llcp_startup,
1150 'on-connect': llcp_connected,
1151 'on-release': llcp_release},
1152 terminate=terminate_loop):
1153 break
1154 else:
1155 if not clf.connect(rdwr={'on-connect': rdwr_connected},
1156 llcp={'on-startup': llcp_startup,
1157 'on-connect': llcp_connected,
1158 'on-release': llcp_release},
1159 terminate=terminate_loop):
1160 break
1161 except Exception as e:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001162 summary("clf.connect failed: " + str(e))
Hai Shalomfdcde762020-04-02 11:19:20 -07001163 break
1164
Hai Shalom899fcc72020-10-19 14:38:18 -07001165 if only_one and handover.connected:
1166 role = "selector" if handover.i_m_selector else "requestor"
1167 summary("Connection handover result: I'm the %s" % role,
1168 color=C_YELLOW)
1169 if handover.peer_uri:
1170 summary("Peer URI: " + handover.peer_uri, color=C_YELLOW)
1171 if handover.my_uri:
1172 summary("My URI: " + handover.my_uri, color=C_YELLOW)
1173 if not (handover.peer_uri and handover.my_uri):
1174 summary("Negotiated connection handover failed",
1175 color=C_YELLOW)
1176 break
Hai Shalomfdcde762020-04-02 11:19:20 -07001177
1178 except KeyboardInterrupt:
1179 raise SystemExit
1180 finally:
1181 clf.close()
1182
1183 raise SystemExit
1184
1185if __name__ == '__main__':
1186 main()