tests: Pass full apdev to add_ap() function (7)
[mech_eap.git] / tests / hwsim / test_ap_dynamic.py
1 # Test cases for dynamic BSS changes with hostapd
2 # Copyright (c) 2013, Qualcomm Atheros, Inc.
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import time
8 import subprocess
9 import logging
10 logger = logging.getLogger()
11 import os
12
13 import hwsim_utils
14 import hostapd
15 from utils import alloc_fail
16 from test_ap_acs import force_prev_ap_on_24g
17
18 def test_ap_change_ssid(dev, apdev):
19     """Dynamic SSID change with hostapd and WPA2-PSK"""
20     params = hostapd.wpa2_params(ssid="test-wpa2-psk-start",
21                                  passphrase="12345678")
22     hostapd.add_ap(apdev[0], params)
23     id = dev[0].connect("test-wpa2-psk-start", psk="12345678",
24                         scan_freq="2412")
25     dev[0].request("DISCONNECT")
26
27     logger.info("Change SSID dynamically")
28     hapd = hostapd.Hostapd(apdev[0]['ifname'])
29     res = hapd.request("SET ssid test-wpa2-psk-new")
30     if "OK" not in res:
31         raise Exception("SET command failed")
32     res = hapd.request("RELOAD")
33     if "OK" not in res:
34         raise Exception("RELOAD command failed")
35
36     dev[0].set_network_quoted(id, "ssid", "test-wpa2-psk-new")
37     dev[0].connect_network(id)
38
39 def multi_check(dev, check, scan_opt=True):
40     id = []
41     num_bss = len(check)
42     for i in range(0, num_bss):
43         dev[i].request("BSS_FLUSH 0")
44         dev[i].dump_monitor()
45     for i in range(0, num_bss):
46         if check[i]:
47             continue
48         id.append(dev[i].connect("bss-" + str(i + 1), key_mgmt="NONE",
49                                  scan_freq="2412", wait_connect=False))
50     for i in range(num_bss):
51         if not check[i]:
52             continue
53         bssid = '02:00:00:00:03:0' + str(i)
54         if scan_opt:
55             dev[i].scan_for_bss(bssid, freq=2412)
56         id.append(dev[i].connect("bss-" + str(i + 1), key_mgmt="NONE",
57                                  scan_freq="2412", wait_connect=True))
58     first = True
59     for i in range(num_bss):
60         if not check[i]:
61             timeout=0.2 if first else 0.01
62             first = False
63             ev = dev[i].wait_event(["CTRL-EVENT-CONNECTED"], timeout=timeout)
64             if ev:
65                 raise Exception("Unexpected connection")
66
67     for i in range(0, num_bss):
68         dev[i].remove_network(id[i])
69     for i in range(num_bss):
70         if check[i]:
71             dev[i].wait_disconnected(timeout=5)
72
73     res = ''
74     for i in range(0, num_bss):
75         res = res + dev[i].request("BSS RANGE=ALL MASK=0x2")
76
77     for i in range(0, num_bss):
78         if not check[i]:
79             bssid = '02:00:00:00:03:0' + str(i)
80             if bssid in res:
81                 raise Exception("Unexpected BSS" + str(i) + " in scan results")
82
83 def test_ap_bss_add_remove(dev, apdev):
84     """Dynamic BSS add/remove operations with hostapd"""
85     try:
86         _test_ap_bss_add_remove(dev, apdev)
87     finally:
88         for i in range(3):
89             dev[i].request("SCAN_INTERVAL 5")
90
91 def _test_ap_bss_add_remove(dev, apdev):
92     for i in range(3):
93         dev[i].flush_scan_cache()
94         dev[i].request("SCAN_INTERVAL 1")
95     ifname1 = apdev[0]['ifname']
96     ifname2 = apdev[0]['ifname'] + '-2'
97     ifname3 = apdev[0]['ifname'] + '-3'
98     logger.info("Set up three BSSes one by one")
99     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
100     multi_check(dev, [ True, False, False ])
101     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
102     multi_check(dev, [ True, True, False ])
103     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
104     multi_check(dev, [ True, True, True ])
105
106     logger.info("Remove the last BSS and re-add it")
107     hostapd.remove_bss(ifname3)
108     multi_check(dev, [ True, True, False ])
109     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
110     multi_check(dev, [ True, True, True ])
111
112     logger.info("Remove the middle BSS and re-add it")
113     hostapd.remove_bss(ifname2)
114     multi_check(dev, [ True, False, True ])
115     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
116     multi_check(dev, [ True, True, True ])
117
118     logger.info("Remove the first BSS and re-add it and other BSSs")
119     hostapd.remove_bss(ifname1)
120     multi_check(dev, [ False, False, False ])
121     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
122     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
123     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
124     multi_check(dev, [ True, True, True ])
125
126     logger.info("Remove two BSSes and re-add them")
127     hostapd.remove_bss(ifname2)
128     multi_check(dev, [ True, False, True ])
129     hostapd.remove_bss(ifname3)
130     multi_check(dev, [ True, False, False ])
131     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
132     multi_check(dev, [ True, True, False ])
133     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
134     multi_check(dev, [ True, True, True ])
135
136     logger.info("Remove three BSSes in and re-add them")
137     hostapd.remove_bss(ifname3)
138     multi_check(dev, [ True, True, False ])
139     hostapd.remove_bss(ifname2)
140     multi_check(dev, [ True, False, False ])
141     hostapd.remove_bss(ifname1)
142     multi_check(dev, [ False, False, False ])
143     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
144     multi_check(dev, [ True, False, False ])
145     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
146     multi_check(dev, [ True, True, False ])
147     hostapd.add_bss('phy3', ifname3, 'bss-3.conf')
148     multi_check(dev, [ True, True, True ])
149
150     logger.info("Test error handling if a duplicate ifname is tried")
151     hostapd.add_bss('phy3', ifname3, 'bss-3.conf', ignore_error=True)
152     multi_check(dev, [ True, True, True ])
153
154 def test_ap_bss_add_remove_during_ht_scan(dev, apdev):
155     """Dynamic BSS add during HT40 co-ex scan"""
156     for i in range(3):
157         dev[i].flush_scan_cache()
158     ifname1 = apdev[0]['ifname']
159     ifname2 = apdev[0]['ifname'] + '-2'
160     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
161     hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
162     multi_check(dev, [ True, True ], scan_opt=False)
163     hostapd.remove_bss(ifname2)
164     hostapd.remove_bss(ifname1)
165
166     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
167     hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
168     hostapd.remove_bss(ifname2)
169     multi_check(dev, [ True, False ], scan_opt=False)
170     hostapd.remove_bss(ifname1)
171
172     hostapd.add_bss('phy3', ifname1, 'bss-ht40-1.conf')
173     hostapd.add_bss('phy3', ifname2, 'bss-ht40-2.conf')
174     hostapd.remove_bss(ifname1)
175     multi_check(dev, [ False, False ])
176
177 def test_ap_multi_bss_config(dev, apdev):
178     """hostapd start with a multi-BSS configuration file"""
179     for i in range(3):
180         dev[i].flush_scan_cache()
181     ifname1 = apdev[0]['ifname']
182     ifname2 = apdev[0]['ifname'] + '-2'
183     ifname3 = apdev[0]['ifname'] + '-3'
184     logger.info("Set up three BSSes with one configuration file")
185     hostapd.add_iface(ifname1, 'multi-bss.conf')
186     hapd = hostapd.Hostapd(ifname1)
187     hapd.enable()
188     multi_check(dev, [ True, True, True ])
189     hostapd.remove_bss(ifname2)
190     multi_check(dev, [ True, False, True ])
191     hostapd.remove_bss(ifname3)
192     multi_check(dev, [ True, False, False ])
193     hostapd.remove_bss(ifname1)
194     multi_check(dev, [ False, False, False ])
195
196     hostapd.add_iface(ifname1, 'multi-bss.conf')
197     hapd = hostapd.Hostapd(ifname1)
198     hapd.enable()
199     hostapd.remove_bss(ifname1)
200     multi_check(dev, [ False, False, False ])
201
202 def invalid_ap(hapd_global, ifname):
203     logger.info("Trying to start AP " + ifname + " with invalid configuration")
204     hapd_global.remove(ifname)
205     hapd_global.add(ifname)
206     hapd = hostapd.Hostapd(ifname)
207     if not hapd.ping():
208         raise Exception("Could not ping hostapd")
209     hapd.set_defaults()
210     hapd.set("ssid", "invalid-config")
211     hapd.set("channel", "12345")
212     try:
213         hapd.enable()
214         started = True
215     except Exception, e:
216         started = False
217     if started:
218         raise Exception("ENABLE command succeeded unexpectedly")
219     return hapd
220
221 def test_ap_invalid_config(dev, apdev):
222     """Try to start AP with invalid configuration and fix configuration"""
223     hapd_global = hostapd.HostapdGlobal()
224     ifname = apdev[0]['ifname']
225     hapd = invalid_ap(hapd_global, ifname)
226
227     logger.info("Fix configuration and start AP again")
228     hapd.set("channel", "1")
229     hapd.enable()
230     dev[0].connect("invalid-config", key_mgmt="NONE", scan_freq="2412")
231
232 def test_ap_invalid_config2(dev, apdev):
233     """Try to start AP with invalid configuration and remove interface"""
234     hapd_global = hostapd.HostapdGlobal()
235     ifname = apdev[0]['ifname']
236     hapd = invalid_ap(hapd_global, ifname)
237     logger.info("Remove interface with failed configuration")
238     hapd_global.remove(ifname)
239
240 def test_ap_remove_during_acs(dev, apdev):
241     """Remove interface during ACS"""
242     force_prev_ap_on_24g(apdev[0])
243     params = hostapd.wpa2_params(ssid="test-acs-remove", passphrase="12345678")
244     params['channel'] = '0'
245     ifname = apdev[0]['ifname']
246     hapd = hostapd.HostapdGlobal()
247     hostapd.add_ap(apdev[0], params)
248     hapd.remove(ifname)
249
250 def test_ap_remove_during_acs2(dev, apdev):
251     """Remove BSS during ACS in multi-BSS configuration"""
252     force_prev_ap_on_24g(apdev[0])
253     ifname = apdev[0]['ifname']
254     ifname2 = ifname + "-2"
255     hapd_global = hostapd.HostapdGlobal()
256     hapd_global.add(ifname)
257     hapd = hostapd.Hostapd(ifname)
258     hapd.set_defaults()
259     hapd.set("ssid", "test-acs-remove")
260     hapd.set("channel", "0")
261     hapd.set("bss", ifname2)
262     hapd.set("ssid", "test-acs-remove2")
263     hapd.enable()
264     hapd_global.remove(ifname)
265
266 def test_ap_remove_during_acs3(dev, apdev):
267     """Remove second BSS during ACS in multi-BSS configuration"""
268     force_prev_ap_on_24g(apdev[0])
269     ifname = apdev[0]['ifname']
270     ifname2 = ifname + "-2"
271     hapd_global = hostapd.HostapdGlobal()
272     hapd_global.add(ifname)
273     hapd = hostapd.Hostapd(ifname)
274     hapd.set_defaults()
275     hapd.set("ssid", "test-acs-remove")
276     hapd.set("channel", "0")
277     hapd.set("bss", ifname2)
278     hapd.set("ssid", "test-acs-remove2")
279     hapd.enable()
280     hapd_global.remove(ifname2)
281
282 def test_ap_remove_during_ht_coex_scan(dev, apdev):
283     """Remove interface during HT co-ex scan"""
284     params = hostapd.wpa2_params(ssid="test-ht-remove", passphrase="12345678")
285     params['channel'] = '1'
286     params['ht_capab'] = "[HT40+]"
287     ifname = apdev[0]['ifname']
288     hapd = hostapd.HostapdGlobal()
289     hostapd.add_ap(apdev[0], params)
290     hapd.remove(ifname)
291
292 def test_ap_remove_during_ht_coex_scan2(dev, apdev):
293     """Remove BSS during HT co-ex scan in multi-BSS configuration"""
294     ifname = apdev[0]['ifname']
295     ifname2 = ifname + "-2"
296     hapd_global = hostapd.HostapdGlobal()
297     hapd_global.add(ifname)
298     hapd = hostapd.Hostapd(ifname)
299     hapd.set_defaults()
300     hapd.set("ssid", "test-ht-remove")
301     hapd.set("channel", "1")
302     hapd.set("ht_capab", "[HT40+]")
303     hapd.set("bss", ifname2)
304     hapd.set("ssid", "test-ht-remove2")
305     hapd.enable()
306     hapd_global.remove(ifname)
307
308 def test_ap_remove_during_ht_coex_scan3(dev, apdev):
309     """Remove second BSS during HT co-ex scan in multi-BSS configuration"""
310     ifname = apdev[0]['ifname']
311     ifname2 = ifname + "-2"
312     hapd_global = hostapd.HostapdGlobal()
313     hapd_global.add(ifname)
314     hapd = hostapd.Hostapd(ifname)
315     hapd.set_defaults()
316     hapd.set("ssid", "test-ht-remove")
317     hapd.set("channel", "1")
318     hapd.set("ht_capab", "[HT40+]")
319     hapd.set("bss", ifname2)
320     hapd.set("ssid", "test-ht-remove2")
321     hapd.enable()
322     hapd_global.remove(ifname2)
323
324 def test_ap_enable_disable_reenable(dev, apdev):
325     """Enable, disable, re-enable AP"""
326     ifname = apdev[0]['ifname']
327     hapd_global = hostapd.HostapdGlobal()
328     hapd_global.add(ifname)
329     hapd = hostapd.Hostapd(ifname)
330     hapd.set_defaults()
331     hapd.set("ssid", "dynamic")
332     hapd.enable()
333     ev = hapd.wait_event(["AP-ENABLED"], timeout=30)
334     if ev is None:
335         raise Exception("AP startup timed out")
336     dev[0].connect("dynamic", key_mgmt="NONE", scan_freq="2412")
337     hapd.disable()
338     ev = hapd.wait_event(["AP-DISABLED"], timeout=30)
339     if ev is None:
340         raise Exception("AP disabling timed out")
341     dev[0].wait_disconnected(timeout=10)
342     hapd.enable()
343     ev = hapd.wait_event(["AP-ENABLED"], timeout=30)
344     if ev is None:
345         raise Exception("AP startup timed out")
346     dev[1].connect("dynamic", key_mgmt="NONE", scan_freq="2412")
347     dev[0].wait_connected(timeout=10)
348
349 def test_ap_double_disable(dev, apdev):
350     """Double DISABLE regression test"""
351     hostapd.add_bss('phy3', apdev[0]['ifname'], 'bss-1.conf')
352     hostapd.add_bss('phy3', apdev[0]['ifname'] + '-2', 'bss-2.conf')
353     hapd = hostapd.Hostapd(apdev[0]['ifname'])
354     hapd.disable()
355     if "FAIL" not in hapd.request("DISABLE"):
356         raise Exception("Second DISABLE accepted unexpectedly")
357     hapd.enable()
358     hapd.disable()
359     if "FAIL" not in hapd.request("DISABLE"):
360         raise Exception("Second DISABLE accepted unexpectedly")
361
362 def test_ap_bss_add_many(dev, apdev):
363     """Large number of BSS add operations with hostapd"""
364     try:
365         _test_ap_bss_add_many(dev, apdev)
366     finally:
367         dev[0].request("SCAN_INTERVAL 5")
368         ifname = apdev[0]['ifname']
369         hapd = hostapd.HostapdGlobal()
370         hapd.flush()
371         for i in range(16):
372             ifname2 = ifname + '-' + str(i)
373             hapd.remove(ifname2)
374         try:
375             os.remove('/tmp/hwsim-bss.conf')
376         except:
377             pass
378
379 def _test_ap_bss_add_many(dev, apdev):
380     ifname = apdev[0]['ifname']
381     phy = 'phy3'
382     hostapd.add_bss(phy, ifname, 'bss-1.conf')
383     hapd = hostapd.HostapdGlobal()
384     fname = '/tmp/hwsim-bss.conf'
385     for i in range(16):
386         ifname2 = ifname + '-' + str(i)
387         with open(fname, 'w') as f:
388             f.write("driver=nl80211\n")
389             f.write("hw_mode=g\n")
390             f.write("channel=1\n")
391             f.write("ieee80211n=1\n")
392             f.write("interface=%s\n" % ifname2)
393             f.write("bssid=02:00:00:00:03:%02x\n" % (i + 1))
394             f.write("ctrl_interface=/var/run/hostapd\n")
395             f.write("ssid=test-%d\n" % i)
396         hostapd.add_bss(phy, ifname2, fname)
397         os.remove(fname)
398
399     dev[0].request("SCAN_INTERVAL 1")
400     dev[0].connect("bss-1", key_mgmt="NONE", scan_freq="2412")
401     dev[0].request("DISCONNECT")
402     dev[0].wait_disconnected(timeout=5)
403     for i in range(16):
404         dev[0].connect("test-%d" % i, key_mgmt="NONE", scan_freq="2412")
405         dev[0].request("DISCONNECT")
406         dev[0].wait_disconnected(timeout=5)
407         ifname2 = ifname + '-' + str(i)
408         hapd.remove(ifname2)
409
410 def test_ap_bss_add_reuse_existing(dev, apdev):
411     """Dynamic BSS add operation reusing existing interface"""
412     ifname1 = apdev[0]['ifname']
413     ifname2 = apdev[0]['ifname'] + '-2'
414     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
415     subprocess.check_call(["iw", "dev", ifname1, "interface", "add", ifname2,
416                            "type", "__ap"])
417     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
418     hostapd.remove_bss(ifname2)
419     subprocess.check_call(["iw", "dev", ifname2, "del"])
420
421 def hapd_bss_out_of_mem(hapd, phy, confname, count, func):
422     with alloc_fail(hapd, count, func):
423         hapd_global = hostapd.HostapdGlobal()
424         res = hapd_global.ctrl.request("ADD bss_config=" + phy + ":" + confname)
425         if "OK" in res:
426             raise Exception("add_bss succeeded")
427
428 def test_ap_bss_add_out_of_memory(dev, apdev):
429     """Running out of memory while adding a BSS"""
430     hapd2 = hostapd.add_ap(apdev[1], { "ssid": "open" })
431
432     ifname1 = apdev[0]['ifname']
433     ifname2 = apdev[0]['ifname'] + '-2'
434
435     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf', 1, 'hostapd_add_iface')
436     for i in range(1, 3):
437         hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf',
438                             i, 'hostapd_interface_init_bss')
439     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-1.conf',
440                         1, 'ieee802_11_build_ap_params')
441
442     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
443
444     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
445                         1, 'hostapd_interface_init_bss')
446     hapd_bss_out_of_mem(hapd2, 'phy3', 'bss-2.conf',
447                         1, 'ieee802_11_build_ap_params')
448
449     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
450     hostapd.remove_bss(ifname2)
451     hostapd.remove_bss(ifname1)
452
453 def test_ap_multi_bss(dev, apdev):
454     """Multiple BSSes with hostapd"""
455     ifname1 = apdev[0]['ifname']
456     ifname2 = apdev[0]['ifname'] + '-2'
457     hostapd.add_bss('phy3', ifname1, 'bss-1.conf')
458     hostapd.add_bss('phy3', ifname2, 'bss-2.conf')
459     dev[0].connect("bss-1", key_mgmt="NONE", scan_freq="2412")
460     dev[1].connect("bss-2", key_mgmt="NONE", scan_freq="2412")
461
462     hapd1 = hostapd.Hostapd(ifname1)
463     hapd2 = hostapd.Hostapd(ifname2)
464
465     hwsim_utils.test_connectivity(dev[0], hapd1)
466     hwsim_utils.test_connectivity(dev[1], hapd2)
467
468     sta0 = hapd1.get_sta(dev[0].own_addr())
469     sta1 = hapd2.get_sta(dev[1].own_addr())
470     if 'rx_packets' not in sta0 or int(sta0['rx_packets']) < 1:
471         raise Exception("sta0 did not report receiving packets")
472     if 'rx_packets' not in sta1 or int(sta1['rx_packets']) < 1:
473         raise Exception("sta1 did not report receiving packets")
474
475 def test_ap_add_with_driver(dev, apdev):
476     """Add hostapd interface with driver specified"""
477     ifname = apdev[0]['ifname']
478     hapd_global = hostapd.HostapdGlobal()
479     hapd_global.add(ifname, driver="nl80211")
480     hapd = hostapd.Hostapd(ifname)
481     hapd.set_defaults()
482     hapd.set("ssid", "dynamic")
483     hapd.enable()
484     ev = hapd.wait_event(["AP-ENABLED"], timeout=30)
485     if ev is None:
486         raise Exception("AP startup timed out")
487     dev[0].connect("dynamic", key_mgmt="NONE", scan_freq="2412")
488     dev[0].request("DISCONNECT")
489     dev[0].wait_disconnected()
490     hapd.disable()