tests: Add FST module tests
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
a8dab08a28
commit
41a256ecd9
10 changed files with 3060 additions and 2 deletions
|
@ -71,6 +71,9 @@ CONFIG_SQLITE=y
|
||||||
CONFIG_SAE=y
|
CONFIG_SAE=y
|
||||||
CFLAGS += -DALL_DH_GROUPS
|
CFLAGS += -DALL_DH_GROUPS
|
||||||
|
|
||||||
|
CONFIG_FST=y
|
||||||
|
CONFIG_FST_TEST=y
|
||||||
|
|
||||||
CONFIG_TESTING_OPTIONS=y
|
CONFIG_TESTING_OPTIONS=y
|
||||||
CONFIG_MODULE_TESTS=y
|
CONFIG_MODULE_TESTS=y
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,9 @@ CFLAGS += -DALL_DH_GROUPS
|
||||||
|
|
||||||
CONFIG_WNM=y
|
CONFIG_WNM=y
|
||||||
|
|
||||||
|
CONFIG_FST=y
|
||||||
|
CONFIG_FST_TEST=y
|
||||||
|
|
||||||
CONFIG_TESTING_OPTIONS=y
|
CONFIG_TESTING_OPTIONS=y
|
||||||
CONFIG_MODULE_TESTS=y
|
CONFIG_MODULE_TESTS=y
|
||||||
|
|
||||||
|
|
745
tests/hwsim/fst_module_aux.py
Normal file
745
tests/hwsim/fst_module_aux.py
Normal file
|
@ -0,0 +1,745 @@
|
||||||
|
# FST tests related classes
|
||||||
|
# Copyright (c) 2015, Qualcomm Atheros, Inc.
|
||||||
|
#
|
||||||
|
# This software may be distributed under the terms of the BSD license.
|
||||||
|
# See README for more details.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
|
import hostapd
|
||||||
|
import wpaspy
|
||||||
|
import utils
|
||||||
|
from wpasupplicant import WpaSupplicant
|
||||||
|
|
||||||
|
import fst_test_common
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
def parse_fst_iface_event(ev):
|
||||||
|
"""Parses FST iface event that comes as a string, e.g.
|
||||||
|
"<3>FST-EVENT-IFACE attached ifname=wlan9 group=fstg0"
|
||||||
|
Returns a dictionary with parsed "event_type", "ifname", and "group"; or
|
||||||
|
None if not an FST event or can't be parsed."""
|
||||||
|
event = {}
|
||||||
|
if ev.find("FST-EVENT-IFACE") == -1:
|
||||||
|
return None
|
||||||
|
if ev.find("attached") != -1:
|
||||||
|
event['event_type'] = 'attached'
|
||||||
|
elif ev.find("detached") != -1:
|
||||||
|
event['event_type'] = 'detached'
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
f = re.search("ifname=(\S+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['ifname'] = f.group(1)
|
||||||
|
f = re.search("group=(\S+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['group'] = f.group(1)
|
||||||
|
return event
|
||||||
|
|
||||||
|
def parse_fst_session_event(ev):
|
||||||
|
"""Parses FST session event that comes as a string, e.g.
|
||||||
|
"<3>FST-EVENT-SESSION event_type=EVENT_FST_SESSION_STATE session_id=0 reason=REASON_STT"
|
||||||
|
Returns a dictionary with parsed "type", "id", and "reason"; or None if not
|
||||||
|
a FST event or can't be parsed"""
|
||||||
|
event = {}
|
||||||
|
if ev.find("FST-EVENT-SESSION") == -1:
|
||||||
|
return None
|
||||||
|
event['new_state'] = '' # The field always exists in the dictionary
|
||||||
|
f = re.search("event_type=(\S+)", ev)
|
||||||
|
if f is None:
|
||||||
|
return None
|
||||||
|
event['type'] = f.group(1)
|
||||||
|
f = re.search("session_id=(\d+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['id'] = f.group(1)
|
||||||
|
f = re.search("old_state=(\S+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['old_state'] = f.group(1)
|
||||||
|
f = re.search("new_state=(\S+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['new_state'] = f.group(1)
|
||||||
|
f = re.search("reason=(\S+)", ev)
|
||||||
|
if f is not None:
|
||||||
|
event['reason'] = f.group(1)
|
||||||
|
return event
|
||||||
|
|
||||||
|
def start_two_ap_sta_pairs(apdev):
|
||||||
|
"""auxiliary function that creates two pairs of APs and STAs"""
|
||||||
|
ap1 = FstAP(apdev[0]['ifname'], 'fst_11a', 'a',
|
||||||
|
fst_test_common.fst_test_def_chan_a,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_low,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
ap1.start()
|
||||||
|
ap2 = FstAP(apdev[1]['ifname'], 'fst_11g', 'g',
|
||||||
|
fst_test_common.fst_test_def_chan_g,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_high,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
ap2.start()
|
||||||
|
|
||||||
|
sta1 = FstSTA('wlan5',
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_low,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
sta1.start()
|
||||||
|
sta2 = FstSTA('wlan6',
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_high,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
sta2.start()
|
||||||
|
|
||||||
|
return ap1, ap2, sta1, sta2
|
||||||
|
|
||||||
|
def stop_two_ap_sta_pairs(ap1, ap2, sta1, sta2):
|
||||||
|
sta1.stop()
|
||||||
|
sta2.stop()
|
||||||
|
ap1.stop()
|
||||||
|
ap2.stop()
|
||||||
|
|
||||||
|
def connect_two_ap_sta_pairs(ap1, ap2, dev1, dev2):
|
||||||
|
"""Connects a pair of stations, each one to a separate AP"""
|
||||||
|
dev1.scan(freq=fst_test_common.fst_test_def_freq_a)
|
||||||
|
dev2.scan(freq=fst_test_common.fst_test_def_freq_g)
|
||||||
|
|
||||||
|
dev1.connect(ap1, key_mgmt="NONE",
|
||||||
|
scan_freq=fst_test_common.fst_test_def_freq_a)
|
||||||
|
dev2.connect(ap2, key_mgmt="NONE",
|
||||||
|
scan_freq=fst_test_common.fst_test_def_freq_g)
|
||||||
|
|
||||||
|
def disconnect_two_ap_sta_pairs(ap1, ap2, dev1, dev2):
|
||||||
|
dev1.disconnect()
|
||||||
|
dev2.disconnect()
|
||||||
|
|
||||||
|
def external_sta_connect(sta, ap, **kwargs):
|
||||||
|
"""Connects the external station to the given AP"""
|
||||||
|
if not isinstance(sta, WpaSupplicant):
|
||||||
|
raise Exception("Bad STA object")
|
||||||
|
if not isinstance(ap, FstAP):
|
||||||
|
raise Exception("Bad AP object to connect to")
|
||||||
|
hap = ap.get_instance()
|
||||||
|
sta.connect(ap.get_ssid(), **kwargs)
|
||||||
|
|
||||||
|
def disconnect_external_sta(sta, ap, check_disconnect=True):
|
||||||
|
"""Disconnects the external station from the AP"""
|
||||||
|
if not isinstance(sta, WpaSupplicant):
|
||||||
|
raise Exception("Bad STA object")
|
||||||
|
if not isinstance(ap, FstAP):
|
||||||
|
raise Exception("Bad AP object to connect to")
|
||||||
|
sta.request("DISCONNECT")
|
||||||
|
if check_disconnect:
|
||||||
|
hap = ap.get_instance()
|
||||||
|
ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No disconnection event received from %s" % ap.get_ssid())
|
||||||
|
|
||||||
|
#
|
||||||
|
# FstDevice class
|
||||||
|
# This is the parent class for the AP (FstAP) and STA (FstSTA) that implements
|
||||||
|
# FST functionality.
|
||||||
|
#
|
||||||
|
class FstDevice:
|
||||||
|
def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
|
||||||
|
self.iface = iface
|
||||||
|
self.fst_group = fst_group
|
||||||
|
self.fst_pri = fst_pri
|
||||||
|
self.fst_llt = fst_llt # None llt means no llt parameter will be set
|
||||||
|
self.instance = None # Hostapd/WpaSupplicant instance
|
||||||
|
self.peer_obj = None # Peer object, must be a FstDevice child object
|
||||||
|
self.new_peer_addr = None # Peer MAC address for new session iface
|
||||||
|
self.old_peer_addr = None # Peer MAC address for old session iface
|
||||||
|
self.role = 'initiator' # Role: initiator/responder
|
||||||
|
s = self.grequest("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise utils.HwsimSkip("FST not supported")
|
||||||
|
|
||||||
|
def ifname(self):
|
||||||
|
return self.iface
|
||||||
|
|
||||||
|
def get_instance(self):
|
||||||
|
"""Gets the Hostapd/WpaSupplicant instance"""
|
||||||
|
raise Exception("Virtual get_instance() called!")
|
||||||
|
|
||||||
|
def get_own_mac_address(self):
|
||||||
|
"""Gets the device's own MAC address"""
|
||||||
|
raise Exception("Virtual get_own_mac_address() called!")
|
||||||
|
|
||||||
|
def get_new_peer_addr(self):
|
||||||
|
return self.new_peer_addr
|
||||||
|
|
||||||
|
def get_old_peer_addr(self):
|
||||||
|
return self.old_peer_addr
|
||||||
|
|
||||||
|
def get_actual_peer_addr(self):
|
||||||
|
"""Gets the peer address. A connected AP/station address is returned."""
|
||||||
|
raise Exception("Virtual get_actual_peer_addr() called!")
|
||||||
|
|
||||||
|
def grequest(self, req):
|
||||||
|
"""Send request on the global control interface"""
|
||||||
|
raise Exception, "Virtual grequest() called!"
|
||||||
|
|
||||||
|
def wait_gevent(self, events, timeout=None):
|
||||||
|
"""Wait for a list of events on the global interface"""
|
||||||
|
raise Exception("Virtual wait_gevent() called!")
|
||||||
|
|
||||||
|
def request(self, req):
|
||||||
|
"""Issue a request to the control interface"""
|
||||||
|
h = self.get_instance()
|
||||||
|
return h.request(req)
|
||||||
|
|
||||||
|
def wait_event(self, events, timeout=None):
|
||||||
|
"""Wait for an event from the control interface"""
|
||||||
|
h = self.get_instance()
|
||||||
|
if timeout is not None:
|
||||||
|
return h.wait_event(events, timeout=timeout)
|
||||||
|
else:
|
||||||
|
return h.wait_event(events)
|
||||||
|
|
||||||
|
def set_old_peer_addr(self, peer_addr=None):
|
||||||
|
"""Sets the peer address"""
|
||||||
|
if peer_addr is not None:
|
||||||
|
self.old_peer_addr = peer_addr
|
||||||
|
else:
|
||||||
|
self.old_peer_addr = self.get_actual_peer_addr()
|
||||||
|
|
||||||
|
def set_new_peer_addr(self, peer_addr=None):
|
||||||
|
"""Sets the peer address"""
|
||||||
|
if peer_addr is not None:
|
||||||
|
self.new_peer_addr = peer_addr
|
||||||
|
else:
|
||||||
|
self.new_peer_addr = self.get_actual_peer_addr()
|
||||||
|
|
||||||
|
def add_peer(self, obj, old_peer_addr=None, new_peer_addr=None):
|
||||||
|
"""Add peer for FST session(s). 'obj' is a FstDevice subclass object.
|
||||||
|
The method must be called before add_session().
|
||||||
|
If peer_addr is not specified, the address of the currently connected
|
||||||
|
station is used."""
|
||||||
|
if not isinstance(obj, FstDevice):
|
||||||
|
raise Exception("Peer must be a FstDevice object")
|
||||||
|
self.peer_obj = obj
|
||||||
|
self.set_old_peer_addr(old_peer_addr)
|
||||||
|
self.set_new_peer_addr(new_peer_addr)
|
||||||
|
|
||||||
|
def get_peer(self):
|
||||||
|
"""Returns peer object"""
|
||||||
|
return self.peer_obj
|
||||||
|
|
||||||
|
def set_fst_parameters(self, group_id=None, pri=None, llt=None):
|
||||||
|
"""Change/set new FST parameters. Can be used to start FST sessions with
|
||||||
|
different FST parameters than defined in the configuration file."""
|
||||||
|
if group_id is not None:
|
||||||
|
self.fst_group = group_id
|
||||||
|
if pri is not None:
|
||||||
|
self.fst_pri = pri
|
||||||
|
if llt is not None:
|
||||||
|
self.fst_llt = llt
|
||||||
|
|
||||||
|
def get_local_mbies(self, ifname=None):
|
||||||
|
if_name = ifname if ifname is not None else self.iface
|
||||||
|
return self.grequest("FST-MANAGER TEST_REQUEST GET_LOCAL_MBIES " + if_name)
|
||||||
|
|
||||||
|
def add_session(self):
|
||||||
|
"""Adds an FST session. add_peer() must be called calling this
|
||||||
|
function"""
|
||||||
|
if self.peer_obj is None:
|
||||||
|
raise Exception("Peer wasn't added before starting session")
|
||||||
|
grp = ' ' + self.fst_group if self.fst_group != '' else ''
|
||||||
|
sid = self.grequest("FST-MANAGER SESSION_ADD" + grp)
|
||||||
|
sid = sid.strip()
|
||||||
|
if sid.startswith("FAIL"):
|
||||||
|
raise Exception("Cannot add FST session with groupid ==" + grp)
|
||||||
|
return sid
|
||||||
|
|
||||||
|
def set_session_param(self, params):
|
||||||
|
request = "FST-MANAGER SESSION_SET"
|
||||||
|
if params is not None and params != '':
|
||||||
|
request = request + ' ' + params
|
||||||
|
return self.grequest(request)
|
||||||
|
|
||||||
|
def configure_session(self, sid, new_iface, old_iface = None):
|
||||||
|
"""Calls session_set for a number of parameters some of which are stored
|
||||||
|
in "self" while others are passed to this function explicitly. If
|
||||||
|
old_iface is None, current iface is used; if old_iface is an empty
|
||||||
|
string."""
|
||||||
|
oldiface = old_iface if old_iface is not None else self.iface
|
||||||
|
s = self.set_session_param(sid + ' old_ifname=' + oldiface)
|
||||||
|
if not s.startswith("OK"):
|
||||||
|
raise Exception("Cannot set FST session old_ifname: " + s)
|
||||||
|
if new_iface is not None:
|
||||||
|
s = self.set_session_param(sid + " new_ifname=" + new_iface)
|
||||||
|
if not s.startswith("OK"):
|
||||||
|
raise Exception("Cannot set FST session new_ifname:" + s)
|
||||||
|
if self.new_peer_addr is not None and self.new_peer_addr != '':
|
||||||
|
s = self.set_session_param(sid + " new_peer_addr=" + self.new_peer_addr)
|
||||||
|
if not s.startswith("OK"):
|
||||||
|
raise Exception("Cannot set FST session peer address:" + s + " (new)")
|
||||||
|
if self.old_peer_addr is not None and self.old_peer_addr != '':
|
||||||
|
s = self.set_session_param(sid + " old_peer_addr=" + self.old_peer_addr)
|
||||||
|
if not s.startswith("OK"):
|
||||||
|
raise Exception("Cannot set FST session peer address:" + s + " (old)")
|
||||||
|
if self.fst_llt is not None and self.fst_llt != '':
|
||||||
|
s = self.set_session_param(sid + " llt=" + self.fst_llt)
|
||||||
|
if not s.startswith("OK"):
|
||||||
|
raise Exception("Cannot set FST session llt:" + s)
|
||||||
|
|
||||||
|
def send_iface_attach_request(self, ifname, group, llt, priority):
|
||||||
|
request = "FST-ATTACH " + ifname + ' ' + group
|
||||||
|
if llt is not None:
|
||||||
|
request += " llt=" + llt
|
||||||
|
if priority is not None:
|
||||||
|
request += " priority=" + priority
|
||||||
|
res = self.grequest(request)
|
||||||
|
if not res.startswith("OK"):
|
||||||
|
raise Exception("Cannot attach FST iface: " + res)
|
||||||
|
|
||||||
|
def send_iface_detach_request(self, ifname):
|
||||||
|
res = self.grequest("FST-DETACH " + ifname)
|
||||||
|
if not res.startswith("OK"):
|
||||||
|
raise Exception("Cannot detach FST iface: " + res)
|
||||||
|
|
||||||
|
def send_session_setup_request(self, sid):
|
||||||
|
s = self.grequest("FST-MANAGER SESSION_INITIATE " + sid)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send setup request: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_session_setup_response(self, sid, response):
|
||||||
|
request = "FST-MANAGER SESSION_RESPOND " + sid + " " + response
|
||||||
|
s = self.grequest(request)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send setup response: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_test_session_setup_request(self, fsts_id,
|
||||||
|
additional_parameter = None):
|
||||||
|
request = "FST-MANAGER TEST_REQUEST SEND_SETUP_REQUEST " + fsts_id
|
||||||
|
if additional_parameter is not None:
|
||||||
|
request += " " + additional_parameter
|
||||||
|
s = self.grequest(request)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send FST setup request: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_test_session_setup_response(self, fsts_id,
|
||||||
|
response, additional_parameter = None):
|
||||||
|
request = "FST-MANAGER TEST_REQUEST SEND_SETUP_RESPONSE " + fsts_id + " " + response
|
||||||
|
if additional_parameter is not None:
|
||||||
|
request += " " + additional_parameter
|
||||||
|
s = self.grequest(request)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send FST setup response: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_test_ack_request(self, fsts_id):
|
||||||
|
s = self.grequest("FST-MANAGER TEST_REQUEST SEND_ACK_REQUEST " + fsts_id)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send FST ack request: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_test_ack_response(self, fsts_id):
|
||||||
|
s = self.grequest("FST-MANAGER TEST_REQUEST SEND_ACK_RESPONSE " + fsts_id)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send FST ack response: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def send_test_tear_down(self, fsts_id):
|
||||||
|
s = self.grequest("FST-MANAGER TEST_REQUEST SEND_TEAR_DOWN " + fsts_id)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot send FST tear down: %s" % s)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def get_fsts_id_by_sid(self, sid):
|
||||||
|
s = self.grequest("FST-MANAGER TEST_REQUEST GET_FSTS_ID " + sid)
|
||||||
|
if s == ' ' or s.startswith('FAIL'):
|
||||||
|
raise Exception("Cannot get fsts_id for sid == " % sid)
|
||||||
|
return int(s)
|
||||||
|
|
||||||
|
def wait_for_iface_event(self, timeout):
|
||||||
|
while True:
|
||||||
|
ev = self.wait_gevent(["FST-EVENT-IFACE"], timeout)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No FST-EVENT-IFACE received")
|
||||||
|
event = parse_fst_iface_event(ev)
|
||||||
|
if event is None:
|
||||||
|
# We can't parse so it's not our event, wait for next one
|
||||||
|
continue
|
||||||
|
return event
|
||||||
|
|
||||||
|
def wait_for_session_event(self, timeout, events_to_ignore=[],
|
||||||
|
events_to_count=[]):
|
||||||
|
while True:
|
||||||
|
ev = self.wait_gevent(["FST-EVENT-SESSION"], timeout)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No FST-EVENT-SESSION received")
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event is None:
|
||||||
|
# We can't parse so it's not our event, wait for next one
|
||||||
|
continue
|
||||||
|
if len(events_to_ignore) > 0:
|
||||||
|
if event['type'] in events_to_ignore:
|
||||||
|
continue
|
||||||
|
elif len(events_to_count) > 0:
|
||||||
|
if not event['type'] in events_to_count:
|
||||||
|
continue
|
||||||
|
return event
|
||||||
|
|
||||||
|
def initiate_session(self, sid, response="accept"):
|
||||||
|
"""Initiates FST session with given session id 'sid'.
|
||||||
|
'response' is the session respond answer: "accept", "reject", or a
|
||||||
|
special "timeout" value to skip the response in order to test session
|
||||||
|
timeouts.
|
||||||
|
Returns: "OK" - session has been initiated, otherwise the reason for the
|
||||||
|
reset: REASON_REJECT, REASON_STT."""
|
||||||
|
strsid = ' ' + sid if sid != '' else ''
|
||||||
|
s = self.grequest("FST-MANAGER SESSION_INITIATE"+ strsid)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot initiate fst session: %s" % s)
|
||||||
|
ev = self.peer_obj.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No FST-EVENT-SESSION received")
|
||||||
|
# We got FST event
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event == None:
|
||||||
|
raise Exception("Unrecognized FST event: " % ev)
|
||||||
|
if event['type'] != 'EVENT_FST_SETUP':
|
||||||
|
raise Exception("Expected FST_SETUP event, got: " + event['type'])
|
||||||
|
ev = self.peer_obj.wait_gevent(["FST-EVENT-SESSION"], timeout=5)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No FST-EVENT-SESSION received")
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event == None:
|
||||||
|
raise Exception("Unrecognized FST event: " % ev)
|
||||||
|
if event['type'] != 'EVENT_FST_SESSION_STATE':
|
||||||
|
raise Exception("Expected EVENT_FST_SESSION_STATE event, got: " + event['type'])
|
||||||
|
if event['new_state'] != "SETUP_COMPLETION":
|
||||||
|
raise Exception("Expected new state SETUP_COMPLETION, got: " + event['new_state'])
|
||||||
|
if response == '':
|
||||||
|
return 'OK'
|
||||||
|
if response != "timeout":
|
||||||
|
s = self.peer_obj.grequest("FST-MANAGER SESSION_RESPOND "+ event['id'] + " " + response) # Or reject
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Error session_respond: %s" % s)
|
||||||
|
# Wait for EVENT_FST_SESSION_STATE events. We should get at least 2
|
||||||
|
# events. The 1st event will be EVENT_FST_SESSION_STATE
|
||||||
|
# old_state=INITIAL new_state=SETUP_COMPLETED. The 2nd event will be
|
||||||
|
# either EVENT_FST_ESTABLISHED with the session id or
|
||||||
|
# EVENT_FST_SESSION_STATE with new_state=INITIAL if the session was
|
||||||
|
# reset, the reason field will tell why.
|
||||||
|
result = ''
|
||||||
|
while result == '':
|
||||||
|
ev = self.wait_gevent(["FST-EVENT-SESSION"], timeout=5)
|
||||||
|
if ev is None:
|
||||||
|
break # No session event received
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event == None:
|
||||||
|
# We can't parse so it's not our event, wait for next one
|
||||||
|
continue
|
||||||
|
if event['type'] == 'EVENT_FST_ESTABLISHED':
|
||||||
|
result = "OK"
|
||||||
|
break
|
||||||
|
elif event['type'] == "EVENT_FST_SESSION_STATE":
|
||||||
|
if event['new_state'] == "INITIAL":
|
||||||
|
# Session was reset, the only reason to get back to initial
|
||||||
|
# state.
|
||||||
|
result = event['reason']
|
||||||
|
break
|
||||||
|
if result == '':
|
||||||
|
raise Exception("No event for session respond")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def transfer_session(self, sid):
|
||||||
|
"""Transfers the session. 'sid' is the session id. 'hsta' is the
|
||||||
|
station-responder object.
|
||||||
|
Returns: REASON_SWITCH - the session has been transferred successfully
|
||||||
|
or a REASON_... reported by the reset event."""
|
||||||
|
request = "FST-MANAGER SESSION_TRANSFER"
|
||||||
|
if sid != '':
|
||||||
|
request += ' ' + sid
|
||||||
|
s = self.grequest(request)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot transfer fst session: %s" % s)
|
||||||
|
result = ''
|
||||||
|
while result == '':
|
||||||
|
ev = self.peer_obj.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("Missing session transfer event")
|
||||||
|
# We got FST event. We expect TRANSITION_CONFIRMED state and then
|
||||||
|
# INITIAL (reset) with the reason (e.g. "REASON_SWITCH").
|
||||||
|
# Right now we'll be waiting for the reset event and record the
|
||||||
|
# reason.
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event == None:
|
||||||
|
raise Exception("Unrecognized FST event: " % ev)
|
||||||
|
if event['new_state'] == 'INITIAL':
|
||||||
|
result = event['reason']
|
||||||
|
return result
|
||||||
|
|
||||||
|
def wait_for_tear_down(self):
|
||||||
|
ev = self.wait_gevent([ "FST-EVENT-SESSION" ], timeout=5)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No FST-EVENT-SESSION received")
|
||||||
|
# We got FST event
|
||||||
|
event = parse_fst_session_event(ev)
|
||||||
|
if event == None:
|
||||||
|
raise Exception("Unrecognized FST event: " % ev)
|
||||||
|
if event['type'] != 'EVENT_FST_SESSION_STATE':
|
||||||
|
raise Exception("Expected EVENT_FST_SESSION_STATE event, got: " + event['type'])
|
||||||
|
if event['new_state'] != "INITIAL":
|
||||||
|
raise Exception("Expected new state INITIAL, got: " + event['new_state'])
|
||||||
|
if event['reason'] != 'REASON_TEARDOWN':
|
||||||
|
raise Exception("Expected reason REASON_TEARDOWN, got: " + event['reason'])
|
||||||
|
|
||||||
|
def teardown_session(self, sid):
|
||||||
|
"""Tears down FST session with a given session id ('sid')"""
|
||||||
|
strsid = ' ' + sid if sid != '' else ''
|
||||||
|
s = self.grequest("FST-MANAGER SESSION_TEARDOWN" + strsid)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot tear down fst session: %s" % s)
|
||||||
|
self.peer_obj.wait_for_tear_down()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_session(self, sid, wait_for_tear_down=True):
|
||||||
|
"""Removes FST session with a given session id ('sid')"""
|
||||||
|
strsid = ' ' + sid if sid != '' else ''
|
||||||
|
s = self.grequest("FST-MANAGER SESSION_REMOVE" + strsid)
|
||||||
|
if not s.startswith('OK'):
|
||||||
|
raise Exception("Cannot remove fst session: %s" % s)
|
||||||
|
if wait_for_tear_down == True:
|
||||||
|
self.peer_obj.wait_for_tear_down()
|
||||||
|
|
||||||
|
def remove_all_sessions(self):
|
||||||
|
"""Removes FST session with a given session id ('sid')"""
|
||||||
|
grp = ' ' + self.fst_group if self.fst_group != '' else ''
|
||||||
|
s = self.grequest("FST-MANAGER LIST_SESSIONS" + grp)
|
||||||
|
if not s.startswith('FAIL'):
|
||||||
|
for sid in s.splitlines():
|
||||||
|
sid = sid.strip()
|
||||||
|
if len(sid) != 0:
|
||||||
|
self.remove_session(sid, wait_for_tear_down=False)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# FstAP class
|
||||||
|
#
|
||||||
|
class FstAP (FstDevice):
|
||||||
|
def __init__(self, iface, ssid, mode, chan, fst_group, fst_pri,
|
||||||
|
fst_llt=None):
|
||||||
|
"""If fst_group is empty, then FST parameters will not be set
|
||||||
|
If fst_llt is empty, the parameter will not be set and the default value
|
||||||
|
is expected to be configured."""
|
||||||
|
self.ssid = ssid
|
||||||
|
self.mode = mode
|
||||||
|
self.chan = chan
|
||||||
|
self.reg_ctrl = fst_test_common.HapdRegCtrl()
|
||||||
|
self.reg_ctrl.add_ap(iface, self.chan)
|
||||||
|
self.global_instance = hostapd.HostapdGlobal()
|
||||||
|
FstDevice.__init__(self, iface, fst_group, fst_pri, fst_llt)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Starts AP the "standard" way as it was intended by hostapd tests.
|
||||||
|
This will work only when FST supports fully dynamically loading
|
||||||
|
parameters in hostapd."""
|
||||||
|
params = {}
|
||||||
|
params['ssid'] = self.ssid
|
||||||
|
params['hw_mode'] = self.mode
|
||||||
|
params['channel'] = self.chan
|
||||||
|
params['country_code'] = 'US'
|
||||||
|
self.hapd=hostapd.add_ap(self.iface, params)
|
||||||
|
if not self.hapd.ping():
|
||||||
|
raise Exception("Could not ping FST hostapd")
|
||||||
|
self.reg_ctrl.start()
|
||||||
|
self.get_global_instance()
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
self.send_iface_attach_request(self.iface, self.fst_group,
|
||||||
|
self.fst_llt, self.fst_pri)
|
||||||
|
return self.hapd
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Removes the AP, To be used when dynamic fst APs are implemented in
|
||||||
|
hostapd."""
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
self.remove_all_sessions()
|
||||||
|
self.send_iface_detach_request(self.iface)
|
||||||
|
self.reg_ctrl.stop()
|
||||||
|
del self.global_instance
|
||||||
|
self.global_instance = None
|
||||||
|
|
||||||
|
def get_instance(self):
|
||||||
|
"""Return the Hostapd/WpaSupplicant instance"""
|
||||||
|
if self.instance is None:
|
||||||
|
self.instance = hostapd.Hostapd(self.iface)
|
||||||
|
return self.instance
|
||||||
|
|
||||||
|
def get_global_instance(self):
|
||||||
|
return self.global_instance
|
||||||
|
|
||||||
|
def get_own_mac_address(self):
|
||||||
|
"""Gets the device's own MAC address"""
|
||||||
|
h = self.get_instance()
|
||||||
|
status = h.get_status()
|
||||||
|
return status['bssid[0]']
|
||||||
|
|
||||||
|
def get_actual_peer_addr(self):
|
||||||
|
"""Gets the peer address. A connected station address is returned."""
|
||||||
|
# Use the device instance, the global control interface doesn't have
|
||||||
|
# station address
|
||||||
|
h = self.get_instance()
|
||||||
|
sta = h.get_sta(None)
|
||||||
|
if sta is None or 'addr' not in sta:
|
||||||
|
# Maybe station is not connected?
|
||||||
|
addr = None
|
||||||
|
else:
|
||||||
|
addr=sta['addr']
|
||||||
|
return addr
|
||||||
|
|
||||||
|
def grequest(self, req):
|
||||||
|
"""Send request on the global control interface"""
|
||||||
|
logger.debug("FstAP::grequest: " + req)
|
||||||
|
h = self.get_global_instance()
|
||||||
|
return h.request(req)
|
||||||
|
|
||||||
|
def wait_gevent(self, events, timeout=None):
|
||||||
|
"""Wait for a list of events on the global interface"""
|
||||||
|
h = self.get_global_instance()
|
||||||
|
if timeout is not None:
|
||||||
|
return h.wait_event(events, timeout=timeout)
|
||||||
|
else:
|
||||||
|
return h.wait_event(events)
|
||||||
|
|
||||||
|
def get_ssid(self):
|
||||||
|
return self.ssid
|
||||||
|
|
||||||
|
#
|
||||||
|
# FstSTA class
|
||||||
|
#
|
||||||
|
class FstSTA (FstDevice):
|
||||||
|
def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
|
||||||
|
"""If fst_group is empty, then FST parameters will not be set
|
||||||
|
If fst_llt is empty, the parameter will not be set and the default value
|
||||||
|
is expected to be configured."""
|
||||||
|
FstDevice.__init__(self, iface, fst_group, fst_pri, fst_llt)
|
||||||
|
self.connected = None # FstAP object the station is connected to
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Current implementation involves running another instance of
|
||||||
|
wpa_supplicant with fixed FST STAs configurations. When any type of
|
||||||
|
dynamic STA loading is implemented, rewrite the function similarly to
|
||||||
|
FstAP."""
|
||||||
|
h = self.get_instance()
|
||||||
|
h.interface_add(self.iface, drv_params="force_connect_cmd=1")
|
||||||
|
if not h.global_ping():
|
||||||
|
raise Exception("Could not ping FST wpa_supplicant")
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
self.send_iface_attach_request(self.iface, self.fst_group,
|
||||||
|
self.fst_llt, self.fst_pri)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Removes the STA. In a static (temporary) implementation does nothing,
|
||||||
|
the STA will be removed when the fst wpa_supplicant process is killed by
|
||||||
|
fstap.cleanup()."""
|
||||||
|
h = self.get_instance()
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
self.remove_all_sessions()
|
||||||
|
self.send_iface_detach_request(self.iface)
|
||||||
|
h.interface_remove(self.iface)
|
||||||
|
h.close_ctrl()
|
||||||
|
del h
|
||||||
|
self.instance = None
|
||||||
|
|
||||||
|
def get_instance(self):
|
||||||
|
"""Return the Hostapd/WpaSupplicant instance"""
|
||||||
|
if self.instance is None:
|
||||||
|
self.instance = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
|
||||||
|
return self.instance
|
||||||
|
|
||||||
|
def get_own_mac_address(self):
|
||||||
|
"""Gets the device's own MAC address"""
|
||||||
|
h = self.get_instance()
|
||||||
|
status = h.get_status()
|
||||||
|
return status['address']
|
||||||
|
|
||||||
|
def get_actual_peer_addr(self):
|
||||||
|
"""Gets the peer address. A connected station address is returned"""
|
||||||
|
h = self.get_instance()
|
||||||
|
status = h.get_status()
|
||||||
|
return status['bssid']
|
||||||
|
|
||||||
|
def grequest(self, req):
|
||||||
|
"""Send request on the global control interface"""
|
||||||
|
logger.debug("FstSTA::grequest: " + req)
|
||||||
|
h = self.get_instance()
|
||||||
|
return h.global_request(req)
|
||||||
|
|
||||||
|
def wait_gevent(self, events, timeout=None):
|
||||||
|
"""Wait for a list of events on the global interface"""
|
||||||
|
h = self.get_instance()
|
||||||
|
if timeout is not None:
|
||||||
|
return h.wait_global_event(events, timeout=timeout)
|
||||||
|
else:
|
||||||
|
return h.wait_global_event(events)
|
||||||
|
|
||||||
|
def scan(self, freq=None, no_wait=False, only_new=False):
|
||||||
|
"""Issue Scan with given parameters. Returns the BSS dictionary for the
|
||||||
|
AP found (the 1st BSS found. TODO: What if the AP required is not the
|
||||||
|
1st in list?) or None if no BSS found. None call be also a result of
|
||||||
|
no_wait=True. Note, request("SCAN_RESULTS") can be used to get all the
|
||||||
|
results at once."""
|
||||||
|
h = self.get_instance()
|
||||||
|
h.scan(None, freq, no_wait, only_new)
|
||||||
|
r = h.get_bss('0')
|
||||||
|
return r
|
||||||
|
|
||||||
|
def connect(self, ap, **kwargs):
|
||||||
|
"""Connects to the given AP"""
|
||||||
|
if not isinstance(ap, FstAP):
|
||||||
|
raise Exception("Bad AP object to connect to")
|
||||||
|
h = self.get_instance()
|
||||||
|
hap = ap.get_instance()
|
||||||
|
h.connect(ap.get_ssid(), **kwargs)
|
||||||
|
self.connected = ap
|
||||||
|
|
||||||
|
def connect_to_external_ap(self, ap, ssid, check_connection=True, **kwargs):
|
||||||
|
"""Connects to the given external AP"""
|
||||||
|
if not isinstance(ap, hostapd.Hostapd):
|
||||||
|
raise Exception("Bad AP object to connect to")
|
||||||
|
h = self.get_instance()
|
||||||
|
h.connect(ssid, **kwargs)
|
||||||
|
self.connected = ap
|
||||||
|
if check_connection:
|
||||||
|
ev = ap.wait_event([ "AP-STA-CONNECTED" ], timeout=10)
|
||||||
|
if ev is None:
|
||||||
|
self.connected = None
|
||||||
|
raise Exception("No connection event received from %s" % ssid)
|
||||||
|
|
||||||
|
def disconnect(self, check_disconnect=True):
|
||||||
|
"""Disconnects from the AP the station is currently connected to"""
|
||||||
|
if self.connected is not None:
|
||||||
|
h = self.get_instance()
|
||||||
|
h.request("DISCONNECT")
|
||||||
|
if check_disconnect:
|
||||||
|
hap = self.connected.get_instance()
|
||||||
|
ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No disconnection event received from %s" % self.connected.get_ssid())
|
||||||
|
self.connected = None
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect_from_external_ap(self, check_disconnect=True):
|
||||||
|
"""Disconnects from the external AP the station is currently connected
|
||||||
|
to"""
|
||||||
|
if self.connected is not None:
|
||||||
|
h = self.get_instance()
|
||||||
|
h.request("DISCONNECT")
|
||||||
|
if check_disconnect:
|
||||||
|
hap = self.connected
|
||||||
|
ev = hap.wait_event([ "AP-STA-DISCONNECTED" ], timeout=10)
|
||||||
|
if ev is None:
|
||||||
|
raise Exception("No disconnection event received from AP")
|
||||||
|
self.connected = None
|
88
tests/hwsim/fst_test_common.py
Normal file
88
tests/hwsim/fst_test_common.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# FST tests related definitions
|
||||||
|
# Copyright (c) 2015, Qualcomm Atheros, Inc.
|
||||||
|
#
|
||||||
|
# This software may be distributed under the terms of the BSD license.
|
||||||
|
# See README for more details.
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import hostapd
|
||||||
|
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
fst_test_def_group='fstg0'
|
||||||
|
fst_test_def_freq_g='2412' # Channel 1
|
||||||
|
fst_test_def_freq_a='5180' # Channel 36
|
||||||
|
fst_test_def_chan_g='1'
|
||||||
|
fst_test_def_chan_a='36'
|
||||||
|
fst_test_def_prio_low='100'
|
||||||
|
fst_test_def_prio_high='110'
|
||||||
|
fst_test_def_llt='100'
|
||||||
|
fst_test_def_reg_domain='00'
|
||||||
|
|
||||||
|
class HapdRegCtrl:
|
||||||
|
def __init__(self):
|
||||||
|
self.refcnt = 0
|
||||||
|
self.ifname = None
|
||||||
|
self.changed = False
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if self.refcnt != 0 and self.changed == True:
|
||||||
|
self.restore_reg_domain()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if self.ifname != None:
|
||||||
|
hapd = hostapd.Hostapd(self.ifname)
|
||||||
|
self.changed = self.wait_hapd_reg_change(hapd)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self.changed == True:
|
||||||
|
self.restore_reg_domain()
|
||||||
|
self.changed = False
|
||||||
|
|
||||||
|
def add_ap(self, ifname, chan):
|
||||||
|
if self.changed == False and self.channel_may_require_reg_change(chan):
|
||||||
|
self.ifname = ifname
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def channel_may_require_reg_change(chan):
|
||||||
|
if int(chan) > 14:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def wait_hapd_reg_change(hapd):
|
||||||
|
state = hapd.get_status_field("state")
|
||||||
|
if state != "COUNTRY_UPDATE":
|
||||||
|
state = hapd.get_status_field("state")
|
||||||
|
if state != "ENABLED":
|
||||||
|
raise Exception("Unexpected interface state - expected COUNTRY_UPDATE")
|
||||||
|
else:
|
||||||
|
logger.debug("fst hostapd: regulatory domain already set")
|
||||||
|
return True
|
||||||
|
|
||||||
|
logger.debug("fst hostapd: waiting for regulatory domain to be set...")
|
||||||
|
|
||||||
|
ev = hapd.wait_event(["AP-ENABLED"], timeout=10)
|
||||||
|
if not ev:
|
||||||
|
raise Exception("AP setup timed out")
|
||||||
|
|
||||||
|
logger.debug("fst hostapd: regulatory domain set")
|
||||||
|
|
||||||
|
state = hapd.get_status_field("state")
|
||||||
|
if state != "ENABLED":
|
||||||
|
raise Exception("Unexpected interface state - expected ENABLED")
|
||||||
|
|
||||||
|
logger.debug("fst hostapd: regulatory domain ready")
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def restore_reg_domain():
|
||||||
|
logger.debug("fst hostapd: waiting for regulatory domain to be restored...")
|
||||||
|
|
||||||
|
res = subprocess.call(['iw', 'reg', 'set', fst_test_def_reg_domain])
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("Cannot restore regulatory domain")
|
||||||
|
|
||||||
|
logger.debug("fst hostapd: regulatory domain ready")
|
|
@ -21,6 +21,28 @@ def mac2tuple(mac):
|
||||||
class HostapdGlobal:
|
class HostapdGlobal:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.ctrl = wpaspy.Ctrl(hapd_global)
|
self.ctrl = wpaspy.Ctrl(hapd_global)
|
||||||
|
self.mon = wpaspy.Ctrl(hapd_global)
|
||||||
|
self.mon.attach()
|
||||||
|
|
||||||
|
def request(self, cmd):
|
||||||
|
return self.ctrl.request(cmd)
|
||||||
|
|
||||||
|
def wait_event(self, events, timeout):
|
||||||
|
start = os.times()[4]
|
||||||
|
while True:
|
||||||
|
while self.mon.pending():
|
||||||
|
ev = self.mon.recv()
|
||||||
|
logger.debug("(global): " + ev)
|
||||||
|
for event in events:
|
||||||
|
if event in ev:
|
||||||
|
return ev
|
||||||
|
now = os.times()[4]
|
||||||
|
remaining = start + timeout - now
|
||||||
|
if remaining <= 0:
|
||||||
|
break
|
||||||
|
if not self.mon.pending(timeout=remaining):
|
||||||
|
break
|
||||||
|
return None
|
||||||
|
|
||||||
def add(self, ifname):
|
def add(self, ifname):
|
||||||
res = self.ctrl.request("ADD " + ifname + " " + hapd_ctrl)
|
res = self.ctrl.request("ADD " + ifname + " " + hapd_ctrl)
|
||||||
|
|
|
@ -487,6 +487,10 @@ def main():
|
||||||
wt = Wlantest()
|
wt = Wlantest()
|
||||||
rename_log(args.logdir, 'hwsim0.pcapng', name, wt)
|
rename_log(args.logdir, 'hwsim0.pcapng', name, wt)
|
||||||
rename_log(args.logdir, 'hwsim0', name, wt)
|
rename_log(args.logdir, 'hwsim0', name, wt)
|
||||||
|
if os.path.exists(os.path.join(args.logdir, 'fst-wpa_supplicant')):
|
||||||
|
rename_log(args.logdir, 'fst-wpa_supplicant', name, None)
|
||||||
|
if os.path.exists(os.path.join(args.logdir, 'fst-hostapd')):
|
||||||
|
rename_log(args.logdir, 'fst-hostapd', name, None)
|
||||||
|
|
||||||
end = datetime.now()
|
end = datetime.now()
|
||||||
diff = end - start
|
diff = end - start
|
||||||
|
|
|
@ -100,7 +100,8 @@ else
|
||||||
NUM_CH=1
|
NUM_CH=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
test -f /proc/modules && sudo modprobe mac80211_hwsim radios=6 channels=$NUM_CH support_p2p_device=0
|
test -f /proc/modules && sudo modprobe mac80211_hwsim radios=7 channels=$NUM_CH support_p2p_device=0
|
||||||
|
|
||||||
sudo ifconfig hwsim0 up
|
sudo ifconfig hwsim0 up
|
||||||
sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dt -L $LOGDIR/hwsim0 &
|
sudo $WLANTEST -i hwsim0 -n $LOGDIR/hwsim0.pcapng -c -dt -L $LOGDIR/hwsim0 &
|
||||||
for i in 0 1 2; do
|
for i in 0 1 2; do
|
||||||
|
|
528
tests/hwsim/test_fst_config.py
Normal file
528
tests/hwsim/test_fst_config.py
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
# FST configuration tests
|
||||||
|
# Copyright (c) 2015, Qualcomm Atheros, Inc.
|
||||||
|
#
|
||||||
|
# This software may be distributed under the terms of the BSD license.
|
||||||
|
# See README for more details.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger()
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import hostapd
|
||||||
|
import wpasupplicant
|
||||||
|
import utils
|
||||||
|
|
||||||
|
import fst_test_common
|
||||||
|
|
||||||
|
class FstLauncherConfig:
|
||||||
|
"""FstLauncherConfig class represents configuration to be used for
|
||||||
|
FST config tests related hostapd/wpa_supplicant instances"""
|
||||||
|
def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
|
||||||
|
self.iface = iface
|
||||||
|
self.fst_group = fst_group
|
||||||
|
self.fst_pri = fst_pri
|
||||||
|
self.fst_llt = fst_llt # None llt means no llt parameter will be set
|
||||||
|
|
||||||
|
def ifname(self):
|
||||||
|
return self.iface
|
||||||
|
|
||||||
|
def is_ap(self):
|
||||||
|
"""Returns True if the configuration is for AP, otherwise - False"""
|
||||||
|
raise Exception("Virtual is_ap() called!")
|
||||||
|
|
||||||
|
def to_file(self, pathname):
|
||||||
|
"""Creates configuration file to be used by FST config tests related
|
||||||
|
hostapd/wpa_supplicant instances"""
|
||||||
|
raise Exception("Virtual to_file() called!")
|
||||||
|
|
||||||
|
class FstLauncherConfigAP(FstLauncherConfig):
|
||||||
|
"""FstLauncherConfigAP class represents configuration to be used for
|
||||||
|
FST config tests related hostapd instance"""
|
||||||
|
def __init__(self, iface, ssid, mode, chan, fst_group, fst_pri,
|
||||||
|
fst_llt=None):
|
||||||
|
self.ssid = ssid
|
||||||
|
self.mode = mode
|
||||||
|
self.chan = chan
|
||||||
|
FstLauncherConfig.__init__(self, iface, fst_group, fst_pri, fst_llt)
|
||||||
|
|
||||||
|
def is_ap(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_channel(self):
|
||||||
|
return self.chan
|
||||||
|
|
||||||
|
def to_file(self, pathname):
|
||||||
|
"""Creates configuration file to be used by FST config tests related
|
||||||
|
hostapd instance"""
|
||||||
|
with open(pathname, "w") as f:
|
||||||
|
f.write("country_code=US\n"
|
||||||
|
"interface=%s\n"
|
||||||
|
"ctrl_interface=/var/run/hostapd\n"
|
||||||
|
"ssid=%s\n"
|
||||||
|
"channel=%s\n"
|
||||||
|
"hw_mode=%s\n"
|
||||||
|
"ieee80211n=1\n" % (self.iface, self.ssid, self.chan,
|
||||||
|
self.mode))
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
f.write("fst_group_id=%s\n"
|
||||||
|
"fst_priority=%s\n" % (self.fst_group, self.fst_pri))
|
||||||
|
if self.fst_llt is not None:
|
||||||
|
f.write("fst_llt=%s\n" % self.fst_llt)
|
||||||
|
with open(pathname, "r") as f:
|
||||||
|
logger.debug("wrote hostapd config file %s:\n%s" % (pathname,
|
||||||
|
f.read()))
|
||||||
|
|
||||||
|
class FstLauncherConfigSTA(FstLauncherConfig):
|
||||||
|
"""FstLauncherConfig class represents configuration to be used for
|
||||||
|
FST config tests related wpa_supplicant instance"""
|
||||||
|
def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
|
||||||
|
FstLauncherConfig.__init__(self, iface, fst_group, fst_pri, fst_llt)
|
||||||
|
|
||||||
|
def is_ap(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def to_file(self, pathname):
|
||||||
|
"""Creates configuration file to be used by FST config tests related
|
||||||
|
wpa_supplicant instance"""
|
||||||
|
with open(pathname, "w") as f:
|
||||||
|
f.write("ctrl_interface=DIR=/var/run/wpa_supplicant\n"
|
||||||
|
"p2p_no_group_iface=1\n")
|
||||||
|
if len(self.fst_group) != 0:
|
||||||
|
f.write("fst_group_id=%s\n"
|
||||||
|
"fst_priority=%s\n" % (self.fst_group, self.fst_pri))
|
||||||
|
if self.fst_llt is not None:
|
||||||
|
f.write("fst_llt=%s\n" % self.fst_llt)
|
||||||
|
with open(pathname, "r") as f:
|
||||||
|
logger.debug("wrote wpa_supplicant config file %s:\n%s" % (pathname, f.read()))
|
||||||
|
|
||||||
|
class FstLauncher:
|
||||||
|
"""FstLauncher class is responsible for launching and cleaning up of FST
|
||||||
|
config tests related hostapd/wpa_supplicant instances"""
|
||||||
|
def __init__(self, logpath):
|
||||||
|
self.logger = logging.getLogger()
|
||||||
|
self.fst_logpath = logpath
|
||||||
|
self.cfgs_to_run = []
|
||||||
|
self.hapd_fst_global = '/var/run/hostapd-fst-global'
|
||||||
|
self.wsup_fst_global = '/tmp/fststa'
|
||||||
|
self.nof_aps = 0
|
||||||
|
self.nof_stas = 0
|
||||||
|
self.reg_ctrl = fst_test_common.HapdRegCtrl()
|
||||||
|
self.test_is_supported()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.cleanup()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def test_is_supported():
|
||||||
|
h = hostapd.HostapdGlobal()
|
||||||
|
resp = h.request("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
|
||||||
|
if not resp.startswith("OK"):
|
||||||
|
raise utils.HwsimSkip("FST not supported")
|
||||||
|
w = wpasupplicant.WpaSupplicant(global_iface='/tmp/wpas-wlan5')
|
||||||
|
resp = w.global_request("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
|
||||||
|
if not resp.startswith("OK"):
|
||||||
|
raise utils.HwsimSkip("FST not supported")
|
||||||
|
|
||||||
|
def get_cfg_pathname(self, cfg):
|
||||||
|
"""Returns pathname of ifname based configuration file"""
|
||||||
|
return self.fst_logpath +'/'+ cfg.ifname() + '.conf'
|
||||||
|
|
||||||
|
def add_cfg(self, cfg):
|
||||||
|
"""Adds configuration to be used for launching hostapd/wpa_supplicant
|
||||||
|
instances"""
|
||||||
|
if cfg not in self.cfgs_to_run:
|
||||||
|
self.cfgs_to_run.append(cfg)
|
||||||
|
if cfg.is_ap() == True:
|
||||||
|
self.nof_aps += 1
|
||||||
|
else:
|
||||||
|
self.nof_stas += 1
|
||||||
|
|
||||||
|
def remove_cfg(self, cfg):
|
||||||
|
"""Removes configuration previously added with add_cfg"""
|
||||||
|
if cfg in self.cfgs_to_run:
|
||||||
|
self.cfgs_to_run.remove(cfg)
|
||||||
|
if cfg.is_ap() == True:
|
||||||
|
self.nof_aps -= 1
|
||||||
|
else:
|
||||||
|
self.nof_stas -= 1
|
||||||
|
config_file = self.get_cfg_pathname(cfg);
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
os.remove(config_file)
|
||||||
|
|
||||||
|
def run_hostapd(self):
|
||||||
|
"""Lauches hostapd with interfaces configured according to
|
||||||
|
FstLauncherConfigAP configurations added"""
|
||||||
|
if self.nof_aps == 0:
|
||||||
|
raise Exception("No FST APs to start")
|
||||||
|
pidfile = self.fst_logpath + '/' + 'myhostapd.pid'
|
||||||
|
mylogfile = self.fst_logpath + '/' + 'fst-hostapd'
|
||||||
|
cmd = [ '../../hostapd/hostapd', '-B', '-ddd',
|
||||||
|
'-P', pidfile, '-f', mylogfile, '-g', self.hapd_fst_global]
|
||||||
|
for i in range(0, len(self.cfgs_to_run)):
|
||||||
|
cfg = self.cfgs_to_run[i]
|
||||||
|
if cfg.is_ap() == True:
|
||||||
|
cfgfile = self.get_cfg_pathname(cfg)
|
||||||
|
cfg.to_file(cfgfile)
|
||||||
|
cmd.append(cfgfile)
|
||||||
|
self.reg_ctrl.add_ap(cfg.ifname(), cfg.get_channel())
|
||||||
|
self.logger.debug("Starting fst hostapd: " + ' '.join(cmd))
|
||||||
|
res = subprocess.call(cmd)
|
||||||
|
self.logger.debug("fst hostapd start result: %d" % res)
|
||||||
|
if res == 0:
|
||||||
|
self.reg_ctrl.start()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def run_wpa_supplicant(self):
|
||||||
|
"""Lauches wpa_supplicant with interfaces configured according to
|
||||||
|
FstLauncherConfigSTA configurations added"""
|
||||||
|
if self.nof_stas == 0:
|
||||||
|
raise Exception("No FST STAs to start")
|
||||||
|
pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
|
||||||
|
mylogfile = self.fst_logpath + '/' + 'fst-wpa_supplicant'
|
||||||
|
cmd = [ '../../wpa_supplicant/wpa_supplicant', '-B', '-ddd',
|
||||||
|
'-P' + pidfile, '-f', mylogfile, '-g', self.wsup_fst_global ]
|
||||||
|
sta_no = 0
|
||||||
|
for i in range(0, len(self.cfgs_to_run)):
|
||||||
|
cfg = self.cfgs_to_run[i]
|
||||||
|
if cfg.is_ap() == False:
|
||||||
|
cfgfile = self.get_cfg_pathname(cfg)
|
||||||
|
cfg.to_file(cfgfile)
|
||||||
|
cmd.append('-c' + cfgfile)
|
||||||
|
cmd.append('-i' + cfg.ifname())
|
||||||
|
cmd.append('-Dnl80211')
|
||||||
|
if sta_no != self.nof_stas -1:
|
||||||
|
cmd.append('-N') # Next station configuration
|
||||||
|
sta_no += 1
|
||||||
|
self.logger.debug("Starting fst supplicant: " + ' '.join(cmd))
|
||||||
|
res = subprocess.call(cmd)
|
||||||
|
self.logger.debug("fst supplicant start result: %d" % res)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""Terminates hostapd/wpa_supplicant processes previously launched with
|
||||||
|
run_hostapd/run_wpa_supplicant"""
|
||||||
|
pidfile = self.fst_logpath + '/' + 'myhostapd.pid'
|
||||||
|
self.kill_pid(pidfile)
|
||||||
|
pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
|
||||||
|
self.kill_pid(pidfile)
|
||||||
|
self.reg_ctrl.stop()
|
||||||
|
while len(self.cfgs_to_run) != 0:
|
||||||
|
cfg = self.cfgs_to_run[0]
|
||||||
|
self.remove_cfg(cfg)
|
||||||
|
|
||||||
|
def kill_pid(self, pidfile):
|
||||||
|
"""Kills process by PID file"""
|
||||||
|
if not os.path.exists(pidfile):
|
||||||
|
return
|
||||||
|
pid = -1
|
||||||
|
try:
|
||||||
|
pf = file(pidfile, 'r')
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
pf.close()
|
||||||
|
self.logger.debug("kill_pid %s --> pid %d" % (pidfile, pid))
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
for i in range(10):
|
||||||
|
try:
|
||||||
|
# Poll the pid (Is the process still existing?)
|
||||||
|
os.kill(pid, 0)
|
||||||
|
except OSError:
|
||||||
|
# No, already done
|
||||||
|
break
|
||||||
|
# Wait and check again
|
||||||
|
time.sleep(1)
|
||||||
|
except Exception, e:
|
||||||
|
self.logger.debug("Didn't stop the pid=%d. Was it stopped already? (%s)" % (pid, str(e)))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_ies(iehex, el=-1):
|
||||||
|
"""Parses the information elements hex string 'iehex' in format
|
||||||
|
"0a0b0c0d0e0f". If no 'el' defined just checks the IE string for integrity.
|
||||||
|
If 'el' is defined returns the list of hex values of the specific IE (or
|
||||||
|
empty list if the element is not in the string."""
|
||||||
|
iel = [iehex[i:i + 2] for i in range(0, len(iehex), 2)]
|
||||||
|
for i in range(0, len(iel)):
|
||||||
|
iel[i] = int(iel[i], 16)
|
||||||
|
# Sanity check
|
||||||
|
i = 0
|
||||||
|
res = []
|
||||||
|
while i < len(iel):
|
||||||
|
logger.debug("IE found: %x" % iel[i])
|
||||||
|
if el != -1 and el == iel[i]:
|
||||||
|
res = iel[i + 2:i + 2 + iel[i + 1]]
|
||||||
|
i += 2 + iel[i + 1]
|
||||||
|
if i != len(iel):
|
||||||
|
logger.error("Bad IE string: " + iehex)
|
||||||
|
res = []
|
||||||
|
return res
|
||||||
|
|
||||||
|
def scan_and_get_bss(dev, frq):
|
||||||
|
"""Issues a scan on given device on given frequency, returns the bss info
|
||||||
|
dictionary ('ssid','ie','flags', etc.) or None. Note, the function
|
||||||
|
implies there is only one AP on the given channel. If not a case,
|
||||||
|
the function must be changed to call dev.get_bss() till the AP with the
|
||||||
|
[b]ssid that we need is found"""
|
||||||
|
dev.scan(freq=frq)
|
||||||
|
return dev.get_bss('0')
|
||||||
|
|
||||||
|
|
||||||
|
# AP configuration tests
|
||||||
|
|
||||||
|
def run_test_ap_configuration(apdev, test_params,
|
||||||
|
fst_group = fst_test_common.fst_test_def_group,
|
||||||
|
fst_pri = fst_test_common.fst_test_def_prio_high,
|
||||||
|
fst_llt = fst_test_common.fst_test_def_llt):
|
||||||
|
"""Runs FST hostapd where the 1st AP configuration is fixed, the 2nd fst
|
||||||
|
configuration is provided by the parameters. Returns the result of the run:
|
||||||
|
0 - no errors discovered, an error otherwise. The function is used for
|
||||||
|
simplek "bad configuration" tests."""
|
||||||
|
logdir = test_params['logdir']
|
||||||
|
fst_launcher = FstLauncher(logdir)
|
||||||
|
ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_goodconf', 'a',
|
||||||
|
fst_test_common.fst_test_def_chan_a,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_low,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_badconf', 'b',
|
||||||
|
fst_test_common.fst_test_def_chan_g, fst_group,
|
||||||
|
fst_pri, fst_llt)
|
||||||
|
fst_launcher.add_cfg(ap1)
|
||||||
|
fst_launcher.add_cfg(ap2)
|
||||||
|
res = fst_launcher.run_hostapd()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def run_test_sta_configuration(test_params,
|
||||||
|
fst_group = fst_test_common.fst_test_def_group,
|
||||||
|
fst_pri = fst_test_common.fst_test_def_prio_high,
|
||||||
|
fst_llt = fst_test_common.fst_test_def_llt):
|
||||||
|
"""Runs FST wpa_supplicant where the 1st STA configuration is fixed, the
|
||||||
|
2nd fst configuration is provided by the parameters. Returns the result of
|
||||||
|
the run: 0 - no errors discovered, an error otherwise. The function is used
|
||||||
|
for simple "bad configuration" tests."""
|
||||||
|
logdir = test_params['logdir']
|
||||||
|
fst_launcher = FstLauncher(logdir)
|
||||||
|
sta1 = FstLauncherConfigSTA('wlan5',
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_low,
|
||||||
|
fst_test_common.fst_test_def_llt)
|
||||||
|
sta2 = FstLauncherConfigSTA('wlan6', fst_group, fst_pri, fst_llt)
|
||||||
|
fst_launcher.add_cfg(sta1)
|
||||||
|
fst_launcher.add_cfg(sta2)
|
||||||
|
res = fst_launcher.run_wpa_supplicant()
|
||||||
|
return res
|
||||||
|
|
||||||
|
def test_fst_ap_config_llt_neg(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration negative LLT"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_llt = '-1')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with a negative llt")
|
||||||
|
|
||||||
|
def test_fst_ap_config_llt_zero(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration zero LLT"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_llt = '0')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with a zero llt")
|
||||||
|
|
||||||
|
def test_fst_ap_config_llt_too_big(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration LLT is too big"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params,
|
||||||
|
fst_llt = '4294967296') #0x100000000
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with llt that is too big")
|
||||||
|
|
||||||
|
def test_fst_ap_config_llt_nan(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration LLT is not a number"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_llt = 'nan')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with llt not a number")
|
||||||
|
|
||||||
|
def test_fst_ap_config_pri_neg(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration Priority negative"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_pri = '-1')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with a negative fst priority")
|
||||||
|
|
||||||
|
def test_fst_ap_config_pri_zero(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration Priority zero"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_pri = '0')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with a zero fst priority")
|
||||||
|
|
||||||
|
def test_fst_ap_config_pri_large(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration Priority too large"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_pri = '256')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with too large fst priority")
|
||||||
|
|
||||||
|
def test_fst_ap_config_pri_nan(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration Priority not a number"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_pri = 'nan')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with fst priority not a number")
|
||||||
|
|
||||||
|
def test_fst_ap_config_group_len(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration Group max length"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params,
|
||||||
|
fst_group = 'fstg5678abcd34567')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("hostapd started with fst_group length too big")
|
||||||
|
|
||||||
|
def test_fst_ap_config_good(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration good parameters"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params)
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("hostapd didn't start with valid config parameters")
|
||||||
|
|
||||||
|
def test_fst_ap_config_default(dev, apdev, test_params):
|
||||||
|
"""FST AP configuration default parameters"""
|
||||||
|
res = run_test_ap_configuration(apdev, test_params, fst_llt = None)
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("hostapd didn't start with valid config parameters")
|
||||||
|
|
||||||
|
|
||||||
|
# STA configuration tests
|
||||||
|
|
||||||
|
def test_fst_sta_config_llt_neg(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration negative LLT"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_llt = '-1')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with a negative llt")
|
||||||
|
|
||||||
|
def test_fst_sta_config_llt_zero(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration zero LLT"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_llt = '0')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with a zero llt")
|
||||||
|
|
||||||
|
def test_fst_sta_config_llt_large(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration LLT is too large"""
|
||||||
|
res = run_test_sta_configuration(test_params,
|
||||||
|
fst_llt = '4294967296') #0x100000000
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with llt that is too large")
|
||||||
|
|
||||||
|
def test_fst_sta_config_llt_nan(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration LLT is not a number"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_llt = 'nan')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with llt not a number")
|
||||||
|
|
||||||
|
def test_fst_sta_config_pri_neg(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration Priority negative"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_pri = '-1')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with a negative fst priority")
|
||||||
|
|
||||||
|
def test_fst_sta_config_pri_zero(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration Priority zero"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_pri = '0')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with a zero fst priority")
|
||||||
|
|
||||||
|
def test_fst_sta_config_pri_big(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration Priority too large"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_pri = '256')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with too large fst priority")
|
||||||
|
|
||||||
|
def test_fst_sta_config_pri_nan(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration Priority not a number"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_pri = 'nan')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with fst priority not a number")
|
||||||
|
|
||||||
|
def test_fst_sta_config_group_len(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration Group max length"""
|
||||||
|
res = run_test_sta_configuration(test_params,
|
||||||
|
fst_group = 'fstg5678abcd34567')
|
||||||
|
if res == 0:
|
||||||
|
raise Exception("wpa_supplicant started with fst_group length too big")
|
||||||
|
|
||||||
|
def test_fst_sta_config_good(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration good parameters"""
|
||||||
|
res = run_test_sta_configuration(test_params)
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("wpa_supplicant didn't start with valid config parameters")
|
||||||
|
|
||||||
|
def test_fst_sta_config_default(dev, apdev, test_params):
|
||||||
|
"""FST STA configuration default parameters"""
|
||||||
|
res = run_test_sta_configuration(test_params, fst_llt = None)
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("wpa_supplicant didn't start with valid config parameters")
|
||||||
|
|
||||||
|
def test_fst_scan_mb(dev, apdev, test_params):
|
||||||
|
"""FST scan valid MB IE presence with normal start"""
|
||||||
|
logdir = test_params['logdir']
|
||||||
|
|
||||||
|
# Test valid MB IE in scan results
|
||||||
|
fst_launcher = FstLauncher(logdir)
|
||||||
|
ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
|
||||||
|
fst_test_common.fst_test_def_chan_a,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_high)
|
||||||
|
ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_11g', 'b',
|
||||||
|
fst_test_common.fst_test_def_chan_g,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_low)
|
||||||
|
fst_launcher.add_cfg(ap1)
|
||||||
|
fst_launcher.add_cfg(ap2)
|
||||||
|
res = fst_launcher.run_hostapd()
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("hostapd didn't start properly")
|
||||||
|
try:
|
||||||
|
mbie1=[]
|
||||||
|
flags1 = ''
|
||||||
|
mbie2=[]
|
||||||
|
flags2 = ''
|
||||||
|
# Scan 1st AP
|
||||||
|
vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
|
||||||
|
if vals1 != None:
|
||||||
|
if 'ie' in vals1:
|
||||||
|
mbie1 = parse_ies(vals1['ie'], 0x9e)
|
||||||
|
if 'flags' in vals1:
|
||||||
|
flags1 = vals1['flags']
|
||||||
|
# Scan 2nd AP
|
||||||
|
vals2 = scan_and_get_bss(dev[2], fst_test_common.fst_test_def_freq_g)
|
||||||
|
if vals2 != None:
|
||||||
|
if 'ie' in vals2:
|
||||||
|
mbie2 = parse_ies(vals2['ie'],0x9e)
|
||||||
|
if 'flags' in vals2:
|
||||||
|
flags2 = vals2['flags']
|
||||||
|
finally:
|
||||||
|
fst_launcher.cleanup()
|
||||||
|
|
||||||
|
if len(mbie1) == 0:
|
||||||
|
raise Exception("No MB IE created by 1st AP")
|
||||||
|
if len(mbie2) == 0:
|
||||||
|
raise Exception("No MB IE created by 2nd AP")
|
||||||
|
|
||||||
|
def test_fst_scan_nomb(dev, apdev, test_params):
|
||||||
|
"""FST scan no MB IE presence with 1 AP start"""
|
||||||
|
logdir = test_params['logdir']
|
||||||
|
|
||||||
|
# Test valid MB IE in scan results
|
||||||
|
fst_launcher = FstLauncher(logdir)
|
||||||
|
ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
|
||||||
|
fst_test_common.fst_test_def_chan_a,
|
||||||
|
fst_test_common.fst_test_def_group,
|
||||||
|
fst_test_common.fst_test_def_prio_high)
|
||||||
|
fst_launcher.add_cfg(ap1)
|
||||||
|
res = fst_launcher.run_hostapd()
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("Hostapd didn't start properly")
|
||||||
|
try:
|
||||||
|
time.sleep(2)
|
||||||
|
mbie1=[]
|
||||||
|
flags1 = ''
|
||||||
|
vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
|
||||||
|
if vals1 != None:
|
||||||
|
if 'ie' in vals1:
|
||||||
|
mbie1 = parse_ies(vals1['ie'], 0x9e)
|
||||||
|
if 'flags' in vals1:
|
||||||
|
flags1 = vals1['flags']
|
||||||
|
finally:
|
||||||
|
fst_launcher.cleanup()
|
||||||
|
|
||||||
|
if len(mbie1) != 0:
|
||||||
|
raise Exception("MB IE exists with 1 AP")
|
1664
tests/hwsim/test_fst_module.py
Normal file
1664
tests/hwsim/test_fst_module.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -109,7 +109,7 @@ kvm \
|
||||||
-fsdev local,security_model=none,id=fsdev-logs,path="$LOGDIR",writeout=immediate \
|
-fsdev local,security_model=none,id=fsdev-logs,path="$LOGDIR",writeout=immediate \
|
||||||
-device virtio-9p-pci,id=fs-logs,fsdev=fsdev-logs,mount_tag=logshare \
|
-device virtio-9p-pci,id=fs-logs,fsdev=fsdev-logs,mount_tag=logshare \
|
||||||
-monitor null -serial stdio -serial file:$LOGDIR/console \
|
-monitor null -serial stdio -serial file:$LOGDIR/console \
|
||||||
-append "mac80211_hwsim.support_p2p_device=0 mac80211_hwsim.channels=$CHANNELS mac80211_hwsim.radios=6 init=$CMD testdir=$TESTDIR timewarp=$TIMEWARP console=$KVMOUT root=/dev/root rootflags=trans=virtio,version=9p2000.u ro rootfstype=9p EPATH=$EPATH ARGS=$RUN_TEST_ARGS"
|
-append "mac80211_hwsim.support_p2p_device=0 mac80211_hwsim.channels=$CHANNELS mac80211_hwsim.radios=7 init=$CMD testdir=$TESTDIR timewarp=$TIMEWARP console=$KVMOUT root=/dev/root rootflags=trans=virtio,version=9p2000.u ro rootfstype=9p EPATH=$EPATH ARGS=$RUN_TEST_ARGS"
|
||||||
|
|
||||||
if [ $CODECOV = "yes" ]; then
|
if [ $CODECOV = "yes" ]; then
|
||||||
echo "Preparing code coverage reports"
|
echo "Preparing code coverage reports"
|
||||||
|
|
Loading…
Reference in a new issue