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', '-ddd',
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', '-ddd',
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)
216 pidfile = self.fst_logpath + '/' + 'mywpa_supplicant.pid'
217 self.kill_pid(pidfile)
219 while len(self.cfgs_to_run) != 0:
220 cfg = self.cfgs_to_run[0]
223 def kill_pid(self, pidfile):
224 """Kills process by PID file"""
225 if not os.path.exists(pidfile):
229 pf = file(pidfile, 'r')
230 pid = int(pf.read().strip())
232 self.logger.debug("kill_pid %s --> pid %d" % (pidfile, pid))
233 os.kill(pid, signal.SIGTERM)
236 # Poll the pid (Is the process still existing?)
241 # Wait and check again
244 self.logger.debug("Didn't stop the pid=%d. Was it stopped already? (%s)" % (pid, str(e)))
247 def parse_ies(iehex, el=-1):
248 """Parses the information elements hex string 'iehex' in format
249 "0a0b0c0d0e0f". If no 'el' defined just checks the IE string for integrity.
250 If 'el' is defined returns the list of hex values of the specific IE (or
251 empty list if the element is not in the string."""
252 iel = [iehex[i:i + 2] for i in range(0, len(iehex), 2)]
253 for i in range(0, len(iel)):
254 iel[i] = int(iel[i], 16)
259 logger.debug("IE found: %x" % iel[i])
260 if el != -1 and el == iel[i]:
261 res = iel[i + 2:i + 2 + iel[i + 1]]
264 logger.error("Bad IE string: " + iehex)
268 def scan_and_get_bss(dev, frq):
269 """Issues a scan on given device on given frequency, returns the bss info
270 dictionary ('ssid','ie','flags', etc.) or None. Note, the function
271 implies there is only one AP on the given channel. If not a case,
272 the function must be changed to call dev.get_bss() till the AP with the
273 [b]ssid that we need is found"""
275 return dev.get_bss('0')
278 # AP configuration tests
280 def run_test_ap_configuration(apdev, test_params,
281 fst_group = fst_test_common.fst_test_def_group,
282 fst_pri = fst_test_common.fst_test_def_prio_high,
283 fst_llt = fst_test_common.fst_test_def_llt):
284 """Runs FST hostapd where the 1st AP configuration is fixed, the 2nd fst
285 configuration is provided by the parameters. Returns the result of the run:
286 0 - no errors discovered, an error otherwise. The function is used for
287 simplek "bad configuration" tests."""
288 logdir = test_params['logdir']
289 fst_launcher = FstLauncher(logdir)
290 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_goodconf', 'a',
291 fst_test_common.fst_test_def_chan_a,
292 fst_test_common.fst_test_def_group,
293 fst_test_common.fst_test_def_prio_low,
294 fst_test_common.fst_test_def_llt)
295 ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_badconf', 'b',
296 fst_test_common.fst_test_def_chan_g, fst_group,
298 fst_launcher.add_cfg(ap1)
299 fst_launcher.add_cfg(ap2)
300 res = fst_launcher.run_hostapd()
303 def run_test_sta_configuration(test_params,
304 fst_group = fst_test_common.fst_test_def_group,
305 fst_pri = fst_test_common.fst_test_def_prio_high,
306 fst_llt = fst_test_common.fst_test_def_llt):
307 """Runs FST wpa_supplicant where the 1st STA configuration is fixed, the
308 2nd fst configuration is provided by the parameters. Returns the result of
309 the run: 0 - no errors discovered, an error otherwise. The function is used
310 for simple "bad configuration" tests."""
311 logdir = test_params['logdir']
312 fst_launcher = FstLauncher(logdir)
313 sta1 = FstLauncherConfigSTA('wlan5',
314 fst_test_common.fst_test_def_group,
315 fst_test_common.fst_test_def_prio_low,
316 fst_test_common.fst_test_def_llt)
317 sta2 = FstLauncherConfigSTA('wlan6', fst_group, fst_pri, fst_llt)
318 fst_launcher.add_cfg(sta1)
319 fst_launcher.add_cfg(sta2)
320 res = fst_launcher.run_wpa_supplicant()
323 def test_fst_ap_config_llt_neg(dev, apdev, test_params):
324 """FST AP configuration negative LLT"""
325 res = run_test_ap_configuration(apdev, test_params, fst_llt = '-1')
327 raise Exception("hostapd started with a negative llt")
329 def test_fst_ap_config_llt_zero(dev, apdev, test_params):
330 """FST AP configuration zero LLT"""
331 res = run_test_ap_configuration(apdev, test_params, fst_llt = '0')
333 raise Exception("hostapd started with a zero llt")
335 def test_fst_ap_config_llt_too_big(dev, apdev, test_params):
336 """FST AP configuration LLT is too big"""
337 res = run_test_ap_configuration(apdev, test_params,
338 fst_llt = '4294967296') #0x100000000
340 raise Exception("hostapd started with llt that is too big")
342 def test_fst_ap_config_llt_nan(dev, apdev, test_params):
343 """FST AP configuration LLT is not a number"""
344 res = run_test_ap_configuration(apdev, test_params, fst_llt = 'nan')
346 raise Exception("hostapd started with llt not a number")
348 def test_fst_ap_config_pri_neg(dev, apdev, test_params):
349 """FST AP configuration Priority negative"""
350 res = run_test_ap_configuration(apdev, test_params, fst_pri = '-1')
352 raise Exception("hostapd started with a negative fst priority")
354 def test_fst_ap_config_pri_zero(dev, apdev, test_params):
355 """FST AP configuration Priority zero"""
356 res = run_test_ap_configuration(apdev, test_params, fst_pri = '0')
358 raise Exception("hostapd started with a zero fst priority")
360 def test_fst_ap_config_pri_large(dev, apdev, test_params):
361 """FST AP configuration Priority too large"""
362 res = run_test_ap_configuration(apdev, test_params, fst_pri = '256')
364 raise Exception("hostapd started with too large fst priority")
366 def test_fst_ap_config_pri_nan(dev, apdev, test_params):
367 """FST AP configuration Priority not a number"""
368 res = run_test_ap_configuration(apdev, test_params, fst_pri = 'nan')
370 raise Exception("hostapd started with fst priority not a number")
372 def test_fst_ap_config_group_len(dev, apdev, test_params):
373 """FST AP configuration Group max length"""
374 res = run_test_ap_configuration(apdev, test_params,
375 fst_group = 'fstg5678abcd34567')
377 raise Exception("hostapd started with fst_group length too big")
379 def test_fst_ap_config_good(dev, apdev, test_params):
380 """FST AP configuration good parameters"""
381 res = run_test_ap_configuration(apdev, test_params)
383 raise Exception("hostapd didn't start with valid config parameters")
385 def test_fst_ap_config_default(dev, apdev, test_params):
386 """FST AP configuration default parameters"""
387 res = run_test_ap_configuration(apdev, test_params, fst_llt = None)
389 raise Exception("hostapd didn't start with valid config parameters")
392 # STA configuration tests
394 def test_fst_sta_config_llt_neg(dev, apdev, test_params):
395 """FST STA configuration negative LLT"""
396 res = run_test_sta_configuration(test_params, fst_llt = '-1')
398 raise Exception("wpa_supplicant started with a negative llt")
400 def test_fst_sta_config_llt_zero(dev, apdev, test_params):
401 """FST STA configuration zero LLT"""
402 res = run_test_sta_configuration(test_params, fst_llt = '0')
404 raise Exception("wpa_supplicant started with a zero llt")
406 def test_fst_sta_config_llt_large(dev, apdev, test_params):
407 """FST STA configuration LLT is too large"""
408 res = run_test_sta_configuration(test_params,
409 fst_llt = '4294967296') #0x100000000
411 raise Exception("wpa_supplicant started with llt that is too large")
413 def test_fst_sta_config_llt_nan(dev, apdev, test_params):
414 """FST STA configuration LLT is not a number"""
415 res = run_test_sta_configuration(test_params, fst_llt = 'nan')
417 raise Exception("wpa_supplicant started with llt not a number")
419 def test_fst_sta_config_pri_neg(dev, apdev, test_params):
420 """FST STA configuration Priority negative"""
421 res = run_test_sta_configuration(test_params, fst_pri = '-1')
423 raise Exception("wpa_supplicant started with a negative fst priority")
425 def test_fst_sta_config_pri_zero(dev, apdev, test_params):
426 """FST STA configuration Priority zero"""
427 res = run_test_sta_configuration(test_params, fst_pri = '0')
429 raise Exception("wpa_supplicant started with a zero fst priority")
431 def test_fst_sta_config_pri_big(dev, apdev, test_params):
432 """FST STA configuration Priority too large"""
433 res = run_test_sta_configuration(test_params, fst_pri = '256')
435 raise Exception("wpa_supplicant started with too large fst priority")
437 def test_fst_sta_config_pri_nan(dev, apdev, test_params):
438 """FST STA configuration Priority not a number"""
439 res = run_test_sta_configuration(test_params, fst_pri = 'nan')
441 raise Exception("wpa_supplicant started with fst priority not a number")
443 def test_fst_sta_config_group_len(dev, apdev, test_params):
444 """FST STA configuration Group max length"""
445 res = run_test_sta_configuration(test_params,
446 fst_group = 'fstg5678abcd34567')
448 raise Exception("wpa_supplicant started with fst_group length too big")
450 def test_fst_sta_config_good(dev, apdev, test_params):
451 """FST STA configuration good parameters"""
452 res = run_test_sta_configuration(test_params)
454 raise Exception("wpa_supplicant didn't start with valid config parameters")
456 def test_fst_sta_config_default(dev, apdev, test_params):
457 """FST STA configuration default parameters"""
458 res = run_test_sta_configuration(test_params, fst_llt = None)
460 raise Exception("wpa_supplicant didn't start with valid config parameters")
462 def test_fst_scan_mb(dev, apdev, test_params):
463 """FST scan valid MB IE presence with normal start"""
464 logdir = test_params['logdir']
466 # Test valid MB IE in scan results
467 fst_launcher = FstLauncher(logdir)
468 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
469 fst_test_common.fst_test_def_chan_a,
470 fst_test_common.fst_test_def_group,
471 fst_test_common.fst_test_def_prio_high)
472 ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_11g', 'b',
473 fst_test_common.fst_test_def_chan_g,
474 fst_test_common.fst_test_def_group,
475 fst_test_common.fst_test_def_prio_low)
476 fst_launcher.add_cfg(ap1)
477 fst_launcher.add_cfg(ap2)
478 res = fst_launcher.run_hostapd()
480 raise Exception("hostapd didn't start properly")
487 vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
490 mbie1 = parse_ies(vals1['ie'], 0x9e)
492 flags1 = vals1['flags']
494 vals2 = scan_and_get_bss(dev[2], fst_test_common.fst_test_def_freq_g)
497 mbie2 = parse_ies(vals2['ie'],0x9e)
499 flags2 = vals2['flags']
501 fst_launcher.cleanup()
504 raise Exception("No MB IE created by 1st AP")
506 raise Exception("No MB IE created by 2nd AP")
508 def test_fst_scan_nomb(dev, apdev, test_params):
509 """FST scan no MB IE presence with 1 AP start"""
510 logdir = test_params['logdir']
512 # Test valid MB IE in scan results
513 fst_launcher = FstLauncher(logdir)
514 ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
515 fst_test_common.fst_test_def_chan_a,
516 fst_test_common.fst_test_def_group,
517 fst_test_common.fst_test_def_prio_high)
518 fst_launcher.add_cfg(ap1)
519 res = fst_launcher.run_hostapd()
521 raise Exception("Hostapd didn't start properly")
526 vals1 = scan_and_get_bss(dev[0], fst_test_common.fst_test_def_freq_a)
529 mbie1 = parse_ies(vals1['ie'], 0x9e)
531 flags1 = vals1['flags']
533 fst_launcher.cleanup()
536 raise Exception("MB IE exists with 1 AP")