1 # FST configuration tests
2 # Copyright (c) 2015, Qualcomm Atheros, Inc.
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
8 logger = logging.getLogger()
17 import fst_test_common
19 class FstLauncherConfig:
20 """FstLauncherConfig class represents configuration to be used for
21 FST config tests related hostapd/wpa_supplicant instances"""
22 def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
24 self.fst_group = fst_group
25 self.fst_pri = fst_pri
26 self.fst_llt = fst_llt # None llt means no llt parameter will be set
32 """Returns True if the configuration is for AP, otherwise - False"""
33 raise Exception("Virtual is_ap() called!")
35 def to_file(self, pathname):
36 """Creates configuration file to be used by FST config tests related
37 hostapd/wpa_supplicant instances"""
38 raise Exception("Virtual to_file() called!")
40 class FstLauncherConfigAP(FstLauncherConfig):
41 """FstLauncherConfigAP class represents configuration to be used for
42 FST config tests related hostapd instance"""
43 def __init__(self, iface, ssid, mode, chan, fst_group, fst_pri,
48 FstLauncherConfig.__init__(self, iface, fst_group, fst_pri, fst_llt)
53 def get_channel(self):
56 def to_file(self, pathname):
57 """Creates configuration file to be used by FST config tests related
59 with open(pathname, "w") as f:
60 f.write("country_code=US\n"
62 "ctrl_interface=/var/run/hostapd\n"
66 "ieee80211n=1\n" % (self.iface, self.ssid, self.chan,
68 if len(self.fst_group) != 0:
69 f.write("fst_group_id=%s\n"
70 "fst_priority=%s\n" % (self.fst_group, self.fst_pri))
71 if self.fst_llt is not None:
72 f.write("fst_llt=%s\n" % self.fst_llt)
73 with open(pathname, "r") as f:
74 logger.debug("wrote hostapd config file %s:\n%s" % (pathname,
77 class FstLauncherConfigSTA(FstLauncherConfig):
78 """FstLauncherConfig class represents configuration to be used for
79 FST config tests related wpa_supplicant instance"""
80 def __init__(self, iface, fst_group, fst_pri, fst_llt=None):
81 FstLauncherConfig.__init__(self, iface, fst_group, fst_pri, fst_llt)
86 def to_file(self, pathname):
87 """Creates configuration file to be used by FST config tests related
88 wpa_supplicant instance"""
89 with open(pathname, "w") as f:
90 f.write("ctrl_interface=DIR=/var/run/wpa_supplicant\n"
91 "p2p_no_group_iface=1\n")
92 if len(self.fst_group) != 0:
93 f.write("fst_group_id=%s\n"
94 "fst_priority=%s\n" % (self.fst_group, self.fst_pri))
95 if self.fst_llt is not None:
96 f.write("fst_llt=%s\n" % self.fst_llt)
97 with open(pathname, "r") as f:
98 logger.debug("wrote wpa_supplicant config file %s:\n%s" % (pathname, f.read()))
101 """FstLauncher class is responsible for launching and cleaning up of FST
102 config tests related hostapd/wpa_supplicant instances"""
103 def __init__(self, logpath):
104 self.logger = logging.getLogger()
105 self.fst_logpath = logpath
106 self.cfgs_to_run = []
107 self.hapd_fst_global = '/var/run/hostapd-fst-global'
108 self.wsup_fst_global = '/tmp/fststa'
111 self.reg_ctrl = fst_test_common.HapdRegCtrl()
112 self.test_is_supported()
118 def test_is_supported():
119 h = hostapd.HostapdGlobal()
120 resp = h.request("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
121 if not resp.startswith("OK"):
122 raise utils.HwsimSkip("FST not supported")
123 w = wpasupplicant.WpaSupplicant(global_iface='/tmp/wpas-wlan5')
124 resp = w.global_request("FST-MANAGER TEST_REQUEST IS_SUPPORTED")
125 if not resp.startswith("OK"):
126 raise utils.HwsimSkip("FST not supported")
128 def get_cfg_pathname(self, cfg):
129 """Returns pathname of ifname based configuration file"""
130 return self.fst_logpath +'/'+ cfg.ifname() + '.conf'
132 def add_cfg(self, cfg):
133 """Adds configuration to be used for launching hostapd/wpa_supplicant
135 if cfg not in self.cfgs_to_run:
136 self.cfgs_to_run.append(cfg)
137 if cfg.is_ap() == True:
142 def remove_cfg(self, cfg):
143 """Removes configuration previously added with add_cfg"""
144 if cfg in self.cfgs_to_run:
145 self.cfgs_to_run.remove(cfg)
146 if cfg.is_ap() == True:
150 config_file = self.get_cfg_pathname(cfg)
151 if os.path.exists(config_file):
152 os.remove(config_file)
154 def run_hostapd(self):
155 """Lauches hostapd with interfaces configured according to
156 FstLauncherConfigAP configurations added"""
157 if self.nof_aps == 0:
158 raise Exception("No FST APs to start")
159 pidfile = self.fst_logpath + '/' + 'myhostapd.pid'
160 mylogfile = self.fst_logpath + '/' + 'fst-hostapd'
161 prg = os.path.join(self.fst_logpath,
162 'alt-hostapd/hostapd/hostapd')
163 if not os.path.exists(prg):
164 prg = '../../hostapd/hostapd'
165 cmd = [ prg, '-B', '-dddt',
166 '-P', pidfile, '-f', mylogfile, '-g', self.hapd_fst_global]
167 for i in range(0, len(self.cfgs_to_run)):
168 cfg = self.cfgs_to_run[i]
169 if cfg.is_ap() == True:
170 cfgfile = self.get_cfg_pathname(cfg)
173 self.reg_ctrl.add_ap(cfg.ifname(), cfg.get_channel())
174 self.logger.debug("Starting fst hostapd: " + ' '.join(cmd))
175 res = subprocess.call(cmd)
176 self.logger.debug("fst hostapd start result: %d" % res)
178 self.reg_ctrl.start()
181 def run_wpa_supplicant(self):
182 """Lauches wpa_supplicant with interfaces configured according to
183 FstLauncherConfigSTA configurations added"""
184 if self.nof_stas == 0:
185 raise Exception("No FST STAs to start")
186 pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
187 mylogfile = self.fst_logpath + '/' + 'fst-wpa_supplicant'
188 prg = os.path.join(self.fst_logpath,
189 'alt-wpa_supplicant/wpa_supplicant/wpa_supplicant')
190 if not os.path.exists(prg):
191 prg = '../../wpa_supplicant/wpa_supplicant'
192 cmd = [ prg, '-B', '-dddt',
193 '-P' + pidfile, '-f', mylogfile, '-g', self.wsup_fst_global ]
195 for i in range(0, len(self.cfgs_to_run)):
196 cfg = self.cfgs_to_run[i]
197 if cfg.is_ap() == False:
198 cfgfile = self.get_cfg_pathname(cfg)
200 cmd.append('-c' + cfgfile)
201 cmd.append('-i' + cfg.ifname())
202 cmd.append('-Dnl80211')
203 if sta_no != self.nof_stas -1:
204 cmd.append('-N') # Next station configuration
206 self.logger.debug("Starting fst supplicant: " + ' '.join(cmd))
207 res = subprocess.call(cmd)
208 self.logger.debug("fst supplicant start result: %d" % res)
212 """Terminates hostapd/wpa_supplicant processes previously launched with
213 run_hostapd/run_wpa_supplicant"""
214 pidfile = self.fst_logpath + '/' + 'myhostapd.pid'
215 self.kill_pid(pidfile, self.nof_aps > 0)
216 pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
217 self.kill_pid(pidfile, self.nof_stas > 0)
219 while len(self.cfgs_to_run) != 0:
220 cfg = self.cfgs_to_run[0]
223 def kill_pid(self, pidfile, try_again=False):
224 """Kills process by PID file"""
225 if not os.path.exists(pidfile):
228 # It might take some time for the process to write the PID file,
229 # so wait a bit longer before giving up.
230 self.logger.info("kill_pid: pidfile %s does not exist - try again after a second" % pidfile)
232 if not os.path.exists(pidfile):
233 self.logger.info("kill_pid: pidfile %s does not exist - could not kill the process" % pidfile)
238 pf = file(pidfile, 'r')
239 pidtxt = pf.read().strip()
240 self.logger.debug("kill_pid: %s: '%s'" % (pidfile, pidtxt))
246 self.logger.debug("kill_pid: No valid PID found: %s" % str(e))
248 self.logger.debug("kill_pid %s --> pid %d" % (pidfile, pid))
249 os.kill(pid, signal.SIGTERM)
252 # Poll the pid (Is the process still existing?)
257 # Wait and check again
260 self.logger.debug("Didn't stop the pid=%d. Was it stopped already? (%s)" % (pid, str(e)))
263 def parse_ies(iehex, el=-1):
264 """Parses the information elements hex string 'iehex' in format
265 "0a0b0c0d0e0f". If no 'el' defined just checks the IE string for integrity.
266 If 'el' is defined returns the list of hex values of the specific IE (or
267 empty list if the element is not in the string."""
268 iel = [iehex[i:i + 2] for i in range(0, len(iehex), 2)]
269 for i in range(0, len(iel)):
270 iel[i] = int(iel[i], 16)
275 logger.debug("IE found: %x" % iel[i])
276 if el != -1 and el == iel[i]:
277 res = iel[i + 2:i + 2 + iel[i + 1]]
280 logger.error("Bad IE string: " + iehex)
284 def scan_and_get_bss(dev, frq):
285 """Issues a scan on given device on given frequency, returns the bss info
286 dictionary ('ssid','ie','flags', etc.) or None. Note, the function
287 implies there is only one AP on the given channel. If not a case,
288 the function must be changed to call dev.get_bss() till the AP with the
289 [b]ssid that we need is found"""
291 return dev.get_bss('0')
294 # AP configuration tests
296 def run_test_ap_configuration(apdev, test_params,
297 fst_group = fst_test_common.fst_test_def_group,
298 fst_pri = fst_test_common.fst_test_def_prio_high,
299 fst_llt = fst_test_common.fst_test_def_llt):
300 """Runs FST hostapd where the 1st AP configuration is fixed, the 2nd fst
301 configuration is provided by the parameters. Returns the result of the run:
302 0 - no errors discovered, an error otherwise. The function is used for
303 simplek "bad configuration" tests."""
304 logdir = test_params['logdir']
305 fst_launcher = FstLauncher(logdir)
306 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_goodconf', 'a',
307 fst_test_common.fst_test_def_chan_a,
308 fst_test_common.fst_test_def_group,
309 fst_test_common.fst_test_def_prio_low,
310 fst_test_common.fst_test_def_llt)
311 ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_badconf', 'b',
312 fst_test_common.fst_test_def_chan_g, fst_group,
314 fst_launcher.add_cfg(ap1)
315 fst_launcher.add_cfg(ap2)
316 res = fst_launcher.run_hostapd()
319 def run_test_sta_configuration(test_params,
320 fst_group = fst_test_common.fst_test_def_group,
321 fst_pri = fst_test_common.fst_test_def_prio_high,
322 fst_llt = fst_test_common.fst_test_def_llt):
323 """Runs FST wpa_supplicant where the 1st STA configuration is fixed, the
324 2nd fst configuration is provided by the parameters. Returns the result of
325 the run: 0 - no errors discovered, an error otherwise. The function is used
326 for simple "bad configuration" tests."""
327 logdir = test_params['logdir']
328 fst_launcher = FstLauncher(logdir)
329 sta1 = FstLauncherConfigSTA('wlan5',
330 fst_test_common.fst_test_def_group,
331 fst_test_common.fst_test_def_prio_low,
332 fst_test_common.fst_test_def_llt)
333 sta2 = FstLauncherConfigSTA('wlan6', fst_group, fst_pri, fst_llt)
334 fst_launcher.add_cfg(sta1)
335 fst_launcher.add_cfg(sta2)
336 res = fst_launcher.run_wpa_supplicant()
339 def test_fst_ap_config_llt_neg(dev, apdev, test_params):
340 """FST AP configuration negative LLT"""
341 res = run_test_ap_configuration(apdev, test_params, fst_llt = '-1')
343 raise Exception("hostapd started with a negative llt")
345 def test_fst_ap_config_llt_zero(dev, apdev, test_params):
346 """FST AP configuration zero LLT"""
347 res = run_test_ap_configuration(apdev, test_params, fst_llt = '0')
349 raise Exception("hostapd started with a zero llt")
351 def test_fst_ap_config_llt_too_big(dev, apdev, test_params):
352 """FST AP configuration LLT is too big"""
353 res = run_test_ap_configuration(apdev, test_params,
354 fst_llt = '4294967296') #0x100000000
356 raise Exception("hostapd started with llt that is too big")
358 def test_fst_ap_config_llt_nan(dev, apdev, test_params):
359 """FST AP configuration LLT is not a number"""
360 res = run_test_ap_configuration(apdev, test_params, fst_llt = 'nan')
362 raise Exception("hostapd started with llt not a number")
364 def test_fst_ap_config_pri_neg(dev, apdev, test_params):
365 """FST AP configuration Priority negative"""
366 res = run_test_ap_configuration(apdev, test_params, fst_pri = '-1')
368 raise Exception("hostapd started with a negative fst priority")
370 def test_fst_ap_config_pri_zero(dev, apdev, test_params):
371 """FST AP configuration Priority zero"""
372 res = run_test_ap_configuration(apdev, test_params, fst_pri = '0')
374 raise Exception("hostapd started with a zero fst priority")
376 def test_fst_ap_config_pri_large(dev, apdev, test_params):
377 """FST AP configuration Priority too large"""
378 res = run_test_ap_configuration(apdev, test_params, fst_pri = '256')
380 raise Exception("hostapd started with too large fst priority")
382 def test_fst_ap_config_pri_nan(dev, apdev, test_params):
383 """FST AP configuration Priority not a number"""
384 res = run_test_ap_configuration(apdev, test_params, fst_pri = 'nan')
386 raise Exception("hostapd started with fst priority not a number")
388 def test_fst_ap_config_group_len(dev, apdev, test_params):
389 """FST AP configuration Group max length"""
390 res = run_test_ap_configuration(apdev, test_params,
391 fst_group = 'fstg5678abcd34567')
393 raise Exception("hostapd started with fst_group length too big")
395 def test_fst_ap_config_good(dev, apdev, test_params):
396 """FST AP configuration good parameters"""
397 res = run_test_ap_configuration(apdev, test_params)
399 raise Exception("hostapd didn't start with valid config parameters")
401 def test_fst_ap_config_default(dev, apdev, test_params):
402 """FST AP configuration default parameters"""
403 res = run_test_ap_configuration(apdev, test_params, fst_llt = None)
405 raise Exception("hostapd didn't start with valid config parameters")
408 # STA configuration tests
410 def test_fst_sta_config_llt_neg(dev, apdev, test_params):
411 """FST STA configuration negative LLT"""
412 res = run_test_sta_configuration(test_params, fst_llt = '-1')
414 raise Exception("wpa_supplicant started with a negative llt")
416 def test_fst_sta_config_llt_zero(dev, apdev, test_params):
417 """FST STA configuration zero LLT"""
418 res = run_test_sta_configuration(test_params, fst_llt = '0')
420 raise Exception("wpa_supplicant started with a zero llt")
422 def test_fst_sta_config_llt_large(dev, apdev, test_params):
423 """FST STA configuration LLT is too large"""
424 res = run_test_sta_configuration(test_params,
425 fst_llt = '4294967296') #0x100000000
427 raise Exception("wpa_supplicant started with llt that is too large")
429 def test_fst_sta_config_llt_nan(dev, apdev, test_params):
430 """FST STA configuration LLT is not a number"""
431 res = run_test_sta_configuration(test_params, fst_llt = 'nan')
433 raise Exception("wpa_supplicant started with llt not a number")
435 def test_fst_sta_config_pri_neg(dev, apdev, test_params):
436 """FST STA configuration Priority negative"""
437 res = run_test_sta_configuration(test_params, fst_pri = '-1')
439 raise Exception("wpa_supplicant started with a negative fst priority")
441 def test_fst_sta_config_pri_zero(dev, apdev, test_params):
442 """FST STA configuration Priority zero"""
443 res = run_test_sta_configuration(test_params, fst_pri = '0')
445 raise Exception("wpa_supplicant started with a zero fst priority")
447 def test_fst_sta_config_pri_big(dev, apdev, test_params):
448 """FST STA configuration Priority too large"""
449 res = run_test_sta_configuration(test_params, fst_pri = '256')
451 raise Exception("wpa_supplicant started with too large fst priority")
453 def test_fst_sta_config_pri_nan(dev, apdev, test_params):
454 """FST STA configuration Priority not a number"""
455 res = run_test_sta_configuration(test_params, fst_pri = 'nan')
457 raise Exception("wpa_supplicant started with fst priority not a number")
459 def test_fst_sta_config_group_len(dev, apdev, test_params):
460 """FST STA configuration Group max length"""
461 res = run_test_sta_configuration(test_params,
462 fst_group = 'fstg5678abcd34567')
464 raise Exception("wpa_supplicant started with fst_group length too big")
466 def test_fst_sta_config_good(dev, apdev, test_params):
467 """FST STA configuration good parameters"""
468 res = run_test_sta_configuration(test_params)
470 raise Exception("wpa_supplicant didn't start with valid config parameters")
472 def test_fst_sta_config_default(dev, apdev, test_params):
473 """FST STA configuration default parameters"""
474 res = run_test_sta_configuration(test_params, fst_llt = None)
476 raise Exception("wpa_supplicant didn't start with valid config parameters")
478 def test_fst_scan_mb(dev, apdev, test_params):
479 """FST scan valid MB IE presence with normal start"""
480 logdir = test_params['logdir']
482 # Test valid MB IE in scan results
483 fst_launcher = FstLauncher(logdir)
484 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
485 fst_test_common.fst_test_def_chan_a,
486 fst_test_common.fst_test_def_group,
487 fst_test_common.fst_test_def_prio_high)
488 ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_11g', 'b',
489 fst_test_common.fst_test_def_chan_g,
490 fst_test_common.fst_test_def_group,
491 fst_test_common.fst_test_def_prio_low)
492 fst_launcher.add_cfg(ap1)
493 fst_launcher.add_cfg(ap2)
494 res = fst_launcher.run_hostapd()
496 raise Exception("hostapd didn't start properly")
503 vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
506 mbie1 = parse_ies(vals1['ie'], 0x9e)
508 flags1 = vals1['flags']
510 vals2 = scan_and_get_bss(dev[2], fst_test_common.fst_test_def_freq_g)
513 mbie2 = parse_ies(vals2['ie'],0x9e)
515 flags2 = vals2['flags']
517 fst_launcher.cleanup()
520 raise Exception("No MB IE created by 1st AP")
522 raise Exception("No MB IE created by 2nd AP")
524 def test_fst_scan_nomb(dev, apdev, test_params):
525 """FST scan no MB IE presence with 1 AP start"""
526 logdir = test_params['logdir']
528 # Test valid MB IE in scan results
529 fst_launcher = FstLauncher(logdir)
530 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
531 fst_test_common.fst_test_def_chan_a,
532 fst_test_common.fst_test_def_group,
533 fst_test_common.fst_test_def_prio_high)
534 fst_launcher.add_cfg(ap1)
535 res = fst_launcher.run_hostapd()
537 raise Exception("Hostapd didn't start properly")
542 vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
545 mbie1 = parse_ies(vals1['ie'], 0x9e)
547 flags1 = vals1['flags']
549 fst_launcher.cleanup()
552 raise Exception("MB IE exists with 1 AP")