]>
git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/wpasupplicant.py
1 # Python class for controlling wpa_supplicant
2 # Copyright (c) 2013-2019, Jouni Malinen <j@w1.fi>
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
17 logger
= logging
.getLogger()
18 wpas_ctrl
= '/var/run/wpa_supplicant'
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
27 self
.host
= remotehost
.Host(hostname
, ifname
)
28 self
._group
_dbg
= None
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
35 self
.p2p_dev_ifname
= ifname
39 self
.global_iface
= global_iface
41 self
.global_mon
= None
43 self
.global_ctrl
= wpaspy
.Ctrl(hostname
, global_port
)
45 self
.global_mon
= wpaspy
.Ctrl(hostname
, global_port
)
46 self
.global_dbg
= hostname
+ "/" + str(global_port
) + "/"
48 self
.global_ctrl
= wpaspy
.Ctrl(global_iface
)
50 self
.global_mon
= wpaspy
.Ctrl(global_iface
)
53 self
.global_mon
.attach()
55 self
.global_mon
= None
57 def cmd_execute(self
, cmd_array
, shell
=False):
58 if self
.hostname
is None:
60 cmd
= ' '.join(cmd_array
)
63 proc
= subprocess
.Popen(cmd
, stderr
=subprocess
.STDOUT
,
64 stdout
=subprocess
.PIPE
, shell
=shell
)
65 out
= proc
.communicate()[0]
69 return self
.host
.execute(cmd_array
)
73 self
.global_mon
.detach()
74 self
.global_mon
= None
75 self
.global_ctrl
.terminate()
76 self
.global_ctrl
= None
80 self
.global_mon
.detach()
81 self
.global_mon
= None
82 self
.global_ctrl
= None
85 def set_ifname(self
, ifname
, hostname
=None, port
=9877):
88 self
.ctrl
= wpaspy
.Ctrl(hostname
, port
)
90 self
.mon
= wpaspy
.Ctrl(hostname
, port
)
91 self
.host
= remotehost
.Host(hostname
, ifname
)
92 self
.dbg
= hostname
+ "/" + ifname
94 self
.ctrl
= wpaspy
.Ctrl(os
.path
.join(wpas_ctrl
, ifname
))
96 self
.mon
= wpaspy
.Ctrl(os
.path
.join(wpas_ctrl
, ifname
))
101 def remove_ifname(self
):
108 def get_ctrl_iface_port(self
, ifname
):
109 if self
.hostname
is None:
112 res
= self
.global_request("INTERFACES ctrl")
113 lines
= res
.splitlines()
117 if words
[0] == ifname
:
121 raise Exception("Could not find UDP port for " + ifname
)
122 res
= line
.find("ctrl_iface=udp:")
124 raise Exception("Wrong ctrl_interface format")
125 words
= line
.split(":")
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"])
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
137 cmd
= cmd
+ '\t' + drv_params
141 cmd
+= '\t' + br_ifname
149 cmd
+= '\t' + if_type
150 if all_params
and not create
:
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
165 self
.p2p_dev_ifname
= ifname
167 def interface_remove(self
, ifname
):
169 self
.global_request("INTERFACE_REMOVE " + ifname
)
171 def request(self
, cmd
, timeout
=10):
172 logger
.debug(self
.dbg
+ ": CTRL: " + cmd
)
173 return self
.ctrl
.request(cmd
, timeout
=timeout
)
175 def global_request(self
, cmd
):
176 if self
.global_iface
is None:
177 return self
.request(cmd
)
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
)
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
192 self
._group
_dbg
= self
.hostname
+ "/" + self
.group_ifname
193 return self
._group
_dbg
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
))
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
)
207 return "PONG" in self
.request("PING")
209 def global_ping(self
):
210 return "PONG" in self
.global_request("PING")
214 res
= self
.request("FLUSH")
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")
222 self
.gctrl_mon
.detach()
225 self
.gctrl_mon
= None
226 self
.group_ifname
= None
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")
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"])
246 logger
.info("ifconfig failed: " + buf
)
248 status
, buf
= self
.host
.execute(["ifconfig", self
.ifname
, "up"])
250 logger
.info("ifconfig failed: " + buf
)
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")
259 logger
.info("No PING response from " + self
.ifname
+ " after reset")
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
)
265 def add_network(self
):
266 id = self
.request("ADD_NETWORK")
268 raise Exception("ADD_NETWORK failed")
271 def remove_network(self
, id):
272 id = self
.request("REMOVE_NETWORK " + str(id))
274 raise Exception("REMOVE_NETWORK failed")
277 def get_network(self
, id, field
):
278 res
= self
.request("GET_NETWORK " + str(id) + " " + field
)
283 def set_network(self
, id, field
, value
):
284 res
= self
.request("SET_NETWORK " + str(id) + " " + field
+ " " + value
)
286 raise Exception("SET_NETWORK failed")
289 def set_network_quoted(self
, id, field
, value
):
290 res
= self
.request("SET_NETWORK " + str(id) + " " + field
+ ' "' + value
+ '"')
292 raise Exception("SET_NETWORK failed")
295 def p2pdev_request(self
, cmd
):
296 return self
.global_request("IFNAME=" + self
.p2p_dev_ifname
+ " " + cmd
)
298 def p2pdev_add_network(self
):
299 id = self
.p2pdev_request("ADD_NETWORK")
301 raise Exception("p2pdev ADD_NETWORK failed")
304 def p2pdev_set_network(self
, id, field
, value
):
305 res
= self
.p2pdev_request("SET_NETWORK " + str(id) + " " + field
+ " " + value
)
307 raise Exception("p2pdev SET_NETWORK failed")
310 def p2pdev_set_network_quoted(self
, id, field
, value
):
311 res
= self
.p2pdev_request("SET_NETWORK " + str(id) + " " + field
+ ' "' + value
+ '"')
313 raise Exception("p2pdev SET_NETWORK failed")
316 def list_networks(self
, p2p
=False):
318 res
= self
.global_request("LIST_NETWORKS")
320 res
= self
.request("LIST_NETWORKS")
321 lines
= res
.splitlines()
324 if "network id" in l
:
326 [id,ssid
,bssid
,flags
] = l
.split('\t')
329 network
['ssid'] = ssid
330 network
['bssid'] = bssid
331 network
['flags'] = flags
332 networks
.append(network
)
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")
341 self
.request("SET auto_interworking 0")
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")
350 id = self
.request("ADD_CRED")
352 raise Exception("ADD_CRED failed")
355 def remove_cred(self
, id):
356 id = self
.request("REMOVE_CRED " + str(id))
358 raise Exception("REMOVE_CRED failed")
361 def set_cred(self
, id, field
, value
):
362 res
= self
.request("SET_CRED " + str(id) + " " + field
+ " " + value
)
364 raise Exception("SET_CRED failed")
367 def set_cred_quoted(self
, id, field
, value
):
368 res
= self
.request("SET_CRED " + str(id) + " " + field
+ ' "' + value
+ '"')
370 raise Exception("SET_CRED failed")
373 def get_cred(self
, id, field
):
374 return self
.request("GET_CRED " + str(id) + " " + field
)
376 def add_cred_values(self
, params
):
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" ]
386 self
.set_cred_quoted(id, field
, params
[field
])
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
:
395 self
.set_cred(id, field
, params
[field
])
399 def select_network(self
, id, freq
=None):
401 extra
= " freq=" + str(freq
)
404 id = self
.request("SELECT_NETWORK " + str(id) + extra
)
406 raise Exception("SELECT_NETWORK failed")
409 def mesh_group_add(self
, id):
410 id = self
.request("MESH_GROUP_ADD " + str(id))
412 raise Exception("MESH_GROUP_ADD failed")
415 def mesh_group_remove(self
):
416 id = self
.request("MESH_GROUP_REMOVE " + str(self
.ifname
))
418 raise Exception("MESH_GROUP_REMOVE failed")
421 def connect_network(self
, id, timeout
=None):
423 timeout
= 10 if self
.hostname
is None else 60
425 self
.select_network(id)
426 self
.wait_connected(timeout
=timeout
)
429 def get_status(self
, extra
=None):
434 res
= self
.request("STATUS" + extra
)
435 lines
= res
.splitlines()
439 [name
,value
] = l
.split('=', 1)
441 except ValueError as e
:
442 logger
.info(self
.ifname
+ ": Ignore unexpected STATUS line: " + l
)
445 def get_status_field(self
, field
, extra
=None):
446 vals
= self
.get_status(extra
)
451 def get_group_status(self
, extra
=None):
456 res
= self
.group_request("STATUS" + extra
)
457 lines
= res
.splitlines()
461 [name
,value
] = l
.split('=', 1)
463 logger
.info(self
.ifname
+ ": Ignore unexpected status line: " + l
)
468 def get_group_status_field(self
, field
, extra
=None):
469 vals
= self
.get_group_status(extra
)
474 def get_driver_status(self
, ifname
=None):
476 res
= self
.request("STATUS-DRIVER")
478 res
= self
.global_request("IFNAME=%s STATUS-DRIVER" % ifname
)
479 if res
.startswith("FAIL"):
481 lines
= res
.splitlines()
485 [name
,value
] = l
.split('=', 1)
487 logger
.info(self
.ifname
+ ": Ignore unexpected status-driver line: " + l
)
492 def get_driver_status_field(self
, field
, ifname
=None):
493 vals
= self
.get_driver_status(ifname
)
499 mcc
= int(self
.get_driver_status_field('capa.num_multichan_concurrent'))
500 return 1 if mcc
< 2 else mcc
503 res
= self
.request("MIB")
504 lines
= res
.splitlines()
508 [name
,value
] = l
.split('=', 1)
510 except ValueError as e
:
511 logger
.info(self
.ifname
+ ": Ignore unexpected MIB line: " + l
)
514 def p2p_dev_addr(self
):
515 return self
.get_status_field("p2p_device_address")
517 def p2p_interface_addr(self
):
518 return self
.get_group_status_field("address")
522 res
= self
.p2p_interface_addr()
524 res
= self
.p2p_dev_addr()
527 def p2p_listen(self
):
528 return self
.global_request("P2P_LISTEN")
530 def p2p_ext_listen(self
, period
, interval
):
531 return self
.global_request("P2P_EXT_LISTEN %d %d" % (period
, interval
))
533 def p2p_cancel_ext_listen(self
):
534 return self
.global_request("P2P_EXT_LISTEN")
536 def p2p_find(self
, social
=False, progressive
=False, dev_id
=None,
537 dev_type
=None, delay
=None, freq
=None):
540 cmd
= cmd
+ " type=social"
542 cmd
= cmd
+ " type=progressive"
544 cmd
= cmd
+ " dev_id=" + dev_id
546 cmd
= cmd
+ " dev_type=" + dev_type
548 cmd
= cmd
+ " delay=" + str(delay
)
550 cmd
= cmd
+ " freq=" + str(freq
)
551 return self
.global_request(cmd
)
553 def p2p_stop_find(self
):
554 return self
.global_request("P2P_STOP_FIND")
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")
562 def peer_known(self
, peer
, full
=True):
563 res
= self
.global_request("P2P_PEER " + peer
)
564 if peer
.lower() not in res
.lower():
568 return "[PROBE_REQ_ONLY]" not in res
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
):
575 self
.p2p_find(social
, freq
=freq
)
577 while count
< timeout
* 4:
580 if self
.peer_known(peer
, full
):
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()
592 [name
,value
] = l
.split('=', 1)
596 def group_form_result(self
, ev
, expect_failure
=False, go_neg_res
=None):
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
)
605 res
['result'] = 'go-neg-failed'
606 res
['status'] = int(s
[2])
609 if "P2P-GROUP-STARTED" not in ev
:
610 raise Exception("No P2P-GROUP-STARTED event seen")
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
)
615 exp
= r
'<.>(P2P-GROUP-STARTED) ([^ ]*) ([^ ]*) ssid="(.*)" freq=([0-9]*) ((?:psk=.*)|(?:passphrase=".*")) go_dev_addr=([0-9a-f:]*)'
616 s
= re
.split(exp
, ev
)
618 raise Exception("Could not parse P2P-GROUP-STARTED")
620 res
['result'] = 'success'
622 self
.group_ifname
= s
[2]
624 if self
.hostname
is None:
625 self
.gctrl_mon
= wpaspy
.Ctrl(os
.path
.join(wpas_ctrl
,
628 port
= self
.get_ctrl_iface_port(self
.group_ifname
)
629 self
.gctrl_mon
= wpaspy
.Ctrl(self
.hostname
, port
)
630 self
.gctrl_mon
.attach()
632 logger
.debug("Could not open monitor socket for group interface")
633 self
.gctrl_mon
= None
637 if "[PERSISTENT]" in ev
:
638 res
['persistent'] = True
640 res
['persistent'] = False
641 p
= re
.match(r
'psk=([0-9a-f]*)', s
[6])
643 res
['psk'] = p
.group(1)
644 p
= re
.match(r
'passphrase="(.*)"', s
[6])
646 res
['passphrase'] = p
.group(1)
647 res
['go_dev_addr'] = s
[7]
649 if len(s
) > 8 and len(s
[8]) > 0 and "[PERSISTENT]" not in s
[8]:
650 res
['ip_addr'] = s
[8]
652 res
['ip_mask'] = s
[9]
654 res
['go_ip_addr'] = s
[10]
657 exp
= r
'<.>(P2P-GO-NEG-SUCCESS) role=(GO|client) freq=([0-9]*)'
658 s
= re
.split(exp
, go_neg_res
)
660 raise Exception("Could not parse P2P-GO-NEG-SUCCESS")
661 res
['go_neg_role'] = s
[2]
662 res
['go_neg_freq'] = s
[3]
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")
673 cmd
= "P2P_CONNECT " + peer
+ " " + pin
+ " " + method
+ " auth"
675 cmd
= "P2P_CONNECT " + peer
+ " " + method
+ " auth"
677 cmd
= cmd
+ ' go_intent=' + str(go_intent
)
679 cmd
= cmd
+ ' freq=' + str(freq
)
681 cmd
= cmd
+ ' freq2=' + str(freq2
)
683 cmd
= cmd
+ ' max_oper_chwidth=' + str(max_oper_chwidth
)
689 cmd
= cmd
+ " persistent"
690 if "OK" in self
.global_request(cmd
):
692 raise Exception("P2P_CONNECT (auth) failed")
694 def p2p_go_neg_auth_result(self
, timeout
=None, expect_failure
=False):
696 timeout
= 1 if expect_failure
else 5
698 ev
= self
.wait_global_event(["P2P-GO-NEG-SUCCESS",
699 "P2P-GO-NEG-FAILURE"], timeout
)
703 raise Exception("Group formation timed out")
704 if "P2P-GO-NEG-SUCCESS" in ev
:
706 ev
= self
.wait_global_event(["P2P-GROUP-STARTED"], timeout
)
710 raise Exception("Group formation timed out")
712 return self
.group_form_result(ev
, expect_failure
, go_neg_res
)
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")
723 cmd
= "P2P_CONNECT " + peer
+ " " + pin
+ " " + method
725 cmd
= "P2P_CONNECT " + peer
+ " " + method
726 if go_intent
is not None:
727 cmd
= cmd
+ ' go_intent=' + str(go_intent
)
729 cmd
= cmd
+ ' freq=' + str(freq
)
731 cmd
= cmd
+ ' freq2=' + str(freq2
)
733 cmd
= cmd
+ ' max_oper_chwidth=' + str(max_oper_chwidth
)
739 cmd
= cmd
+ " persistent"
741 cmd
= cmd
+ " persistent=" + persistent_id
743 cmd
= cmd
+ " provdisc"
744 if "OK" in self
.global_request(cmd
):
748 ev
= self
.wait_global_event(["P2P-GO-NEG-SUCCESS",
749 "P2P-GO-NEG-FAILURE"], timeout
)
753 raise Exception("Group formation timed out")
754 if "P2P-GO-NEG-SUCCESS" in ev
:
758 ev
= self
.wait_global_event(["P2P-GROUP-STARTED"], timeout
)
762 raise Exception("Group formation timed out")
764 return self
.group_form_result(ev
, expect_failure
, go_neg_res
)
765 raise Exception("P2P_CONNECT failed")
767 def wait_event(self
, events
, timeout
=10):
768 start
= os
.times()[4]
770 while self
.mon
.pending():
772 logger
.debug(self
.dbg
+ ": " + ev
)
777 remaining
= start
+ timeout
- now
780 if not self
.mon
.pending(timeout
=remaining
):
784 def wait_global_event(self
, events
, timeout
):
785 if self
.global_iface
is None:
786 self
.wait_event(events
, timeout
)
788 start
= os
.times()[4]
790 while self
.global_mon
.pending():
791 ev
= self
.global_mon
.recv()
792 logger
.debug(self
.global_dbg
+ self
.ifname
+ "(global): " + ev
)
797 remaining
= start
+ timeout
- now
800 if not self
.global_mon
.pending(timeout
=remaining
):
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:
808 start
= os
.times()[4]
810 while self
.gctrl_mon
.pending():
811 ev
= self
.gctrl_mon
.recv()
812 logger
.debug(self
.group_dbg
+ "(group): " + ev
)
817 remaining
= start
+ timeout
- now
820 if not self
.gctrl_mon
.pending(timeout
=remaining
):
824 return self
.wait_event(events
, timeout
)
826 def wait_go_ending_session(self
):
829 self
.gctrl_mon
.detach()
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
)
836 raise Exception("Group removal event timed out")
837 if "reason=GO_ENDING_SESSION" not in ev
:
838 raise Exception("Unexpected group removal reason")
840 def dump_monitor(self
):
843 while self
.mon
.pending():
845 logger
.debug(self
.dbg
+ ": " + ev
)
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
)
851 return (count_iface
, count_global
)
853 def remove_group(self
, ifname
=None):
856 self
.gctrl_mon
.detach()
859 self
.gctrl_mon
= 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
866 def p2p_start_go(self
, persistent
=None, freq
=None, no_event_clear
=False):
868 cmd
= "P2P_GROUP_ADD"
869 if persistent
is None:
871 elif persistent
is True:
872 cmd
= cmd
+ " persistent"
874 cmd
= cmd
+ " persistent=" + str(persistent
)
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)
880 raise Exception("GO start up timed out")
881 if not no_event_clear
:
883 return self
.group_form_result(ev
)
884 raise Exception("P2P_GROUP_ADD failed")
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")
892 def p2p_go_authorize_client_pbc(self
):
894 if "FAIL" in self
.group_request(cmd
):
895 raise Exception("Failed to authorize client connection on GO")
898 def p2p_connect_group(self
, go_addr
, pin
, timeout
=0, social
=False,
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")
906 cmd
= "P2P_CONNECT " + go_addr
+ " " + pin
+ " join"
908 cmd
+= " freq=" + str(freq
)
909 if "OK" in self
.global_request(cmd
):
913 ev
= self
.wait_global_event(["P2P-GROUP-STARTED",
914 "P2P-GROUP-FORMATION-FAILURE"],
917 raise Exception("Joining the group timed out")
918 if "P2P-GROUP-STARTED" not in ev
:
919 raise Exception("Failed to join the group")
921 return self
.group_form_result(ev
)
922 raise Exception("P2P_CONNECT(join) failed")
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")
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")
936 def tdls_link_status(self
, peer
):
937 cmd
= "TDLS_LINK_STATUS " + peer
938 ret
= self
.group_request(cmd
)
940 raise Exception("Failed to request TDLS link status")
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
]
949 logger
.debug("tspecs: " + str(tspecs
))
952 def add_ts(self
, tsid
, up
, direction
="downlink", expect_failure
=False,
956 "nominal_msdu_size": 1500,
957 "min_phy_rate": 6000000,
958 "mean_data_rate": 1500,
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
)
966 if self
.request(cmd
).strip() != "OK":
967 raise Exception("ADDTS failed (tsid=%d up=%d)" % (tsid
, up
))
970 ev
= self
.wait_event(["TSPEC-REQ-FAILED"], timeout
=2)
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")
977 ev
= self
.wait_event(["TSPEC-ADDED"], timeout
=1)
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)")
983 if not (tsid
, up
) in self
.tspecs():
984 raise Exception("ADDTS failed (tsid not in tspec list)")
986 def del_ts(self
, tsid
):
987 if self
.request("WMM_AC_DELTS %d" % (tsid
)).strip() != "OK":
988 raise Exception("DELTS failed")
990 ev
= self
.wait_event(["TSPEC-REMOVED"], timeout
=1)
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)")
996 tspecs
= [(t
, u
) for (t
, u
) in self
.tspecs() if t
== tsid
]
998 raise Exception("DELTS failed (still in tspec list)")
1000 def connect(self
, ssid
=None, ssid2
=None, **kwargs
):
1001 logger
.info("Connect STA " + self
.ifname
+ " to AP")
1002 id = self
.add_network()
1004 self
.set_network_quoted(id, "ssid", ssid
)
1006 self
.set_network(id, "ssid", ssid2
)
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",
1016 for field
in quoted
:
1017 if field
in kwargs
and kwargs
[field
]:
1018 self
.set_network_quoted(id, field
, kwargs
[field
])
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
])
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']:
1052 if "wait_connect" not in kwargs
or kwargs
['wait_connect']:
1054 self
.connect_network(id, timeout
=20)
1056 self
.connect_network(id)
1059 self
.select_network(id)
1062 def scan(self
, type=None, freq
=None, no_wait
=False, only_new
=False,
1065 cmd
= "SCAN TYPE=" + type
1069 cmd
= cmd
+ " freq=" + str(freq
)
1071 cmd
+= " only_new=1"
1076 if not "OK" in self
.request(cmd
):
1077 raise Exception("Failed to trigger scan")
1080 ev
= self
.wait_event(["CTRL-EVENT-SCAN-RESULTS",
1081 "CTRL-EVENT-SCAN-FAILED"], 15)
1083 raise Exception("Scan timed out")
1084 if "CTRL-EVENT-SCAN-FAILED" in ev
:
1085 raise Exception("Scan failed: " + ev
)
1087 def scan_for_bss(self
, bssid
, freq
=None, force_scan
=False, only_new
=False,
1089 if not force_scan
and self
.get_bss(bssid
) is not None:
1091 for i
in range(0, 10):
1092 self
.scan(freq
=freq
, type="ONLY", only_new
=only_new
,
1094 if self
.get_bss(bssid
) is not None:
1096 raise Exception("Could not find BSS " + bssid
+ " in scan")
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
)
1109 def roam(self
, bssid
, fail_test
=False, assoc_reject_ok
=False):
1111 if "OK" not in self
.request("ROAM " + bssid
):
1112 raise Exception("ROAM failed")
1115 ev
= self
.wait_event(["CTRL-EVENT-CONNECTED",
1116 "CTRL-EVENT-ASSOC-REJECT"], timeout
=1)
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")
1123 ev
= self
.wait_event(["CTRL-EVENT-CONNECTED",
1124 "CTRL-EVENT-ASSOC-REJECT"], timeout
=10)
1126 raise Exception("Roaming with the AP timed out")
1127 if "CTRL-EVENT-ASSOC-REJECT" in ev
:
1128 raise Exception("Roaming association rejected")
1131 def roam_over_ds(self
, bssid
, fail_test
=False):
1133 if "OK" not in self
.request("FT_DS " + bssid
):
1134 raise Exception("FT_DS failed")
1136 ev
= self
.wait_event(["CTRL-EVENT-CONNECTED"], timeout
=1)
1138 raise Exception("Unexpected connection")
1141 ev
= self
.wait_event(["CTRL-EVENT-CONNECTED",
1142 "CTRL-EVENT-ASSOC-REJECT"], timeout
=10)
1144 raise Exception("Roaming with the AP timed out")
1145 if "CTRL-EVENT-ASSOC-REJECT" in ev
:
1146 raise Exception("Roaming association rejected")
1149 def wps_reg(self
, bssid
, pin
, new_ssid
=None, key_mgmt
=None, cipher
=None,
1150 new_passphrase
=None, no_wait
=False):
1153 self
.request("WPS_REG " + bssid
+ " " + pin
+ " " +
1154 new_ssid
.encode("hex") + " " + key_mgmt
+ " " +
1155 cipher
+ " " + new_passphrase
.encode("hex"))
1158 ev
= self
.wait_event(["WPS-SUCCESS"], timeout
=15)
1160 self
.request("WPS_REG " + bssid
+ " " + pin
)
1163 ev
= self
.wait_event(["WPS-CRED-RECEIVED"], timeout
=15)
1165 raise Exception("WPS cred timed out")
1166 ev
= self
.wait_event(["WPS-FAIL"], timeout
=15)
1168 raise Exception("WPS timed out")
1169 self
.wait_connected(timeout
=15)
1172 self
.global_request("RELOG")
1174 def wait_completed(self
, timeout
=10):
1175 for i
in range(0, timeout
* 2):
1176 if self
.get_status_field("wpa_state") == "COMPLETED":
1179 raise Exception("Timeout while waiting for COMPLETED state")
1181 def get_capability(self
, field
):
1182 res
= self
.request("GET_CAPABILITY " + field
)
1185 return res
.split(' ')
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
)
1197 lines
= res
.splitlines()
1200 [name
,value
] = l
.split('=', 1)
1206 def get_pmksa(self
, bssid
):
1207 res
= self
.request("PMKSA")
1208 lines
= res
.splitlines()
1214 [index
,aa
,pmkid
,expiration
,opportunistic
] = l
.split(' ')
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
1227 def get_sta(self
, addr
, info
=None, next
=False):
1228 cmd
= "STA-NEXT " if next
else "STA "
1230 res
= self
.request("STA-FIRST")
1232 res
= self
.request(cmd
+ addr
+ " " + info
)
1234 res
= self
.request(cmd
+ addr
)
1235 lines
= res
.splitlines()
1243 [name
,value
] = l
.split('=', 1)
1247 def mgmt_rx(self
, timeout
=5):
1248 ev
= self
.wait_event(["MGMT-RX"], timeout
=timeout
)
1252 items
= ev
.split(' ')
1253 field
,val
= items
[1].split('=')
1255 raise Exception("Unexpected MGMT-RX event format: " + ev
)
1258 field
,val
= items
[2].split('=')
1259 if field
!= "datarate":
1260 raise Exception("Unexpected MGMT-RX event format: " + ev
)
1261 msg
['datarate'] = val
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
1268 frame
= binascii
.unhexlify(items
[4])
1269 msg
['frame'] = frame
1271 hdr
= struct
.unpack('<HH6B6B6BH', frame
[0:24])
1273 msg
['subtype'] = (hdr
[0] >> 4) & 0xf
1275 msg
['duration'] = hdr
[0]
1277 msg
['da'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr
[0:6]
1279 msg
['sa'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr
[0:6]
1281 msg
['bssid'] = "%02x:%02x:%02x:%02x:%02x:%02x" % hdr
[0:6]
1283 msg
['seq_ctrl'] = hdr
[0]
1284 msg
['payload'] = frame
[24:]
1288 def wait_connected(self
, timeout
=10, error
="Connection timed out"):
1289 ev
= self
.wait_event(["CTRL-EVENT-CONNECTED"], timeout
=timeout
)
1291 raise Exception(error
)
1294 def wait_disconnected(self
, timeout
=None, error
="Disconnection timed out"):
1296 timeout
= 10 if self
.hostname
is None else 30
1297 ev
= self
.wait_event(["CTRL-EVENT-DISCONNECTED"], timeout
=timeout
)
1299 raise Exception(error
)
1302 def get_group_ifname(self
):
1303 return self
.group_ifname
if self
.group_ifname
else self
.ifname
1305 def get_config(self
):
1306 res
= self
.request("DUMP")
1307 if res
.startswith("FAIL"):
1308 raise Exception("DUMP failed")
1309 lines
= res
.splitlines()
1312 [name
,value
] = l
.split('=', 1)
1316 def asp_provision(self
, peer
, adv_id
, adv_mac
, session_id
, session_mac
,
1317 method
="1000", info
="", status
=None, cpt
=None, role
=None):
1319 cmd
= "P2P_ASP_PROVISION"
1320 params
= "info='%s' method=%s" % (info
, method
)
1322 cmd
= "P2P_ASP_PROVISION_RESP"
1323 params
= "status=%d" % status
1325 if role
is not None:
1326 params
+= " role=" + role
1328 params
+= " cpt=" + cpt
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
)
1334 def note(self
, txt
):
1335 self
.request("NOTE " + txt
)
1337 def wait_regdom(self
, country_ie
=False):
1339 ev
= self
.wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout
=1)
1343 if "init=COUNTRY_IE" in ev
: