tests: Make PMKSA caching tests more robust
[mech_eap.git] / tests / hwsim / test_pmksa_cache.py
1 # WPA2-Enterprise PMKSA caching tests
2 # Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import logging
8 logger = logging.getLogger()
9 import subprocess
10 import time
11
12 import hostapd
13 from wpasupplicant import WpaSupplicant
14 from test_ap_eap import eap_connect
15
16 def test_pmksa_cache_on_roam_back(dev, apdev):
17     """PMKSA cache to skip EAP on reassociation back to same AP"""
18     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
19     hostapd.add_ap(apdev[0]['ifname'], params)
20     bssid = apdev[0]['bssid']
21     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
22                    eap="GPSK", identity="gpsk user",
23                    password="abcdefghijklmnop0123456789abcdef",
24                    scan_freq="2412")
25     pmksa = dev[0].get_pmksa(bssid)
26     if pmksa is None:
27         raise Exception("No PMKSA cache entry created")
28     if pmksa['opportunistic'] != '0':
29         raise Exception("Unexpected opportunistic PMKSA cache entry")
30
31     hostapd.add_ap(apdev[1]['ifname'], params)
32     bssid2 = apdev[1]['bssid']
33
34     dev[0].dump_monitor()
35     logger.info("Roam to AP2")
36     # It can take some time for the second AP to become ready to reply to Probe
37     # Request frames especially under heavy CPU load, so allow couple of rounds
38     # of scanning to avoid reporting errors incorrectly just because of scans
39     # not having seen the target AP.
40     for i in range(0, 10):
41         dev[0].scan(freq="2412")
42         if dev[0].get_bss(bssid2) is not None:
43             break
44         logger.info("Scan again to find target AP")
45     dev[0].request("ROAM " + bssid2)
46     ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
47     if ev is None:
48         raise Exception("EAP success timed out")
49     dev[0].wait_connected(timeout=10, error="Roaming timed out")
50     pmksa2 = dev[0].get_pmksa(bssid2)
51     if pmksa2 is None:
52         raise Exception("No PMKSA cache entry found")
53     if pmksa2['opportunistic'] != '0':
54         raise Exception("Unexpected opportunistic PMKSA cache entry")
55
56     dev[0].dump_monitor()
57     logger.info("Roam back to AP1")
58     dev[0].scan(freq="2412")
59     dev[0].request("ROAM " + bssid)
60     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
61                             "CTRL-EVENT-CONNECTED"], timeout=10)
62     if ev is None:
63         raise Exception("Roaming with the AP timed out")
64     if "CTRL-EVENT-EAP-STARTED" in ev:
65         raise Exception("Unexpected EAP exchange")
66     pmksa1b = dev[0].get_pmksa(bssid)
67     if pmksa1b is None:
68         raise Exception("No PMKSA cache entry found")
69     if pmksa['pmkid'] != pmksa1b['pmkid']:
70         raise Exception("Unexpected PMKID change for AP1")
71
72     dev[0].dump_monitor()
73     if "FAIL" in dev[0].request("PMKSA_FLUSH"):
74         raise Exception("PMKSA_FLUSH failed")
75     if dev[0].get_pmksa(bssid) is not None or dev[0].get_pmksa(bssid2) is not None:
76         raise Exception("PMKSA_FLUSH did not remove PMKSA entries")
77     dev[0].wait_disconnected(timeout=5)
78     dev[0].wait_connected(timeout=15, error="Reconnection timed out")
79
80 def test_pmksa_cache_opportunistic_only_on_sta(dev, apdev):
81     """Opportunistic PMKSA caching enabled only on station"""
82     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
83     hostapd.add_ap(apdev[0]['ifname'], params)
84     bssid = apdev[0]['bssid']
85     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
86                    eap="GPSK", identity="gpsk user",
87                    password="abcdefghijklmnop0123456789abcdef", okc=True,
88                    scan_freq="2412")
89     pmksa = dev[0].get_pmksa(bssid)
90     if pmksa is None:
91         raise Exception("No PMKSA cache entry created")
92     if pmksa['opportunistic'] != '0':
93         raise Exception("Unexpected opportunistic PMKSA cache entry")
94
95     hostapd.add_ap(apdev[1]['ifname'], params)
96     bssid2 = apdev[1]['bssid']
97
98     dev[0].dump_monitor()
99     logger.info("Roam to AP2")
100     dev[0].scan(freq="2412")
101     dev[0].request("ROAM " + bssid2)
102     ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
103     if ev is None:
104         raise Exception("EAP success timed out")
105     dev[0].wait_connected(timeout=10, error="Roaming timed out")
106     pmksa2 = dev[0].get_pmksa(bssid2)
107     if pmksa2 is None:
108         raise Exception("No PMKSA cache entry found")
109     if pmksa2['opportunistic'] != '0':
110         raise Exception("Unexpected opportunistic PMKSA cache entry")
111
112     dev[0].dump_monitor()
113     logger.info("Roam back to AP1")
114     dev[0].scan(freq="2412")
115     dev[0].request("ROAM " + bssid)
116     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
117                             "CTRL-EVENT-CONNECTED"], timeout=10)
118     if ev is None:
119         raise Exception("Roaming with the AP timed out")
120     if "CTRL-EVENT-EAP-STARTED" in ev:
121         raise Exception("Unexpected EAP exchange")
122     pmksa1b = dev[0].get_pmksa(bssid)
123     if pmksa1b is None:
124         raise Exception("No PMKSA cache entry found")
125     if pmksa['pmkid'] != pmksa1b['pmkid']:
126         raise Exception("Unexpected PMKID change for AP1")
127
128 def test_pmksa_cache_opportunistic(dev, apdev):
129     """Opportunistic PMKSA caching"""
130     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
131     params['okc'] = "1"
132     hostapd.add_ap(apdev[0]['ifname'], params)
133     bssid = apdev[0]['bssid']
134     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
135                    eap="GPSK", identity="gpsk user",
136                    password="abcdefghijklmnop0123456789abcdef", okc=True,
137                    scan_freq="2412")
138     pmksa = dev[0].get_pmksa(bssid)
139     if pmksa is None:
140         raise Exception("No PMKSA cache entry created")
141     if pmksa['opportunistic'] != '0':
142         raise Exception("Unexpected opportunistic PMKSA cache entry")
143
144     hostapd.add_ap(apdev[1]['ifname'], params)
145     bssid2 = apdev[1]['bssid']
146
147     dev[0].dump_monitor()
148     logger.info("Roam to AP2")
149     dev[0].scan(freq="2412")
150     dev[0].request("ROAM " + bssid2)
151     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
152                             "CTRL-EVENT-CONNECTED"], timeout=10)
153     if ev is None:
154         raise Exception("Roaming with the AP timed out")
155     if "CTRL-EVENT-EAP-STARTED" in ev:
156         raise Exception("Unexpected EAP exchange")
157     pmksa2 = dev[0].get_pmksa(bssid2)
158     if pmksa2 is None:
159         raise Exception("No PMKSA cache entry created")
160
161     dev[0].dump_monitor()
162     logger.info("Roam back to AP1")
163     dev[0].scan(freq="2412")
164     dev[0].request("ROAM " + bssid)
165     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
166                             "CTRL-EVENT-CONNECTED"], timeout=10)
167     if ev is None:
168         raise Exception("Roaming with the AP timed out")
169     if "CTRL-EVENT-EAP-STARTED" in ev:
170         raise Exception("Unexpected EAP exchange")
171
172     pmksa1b = dev[0].get_pmksa(bssid)
173     if pmksa1b is None:
174         raise Exception("No PMKSA cache entry found")
175     if pmksa['pmkid'] != pmksa1b['pmkid']:
176         raise Exception("Unexpected PMKID change for AP1")
177
178 def test_pmksa_cache_opportunistic_connect(dev, apdev):
179     """Opportunistic PMKSA caching with connect API"""
180     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
181     params['okc'] = "1"
182     hostapd.add_ap(apdev[0]['ifname'], params)
183     bssid = apdev[0]['bssid']
184     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
185     wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
186     wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
187                  eap="GPSK", identity="gpsk user",
188                  password="abcdefghijklmnop0123456789abcdef", okc=True,
189                  scan_freq="2412")
190     pmksa = wpas.get_pmksa(bssid)
191     if pmksa is None:
192         raise Exception("No PMKSA cache entry created")
193     if pmksa['opportunistic'] != '0':
194         raise Exception("Unexpected opportunistic PMKSA cache entry")
195
196     hostapd.add_ap(apdev[1]['ifname'], params)
197     bssid2 = apdev[1]['bssid']
198
199     wpas.dump_monitor()
200     logger.info("Roam to AP2")
201     wpas.scan_for_bss(bssid2, freq="2412")
202     wpas.request("ROAM " + bssid2)
203     ev = wpas.wait_event(["CTRL-EVENT-EAP-STARTED",
204                             "CTRL-EVENT-CONNECTED"], timeout=10)
205     if ev is None:
206         raise Exception("Roaming with the AP timed out")
207     if "CTRL-EVENT-EAP-STARTED" in ev:
208         raise Exception("Unexpected EAP exchange")
209     pmksa2 = wpas.get_pmksa(bssid2)
210     if pmksa2 is None:
211         raise Exception("No PMKSA cache entry created")
212
213     wpas.dump_monitor()
214     logger.info("Roam back to AP1")
215     wpas.scan(freq="2412")
216     wpas.request("ROAM " + bssid)
217     ev = wpas.wait_event(["CTRL-EVENT-EAP-STARTED",
218                             "CTRL-EVENT-CONNECTED"], timeout=10)
219     if ev is None:
220         raise Exception("Roaming with the AP timed out")
221     if "CTRL-EVENT-EAP-STARTED" in ev:
222         raise Exception("Unexpected EAP exchange")
223
224     pmksa1b = wpas.get_pmksa(bssid)
225     if pmksa1b is None:
226         raise Exception("No PMKSA cache entry found")
227     if pmksa['pmkid'] != pmksa1b['pmkid']:
228         raise Exception("Unexpected PMKID change for AP1")
229
230 def test_pmksa_cache_expiration(dev, apdev):
231     """PMKSA cache entry expiration"""
232     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
233     hostapd.add_ap(apdev[0]['ifname'], params)
234     bssid = apdev[0]['bssid']
235     dev[0].request("SET dot11RSNAConfigPMKLifetime 10")
236     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
237                    eap="GPSK", identity="gpsk user",
238                    password="abcdefghijklmnop0123456789abcdef",
239                    scan_freq="2412")
240     pmksa = dev[0].get_pmksa(bssid)
241     if pmksa is None:
242         raise Exception("No PMKSA cache entry created")
243     logger.info("Wait for PMKSA cache entry to expire")
244     ev = dev[0].wait_event(["WPA: Key negotiation completed",
245                             "CTRL-EVENT-DISCONNECTED"], timeout=15)
246     if ev is None:
247         raise Exception("No EAP reauthentication seen")
248     if "CTRL-EVENT-DISCONNECTED" in ev:
249         raise Exception("Unexpected disconnection")
250     pmksa2 = dev[0].get_pmksa(bssid)
251     if pmksa['pmkid'] == pmksa2['pmkid']:
252         raise Exception("PMKID did not change")
253
254 def test_pmksa_cache_expiration_disconnect(dev, apdev):
255     """PMKSA cache entry expiration (disconnect)"""
256     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
257     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
258     bssid = apdev[0]['bssid']
259     dev[0].request("SET dot11RSNAConfigPMKLifetime 2")
260     dev[0].request("SET dot11RSNAConfigPMKReauthThreshold 100")
261     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
262                    eap="GPSK", identity="gpsk user",
263                    password="abcdefghijklmnop0123456789abcdef",
264                    scan_freq="2412")
265     pmksa = dev[0].get_pmksa(bssid)
266     if pmksa is None:
267         raise Exception("No PMKSA cache entry created")
268     hapd.request("SET auth_server_shared_secret incorrect")
269     logger.info("Wait for PMKSA cache entry to expire")
270     ev = dev[0].wait_event(["WPA: Key negotiation completed",
271                             "CTRL-EVENT-DISCONNECTED"], timeout=15)
272     if ev is None:
273         raise Exception("No EAP reauthentication seen")
274     if "CTRL-EVENT-DISCONNECTED" not in ev:
275         raise Exception("Missing disconnection")
276     hapd.request("SET auth_server_shared_secret radius")
277     ev = dev[0].wait_event(["WPA: Key negotiation completed"], timeout=15)
278     if ev is None:
279         raise Exception("No EAP reauthentication seen")
280     pmksa2 = dev[0].get_pmksa(bssid)
281     if pmksa['pmkid'] == pmksa2['pmkid']:
282         raise Exception("PMKID did not change")
283
284 def test_pmksa_cache_and_cui(dev, apdev):
285     """PMKSA cache and Chargeable-User-Identity"""
286     params = hostapd.wpa2_eap_params(ssid="cui")
287     params['radius_request_cui'] = '1'
288     params['acct_server_addr'] = "127.0.0.1"
289     params['acct_server_port'] = "1813"
290     params['acct_server_shared_secret'] = "radius"
291     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
292     bssid = apdev[0]['bssid']
293     dev[0].connect("cui", proto="RSN", key_mgmt="WPA-EAP",
294                    eap="GPSK", identity="gpsk-cui",
295                    password="abcdefghijklmnop0123456789abcdef",
296                    scan_freq="2412")
297     pmksa = dev[0].get_pmksa(bssid)
298     if pmksa is None:
299         raise Exception("No PMKSA cache entry created")
300     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
301     if ev is None:
302         raise Exception("No connection event received from hostapd")
303
304     dev[0].dump_monitor()
305     logger.info("Disconnect and reconnect to the same AP")
306     dev[0].request("DISCONNECT")
307     dev[0].wait_disconnected()
308     dev[0].request("RECONNECT")
309     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
310                             "CTRL-EVENT-CONNECTED"], timeout=10)
311     if ev is None:
312         raise Exception("Reconnect timed out")
313     if "CTRL-EVENT-EAP-STARTED" in ev:
314         raise Exception("Unexpected EAP exchange")
315     pmksa1b = dev[0].get_pmksa(bssid)
316     if pmksa1b is None:
317         raise Exception("No PMKSA cache entry found")
318     if pmksa['pmkid'] != pmksa1b['pmkid']:
319         raise Exception("Unexpected PMKID change for AP1")
320
321     dev[0].request("REAUTHENTICATE")
322     ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
323     if ev is None:
324         raise Exception("EAP success timed out")
325     for i in range(0, 20):
326         state = dev[0].get_status_field("wpa_state")
327         if state == "COMPLETED":
328             break
329         time.sleep(0.1)
330     if state != "COMPLETED":
331         raise Exception("Reauthentication did not complete")
332
333 def test_pmksa_cache_preauth(dev, apdev):
334     """RSN pre-authentication to generate PMKSA cache entry"""
335     try:
336         params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
337         params['bridge'] = 'ap-br0'
338         hostapd.add_ap(apdev[0]['ifname'], params)
339         subprocess.call(['sudo', 'brctl', 'setfd', 'ap-br0', '0'])
340         subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
341         eap_connect(dev[0], apdev[0], "PAX", "pax.user@example.com",
342                     password_hex="0123456789abcdef0123456789abcdef")
343
344         params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
345         params['bridge'] = 'ap-br0'
346         params['rsn_preauth'] = '1'
347         params['rsn_preauth_interfaces'] = 'ap-br0'
348         hostapd.add_ap(apdev[1]['ifname'], params)
349         bssid1 = apdev[1]['bssid']
350         dev[0].scan(freq="2412")
351         success = False
352         status_seen = False
353         for i in range(0, 50):
354             if not status_seen:
355                 status = dev[0].request("STATUS")
356                 if "Pre-authentication EAPOL state machines:" in status:
357                     status_seen = True
358             time.sleep(0.1)
359             pmksa = dev[0].get_pmksa(bssid1)
360             if pmksa:
361                 success = True
362                 break
363         if not success:
364             raise Exception("No PMKSA cache entry created from pre-authentication")
365         if not status_seen:
366             raise Exception("Pre-authentication EAPOL status was not available")
367
368         dev[0].scan(freq="2412")
369         if "[WPA2-EAP-CCMP-preauth]" not in dev[0].request("SCAN_RESULTS"):
370             raise Exception("Scan results missing RSN element info")
371         dev[0].request("ROAM " + bssid1)
372         ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
373                                 "CTRL-EVENT-CONNECTED"], timeout=10)
374         if ev is None:
375             raise Exception("Roaming with the AP timed out")
376         if "CTRL-EVENT-EAP-STARTED" in ev:
377             raise Exception("Unexpected EAP exchange")
378         pmksa2 = dev[0].get_pmksa(bssid1)
379         if pmksa2 is None:
380             raise Exception("No PMKSA cache entry")
381         if pmksa['pmkid'] != pmksa2['pmkid']:
382             raise Exception("Unexpected PMKID change")
383
384     finally:
385         subprocess.call(['sudo', 'ip', 'link', 'set', 'dev', 'ap-br0', 'down'])
386         subprocess.call(['sudo', 'brctl', 'delbr', 'ap-br0'])
387
388 def test_pmksa_cache_disabled(dev, apdev):
389     """PMKSA cache disabling on AP"""
390     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
391     params['disable_pmksa_caching'] = '1'
392     hostapd.add_ap(apdev[0]['ifname'], params)
393     bssid = apdev[0]['bssid']
394     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
395                    eap="GPSK", identity="gpsk user",
396                    password="abcdefghijklmnop0123456789abcdef",
397                    scan_freq="2412")
398
399     hostapd.add_ap(apdev[1]['ifname'], params)
400     bssid2 = apdev[1]['bssid']
401
402     dev[0].dump_monitor()
403     logger.info("Roam to AP2")
404     dev[0].scan_for_bss(bssid2, freq="2412")
405     dev[0].request("ROAM " + bssid2)
406     ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
407     if ev is None:
408         raise Exception("EAP success timed out")
409     dev[0].wait_connected(timeout=10, error="Roaming timed out")
410
411     dev[0].dump_monitor()
412     logger.info("Roam back to AP1")
413     dev[0].scan(freq="2412")
414     dev[0].request("ROAM " + bssid)
415     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
416                             "CTRL-EVENT-CONNECTED"], timeout=20)
417     if ev is None:
418         raise Exception("Roaming with the AP timed out")
419     if "CTRL-EVENT-CONNECTED" in ev:
420         raise Exception("EAP exchange missing")
421     ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=20)
422     if ev is None:
423         raise Exception("Roaming with the AP timed out")
424
425 def test_pmksa_cache_ap_expiration(dev, apdev):
426     """PMKSA cache entry expiring on AP"""
427     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
428     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
429     bssid = apdev[0]['bssid']
430     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
431                    eap="GPSK", identity="gpsk-user-session-timeout",
432                    password="abcdefghijklmnop0123456789abcdef",
433                    scan_freq="2412")
434     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
435     if ev is None:
436         raise Exception("No connection event received from hostapd")
437     dev[0].request("DISCONNECT")
438     time.sleep(5)
439     dev[0].dump_monitor()
440     dev[0].request("RECONNECT")
441     ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
442                             "CTRL-EVENT-CONNECTED"], timeout=20)
443     if ev is None:
444         raise Exception("Roaming with the AP timed out")
445     if "CTRL-EVENT-CONNECTED" in ev:
446         raise Exception("EAP exchange missing")
447     dev[0].wait_connected(timeout=20, error="Reconnect timed out")
448     dev[0].dump_monitor()
449     dev[0].wait_disconnected(timeout=20)
450     dev[0].wait_connected(timeout=20, error="Reassociation timed out")
451
452 def test_pmksa_cache_multiple_sta(dev, apdev):
453     """PMKSA cache with multiple stations"""
454     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
455     hostapd.add_ap(apdev[0]['ifname'], params)
456     bssid = apdev[0]['bssid']
457     dev[0].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
458                    eap="GPSK", identity="gpsk-user-session-timeout",
459                    password="abcdefghijklmnop0123456789abcdef",
460                    scan_freq="2412")
461     dev[1].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
462                    eap="GPSK", identity="gpsk user",
463                    password="abcdefghijklmnop0123456789abcdef",
464                    scan_freq="2412")
465     dev[2].connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
466                    eap="GPSK", identity="gpsk-user-session-timeout",
467                    password="abcdefghijklmnop0123456789abcdef",
468                    scan_freq="2412")
469
470     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
471     wpas.interface_add("wlan5")
472     wpas.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
473                  eap="GPSK", identity="gpsk user",
474                  password="abcdefghijklmnop0123456789abcdef",
475                  scan_freq="2412")
476
477     hostapd.add_ap(apdev[1]['ifname'], params)
478     bssid2 = apdev[1]['bssid']
479
480     logger.info("Roam to AP2")
481     for sta in [ dev[1], dev[0], dev[2], wpas ]:
482         sta.dump_monitor()
483         sta.scan_for_bss(bssid2, freq="2412")
484         sta.request("ROAM " + bssid2)
485         ev = sta.wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=10)
486         if ev is None:
487             raise Exception("EAP success timed out")
488         sta.wait_connected(timeout=10, error="Roaming timed out")
489
490     logger.info("Roam back to AP1")
491     for sta in [ dev[1], wpas, dev[0], dev[2] ]:
492         sta.dump_monitor()
493         sta.scan(freq="2412")
494         sta.dump_monitor()
495         sta.request("ROAM " + bssid)
496         sta.wait_connected(timeout=10, error="Roaming timed out")
497         sta.dump_monitor()
498
499     time.sleep(4)
500
501     logger.info("Roam back to AP2")
502     for sta in [ dev[1], wpas, dev[0], dev[2] ]:
503         sta.dump_monitor()
504         sta.scan(freq="2412")
505         sta.dump_monitor()
506         sta.request("ROAM " + bssid2)
507         sta.wait_connected(timeout=10, error="Roaming timed out")
508         sta.dump_monitor()
509
510 def test_pmksa_cache_opportunistic_multiple_sta(dev, apdev):
511     """Opportunistic PMKSA caching with multiple stations"""
512     params = hostapd.wpa2_eap_params(ssid="test-pmksa-cache")
513     params['okc'] = "1"
514     hostapd.add_ap(apdev[0]['ifname'], params)
515     bssid = apdev[0]['bssid']
516     wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
517     wpas.interface_add("wlan5")
518     for sta in [ dev[0], dev[1], dev[2], wpas ]:
519         sta.connect("test-pmksa-cache", proto="RSN", key_mgmt="WPA-EAP",
520                     eap="GPSK", identity="gpsk user",
521                     password="abcdefghijklmnop0123456789abcdef", okc=True,
522                     scan_freq="2412")
523
524     hostapd.add_ap(apdev[1]['ifname'], params)
525     bssid2 = apdev[1]['bssid']
526
527     logger.info("Roam to AP2")
528     for sta in [ dev[2], dev[0], wpas, dev[1] ]:
529         sta.dump_monitor()
530         sta.scan_for_bss(bssid2, freq="2412")
531         if "OK" not in sta.request("ROAM " + bssid2):
532             raise Exception("ROAM command failed")
533         ev = sta.wait_event(["CTRL-EVENT-EAP-STARTED",
534                              "CTRL-EVENT-CONNECTED"], timeout=10)
535         if ev is None:
536             raise Exception("Roaming with the AP timed out")
537         if "CTRL-EVENT-EAP-STARTED" in ev:
538             raise Exception("Unexpected EAP exchange")
539         pmksa2 = sta.get_pmksa(bssid2)
540         if pmksa2 is None:
541             raise Exception("No PMKSA cache entry created")
542
543     logger.info("Roam back to AP1")
544     for sta in [ dev[0], dev[1], dev[2], wpas ]:
545         sta.dump_monitor()
546         sta.scan_for_bss(bssid, freq="2412")
547         sta.request("ROAM " + bssid)
548         ev = sta.wait_event(["CTRL-EVENT-EAP-STARTED",
549                              "CTRL-EVENT-CONNECTED"], timeout=10)
550         if ev is None:
551             raise Exception("Roaming with the AP timed out")
552         if "CTRL-EVENT-EAP-STARTED" in ev:
553             raise Exception("Unexpected EAP exchange")