]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/wpasupplicant.py
tests: Use python3 compatible "except" statement
[thirdparty/hostap.git] / tests / hwsim / wpasupplicant.py
1 # Python class for controlling wpa_supplicant
2 # Copyright (c) 2013-2019, Jouni Malinen <j@w1.fi>
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import os
8 import time
9 import logging
10 import binascii
11 import re
12 import struct
13 import wpaspy
14 import remotehost
15 import subprocess
16
17 logger = logging.getLogger()
18 wpas_ctrl = '/var/run/wpa_supplicant'
19
20 class WpaSupplicant:
21 def __init__(self, ifname=None, global_iface=None, hostname=None,
22 port=9877, global_port=9878, monitor=True):
23 self.monitor = monitor
24 self.hostname = hostname
25 self.group_ifname = None
26 self.gctrl_mon = None
27 self.host = remotehost.Host(hostname, ifname)
28 self._group_dbg = None
29 if ifname:
30 self.set_ifname(ifname, hostname, port)
31 res = self.get_driver_status()
32 if 'capa.flags' in res and int(res['capa.flags'], 0) & 0x20000000:
33 self.p2p_dev_ifname = 'p2p-dev-' + self.ifname
34 else:
35 self.p2p_dev_ifname = ifname
36 else:
37 self.ifname = None
38
39 self.global_iface = global_iface
40 if global_iface:
41 self.global_mon = None
42 if hostname != None:
43 self.global_ctrl = wpaspy.Ctrl(hostname, global_port)
44 if self.monitor:
45 self.global_mon = wpaspy.Ctrl(hostname, global_port)
46 self.global_dbg = hostname + "/" + str(global_port) + "/"
47 else:
48 self.global_ctrl = wpaspy.Ctrl(global_iface)
49 if self.monitor:
50 self.global_mon = wpaspy.Ctrl(global_iface)
51 self.global_dbg = ""
52 if self.monitor:
53 self.global_mon.attach()
54 else:
55 self.global_mon = None
56
57 def cmd_execute(self, cmd_array, shell=False):
58 if self.hostname is None:
59 if shell:
60 cmd = ' '.join(cmd_array)
61 else:
62 cmd = cmd_array
63 proc = subprocess.Popen(cmd, stderr=subprocess.STDOUT,
64 stdout=subprocess.PIPE, shell=shell)
65 out = proc.communicate()[0]
66 ret = proc.returncode
67 return ret, out
68 else:
69 return self.host.execute(cmd_array)
70
71 def terminate(self):
72 if self.global_mon:
73 self.global_mon.detach()
74 self.global_mon = None
75 self.global_ctrl.terminate()
76 self.global_ctrl = None
77
78 def close_ctrl(self):
79 if self.global_mon:
80 self.global_mon.detach()
81 self.global_mon = None
82 self.global_ctrl = None
83 self.remove_ifname()
84
85 def set_ifname(self, ifname, hostname=None, port=9877):
86 self.ifname = ifname
87 if hostname != None:
88 self.ctrl = wpaspy.Ctrl(hostname, port)
89 if self.monitor:
90 self.mon = wpaspy.Ctrl(hostname, port)
91 self.host = remotehost.Host(hostname, ifname)
92 self.dbg = hostname + "/" + ifname
93 else:
94 self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
95 if self.monitor:
96 self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname))
97 self.dbg = ifname
98 if self.monitor:
99 self.mon.attach()
100
101 def remove_ifname(self):
102 if self.ifname:
103 self.mon.detach()
104 self.mon = None
105 self.ctrl = None
106 self.ifname = None
107
108 def get_ctrl_iface_port(self, ifname):
109 if self.hostname is None:
110 return None
111
112 res = self.global_request("INTERFACES ctrl")
113 lines = res.splitlines()
114 found = False
115 for line in lines:
116 words = line.split()
117 if words[0] == ifname:
118 found = True
119 break
120 if not found:
121 raise Exception("Could not find UDP port for " + ifname)
122 res = line.find("ctrl_iface=udp:")
123 if res == -1:
124 raise Exception("Wrong ctrl_interface format")
125 words = line.split(":")
126 return int(words[1])
127
128 def interface_add(self, ifname, config="", driver="nl80211",
129 drv_params=None, br_ifname=None, create=False,
130 set_ifname=True, all_params=False, if_type=None):
131 status, groups = self.host.execute(["id"])
132 if status != 0:
133 group = "admin"
134 group = "admin" if "(admin)" in groups else "adm"
135 cmd = "INTERFACE_ADD " + ifname + "\t" + config + "\t" + driver + "\tDIR=/var/run/wpa_supplicant GROUP=" + group
136 if drv_params:
137 cmd = cmd + '\t' + drv_params
138 if br_ifname:
139 if not drv_params:
140 cmd += '\t'
141 cmd += '\t' + br_ifname
142 if create:
143 if not br_ifname:
144 cmd += '\t'
145 if not drv_params:
146 cmd += '\t'
147 cmd += '\tcreate'
148 if if_type:
149 cmd += '\t' + if_type
150 if all_params and not create:
151 if not br_ifname:
152 cmd += '\t'
153 if not drv_params:
154 cmd += '\t'
155 cmd += '\t'
156 if "FAIL" in self.global_request(cmd):
157 raise Exception("Failed to add a dynamic wpa_supplicant interface")
158 if not create and set_ifname:
159 port = self.get_ctrl_iface_port(ifname)
160 self.set_ifname(ifname, self.hostname, port)
161 res = self.get_driver_status()
162 if 'capa.flags' in res and int(res['capa.flags'], 0) & 0x20000000:
163 self.p2p_dev_ifname = 'p2p-dev-' + self.ifname
164 else:
165 self.p2p_dev_ifname = ifname
166
167 def interface_remove(self, ifname):
168 self.remove_ifname()
169 self.global_request("INTERFACE_REMOVE " + ifname)
170
171 def request(self, cmd, timeout=10):
172 logger.debug(self.dbg + ": CTRL: " + cmd)
173 return self.ctrl.request(cmd, timeout=timeout)
174
175 def global_request(self, cmd):
176 if self.global_iface is None:
177 return self.request(cmd)
178 else:
179 ifname = self.ifname or self.global_iface
180 logger.debug(self.global_dbg + ifname + ": CTRL(global): " + cmd)
181 return self.global_ctrl.request(cmd)
182
183 @property
184 def group_dbg(self):
185 if self._group_dbg is not None:
186 return self._group_dbg
187 if self.group_ifname is None:
188 raise Exception("Cannot have group_dbg without group_ifname")
189 if self.hostname is None:
190 self._group_dbg = self.group_ifname
191 else:
192 self._group_dbg = self.hostname + "/" + self.group_ifname
193 return self._group_dbg
194
195 def group_request(self, cmd):
196 if self.group_ifname and self.group_ifname != self.ifname:
197 if self.hostname is None:
198 gctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, self.group_ifname))
199 else:
200 port = self.get_ctrl_iface_port(self.group_ifname)
201 gctrl = wpaspy.Ctrl(self.hostname, port)
202 logger.debug(self.group_dbg + ": CTRL(group): " + cmd)
203 return gctrl.request(cmd)
204 return self.request(cmd)
205
206 def ping(self):
207 return "PONG" in self.request("PING")
208
209 def global_ping(self):
210 return "PONG" in self.global_request("PING")
211
212 def reset(self):
213 self.dump_monitor()
214 res = self.request("FLUSH")
215 if not "OK" in res:
216 logger.info("FLUSH to " + self.ifname + " failed: " + res)
217 self.global_request("REMOVE_NETWORK all")
218 self.global_request("SET p2p_no_group_iface 1")
219 self.global_request("P2P_FLUSH")
220 if self.gctrl_mon:
221 try:
222 self.gctrl_mon.detach()
223 except:
224 pass
225 self.gctrl_mon = None
226 self.group_ifname = None
227 self.dump_monitor()
228
229 iter = 0
230 while iter < 60:
231 state1 = self.get_driver_status_field("scan_state")
232 p2pdev = "p2p-dev-" + self.ifname
233 state2 = self.get_driver_status_field("scan_state", ifname=p2pdev)
234 states = str(state1) + " " + str(state2)
235 if "SCAN_STARTED" in states or "SCAN_REQUESTED" in states:
236 logger.info(self.ifname + ": Waiting for scan operation to complete before continuing")
237 time.sleep(1)
238 else:
239 break
240 iter = iter + 1
241 if iter == 60:
242 logger.error(self.ifname + ": Driver scan state did not clear")
243 print "Trying to clear cfg80211/mac80211 scan state"
244 status, buf = self.host.execute(["ifconfig", self.ifname, "down"])
245 if status != 0:
246 logger.info("ifconfig failed: " + buf)
247 logger.info(status)
248 status, buf = self.host.execute(["ifconfig", self.ifname, "up"])
249 if status != 0:
250 logger.info("ifconfig failed: " + buf)
251 logger.info(status)
252 if iter > 0:
253 # The ongoing scan could have discovered BSSes or P2P peers
254 logger.info("Run FLUSH again since scan was in progress")
255 self.request("FLUSH")
256 self.dump_monitor()
257
258 if not self.ping():
259 logger.info("No PING response from " + self.ifname + " after reset")
260
261 def set(self, field, value):
262 if not "OK" in self.request("SET " + field + " " + value):
263 raise Exception("Failed to set wpa_supplicant parameter " + field)
264
265 def add_network(self):
266 id = self.request("ADD_NETWORK")
267 if "FAIL" in id:
268 raise Exception("ADD_NETWORK failed")
269 return int(id)
270
271 def remove_network(self, id):
272 id = self.request("REMOVE_NETWORK " + str(id))
273 if "FAIL" in id:
274 raise Exception("REMOVE_NETWORK failed")
275 return None
276
277 def get_network(self, id, field):
278 res = self.request("GET_NETWORK " + str(id) + " " + field)
279 if res == "FAIL\n":
280 return None
281 return res
282
283 def set_network(self, id, field, value):
284 res = self.request("SET_NETWORK " + str(id) + " " + field + " " + value)
285 if "FAIL" in res:
286 raise Exception("SET_NETWORK failed")
287 return None
288
289 def set_network_quoted(self, id, field, value):
290 res = self.request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
291 if "FAIL" in res:
292 raise Exception("SET_NETWORK failed")
293 return None
294
295 def p2pdev_request(self, cmd):
296 return self.global_request("IFNAME=" + self.p2p_dev_ifname + " " + cmd)
297
298 def p2pdev_add_network(self):
299 id = self.p2pdev_request("ADD_NETWORK")
300 if "FAIL" in id:
301 raise Exception("p2pdev ADD_NETWORK failed")
302 return int(id)
303
304 def p2pdev_set_network(self, id, field, value):
305 res = self.p2pdev_request("SET_NETWORK " + str(id) + " " + field + " " + value)
306 if "FAIL" in res:
307 raise Exception("p2pdev SET_NETWORK failed")
308 return None
309
310 def p2pdev_set_network_quoted(self, id, field, value):
311 res = self.p2pdev_request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"')
312 if "FAIL" in res:
313 raise Exception("p2pdev SET_NETWORK failed")
314 return None
315
316 def list_networks(self, p2p=False):
317 if p2p:
318 res = self.global_request("LIST_NETWORKS")
319 else:
320 res = self.request("LIST_NETWORKS")
321 lines = res.splitlines()
322 networks = []
323 for l in lines:
324 if "network id" in l:
325 continue
326 [id,ssid,bssid,flags] = l.split('\t')
327 network = {}
328 network['id'] = id
329 network['ssid'] = ssid
330 network['bssid'] = bssid
331 network['flags'] = flags
332 networks.append(network)
333 return networks
334
335 def hs20_enable(self, auto_interworking=False):
336 self.request("SET interworking 1")
337 self.request("SET hs20 1")
338 if auto_interworking:
339 self.request("SET auto_interworking 1")
340 else:
341 self.request("SET auto_interworking 0")
342
343 def interworking_add_network(self, bssid):
344 id = self.request("INTERWORKING_ADD_NETWORK " + bssid)
345 if "FAIL" in id or "OK" in id:
346 raise Exception("INTERWORKING_ADD_NETWORK failed")
347 return int(id)
348
349 def add_cred(self):
350 id = self.request("ADD_CRED")
351 if "FAIL" in id:
352 raise Exception("ADD_CRED failed")
353 return int(id)
354
355 def remove_cred(self, id):
356 id = self.request("REMOVE_CRED " + str(id))
357 if "FAIL" in id:
358 raise Exception("REMOVE_CRED failed")
359 return None
360
361 def set_cred(self, id, field, value):
362 res = self.request("SET_CRED " + str(id) + " " + field + " " + value)
363 if "FAIL" in res:
364 raise Exception("SET_CRED failed")
365 return None
366
367 def set_cred_quoted(self, id, field, value):
368 res = self.request("SET_CRED " + str(id) + " " + field + ' "' + value + '"')
369 if "FAIL" in res:
370 raise Exception("SET_CRED failed")
371 return None
372
373 def get_cred(self, id, field):
374 return self.request("GET_CRED " + str(id) + " " + field)
375
376 def add_cred_values(self, params):
377 id = self.add_cred()
378
379 quoted = [ "realm", "username", "password", "domain", "imsi",
380 "excluded_ssid", "milenage", "ca_cert", "client_cert",
381 "private_key", "domain_suffix_match", "provisioning_sp",
382 "roaming_partner", "phase1", "phase2", "private_key_passwd",
383 "roaming_consortiums" ]
384 for field in quoted:
385 if field in params:
386 self.set_cred_quoted(id, field, params[field])
387
388 not_quoted = [ "eap", "roaming_consortium", "priority",
389 "required_roaming_consortium", "sp_priority",
390 "max_bss_load", "update_identifier", "req_conn_capab",
391 "min_dl_bandwidth_home", "min_ul_bandwidth_home",
392 "min_dl_bandwidth_roaming", "min_ul_bandwidth_roaming" ]
393 for field in not_quoted:
394 if field in params:
395 self.set_cred(id, field, params[field])
396
397 return id
398
399 def select_network(self, id, freq=None):
400 if freq:
401 extra = " freq=" + str(freq)
402 else:
403 extra = ""
404 id = self.request("SELECT_NETWORK " + str(id) + extra)
405 if "FAIL" in id:
406 raise Exception("SELECT_NETWORK failed")
407 return None
408
409 def mesh_group_add(self, id):
410 id = self.request("MESH_GROUP_ADD " + str(id))
411 if "FAIL" in id:
412 raise Exception("MESH_GROUP_ADD failed")
413 return None
414
415 def mesh_group_remove(self):
416 id = self.request("MESH_GROUP_REMOVE " + str(self.ifname))
417 if "FAIL" in id:
418 raise Exception("MESH_GROUP_REMOVE failed")
419 return None
420
421 def connect_network(self, id, timeout=None):
422 if timeout is None:
423 timeout = 10 if self.hostname is None else 60
424 self.dump_monitor()
425 self.select_network(id)
426 self.wait_connected(timeout=timeout)
427 self.dump_monitor()
428
429 def get_status(self, extra=None):
430 if extra:
431 extra = "-" + extra
432 else:
433 extra = ""
434 res = self.request("STATUS" + extra)
435 lines = res.splitlines()
436 vals = dict()
437 for l in lines:
438 try:
439 [name,value] = l.split('=', 1)
440 vals[name] = value
441 except ValueError as e:
442 logger.info(self.ifname + ": Ignore unexpected STATUS line: " + l)
443 return vals
444
445 def get_status_field(self, field, extra=None):
446 vals = self.get_status(extra)
447 if field in vals:
448 return vals[field]
449 return None
450
451 def get_group_status(self, extra=None):
452 if extra:
453 extra = "-" + extra
454 else:
455 extra = ""
456 res = self.group_request("STATUS" + extra)
457 lines = res.splitlines()
458 vals = dict()
459 for l in lines:
460 try:
461 [name,value] = l.split('=', 1)
462 except ValueError:
463 logger.info(self.ifname + ": Ignore unexpected status line: " + l)
464 continue
465 vals[name] = value
466 return vals
467
468 def get_group_status_field(self, field, extra=None):
469 vals = self.get_group_status(extra)
470 if field in vals:
471 return vals[field]
472 return None
473
474 def get_driver_status(self, ifname=None):
475 if ifname is None:
476 res = self.request("STATUS-DRIVER")
477 else:
478 res = self.global_request("IFNAME=%s STATUS-DRIVER" % ifname)
479 if res.startswith("FAIL"):
480 return dict()
481 lines = res.splitlines()
482 vals = dict()
483 for l in lines:
484 try:
485 [name,value] = l.split('=', 1)
486 except ValueError:
487 logger.info(self.ifname + ": Ignore unexpected status-driver line: " + l)
488 continue
489 vals[name] = value
490 return vals
491
492 def get_driver_status_field(self, field, ifname=None):
493 vals = self.get_driver_status(ifname)
494 if field in vals:
495 return vals[field]
496 return None
497
498 def get_mcc(self):
499 mcc = int(self.get_driver_status_field('capa.num_multichan_concurrent'))
500 return 1 if mcc < 2 else mcc
501
502 def get_mib(self):
503 res = self.request("MIB")
504 lines = res.splitlines()
505 vals = dict()
506 for l in lines:
507 try:
508 [name,value] = l.split('=', 1)
509 vals[name] = value
510 except ValueError as e:
511 logger.info(self.ifname + ": Ignore unexpected MIB line: " + l)
512 return vals
513
514 def p2p_dev_addr(self):
515 return self.get_status_field("p2p_device_address")
516
517 def p2p_interface_addr(self):
518 return self.get_group_status_field("address")
519
520 def own_addr(self):
521 try:
522 res = self.p2p_interface_addr()
523 except:
524 res = self.p2p_dev_addr()
525 return res
526
527 def p2p_listen(self):
528 return self.global_request("P2P_LISTEN")
529
530 def p2p_ext_listen(self, period, interval):
531 return self.global_request("P2P_EXT_LISTEN %d %d" % (period, interval))
532
533 def p2p_cancel_ext_listen(self):
534 return self.global_request("P2P_EXT_LISTEN")
535
536 def p2p_find(self, social=False, progressive=False, dev_id=None,
537 dev_type=None, delay=None, freq=None):
538 cmd = "P2P_FIND"
539 if social:
540 cmd = cmd + " type=social"
541 elif progressive:
542 cmd = cmd + " type=progressive"
543 if dev_id:
544 cmd = cmd + " dev_id=" + dev_id
545 if dev_type:
546 cmd = cmd + " dev_type=" + dev_type
547 if delay:
548 cmd = cmd + " delay=" + str(delay)
549 if freq:
550 cmd = cmd + " freq=" + str(freq)
551 return self.global_request(cmd)
552
553 def p2p_stop_find(self):
554 return self.global_request("P2P_STOP_FIND")
555
556 def wps_read_pin(self):
557 self.pin = self.request("WPS_PIN get").rstrip("\n")
558 if "FAIL" in self.pin:
559 raise Exception("Could not generate PIN")
560 return self.pin
561
562 def peer_known(self, peer, full=True):
563 res = self.global_request("P2P_PEER " + peer)
564 if peer.lower() not in res.lower():
565 return False
566 if not full:
567 return True
568 return "[PROBE_REQ_ONLY]" not in res
569
570 def discover_peer(self, peer, full=True, timeout=15, social=True,
571 force_find=False, freq=None):
572 logger.info(self.ifname + ": Trying to discover peer " + peer)
573 if not force_find and self.peer_known(peer, full):
574 return True
575 self.p2p_find(social, freq=freq)
576 count = 0
577 while count < timeout * 4:
578 time.sleep(0.25)
579 count = count + 1
580 if self.peer_known(peer, full):
581 return True
582 return False
583
584 def get_peer(self, peer):
585 res = self.global_request("P2P_PEER " + peer)
586 if peer.lower() not in res.lower():
587 raise Exception("Peer information not available")
588 lines = res.splitlines()
589 vals = dict()
590 for l in lines:
591 if '=' in l:
592 [name,value] = l.split('=', 1)
593 vals[name] = value
594 return vals
595
596 def group_form_result(self, ev, expect_failure=False, go_neg_res=None):
597 if expect_failure:
598 if "P2P-GROUP-STARTED" in ev:
599 raise Exception("Group formation succeeded when expecting failure")
600 exp = r'<.>(P2P-GO-NEG-FAILURE) status=([0-9]*)'
601 s = re.split(exp, ev)
602 if len(s) < 3:
603 return None
604 res = {}
605 res['result'] = 'go-neg-failed'
606 res['status'] = int(s[2])
607 return res
608
609 if "P2P-GROUP-STARTED" not in ev:
610 raise Exception("No P2P-GROUP-STARTED event seen")
611
612 exp = r'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*) ip_addr=([0-9.]*) ip_mask=([0-9.]*) go_ip_addr=([0-9.]*)'
613 s = re.split(exp, ev)
614 if len(s) < 11:
615 exp = r'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*)'
616 s = re.split(exp, ev)
617 if len(s) < 8:
618 raise Exception("Could not parse P2P-GROUP-STARTED")
619 res = {}
620 res['result'] = 'success'
621 res['ifname'] = s[2]
622 self.group_ifname = s[2]
623 try:
624 if self.hostname is None:
625 self.gctrl_mon = wpaspy.Ctrl(os.path.join(wpas_ctrl,
626 self.group_ifname))
627 else:
628 port = self.get_ctrl_iface_port(self.group_ifname)
629 self.gctrl_mon = wpaspy.Ctrl(self.hostname, port)
630 self.gctrl_mon.attach()
631 except:
632 logger.debug("Could not open monitor socket for group interface")
633 self.gctrl_mon = None
634 res['role'] = s[3]
635 res['ssid'] = s[4]
636 res['freq'] = s[5]
637 if "[PERSISTENT]" in ev:
638 res['persistent'] = True
639 else:
640 res['persistent'] = False
641 p = re.match(r'psk=([0-9a-f]*)', s[6])
642 if p:
643 res['psk'] = p.group(1)
644 p = re.match(r'passphrase="(.*)"', s[6])
645 if p:
646 res['passphrase'] = p.group(1)
647 res['go_dev_addr'] = s[7]
648
649 if len(s) > 8 and len(s[8]) > 0 and "[PERSISTENT]" not in s[8]:
650 res['ip_addr'] = s[8]
651 if len(s) > 9:
652 res['ip_mask'] = s[9]
653 if len(s) > 10:
654 res['go_ip_addr'] = s[10]
655
656 if go_neg_res:
657 exp = r'<.>(P2P-GO-NEG-SUCCESS) role=(GO|client) freq=([0-9]*)'
658 s = re.split(exp, go_neg_res)
659 if len(s) < 4:
660 raise Exception("Could not parse P2P-GO-NEG-SUCCESS")
661 res['go_neg_role'] = s[2]
662 res['go_neg_freq'] = s[3]
663
664 return res
665
666 def p2p_go_neg_auth(self, peer, pin, method, go_intent=None,
667 persistent=False, freq=None, freq2=None,
668 max_oper_chwidth=None, ht40=False, vht=False):
669 if not self.discover_peer(peer):
670 raise Exception("Peer " + peer + " not found")
671 self.dump_monitor()
672 if pin:
673 cmd = "P2P_CONNECT " + peer + " " + pin + " " + method + " auth"
674 else:
675 cmd = "P2P_CONNECT " + peer + " " + method + " auth"
676 if go_intent:
677 cmd = cmd + ' go_intent=' + str(go_intent)
678 if freq:
679 cmd = cmd + ' freq=' + str(freq)
680 if freq2:
681 cmd = cmd + ' freq2=' + str(freq2)
682 if max_oper_chwidth:
683 cmd = cmd + ' max_oper_chwidth=' + str(max_oper_chwidth)
684 if ht40:
685 cmd = cmd + ' ht40'
686 if vht:
687 cmd = cmd + ' vht'
688 if persistent:
689 cmd = cmd + " persistent"
690 if "OK" in self.global_request(cmd):
691 return None
692 raise Exception("P2P_CONNECT (auth) failed")
693
694 def p2p_go_neg_auth_result(self, timeout=None, expect_failure=False):
695 if timeout is None:
696 timeout = 1 if expect_failure else 5
697 go_neg_res = None
698 ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
699 "P2P-GO-NEG-FAILURE"], timeout)
700 if ev is None:
701 if expect_failure:
702 return None
703 raise Exception("Group formation timed out")
704 if "P2P-GO-NEG-SUCCESS" in ev:
705 go_neg_res = ev
706 ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
707 if ev is None:
708 if expect_failure:
709 return None
710 raise Exception("Group formation timed out")
711 self.dump_monitor()
712 return self.group_form_result(ev, expect_failure, go_neg_res)
713
714 def p2p_go_neg_init(self, peer, pin, method, timeout=0, go_intent=None,
715 expect_failure=False, persistent=False,
716 persistent_id=None, freq=None, provdisc=False,
717 wait_group=True, freq2=None, max_oper_chwidth=None,
718 ht40=False, vht=False):
719 if not self.discover_peer(peer):
720 raise Exception("Peer " + peer + " not found")
721 self.dump_monitor()
722 if pin:
723 cmd = "P2P_CONNECT " + peer + " " + pin + " " + method
724 else:
725 cmd = "P2P_CONNECT " + peer + " " + method
726 if go_intent is not None:
727 cmd = cmd + ' go_intent=' + str(go_intent)
728 if freq:
729 cmd = cmd + ' freq=' + str(freq)
730 if freq2:
731 cmd = cmd + ' freq2=' + str(freq2)
732 if max_oper_chwidth:
733 cmd = cmd + ' max_oper_chwidth=' + str(max_oper_chwidth)
734 if ht40:
735 cmd = cmd + ' ht40'
736 if vht:
737 cmd = cmd + ' vht'
738 if persistent:
739 cmd = cmd + " persistent"
740 elif persistent_id:
741 cmd = cmd + " persistent=" + persistent_id
742 if provdisc:
743 cmd = cmd + " provdisc"
744 if "OK" in self.global_request(cmd):
745 if timeout == 0:
746 return None
747 go_neg_res = None
748 ev = self.wait_global_event(["P2P-GO-NEG-SUCCESS",
749 "P2P-GO-NEG-FAILURE"], timeout)
750 if ev is None:
751 if expect_failure:
752 return None
753 raise Exception("Group formation timed out")
754 if "P2P-GO-NEG-SUCCESS" in ev:
755 if not wait_group:
756 return ev
757 go_neg_res = ev
758 ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout)
759 if ev is None:
760 if expect_failure:
761 return None
762 raise Exception("Group formation timed out")
763 self.dump_monitor()
764 return self.group_form_result(ev, expect_failure, go_neg_res)
765 raise Exception("P2P_CONNECT failed")
766
767 def wait_event(self, events, timeout=10):
768 start = os.times()[4]
769 while True:
770 while self.mon.pending():
771 ev = self.mon.recv()
772 logger.debug(self.dbg + ": " + ev)
773 for event in events:
774 if event in ev:
775 return ev
776 now = os.times()[4]
777 remaining = start + timeout - now
778 if remaining <= 0:
779 break
780 if not self.mon.pending(timeout=remaining):
781 break
782 return None
783
784 def wait_global_event(self, events, timeout):
785 if self.global_iface is None:
786 self.wait_event(events, timeout)
787 else:
788 start = os.times()[4]
789 while True:
790 while self.global_mon.pending():
791 ev = self.global_mon.recv()
792 logger.debug(self.global_dbg + self.ifname + "(global): " + ev)
793 for event in events:
794 if event in ev:
795 return ev
796 now = os.times()[4]
797 remaining = start + timeout - now
798 if remaining <= 0:
799 break
800 if not self.global_mon.pending(timeout=remaining):
801 break
802 return None
803
804 def wait_group_event(self, events, timeout=10):
805 if self.group_ifname and self.group_ifname != self.ifname:
806 if self.gctrl_mon is None:
807 return None
808 start = os.times()[4]
809 while True:
810 while self.gctrl_mon.pending():
811 ev = self.gctrl_mon.recv()
812 logger.debug(self.group_dbg + "(group): " + ev)
813 for event in events:
814 if event in ev:
815 return ev
816 now = os.times()[4]
817 remaining = start + timeout - now
818 if remaining <= 0:
819 break
820 if not self.gctrl_mon.pending(timeout=remaining):
821 break
822 return None
823
824 return self.wait_event(events, timeout)
825
826 def wait_go_ending_session(self):
827 if self.gctrl_mon:
828 try:
829 self.gctrl_mon.detach()
830 except:
831 pass
832 self.gctrl_mon = None
833 timeout = 3 if self.hostname is None else 10
834 ev = self.wait_global_event(["P2P-GROUP-REMOVED"], timeout=timeout)
835 if ev is None:
836 raise Exception("Group removal event timed out")
837 if "reason=GO_ENDING_SESSION" not in ev:
838 raise Exception("Unexpected group removal reason")
839
840 def dump_monitor(self):
841 count_iface = 0
842 count_global = 0
843 while self.mon.pending():
844 ev = self.mon.recv()
845 logger.debug(self.dbg + ": " + ev)
846 count_iface += 1
847 while self.global_mon and self.global_mon.pending():
848 ev = self.global_mon.recv()
849 logger.debug(self.global_dbg + self.ifname + "(global): " + ev)
850 count_global += 1
851 return (count_iface, count_global)
852
853 def remove_group(self, ifname=None):
854 if self.gctrl_mon:
855 try:
856 self.gctrl_mon.detach()
857 except:
858 pass
859 self.gctrl_mon = None
860 if ifname is None:
861 ifname = self.group_ifname if self.group_ifname else self.ifname
862 if "OK" not in self.global_request("P2P_GROUP_REMOVE " + ifname):
863 raise Exception("Group could not be removed")
864 self.group_ifname = None
865
866 def p2p_start_go(self, persistent=None, freq=None, no_event_clear=False):
867 self.dump_monitor()
868 cmd = "P2P_GROUP_ADD"
869 if persistent is None:
870 pass
871 elif persistent is True:
872 cmd = cmd + " persistent"
873 else:
874 cmd = cmd + " persistent=" + str(persistent)
875 if freq:
876 cmd = cmd + " freq=" + str(freq)
877 if "OK" in self.global_request(cmd):
878 ev = self.wait_global_event(["P2P-GROUP-STARTED"], timeout=5)
879 if ev is None:
880 raise Exception("GO start up timed out")
881 if not no_event_clear:
882 self.dump_monitor()
883 return self.group_form_result(ev)
884 raise Exception("P2P_GROUP_ADD failed")
885
886 def p2p_go_authorize_client(self, pin):
887 cmd = "WPS_PIN any " + pin
888 if "FAIL" in self.group_request(cmd):
889 raise Exception("Failed to authorize client connection on GO")
890 return None
891
892 def p2p_go_authorize_client_pbc(self):
893 cmd = "WPS_PBC"
894 if "FAIL" in self.group_request(cmd):
895 raise Exception("Failed to authorize client connection on GO")
896 return None
897
898 def p2p_connect_group(self, go_addr, pin, timeout=0, social=False,
899 freq=None):
900 self.dump_monitor()
901 if not self.discover_peer(go_addr, social=social, freq=freq):
902 if social or not self.discover_peer(go_addr, social=social):
903 raise Exception("GO " + go_addr + " not found")
904 self.p2p_stop_find()
905 self.dump_monitor()
906 cmd = "P2P_CONNECT " + go_addr + " " + pin + " join"
907 if freq:
908 cmd += " freq=" + str(freq)
909 if "OK" in self.global_request(cmd):
910 if timeout == 0:
911 self.dump_monitor()
912 return None
913 ev = self.wait_global_event(["P2P-GROUP-STARTED",
914 "P2P-GROUP-FORMATION-FAILURE"],
915 timeout)
916 if ev is None:
917 raise Exception("Joining the group timed out")
918 if "P2P-GROUP-STARTED" not in ev:
919 raise Exception("Failed to join the group")
920 self.dump_monitor()
921 return self.group_form_result(ev)
922 raise Exception("P2P_CONNECT(join) failed")
923
924 def tdls_setup(self, peer):
925 cmd = "TDLS_SETUP " + peer
926 if "FAIL" in self.group_request(cmd):
927 raise Exception("Failed to request TDLS setup")
928 return None
929
930 def tdls_teardown(self, peer):
931 cmd = "TDLS_TEARDOWN " + peer
932 if "FAIL" in self.group_request(cmd):
933 raise Exception("Failed to request TDLS teardown")
934 return None
935
936 def tdls_link_status(self, peer):
937 cmd = "TDLS_LINK_STATUS " + peer
938 ret = self.group_request(cmd)
939 if "FAIL" in ret:
940 raise Exception("Failed to request TDLS link status")
941 return ret
942
943 def tspecs(self):
944 """Return (tsid, up) tuples representing current tspecs"""
945 res = self.request("WMM_AC_STATUS")
946 tspecs = re.findall(r"TSID=(\d+) UP=(\d+)", res)
947 tspecs = [tuple(map(int, tspec)) for tspec in tspecs]
948
949 logger.debug("tspecs: " + str(tspecs))
950 return tspecs
951
952 def add_ts(self, tsid, up, direction="downlink", expect_failure=False,
953 extra=None):
954 params = {
955 "sba": 9000,
956 "nominal_msdu_size": 1500,
957 "min_phy_rate": 6000000,
958 "mean_data_rate": 1500,
959 }
960 cmd = "WMM_AC_ADDTS %s tsid=%d up=%d" % (direction, tsid, up)
961 for (key, value) in params.iteritems():
962 cmd += " %s=%d" % (key, value)
963 if extra:
964 cmd += " " + extra
965
966 if self.request(cmd).strip() != "OK":
967 raise Exception("ADDTS failed (tsid=%d up=%d)" % (tsid, up))
968
969 if expect_failure:
970 ev = self.wait_event(["TSPEC-REQ-FAILED"], timeout=2)
971 if ev is None:
972 raise Exception("ADDTS failed (time out while waiting failure)")
973 if "tsid=%d" % (tsid) not in ev:
974 raise Exception("ADDTS failed (invalid tsid in TSPEC-REQ-FAILED")
975 return
976
977 ev = self.wait_event(["TSPEC-ADDED"], timeout=1)
978 if ev is None:
979 raise Exception("ADDTS failed (time out)")
980 if "tsid=%d" % (tsid) not in ev:
981 raise Exception("ADDTS failed (invalid tsid in TSPEC-ADDED)")
982
983 if not (tsid, up) in self.tspecs():
984 raise Exception("ADDTS failed (tsid not in tspec list)")
985
986 def del_ts(self, tsid):
987 if self.request("WMM_AC_DELTS %d" % (tsid)).strip() != "OK":
988 raise Exception("DELTS failed")
989
990 ev = self.wait_event(["TSPEC-REMOVED"], timeout=1)
991 if ev is None:
992 raise Exception("DELTS failed (time out)")
993 if "tsid=%d" % (tsid) not in ev:
994 raise Exception("DELTS failed (invalid tsid in TSPEC-REMOVED)")
995
996 tspecs = [(t, u) for (t, u) in self.tspecs() if t == tsid]
997 if tspecs:
998 raise Exception("DELTS failed (still in tspec list)")
999
1000 def connect(self, ssid=None, ssid2=None, **kwargs):
1001 logger.info("Connect STA " + self.ifname + " to AP")
1002 id = self.add_network()
1003 if ssid:
1004 self.set_network_quoted(id, "ssid", ssid)
1005 elif ssid2:
1006 self.set_network(id, "ssid", ssid2)
1007
1008 quoted = [ "psk", "identity", "anonymous_identity", "password",
1009 "ca_cert", "client_cert", "private_key",
1010 "private_key_passwd", "ca_cert2", "client_cert2",
1011 "private_key2", "phase1", "phase2", "domain_suffix_match",
1012 "altsubject_match", "subject_match", "pac_file", "dh_file",
1013 "bgscan", "ht_mcs", "id_str", "openssl_ciphers",
1014 "domain_match", "dpp_connector", "sae_password",
1015 "sae_password_id" ]
1016 for field in quoted:
1017 if field in kwargs and kwargs[field]:
1018 self.set_network_quoted(id, field, kwargs[field])
1019
1020 not_quoted = [ "proto", "key_mgmt", "ieee80211w", "pairwise",
1021 "group", "wep_key0", "wep_key1", "wep_key2", "wep_key3",
1022 "wep_tx_keyidx", "scan_freq", "freq_list", "eap",
1023 "eapol_flags", "fragment_size", "scan_ssid", "auth_alg",
1024 "wpa_ptk_rekey", "disable_ht", "disable_vht", "bssid",
1025 "disable_max_amsdu", "ampdu_factor", "ampdu_density",
1026 "disable_ht40", "disable_sgi", "disable_ldpc",
1027 "ht40_intolerant", "update_identifier", "mac_addr",
1028 "erp", "bg_scan_period", "bssid_blacklist",
1029 "bssid_whitelist", "mem_only_psk", "eap_workaround",
1030 "engine", "fils_dh_group", "bssid_hint",
1031 "dpp_csign", "dpp_csign_expiry",
1032 "dpp_netaccesskey", "dpp_netaccesskey_expiry",
1033 "group_mgmt", "owe_group",
1034 "roaming_consortium_selection", "ocv",
1035 "multi_ap_backhaul_sta", "rx_stbc", "tx_stbc" ]
1036 for field in not_quoted:
1037 if field in kwargs and kwargs[field]:
1038 self.set_network(id, field, kwargs[field])
1039
1040 if "raw_psk" in kwargs and kwargs['raw_psk']:
1041 self.set_network(id, "psk", kwargs['raw_psk'])
1042 if "password_hex" in kwargs and kwargs['password_hex']:
1043 self.set_network(id, "password", kwargs['password_hex'])
1044 if "peerkey" in kwargs and kwargs['peerkey']:
1045 self.set_network(id, "peerkey", "1")
1046 if "okc" in kwargs and kwargs['okc']:
1047 self.set_network(id, "proactive_key_caching", "1")
1048 if "ocsp" in kwargs and kwargs['ocsp']:
1049 self.set_network(id, "ocsp", str(kwargs['ocsp']))
1050 if "only_add_network" in kwargs and kwargs['only_add_network']:
1051 return id
1052 if "wait_connect" not in kwargs or kwargs['wait_connect']:
1053 if "eap" in kwargs:
1054 self.connect_network(id, timeout=20)
1055 else:
1056 self.connect_network(id)
1057 else:
1058 self.dump_monitor()
1059 self.select_network(id)
1060 return id
1061
1062 def scan(self, type=None, freq=None, no_wait=False, only_new=False,
1063 passive=False):
1064 if type:
1065 cmd = "SCAN TYPE=" + type
1066 else:
1067 cmd = "SCAN"
1068 if freq:
1069 cmd = cmd + " freq=" + str(freq)
1070 if only_new:
1071 cmd += " only_new=1"
1072 if passive:
1073 cmd += " passive=1"
1074 if not no_wait:
1075 self.dump_monitor()
1076 if not "OK" in self.request(cmd):
1077 raise Exception("Failed to trigger scan")
1078 if no_wait:
1079 return
1080 ev = self.wait_event(["CTRL-EVENT-SCAN-RESULTS",
1081 "CTRL-EVENT-SCAN-FAILED"], 15)
1082 if ev is None:
1083 raise Exception("Scan timed out")
1084 if "CTRL-EVENT-SCAN-FAILED" in ev:
1085 raise Exception("Scan failed: " + ev)
1086
1087 def scan_for_bss(self, bssid, freq=None, force_scan=False, only_new=False,
1088 passive=False):
1089 if not force_scan and self.get_bss(bssid) is not None:
1090 return
1091 for i in range(0, 10):
1092 self.scan(freq=freq, type="ONLY", only_new=only_new,
1093 passive=passive)
1094 if self.get_bss(bssid) is not None:
1095 return
1096 raise Exception("Could not find BSS " + bssid + " in scan")
1097
1098 def flush_scan_cache(self, freq=2417):
1099 self.request("BSS_FLUSH 0")
1100 self.scan(freq=freq, only_new=True)
1101 res = self.request("SCAN_RESULTS")
1102 if len(res.splitlines()) > 1:
1103 self.request("BSS_FLUSH 0")
1104 self.scan(freq=2422, only_new=True)
1105 res = self.request("SCAN_RESULTS")
1106 if len(res.splitlines()) > 1:
1107 logger.info("flush_scan_cache: Could not clear all BSS entries. These remain:\n" + res)
1108
1109 def roam(self, bssid, fail_test=False, assoc_reject_ok=False):
1110 self.dump_monitor()
1111 if "OK" not in self.request("ROAM " + bssid):
1112 raise Exception("ROAM failed")
1113 if fail_test:
1114 if assoc_reject_ok:
1115 ev = self.wait_event(["CTRL-EVENT-CONNECTED",
1116 "CTRL-EVENT-ASSOC-REJECT"], timeout=1)
1117 else:
1118 ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1119 if ev is not None and "CTRL-EVENT-ASSOC-REJECT" not in ev:
1120 raise Exception("Unexpected connection")
1121 self.dump_monitor()
1122 return
1123 ev = self.wait_event(["CTRL-EVENT-CONNECTED",
1124 "CTRL-EVENT-ASSOC-REJECT"], timeout=10)
1125 if ev is None:
1126 raise Exception("Roaming with the AP timed out")
1127 if "CTRL-EVENT-ASSOC-REJECT" in ev:
1128 raise Exception("Roaming association rejected")
1129 self.dump_monitor()
1130
1131 def roam_over_ds(self, bssid, fail_test=False):
1132 self.dump_monitor()
1133 if "OK" not in self.request("FT_DS " + bssid):
1134 raise Exception("FT_DS failed")
1135 if fail_test:
1136 ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1137 if ev is not None:
1138 raise Exception("Unexpected connection")
1139 self.dump_monitor()
1140 return
1141 ev = self.wait_event(["CTRL-EVENT-CONNECTED",
1142 "CTRL-EVENT-ASSOC-REJECT"], timeout=10)
1143 if ev is None:
1144 raise Exception("Roaming with the AP timed out")
1145 if "CTRL-EVENT-ASSOC-REJECT" in ev:
1146 raise Exception("Roaming association rejected")
1147 self.dump_monitor()
1148
1149 def wps_reg(self, bssid, pin, new_ssid=None, key_mgmt=None, cipher=None,
1150 new_passphrase=None, no_wait=False):
1151 self.dump_monitor()
1152 if new_ssid:
1153 self.request("WPS_REG " + bssid + " " + pin + " " +
1154 new_ssid.encode("hex") + " " + key_mgmt + " " +
1155 cipher + " " + new_passphrase.encode("hex"))
1156 if no_wait:
1157 return
1158 ev = self.wait_event(["WPS-SUCCESS"], timeout=15)
1159 else:
1160 self.request("WPS_REG " + bssid + " " + pin)
1161 if no_wait:
1162 return
1163 ev = self.wait_event(["WPS-CRED-RECEIVED"], timeout=15)
1164 if ev is None:
1165 raise Exception("WPS cred timed out")
1166 ev = self.wait_event(["WPS-FAIL"], timeout=15)
1167 if ev is None:
1168 raise Exception("WPS timed out")
1169 self.wait_connected(timeout=15)
1170
1171 def relog(self):
1172 self.global_request("RELOG")
1173
1174 def wait_completed(self, timeout=10):
1175 for i in range(0, timeout * 2):
1176 if self.get_status_field("wpa_state") == "COMPLETED":
1177 return
1178 time.sleep(0.5)
1179 raise Exception("Timeout while waiting for COMPLETED state")
1180
1181 def get_capability(self, field):
1182 res = self.request("GET_CAPABILITY " + field)
1183 if "FAIL" in res:
1184 return None
1185 return res.split(' ')
1186
1187 def get_bss(self, bssid, ifname=None):
1188 if not ifname or ifname == self.ifname:
1189 res = self.request("BSS " + bssid)
1190 elif ifname == self.group_ifname:
1191 res = self.group_request("BSS " + bssid)
1192 else:
1193 return None
1194
1195 if "FAIL" in res:
1196 return None
1197 lines = res.splitlines()
1198 vals = dict()
1199 for l in lines:
1200 [name,value] = l.split('=', 1)
1201 vals[name] = value
1202 if len(vals) == 0:
1203 return None
1204 return vals
1205
1206 def get_pmksa(self, bssid):
1207 res = self.request("PMKSA")
1208 lines = res.splitlines()
1209 for l in lines:
1210 if bssid not in l:
1211 continue
1212 vals = dict()
1213 try:
1214 [index,aa,pmkid,expiration,opportunistic] = l.split(' ')
1215 cache_id = None
1216 except ValueError:
1217 [index,aa,pmkid,expiration,opportunistic,cache_id] = l.split(' ')
1218 vals['index'] = index
1219 vals['pmkid'] = pmkid
1220 vals['expiration'] = expiration
1221 vals['opportunistic'] = opportunistic
1222 if cache_id != None:
1223 vals['cache_id'] = cache_id
1224 return vals
1225 return None
1226
1227 def get_sta(self, addr, info=None, next=False):
1228 cmd = "STA-NEXT " if next else "STA "
1229 if addr is None:
1230 res = self.request("STA-FIRST")
1231 elif info:
1232 res = self.request(cmd + addr + " " + info)
1233 else:
1234 res = self.request(cmd + addr)
1235 lines = res.splitlines()
1236 vals = dict()
1237 first = True
1238 for l in lines:
1239 if first:
1240 vals['addr'] = l
1241 first = False
1242 else:
1243 [name,value] = l.split('=', 1)
1244 vals[name] = value
1245 return vals
1246
1247 def mgmt_rx(self, timeout=5):
1248 ev = self.wait_event(["MGMT-RX"], timeout=timeout)
1249 if ev is None:
1250 return None
1251 msg = {}
1252 items = ev.split(' ')
1253 field,val = items[1].split('=')
1254 if field != "freq":
1255 raise Exception("Unexpected MGMT-RX event format: " + ev)
1256 msg['freq'] = val
1257
1258 field,val = items[2].split('=')
1259 if field != "datarate":
1260 raise Exception("Unexpected MGMT-RX event format: " + ev)
1261 msg['datarate'] = val
1262
1263 field,val = items[3].split('=')
1264 if field != "ssi_signal":
1265 raise Exception("Unexpected MGMT-RX event format: " + ev)
1266 msg['ssi_signal'] = val
1267
1268 frame = binascii.unhexlify(items[4])
1269 msg['frame'] = frame
1270
1271 hdr = struct.unpack('<HH6B6B6BH', frame[0:24])
1272 msg['fc'] = hdr[0]
1273 msg['subtype'] = (hdr[0] >> 4) & 0xf
1274 hdr = hdr[1:]
1275 msg['duration'] = hdr[0]
1276 hdr = hdr[1:]
1277 msg['da'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6]
1278 hdr = hdr[6:]
1279 msg['sa'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6]
1280 hdr = hdr[6:]
1281 msg['bssid'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr[0:6]
1282 hdr = hdr[6:]
1283 msg['seq_ctrl'] = hdr[0]
1284 msg['payload'] = frame[24:]
1285
1286 return msg
1287
1288 def wait_connected(self, timeout=10, error="Connection timed out"):
1289 ev = self.wait_event(["CTRL-EVENT-CONNECTED"], timeout=timeout)
1290 if ev is None:
1291 raise Exception(error)
1292 return ev
1293
1294 def wait_disconnected(self, timeout=None, error="Disconnection timed out"):
1295 if timeout is None:
1296 timeout = 10 if self.hostname is None else 30
1297 ev = self.wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=timeout)
1298 if ev is None:
1299 raise Exception(error)
1300 return ev
1301
1302 def get_group_ifname(self):
1303 return self.group_ifname if self.group_ifname else self.ifname
1304
1305 def get_config(self):
1306 res = self.request("DUMP")
1307 if res.startswith("FAIL"):
1308 raise Exception("DUMP failed")
1309 lines = res.splitlines()
1310 vals = dict()
1311 for l in lines:
1312 [name,value] = l.split('=', 1)
1313 vals[name] = value
1314 return vals
1315
1316 def asp_provision(self, peer, adv_id, adv_mac, session_id, session_mac,
1317 method="1000", info="", status=None, cpt=None, role=None):
1318 if status is None:
1319 cmd = "P2P_ASP_PROVISION"
1320 params = "info='%s' method=%s" % (info, method)
1321 else:
1322 cmd = "P2P_ASP_PROVISION_RESP"
1323 params = "status=%d" % status
1324
1325 if role is not None:
1326 params += " role=" + role
1327 if cpt is not None:
1328 params += " cpt=" + cpt
1329
1330 if "OK" not in self.global_request("%s %s adv_id=%s adv_mac=%s session=%d session_mac=%s %s" %
1331 (cmd, peer, adv_id, adv_mac, session_id, session_mac, params)):
1332 raise Exception("%s request failed" % cmd)
1333
1334 def note(self, txt):
1335 self.request("NOTE " + txt)
1336
1337 def wait_regdom(self, country_ie=False):
1338 for i in range(5):
1339 ev = self.wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
1340 if ev is None:
1341 break
1342 if country_ie:
1343 if "init=COUNTRY_IE" in ev:
1344 break
1345 else:
1346 break