tests: WNM BSS Transition Management and security mismatch
[mech_eap.git] / tests / hwsim / test_wnm.py
1 # WNM 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 binascii
8 import struct
9 import time
10 import logging
11 logger = logging.getLogger()
12 import subprocess
13
14 import hostapd
15 from utils import alloc_fail, wait_fail_trigger
16 from wlantest import Wlantest
17
18 def test_wnm_bss_transition_mgmt(dev, apdev):
19     """WNM BSS Transition Management"""
20     params = { "ssid": "test-wnm",
21                "time_advertisement": "2",
22                "time_zone": "EST5",
23                "wnm_sleep_mode": "1",
24                "bss_transition": "1" }
25     hostapd.add_ap(apdev[0]['ifname'], params)
26
27     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
28     dev[0].request("WNM_BSS_QUERY 0")
29
30 def test_wnm_disassoc_imminent(dev, apdev):
31     """WNM Disassociation Imminent"""
32     params = { "ssid": "test-wnm",
33                "time_advertisement": "2",
34                "time_zone": "EST5",
35                "wnm_sleep_mode": "1",
36                "bss_transition": "1" }
37     hostapd.add_ap(apdev[0]['ifname'], params)
38     hapd = hostapd.Hostapd(apdev[0]['ifname'])
39
40     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
41     addr = dev[0].p2p_interface_addr()
42     hapd.request("DISASSOC_IMMINENT " + addr + " 10")
43     ev = dev[0].wait_event(["WNM: Disassociation Imminent"])
44     if ev is None:
45         raise Exception("Timeout while waiting for disassociation imminent")
46     if "Disassociation Timer 10" not in ev:
47         raise Exception("Unexpected disassociation imminent contents")
48     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
49     if ev is None:
50         raise Exception("Timeout while waiting for re-connection scan")
51
52 def test_wnm_ess_disassoc_imminent(dev, apdev):
53     """WNM ESS Disassociation Imminent"""
54     params = { "ssid": "test-wnm",
55                "time_advertisement": "2",
56                "time_zone": "EST5",
57                "wnm_sleep_mode": "1",
58                "bss_transition": "1" }
59     hostapd.add_ap(apdev[0]['ifname'], params)
60     hapd = hostapd.Hostapd(apdev[0]['ifname'])
61
62     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
63     addr = dev[0].p2p_interface_addr()
64     hapd.request("ESS_DISASSOC " + addr + " 10 http://example.com/session-info")
65     ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"])
66     if ev is None:
67         raise Exception("Timeout while waiting for ESS disassociation imminent")
68     if "0 1024 http://example.com/session-info" not in ev:
69         raise Exception("Unexpected ESS disassociation imminent message contents")
70     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
71     if ev is None:
72         raise Exception("Timeout while waiting for re-connection scan")
73
74 def test_wnm_ess_disassoc_imminent_pmf(dev, apdev):
75     """WNM ESS Disassociation Imminent"""
76     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
77     params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
78     params["ieee80211w"] = "2";
79     params["bss_transition"] = "1"
80     hostapd.add_ap(apdev[0]['ifname'], params)
81     hapd = hostapd.Hostapd(apdev[0]['ifname'])
82
83     dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2",
84                    key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
85     addr = dev[0].p2p_interface_addr()
86     hapd.request("ESS_DISASSOC " + addr + " 10 http://example.com/session-info")
87     ev = dev[0].wait_event(["ESS-DISASSOC-IMMINENT"])
88     if ev is None:
89         raise Exception("Timeout while waiting for ESS disassociation imminent")
90     if "1 1024 http://example.com/session-info" not in ev:
91         raise Exception("Unexpected ESS disassociation imminent message contents")
92     ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"])
93     if ev is None:
94         raise Exception("Timeout while waiting for re-connection scan")
95
96 def check_wnm_sleep_mode_enter_exit(hapd, dev, interval=None, tfs_req=None):
97     addr = dev.p2p_interface_addr()
98     sta = hapd.get_sta(addr)
99     if "[WNM_SLEEP_MODE]" in sta['flags']:
100         raise Exception("Station unexpectedly in WNM-Sleep Mode")
101
102     logger.info("Going to WNM Sleep Mode")
103     extra = ""
104     if interval is not None:
105         extra += " interval=" + str(interval)
106     if tfs_req:
107         extra += " tfs_req=" + tfs_req
108     if "OK" not in dev.request("WNM_SLEEP enter" + extra):
109         raise Exception("WNM_SLEEP failed")
110     ok = False
111     for i in range(20):
112         time.sleep(0.1)
113         sta = hapd.get_sta(addr)
114         if "[WNM_SLEEP_MODE]" in sta['flags']:
115             ok = True
116             break
117     if not ok:
118         raise Exception("Station failed to enter WNM-Sleep Mode")
119
120     logger.info("Waking up from WNM Sleep Mode")
121     ok = False
122     dev.request("WNM_SLEEP exit")
123     for i in range(20):
124         time.sleep(0.1)
125         sta = hapd.get_sta(addr)
126         if "[WNM_SLEEP_MODE]" not in sta['flags']:
127             ok = True
128             break
129     if not ok:
130         raise Exception("Station failed to exit WNM-Sleep Mode")
131
132 def test_wnm_sleep_mode_open(dev, apdev):
133     """WNM Sleep Mode - open"""
134     params = { "ssid": "test-wnm",
135                "time_advertisement": "2",
136                "time_zone": "EST5",
137                "wnm_sleep_mode": "1",
138                "bss_transition": "1" }
139     hostapd.add_ap(apdev[0]['ifname'], params)
140     hapd = hostapd.Hostapd(apdev[0]['ifname'])
141
142     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
143     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
144     if ev is None:
145         raise Exception("No connection event received from hostapd")
146     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
147     check_wnm_sleep_mode_enter_exit(hapd, dev[0], interval=100)
148     check_wnm_sleep_mode_enter_exit(hapd, dev[0], tfs_req="5b17010001130e110000071122334455661122334455661234")
149
150     cmds = [ "foo",
151              "exit tfs_req=123 interval=10",
152              "enter tfs_req=qq interval=10" ]
153     for cmd in cmds:
154         if "FAIL" not in dev[0].request("WNM_SLEEP " + cmd):
155             raise Exception("Invalid WNM_SLEEP accepted")
156
157 def test_wnm_sleep_mode_rsn(dev, apdev):
158     """WNM Sleep Mode - RSN"""
159     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
160     params["time_advertisement"] = "2"
161     params["time_zone"] = "EST5"
162     params["wnm_sleep_mode"] = "1"
163     params["bss_transition"] = "1"
164     hostapd.add_ap(apdev[0]['ifname'], params)
165     hapd = hostapd.Hostapd(apdev[0]['ifname'])
166
167     dev[0].connect("test-wnm-rsn", psk="12345678", scan_freq="2412")
168     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
169     if ev is None:
170         raise Exception("No connection event received from hostapd")
171     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
172
173 def test_wnm_sleep_mode_ap_oom(dev, apdev):
174     """WNM Sleep Mode - AP side OOM"""
175     params = { "ssid": "test-wnm",
176                "wnm_sleep_mode": "1" }
177     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
178
179     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
180     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
181     if ev is None:
182         raise Exception("No connection event received from hostapd")
183     with alloc_fail(hapd, 1, "ieee802_11_send_wnmsleep_resp"):
184         dev[0].request("WNM_SLEEP enter")
185         wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
186     with alloc_fail(hapd, 2, "ieee802_11_send_wnmsleep_resp"):
187         dev[0].request("WNM_SLEEP exit")
188         wait_fail_trigger(hapd, "GET_ALLOC_FAIL")
189
190 def test_wnm_sleep_mode_rsn_pmf(dev, apdev):
191     """WNM Sleep Mode - RSN with PMF"""
192     wt = Wlantest()
193     wt.flush()
194     wt.add_passphrase("12345678")
195     params = hostapd.wpa2_params("test-wnm-rsn", "12345678")
196     params["wpa_key_mgmt"] = "WPA-PSK-SHA256";
197     params["ieee80211w"] = "2";
198     params["time_advertisement"] = "2"
199     params["time_zone"] = "EST5"
200     params["wnm_sleep_mode"] = "1"
201     params["bss_transition"] = "1"
202     hostapd.add_ap(apdev[0]['ifname'], params)
203     hapd = hostapd.Hostapd(apdev[0]['ifname'])
204
205     dev[0].connect("test-wnm-rsn", psk="12345678", ieee80211w="2",
206                    key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
207     ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
208     if ev is None:
209         raise Exception("No connection event received from hostapd")
210     check_wnm_sleep_mode_enter_exit(hapd, dev[0])
211
212 MGMT_SUBTYPE_ACTION = 13
213 ACTION_CATEG_WNM = 10
214 WNM_ACT_BSS_TM_REQ = 7
215 WNM_ACT_BSS_TM_RESP = 8
216 WNM_ACT_SLEEP_MODE_REQ = 16
217 WNM_ACT_SLEEP_MODE_RESP = 17
218 WNM_ACT_NOTIFICATION_REQ = 26
219 WNM_ACT_NOTIFICATION_RESP = 27
220 WNM_NOTIF_TYPE_FW_UPGRADE = 0
221 WNM_NOTIF_TYPE_WFA = 1
222 WLAN_EID_TFS_RESP = 92
223 WLAN_EID_WNMSLEEP = 93
224 WNM_SLEEP_MODE_ENTER = 0
225 WNM_SLEEP_MODE_EXIT = 1
226 WNM_STATUS_SLEEP_ACCEPT = 0
227 WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1
228 WNM_STATUS_DENIED_ACTION = 2
229 WNM_STATUS_DENIED_TMP = 3
230 WNM_STATUS_DENIED_KEY = 4
231 WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
232 WNM_SLEEP_SUBELEM_GTK = 0
233 WNM_SLEEP_SUBELEM_IGTK = 1
234
235 def bss_tm_req(dst, src, dialog_token=1, req_mode=0, disassoc_timer=0,
236                validity_interval=1):
237     msg = {}
238     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
239     msg['da'] = dst
240     msg['sa'] = src
241     msg['bssid'] = src
242     msg['payload'] = struct.pack("<BBBBHB",
243                                  ACTION_CATEG_WNM, WNM_ACT_BSS_TM_REQ,
244                                  dialog_token, req_mode, disassoc_timer,
245                                  validity_interval)
246     return msg
247
248 def rx_bss_tm_resp(hapd, expect_dialog=None, expect_status=None):
249     for i in range(0, 100):
250         resp = hapd.mgmt_rx()
251         if resp is None:
252             raise Exception("No BSS TM Response received")
253         if resp['subtype'] == MGMT_SUBTYPE_ACTION:
254             break
255     if i == 99:
256         raise Exception("Not an Action frame")
257     payload = resp['payload']
258     if len(payload) < 2 + 3:
259         raise Exception("Too short payload")
260     (category, action) = struct.unpack('BB', payload[0:2])
261     if category != ACTION_CATEG_WNM or action != WNM_ACT_BSS_TM_RESP:
262         raise Exception("Not a BSS TM Response")
263     pos = payload[2:]
264     (dialog, status, bss_term_delay) = struct.unpack('BBB', pos[0:3])
265     resp['dialog'] = dialog
266     resp['status'] = status
267     resp['bss_term_delay'] = bss_term_delay
268     pos = pos[3:]
269     if len(pos) >= 6 and status == 0:
270         resp['target_bssid'] = binascii.hexlify(pos[0:6])
271         pos = pos[6:]
272     resp['candidates'] = pos
273     if expect_dialog is not None and dialog != expect_dialog:
274         raise Exception("Unexpected dialog token")
275     if expect_status is not None and status != expect_status:
276         raise Exception("Unexpected status code %d" % status)
277     return resp
278
279 def expect_ack(hapd):
280     ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
281     if ev is None:
282         raise Exception("Missing TX status")
283     if "ok=1" not in ev:
284         raise Exception("Action frame not acknowledged")
285
286 def test_wnm_bss_tm_req(dev, apdev):
287     """BSS Transition Management Request"""
288     params = { "ssid": "test-wnm", "bss_transition": "1" }
289     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
290     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
291     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
292
293     hapd.set("ext_mgmt_frame_handling", "1")
294
295     # truncated BSS TM Request
296     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
297                      req_mode=0x08)
298     req['payload'] = struct.pack("<BBBBH",
299                                  ACTION_CATEG_WNM, WNM_ACT_BSS_TM_REQ,
300                                  1, 0, 0)
301     hapd.mgmt_tx(req)
302     expect_ack(hapd)
303
304     # no disassociation and no candidate list
305     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
306                      dialog_token=2)
307     hapd.mgmt_tx(req)
308     resp = rx_bss_tm_resp(hapd, expect_dialog=2, expect_status=1)
309
310     # truncated BSS Termination Duration
311     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
312                      req_mode=0x08)
313     hapd.mgmt_tx(req)
314     expect_ack(hapd)
315
316     # BSS Termination Duration with TSF=0 and Duration=10
317     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
318                      req_mode=0x08, dialog_token=3)
319     req['payload'] += struct.pack("<BBQH", 4, 10, 0, 10)
320     hapd.mgmt_tx(req)
321     resp = rx_bss_tm_resp(hapd, expect_dialog=3, expect_status=1)
322
323     # truncated Session Information URL
324     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
325                      req_mode=0x10)
326     hapd.mgmt_tx(req)
327     expect_ack(hapd)
328     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
329                      req_mode=0x10)
330     req['payload'] += struct.pack("<BBB", 3, 65, 66)
331     hapd.mgmt_tx(req)
332     expect_ack(hapd)
333
334     # Session Information URL
335     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
336                      req_mode=0x10, dialog_token=4)
337     req['payload'] += struct.pack("<BBB", 2, 65, 66)
338     hapd.mgmt_tx(req)
339     resp = rx_bss_tm_resp(hapd, expect_dialog=4, expect_status=0)
340
341     # Preferred Candidate List without any entries
342     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
343                      req_mode=0x01, dialog_token=5)
344     hapd.mgmt_tx(req)
345     resp = rx_bss_tm_resp(hapd, expect_dialog=5, expect_status=7)
346
347     # Preferred Candidate List with a truncated entry
348     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
349                      req_mode=0x01)
350     req['payload'] += struct.pack("<BB", 52, 1)
351     hapd.mgmt_tx(req)
352     expect_ack(hapd)
353
354     # Preferred Candidate List with a too short entry
355     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
356                      req_mode=0x01, dialog_token=6)
357     req['payload'] += struct.pack("<BB", 52, 0)
358     hapd.mgmt_tx(req)
359     resp = rx_bss_tm_resp(hapd, expect_dialog=6, expect_status=7)
360
361     # Preferred Candidate List with a non-matching entry
362     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
363                      req_mode=0x01, dialog_token=6)
364     req['payload'] += struct.pack("<BB6BLBBB", 52, 13,
365                                   1, 2, 3, 4, 5, 6,
366                                   0, 81, 1, 7)
367     hapd.mgmt_tx(req)
368     resp = rx_bss_tm_resp(hapd, expect_dialog=6, expect_status=7)
369
370     # Preferred Candidate List with a truncated subelement
371     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
372                      req_mode=0x01, dialog_token=7)
373     req['payload'] += struct.pack("<BB6BLBBBBB", 52, 13 + 2,
374                                   1, 2, 3, 4, 5, 6,
375                                   0, 81, 1, 7,
376                                   1, 1)
377     hapd.mgmt_tx(req)
378     resp = rx_bss_tm_resp(hapd, expect_dialog=7, expect_status=7)
379
380     # Preferred Candidate List with lots of invalid optional subelements
381     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
382                      req_mode=0x01, dialog_token=8)
383     subelems = struct.pack("<BBHB", 1, 3, 0, 100)
384     subelems += struct.pack("<BBB", 2, 1, 65)
385     subelems += struct.pack("<BB", 3, 0)
386     subelems += struct.pack("<BBQB", 4, 9, 0, 10)
387     subelems += struct.pack("<BBHLB", 5, 7, 0, 0, 0)
388     subelems += struct.pack("<BB", 66, 0)
389     subelems += struct.pack("<BBBBBB", 70, 4, 0, 0, 0, 0)
390     subelems += struct.pack("<BB", 71, 0)
391     req['payload'] += struct.pack("<BB6BLBBB", 52, 13 + len(subelems),
392                                   1, 2, 3, 4, 5, 6,
393                                   0, 81, 1, 7) + subelems
394     hapd.mgmt_tx(req)
395     resp = rx_bss_tm_resp(hapd, expect_dialog=8, expect_status=7)
396
397     # Preferred Candidate List with lots of valid optional subelements (twice)
398     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
399                      req_mode=0x01, dialog_token=8)
400     # TSF Information
401     subelems = struct.pack("<BBHH", 1, 4, 0, 100)
402     # Condensed Country String
403     subelems += struct.pack("<BBBB", 2, 2, 65, 66)
404     # BSS Transition Candidate Preference
405     subelems += struct.pack("<BBB", 3, 1, 100)
406     # BSS Termination Duration
407     subelems += struct.pack("<BBQH", 4, 10, 0, 10)
408     # Bearing
409     subelems += struct.pack("<BBHLH", 5, 8, 0, 0, 0)
410     # Measurement Pilot Transmission
411     subelems += struct.pack("<BBBBB", 66, 3, 0, 0, 0)
412     # RM Enabled Capabilities
413     subelems += struct.pack("<BBBBBBB", 70, 5, 0, 0, 0, 0, 0)
414     # Multiple BSSID
415     subelems += struct.pack("<BBBB", 71, 2, 0, 0)
416     req['payload'] += struct.pack("<BB6BLBBB", 52, 13 + len(subelems) * 2,
417                                   1, 2, 3, 4, 5, 6,
418                                   0, 81, 1, 7) + subelems + subelems
419     hapd.mgmt_tx(req)
420     resp = rx_bss_tm_resp(hapd, expect_dialog=8, expect_status=7)
421
422     # Preferred Candidate List followed by vendor element
423     req = bss_tm_req(dev[0].p2p_interface_addr(), apdev[0]['bssid'],
424                      req_mode=0x01, dialog_token=8)
425     subelems = ""
426     req['payload'] += struct.pack("<BB6BLBBB", 52, 13 + len(subelems),
427                                   1, 2, 3, 4, 5, 6,
428                                   0, 81, 1, 7) + subelems
429     req['payload'] += binascii.unhexlify("DD0411223344")
430     hapd.mgmt_tx(req)
431     resp = rx_bss_tm_resp(hapd, expect_dialog=8, expect_status=7)
432
433 def test_wnm_bss_keep_alive(dev, apdev):
434     """WNM keep-alive"""
435     params = { "ssid": "test-wnm",
436                "ap_max_inactivity": "1" }
437     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
438
439     addr = dev[0].p2p_interface_addr()
440     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
441     start = hapd.get_sta(addr)
442     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=2)
443     if ev is not None:
444         raise Exception("Unexpected disconnection")
445     end = hapd.get_sta(addr)
446     if int(end['rx_packets']) <= int(start['rx_packets']):
447         raise Exception("No keep-alive packets received")
448     try:
449         # Disable client keep-alive so that hostapd will verify connection
450         # with client poll
451         dev[0].request("SET no_keep_alive 1")
452         for i in range(60):
453             sta = hapd.get_sta(addr)
454             logger.info("timeout_next=%s rx_packets=%s tx_packets=%s" % (sta['timeout_next'], sta['rx_packets'], sta['tx_packets']))
455             if i > 1 and sta['timeout_next'] != "NULLFUNC POLL" and int(sta['tx_packets']) > int(end['tx_packets']):
456                 break
457             ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
458             if ev is not None:
459                 raise Exception("Unexpected disconnection (client poll expected)")
460     finally:
461         dev[0].request("SET no_keep_alive 0")
462     if int(sta['tx_packets']) <= int(end['tx_packets']):
463         raise Exception("No client poll packet seen")
464
465 def test_wnm_bss_tm(dev, apdev):
466     """WNM BSS Transition Management"""
467     try:
468         hapd = None
469         hapd2 = None
470         params = { "ssid": "test-wnm",
471                    "country_code": "FI",
472                    "ieee80211d": "1",
473                    "hw_mode": "g",
474                    "channel": "1",
475                    "bss_transition": "1" }
476         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
477
478         id = dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
479         dev[0].set_network(id, "scan_freq", "")
480
481         params = { "ssid": "test-wnm",
482                    "country_code": "FI",
483                    "ieee80211d": "1",
484                    "hw_mode": "a",
485                    "channel": "36",
486                    "bss_transition": "1" }
487         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
488
489         addr = dev[0].p2p_interface_addr()
490         dev[0].dump_monitor()
491
492         logger.info("No neighbor list entries")
493         if "OK" not in hapd.request("BSS_TM_REQ " + addr):
494             raise Exception("BSS_TM_REQ command failed")
495         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
496         if ev is None:
497             raise Exception("No BSS Transition Management Response")
498         if addr not in ev:
499             raise Exception("Unexpected BSS Transition Management Response address")
500         if "status_code=0" in ev:
501             raise Exception("BSS transition accepted unexpectedly")
502         dev[0].dump_monitor()
503
504         logger.info("Neighbor list entry, but not claimed as Preferred Candidate List")
505         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " neighbor=11:22:33:44:55:66,0x0000,81,3,7"):
506             raise Exception("BSS_TM_REQ command failed")
507         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
508         if ev is None:
509             raise Exception("No BSS Transition Management Response")
510         if "status_code=0" in ev:
511             raise Exception("BSS transition accepted unexpectedly")
512         dev[0].dump_monitor()
513
514         logger.info("Preferred Candidate List (no matching neighbor) without Disassociation Imminent")
515         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 neighbor=11:22:33:44:55:66,0x0000,81,3,7,0301ff neighbor=22:33:44:55:66:77,0x0000,1,36,7 neighbor=00:11:22:33:44:55,0x0000,81,4,7,03010a"):
516             raise Exception("BSS_TM_REQ command failed")
517         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
518         if ev is None:
519             raise Exception("No BSS Transition Management Response")
520         if "status_code=0" in ev:
521             raise Exception("BSS transition accepted unexpectedly")
522         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
523         if ev is None:
524             raise Exception("No scan started")
525         dev[0].dump_monitor()
526
527         logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
528         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
529             raise Exception("BSS_TM_REQ command failed")
530         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
531         if ev is None:
532             raise Exception("No BSS Transition Management Response")
533         if "status_code=0" not in ev:
534             raise Exception("BSS transition request was not accepted: " + ev)
535         if "target_bssid=" + apdev[1]['bssid'] not in ev:
536             raise Exception("Unexpected target BSS: " + ev)
537         dev[0].wait_connected(timeout=15, error="No reassociation seen")
538         if apdev[1]['bssid'] not in ev:
539             raise Exception("Unexpected reassociation target: " + ev)
540         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
541         if ev is not None:
542             raise Exception("Unexpected scan started")
543         dev[0].dump_monitor()
544
545         logger.info("Preferred Candidate List with two matches, no roam needed")
546         if "OK" not in hapd2.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[0]['bssid'] + ",0x0000,81,1,7,030101 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
547             raise Exception("BSS_TM_REQ command failed")
548         ev = hapd2.wait_event(['BSS-TM-RESP'], timeout=10)
549         if ev is None:
550             raise Exception("No BSS Transition Management Response")
551         if "status_code=0" not in ev:
552             raise Exception("BSS transition request was not accepted: " + ev)
553         if "target_bssid=" + apdev[1]['bssid'] not in ev:
554             raise Exception("Unexpected target BSS: " + ev)
555         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
556         if ev is not None:
557             raise Exception("Unexpected scan started")
558         ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.5)
559         if ev is not None:
560             raise Exception("Unexpected reassociation");
561     finally:
562         dev[0].request("DISCONNECT")
563         if hapd:
564             hapd.request("DISABLE")
565         if hapd2:
566             hapd2.request("DISABLE")
567         subprocess.call(['iw', 'reg', 'set', '00'])
568         dev[0].flush_scan_cache()
569
570 def test_wnm_bss_tm_scan_not_needed(dev, apdev):
571     """WNM BSS Transition Management and scan not needed"""
572     try:
573         hapd = None
574         hapd2 = None
575         params = { "ssid": "test-wnm",
576                    "country_code": "FI",
577                    "ieee80211d": "1",
578                    "hw_mode": "g",
579                    "channel": "1",
580                    "bss_transition": "1" }
581         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
582
583         params = { "ssid": "test-wnm",
584                    "country_code": "FI",
585                    "ieee80211d": "1",
586                    "hw_mode": "a",
587                    "channel": "36",
588                    "bss_transition": "1" }
589         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
590
591         dev[0].scan_for_bss(apdev[1]['bssid'], 5180)
592
593         id = dev[0].connect("test-wnm", key_mgmt="NONE",
594                             bssid=apdev[0]['bssid'], scan_freq="2412")
595         dev[0].set_network(id, "scan_freq", "")
596         dev[0].set_network(id, "bssid", "")
597
598         addr = dev[0].own_addr()
599         dev[0].dump_monitor()
600
601         logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
602         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
603             raise Exception("BSS_TM_REQ command failed")
604         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
605         if ev is None:
606             raise Exception("No BSS Transition Management Response")
607         if "status_code=0" not in ev:
608             raise Exception("BSS transition request was not accepted: " + ev)
609         if "target_bssid=" + apdev[1]['bssid'] not in ev:
610             raise Exception("Unexpected target BSS: " + ev)
611         dev[0].wait_connected(timeout=15, error="No reassociation seen")
612         if apdev[1]['bssid'] not in ev:
613             raise Exception("Unexpected reassociation target: " + ev)
614         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
615         if ev is not None:
616             raise Exception("Unexpected scan started")
617         dev[0].dump_monitor()
618     finally:
619         dev[0].request("DISCONNECT")
620         if hapd:
621             hapd.request("DISABLE")
622         if hapd2:
623             hapd2.request("DISABLE")
624         subprocess.call(['iw', 'reg', 'set', '00'])
625         dev[0].flush_scan_cache()
626
627 def test_wnm_bss_tm_scan_needed(dev, apdev):
628     """WNM BSS Transition Management and scan needed"""
629     try:
630         hapd = None
631         hapd2 = None
632         params = { "ssid": "test-wnm",
633                    "country_code": "FI",
634                    "ieee80211d": "1",
635                    "hw_mode": "g",
636                    "channel": "1",
637                    "bss_transition": "1" }
638         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
639
640         params = { "ssid": "test-wnm",
641                    "country_code": "FI",
642                    "ieee80211d": "1",
643                    "hw_mode": "a",
644                    "channel": "36",
645                    "bss_transition": "1" }
646         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
647
648         dev[0].scan_for_bss(apdev[1]['bssid'], 5180)
649
650         id = dev[0].connect("test-wnm", key_mgmt="NONE",
651                             bssid=apdev[0]['bssid'], scan_freq="2412")
652         dev[0].set_network(id, "scan_freq", "")
653         dev[0].set_network(id, "bssid", "")
654
655         addr = dev[0].own_addr()
656         dev[0].dump_monitor()
657
658         logger.info("Wait 11 seconds for the last scan result to be too old, but still present in BSS table")
659         time.sleep(11)
660         logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
661         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
662             raise Exception("BSS_TM_REQ command failed")
663         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
664         if ev is None:
665             raise Exception("No BSS Transition Management Response")
666         if "status_code=0" not in ev:
667             raise Exception("BSS transition request was not accepted: " + ev)
668         if "target_bssid=" + apdev[1]['bssid'] not in ev:
669             raise Exception("Unexpected target BSS: " + ev)
670         dev[0].wait_connected(timeout=15, error="No reassociation seen")
671         if apdev[1]['bssid'] not in ev:
672             raise Exception("Unexpected reassociation target: " + ev)
673         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
674         if ev is not None:
675             raise Exception("Unexpected scan started")
676         dev[0].dump_monitor()
677     finally:
678         dev[0].request("DISCONNECT")
679         if hapd:
680             hapd.request("DISABLE")
681         if hapd2:
682             hapd2.request("DISABLE")
683         subprocess.call(['iw', 'reg', 'set', '00'])
684         dev[0].flush_scan_cache()
685
686 def start_wnm_tm(ap, country, dev):
687     params = { "ssid": "test-wnm",
688                "country_code": country,
689                "ieee80211d": "1",
690                "hw_mode": "g",
691                "channel": "1",
692                "bss_transition": "1" }
693     hapd = hostapd.add_ap(ap['ifname'], params)
694     id = dev.connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
695     dev.dump_monitor()
696     dev.set_network(id, "scan_freq", "")
697     return hapd, id
698
699 def stop_wnm_tm(hapd, dev):
700     dev.request("DISCONNECT")
701     try:
702         dev.wait_disconnected()
703     except:
704         pass
705     if hapd:
706         hapd.request("DISABLE")
707     subprocess.call(['iw', 'reg', 'set', '00'])
708     dev.flush_scan_cache()
709
710 def wnm_bss_tm_check(hapd, dev, data):
711     addr = dev.p2p_interface_addr()
712     if "OK" not in hapd.request("BSS_TM_REQ " + addr + " " + data):
713         raise Exception("BSS_TM_REQ command failed")
714     ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
715     if ev is None:
716         raise Exception("No scan started")
717     ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
718     if ev is None:
719         raise Exception("Scan did not complete")
720
721     ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
722     if ev is None:
723         raise Exception("No BSS Transition Management Response")
724     if "status_code=7" not in ev:
725         raise Exception("Unexpected response: " + ev)
726
727 def test_wnm_bss_tm_country_us(dev, apdev):
728     """WNM BSS Transition Management (US)"""
729     try:
730         hapd = None
731         hapd, id = start_wnm_tm(apdev[0], "US", dev[0])
732
733         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
734         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,12,3,7,0301ff neighbor=00:11:22:33:44:55,0x0000,2,52,7,03010a neighbor=00:11:22:33:44:57,0x0000,4,100,7 neighbor=00:11:22:33:44:59,0x0000,3,149,7 neighbor=00:11:22:33:44:5b,0x0000,34,1,7 neighbor=00:11:22:33:44:5d,0x0000,5,149,7")
735
736         # Make the test take less time by limiting full scans
737         dev[0].set_network(id, "scan_freq", "2412")
738         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
739         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,12,0,7,0301ff neighbor=22:33:44:55:66:77,0x0000,12,12,7 neighbor=00:11:22:33:44:55,0x0000,2,35,7,03010a neighbor=00:11:22:33:44:56,0x0000,2,65,7 neighbor=00:11:22:33:44:57,0x0000,4,99,7 neighbor=00:11:22:33:44:58,0x0000,4,145,7")
740
741         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
742         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:59,0x0000,3,148,7 neighbor=00:11:22:33:44:5a,0x0000,3,162,7 neighbor=00:11:22:33:44:5b,0x0000,34,0,7 neighbor=00:11:22:33:44:5c,0x0000,34,4,7 neighbor=00:11:22:33:44:5d,0x0000,5,148,7 neighbor=00:11:22:33:44:5e,0x0000,5,166,7 neighbor=00:11:22:33:44:5f,0x0000,0,0,7")
743     finally:
744         stop_wnm_tm(hapd, dev[0])
745
746 def test_wnm_bss_tm_country_fi(dev, apdev):
747     """WNM BSS Transition Management (FI)"""
748     addr = dev[0].p2p_interface_addr()
749     try:
750         hapd = None
751         hapd, id = start_wnm_tm(apdev[0], "FI", dev[0])
752
753         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
754         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,4,3,7,0301ff neighbor=00:11:22:33:44:55,0x0000,1,36,7,03010a neighbor=00:11:22:33:44:57,0x0000,3,100,7 neighbor=00:11:22:33:44:59,0x0000,17,149,7 neighbor=00:11:22:33:44:5c,0x0000,18,1,7")
755
756         # Make the test take less time by limiting full scans
757         dev[0].set_network(id, "scan_freq", "2412")
758         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
759         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,4,0,7 neighbor=00:11:22:33:44:01,0x0000,4,14,7 neighbor=00:11:22:33:44:02,0x0000,1,35,7 neighbor=00:11:22:33:44:03,0x0000,1,65,7 neighbor=00:11:22:33:44:04,0x0000,3,99,7 neighbor=00:11:22:33:44:05,0x0000,3,141,7 neighbor=00:11:22:33:44:06,0x0000,17,148,7 neighbor=00:11:22:33:44:07,0x0000,17,170,7 neighbor=00:11:22:33:44:08,0x0000,18,0,7 neighbor=00:11:22:33:44:09,0x0000,18,5,7")
760
761         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
762         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,0,0,7")
763     finally:
764         stop_wnm_tm(hapd, dev[0])
765
766 def test_wnm_bss_tm_country_jp(dev, apdev):
767     """WNM BSS Transition Management (JP)"""
768     addr = dev[0].p2p_interface_addr()
769     try:
770         hapd = None
771         hapd, id = start_wnm_tm(apdev[0], "JP", dev[0])
772
773         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
774         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,30,3,7,0301ff neighbor=00:11:22:33:44:55,0x0000,31,14,7,03010a neighbor=00:11:22:33:44:57,0x0000,1,36,7 neighbor=00:11:22:33:44:59,0x0000,34,100,7 neighbor=00:11:22:33:44:5c,0x0000,59,1,7")
775
776         # Make the test take less time by limiting full scans
777         dev[0].set_network(id, "scan_freq", "2412")
778         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
779         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,30,0,7,0301ff neighbor=22:33:44:55:66:77,0x0000,30,14,7 neighbor=00:11:22:33:44:56,0x0000,31,13,7 neighbor=00:11:22:33:44:57,0x0000,1,33,7 neighbor=00:11:22:33:44:58,0x0000,1,65,7 neighbor=00:11:22:33:44:5a,0x0000,34,99,7 neighbor=00:11:22:33:44:5b,0x0000,34,141,7 neighbor=00:11:22:33:44:5d,0x0000,59,0,7 neighbor=00:11:22:33:44:5e,0x0000,59,4,7 neighbor=00:11:22:33:44:5f,0x0000,0,0,7")
780     finally:
781         stop_wnm_tm(hapd, dev[0])
782
783 def test_wnm_bss_tm_country_cn(dev, apdev):
784     """WNM BSS Transition Management (CN)"""
785     addr = dev[0].p2p_interface_addr()
786     try:
787         hapd = None
788         hapd, id = start_wnm_tm(apdev[0], "CN", dev[0])
789
790         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
791         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,7,3,7,0301ff neighbor=00:11:22:33:44:55,0x0000,1,36,7,03010a neighbor=00:11:22:33:44:57,0x0000,3,149,7 neighbor=00:11:22:33:44:59,0x0000,6,149,7")
792
793         # Make the test take less time by limiting full scans
794         dev[0].set_network(id, "scan_freq", "2412")
795         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
796         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,7,0,7,0301ff neighbor=22:33:44:55:66:77,0x0000,7,14,7 neighbor=00:11:22:33:44:56,0x0000,1,35,7 neighbor=00:11:22:33:44:57,0x0000,1,65,7 neighbor=00:11:22:33:44:58,0x0000,3,148,7 neighbor=00:11:22:33:44:5a,0x0000,3,166,7 neighbor=00:11:22:33:44:5f,0x0000,0,0,7")
797     finally:
798         stop_wnm_tm(hapd, dev[0])
799
800 def test_wnm_bss_tm_global(dev, apdev):
801     """WNM BSS Transition Management (global)"""
802     addr = dev[0].p2p_interface_addr()
803     try:
804         hapd = None
805         hapd, id = start_wnm_tm(apdev[0], "XX", dev[0])
806
807         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
808         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=11:22:33:44:55:66,0x0000,81,3,7,0301ff neighbor=00:11:22:33:44:55,0x0000,82,14,7,03010a neighbor=00:11:22:33:44:57,0x0000,83,1,7 neighbor=00:11:22:33:44:59,0x0000,115,36,7 neighbor=00:11:22:33:44:5a,0x0000,121,100,7 neighbor=00:11:22:33:44:5c,0x0000,124,149,7 neighbor=00:11:22:33:44:5d,0x0000,125,149,7 neighbor=00:11:22:33:44:5e,0x0000,128,42,7 neighbor=00:11:22:33:44:5f,0x0000,129,50,7 neighbor=00:11:22:33:44:60,0x0000,180,1,7")
809
810         # Make the test take less time by limiting full scans
811         dev[0].set_network(id, "scan_freq", "2412")
812         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
813         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,81,0,7 neighbor=00:11:22:33:44:01,0x0000,81,14,7 neighbor=00:11:22:33:44:02,0x0000,82,13,7 neighbor=00:11:22:33:44:03,0x0000,83,0,7 neighbor=00:11:22:33:44:04,0x0000,83,14,7 neighbor=00:11:22:33:44:05,0x0000,115,35,7 neighbor=00:11:22:33:44:06,0x0000,115,65,7 neighbor=00:11:22:33:44:07,0x0000,121,99,7 neighbor=00:11:22:33:44:08,0x0000,121,141,7 neighbor=00:11:22:33:44:09,0x0000,124,148,7")
814
815         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
816         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,124,162,7 neighbor=00:11:22:33:44:01,0x0000,125,148,7 neighbor=00:11:22:33:44:02,0x0000,125,170,7 neighbor=00:11:22:33:44:03,0x0000,128,35,7 neighbor=00:11:22:33:44:04,0x0000,128,162,7 neighbor=00:11:22:33:44:05,0x0000,129,49,7 neighbor=00:11:22:33:44:06,0x0000,129,115,7 neighbor=00:11:22:33:44:07,0x0000,180,0,7 neighbor=00:11:22:33:44:08,0x0000,180,5,7 neighbor=00:11:22:33:44:09,0x0000,0,0,7")
817     finally:
818         stop_wnm_tm(hapd, dev[0])
819
820 def test_wnm_bss_tm_op_class_0(dev, apdev):
821     """WNM BSS Transition Management with invalid operating class"""
822     try:
823         hapd = None
824         hapd, id = start_wnm_tm(apdev[0], "US", dev[0])
825
826         logger.info("Preferred Candidate List (no matching neighbor, invalid op class specified for channels)")
827         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:59,0x0000,0,149,7 neighbor=00:11:22:33:44:5b,0x0000,0,1,7")
828     finally:
829         stop_wnm_tm(hapd, dev[0])
830
831 def test_wnm_action_proto(dev, apdev):
832     """WNM Action protocol testing"""
833     params = { "ssid": "test-wnm" }
834     params['wnm_sleep_mode'] = '1'
835     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
836     bssid = apdev[0]['bssid']
837     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
838     dev[0].request("WNM_SLEEP enter")
839     time.sleep(0.1)
840     hapd.set("ext_mgmt_frame_handling", "1")
841
842     msg = {}
843     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
844     msg['da'] = dev[0].own_addr()
845     msg['sa'] = bssid
846     msg['bssid'] = bssid
847
848     dialog_token = 1
849
850     logger.debug("Unexpected WNM-Notification Response")
851     # Note: This is actually not registered for user space processing in
852     # driver_nl80211.c nl80211_mgmt_subscribe_non_ap() and as such, won't make
853     # it to wpa_supplicant.
854     msg['payload'] = struct.pack("<BBBB",
855                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_RESP,
856                                  dialog_token, 0)
857     hapd.mgmt_tx(msg)
858     expect_ack(hapd)
859
860     logger.debug("Truncated WNM-Notification Request (no Type field)")
861     msg['payload'] = struct.pack("<BBB",
862                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
863                                  dialog_token)
864     hapd.mgmt_tx(msg)
865     expect_ack(hapd)
866
867     logger.debug("WFA WNM-Notification Request with truncated IE (min)")
868     msg['payload'] = struct.pack("<BBBBBB",
869                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
870                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 1)
871     hapd.mgmt_tx(msg)
872     expect_ack(hapd)
873
874     logger.debug("WFA WNM-Notification Request with truncated IE (max)")
875     msg['payload'] = struct.pack("<BBBBBB",
876                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
877                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 255)
878     hapd.mgmt_tx(msg)
879     expect_ack(hapd)
880
881     logger.debug("WFA WNM-Notification Request with too short IE")
882     msg['payload'] = struct.pack("<BBBBBB",
883                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
884                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 0)
885     hapd.mgmt_tx(msg)
886     expect_ack(hapd)
887
888     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL")
889     msg['payload'] = struct.pack(">BBBBBBLB",
890                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
891                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
892                                  0x506f9a00, 1)
893     hapd.mgmt_tx(msg)
894     expect_ack(hapd)
895
896     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(2)")
897     msg['payload'] = struct.pack(">BBBBBBLBB",
898                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
899                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 6,
900                                  0x506f9a00, 1, 0)
901     hapd.mgmt_tx(msg)
902     expect_ack(hapd)
903
904     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(3)")
905     msg['payload'] = struct.pack(">BBBBBBLB",
906                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
907                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
908                                  0x506f9a00, 0xff)
909     hapd.mgmt_tx(msg)
910     expect_ack(hapd)
911
912     logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(min)")
913     msg['payload'] = struct.pack(">BBBBBBLBHB",
914                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
915                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
916                                  0x506f9a01, 0, 0, 1)
917     hapd.mgmt_tx(msg)
918     expect_ack(hapd)
919
920     logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(max)")
921     msg['payload'] = struct.pack(">BBBBBBLBHB",
922                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
923                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
924                                  0x506f9a01, 0, 0, 0xff)
925     hapd.mgmt_tx(msg)
926     expect_ack(hapd)
927
928     logger.debug("WFA WNM-Notification Request with unsupported IE")
929     msg['payload'] = struct.pack("<BBBBBBL",
930                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
931                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 4, 0)
932     hapd.mgmt_tx(msg)
933     expect_ack(hapd)
934
935     logger.debug("WNM-Notification Request with unknown WNM-Notification type 0")
936     msg['payload'] = struct.pack("<BBBB",
937                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
938                                  dialog_token, WNM_NOTIF_TYPE_FW_UPGRADE)
939     hapd.mgmt_tx(msg)
940     expect_ack(hapd)
941
942     logger.debug("Truncated WNM Sleep Mode Response - no Dialog Token")
943     msg['payload'] = struct.pack("<BB",
944                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP)
945     hapd.mgmt_tx(msg)
946     expect_ack(hapd)
947
948     logger.debug("Truncated WNM Sleep Mode Response - no Key Data Length")
949     msg['payload'] = struct.pack("<BBB",
950                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0)
951     hapd.mgmt_tx(msg)
952     expect_ack(hapd)
953
954     logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (min)")
955     msg['payload'] = struct.pack("<BBBH",
956                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
957                                  1)
958     hapd.mgmt_tx(msg)
959     expect_ack(hapd)
960
961     logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (max)")
962     msg['payload'] = struct.pack("<BBBH",
963                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
964                                  0xffff)
965     hapd.mgmt_tx(msg)
966     expect_ack(hapd)
967
968     logger.debug("WNM Sleep Mode Response - truncated IE header")
969     msg['payload'] = struct.pack("<BBBHB",
970                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
971                                  0, 0)
972     hapd.mgmt_tx(msg)
973     expect_ack(hapd)
974
975     logger.debug("WNM Sleep Mode Response - truncated IE")
976     msg['payload'] = struct.pack("<BBBHBB",
977                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
978                                  0, 0, 1)
979     hapd.mgmt_tx(msg)
980     expect_ack(hapd)
981
982     logger.debug("WNM Sleep Mode Response - Empty TFS Response")
983     msg['payload'] = struct.pack("<BBBHBB",
984                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
985                                  0, WLAN_EID_TFS_RESP, 0)
986     hapd.mgmt_tx(msg)
987     expect_ack(hapd)
988
989     logger.debug("WNM Sleep Mode Response - EID 0 not recognized")
990     msg['payload'] = struct.pack("<BBBHBB",
991                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
992                                  0, 0, 0)
993     hapd.mgmt_tx(msg)
994     expect_ack(hapd)
995
996     logger.debug("WNM Sleep Mode Response - Empty WNM Sleep Mode element and TFS Response element")
997     msg['payload'] = struct.pack("<BBBHBBBB",
998                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
999                                  0, WLAN_EID_WNMSLEEP, 0, WLAN_EID_TFS_RESP, 0)
1000     hapd.mgmt_tx(msg)
1001     expect_ack(hapd)
1002
1003     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element and empty TFS Response element")
1004     msg['payload'] = struct.pack("<BBBHBBBBHBB",
1005                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1006                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
1007                                  WNM_STATUS_SLEEP_ACCEPT, 0,
1008                                  WLAN_EID_TFS_RESP, 0)
1009     hapd.mgmt_tx(msg)
1010     expect_ack(hapd)
1011
1012     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(exit, deny key) and empty TFS Response element")
1013     msg['payload'] = struct.pack("<BBBHBBBBHBB",
1014                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1015                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1016                                  WNM_STATUS_DENIED_KEY, 0,
1017                                  WLAN_EID_TFS_RESP, 0)
1018     hapd.mgmt_tx(msg)
1019     expect_ack(hapd)
1020
1021     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(enter, deny key) and empty TFS Response element")
1022     msg['payload'] = struct.pack("<BBBHBBBBHBB",
1023                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1024                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
1025                                  WNM_STATUS_DENIED_KEY, 0,
1026                                  WLAN_EID_TFS_RESP, 0)
1027     hapd.mgmt_tx(msg)
1028     expect_ack(hapd)
1029
1030 def test_wnm_action_proto_pmf(dev, apdev):
1031     """WNM Action protocol testing (PMF enabled)"""
1032     ssid = "test-wnm-pmf"
1033     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
1034     params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
1035     params["ieee80211w"] = "2"
1036     params['wnm_sleep_mode'] = '1'
1037     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1038     bssid = apdev[0]['bssid']
1039     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK-SHA256",
1040                    proto="WPA2", ieee80211w="2", scan_freq="2412")
1041     dev[0].request("WNM_SLEEP enter")
1042     time.sleep(0.1)
1043     hapd.set("ext_mgmt_frame_handling", "1")
1044
1045     msg = {}
1046     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
1047     msg['da'] = dev[0].own_addr()
1048     msg['sa'] = bssid
1049     msg['bssid'] = bssid
1050
1051     logger.debug("WNM Sleep Mode Response - Invalid Key Data element length")
1052     keydata = struct.pack("<BB", 0, 1)
1053     msg['payload'] = struct.pack("<BBBH",
1054                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1055                                  len(keydata))
1056     msg['payload'] += keydata
1057     msg['payload'] += struct.pack("<BBBBHBB",
1058                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1059                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1060                                   WLAN_EID_TFS_RESP, 0)
1061     hapd.mgmt_tx(msg)
1062     expect_ack(hapd)
1063
1064     logger.debug("WNM Sleep Mode Response - Too short GTK subelem")
1065     keydata = struct.pack("<BB", WNM_SLEEP_SUBELEM_GTK, 0)
1066     msg['payload'] = struct.pack("<BBBH",
1067                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1068                                  len(keydata))
1069     msg['payload'] += keydata
1070     msg['payload'] += struct.pack("<BBBBHBB",
1071                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1072                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1073                                   WLAN_EID_TFS_RESP, 0)
1074     hapd.mgmt_tx(msg)
1075     expect_ack(hapd)
1076
1077     logger.debug("WNM Sleep Mode Response - Invalid GTK subelem")
1078     keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
1079                           0, 17, 0, 0, 0, 0, 0, 0)
1080     msg['payload'] = struct.pack("<BBBH",
1081                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1082                                  len(keydata))
1083     msg['payload'] += keydata
1084     msg['payload'] += struct.pack("<BBBBHBB",
1085                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1086                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1087                                   WLAN_EID_TFS_RESP, 0)
1088     hapd.mgmt_tx(msg)
1089     expect_ack(hapd)
1090
1091     logger.debug("WNM Sleep Mode Response - Invalid GTK subelem (2)")
1092     keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
1093                           0, 0, 0, 0, 0, 0, 0, 0)
1094     msg['payload'] = struct.pack("<BBBH",
1095                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1096                                  len(keydata))
1097     msg['payload'] += keydata
1098     msg['payload'] += struct.pack("<BBBBHBB",
1099                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1100                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1101                                   WLAN_EID_TFS_RESP, 0)
1102     hapd.mgmt_tx(msg)
1103     expect_ack(hapd)
1104
1105     logger.debug("WNM Sleep Mode Response - GTK subelem and too short IGTK subelem")
1106     keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
1107     keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
1108                            0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
1109     keydata += struct.pack("<BB", WNM_SLEEP_SUBELEM_IGTK, 0)
1110     msg['payload'] = struct.pack("<BBBH",
1111                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1112                                  len(keydata))
1113     msg['payload'] += keydata
1114     msg['payload'] += struct.pack("<BBBBHBB",
1115                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1116                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1117                                   WLAN_EID_TFS_RESP, 0)
1118     hapd.mgmt_tx(msg)
1119     expect_ack(hapd)
1120
1121     logger.debug("WNM Sleep Mode Response - Unknown subelem")
1122     keydata = struct.pack("<BB", 255, 0)
1123     msg['payload'] = struct.pack("<BBBH",
1124                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1125                                  len(keydata))
1126     msg['payload'] += keydata
1127     msg['payload'] += struct.pack("<BBBBHBB",
1128                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1129                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1130                                   WLAN_EID_TFS_RESP, 0)
1131     hapd.mgmt_tx(msg)
1132     expect_ack(hapd)
1133
1134 def test_wnm_action_proto_no_pmf(dev, apdev):
1135     """WNM Action protocol testing (PMF disabled)"""
1136     ssid = "test-wnm-no-pmf"
1137     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
1138     params['wnm_sleep_mode'] = '1'
1139     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1140     bssid = apdev[0]['bssid']
1141     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
1142                    proto="WPA2", ieee80211w="0", scan_freq="2412")
1143     dev[0].request("WNM_SLEEP enter")
1144     time.sleep(0.1)
1145     hapd.set("ext_mgmt_frame_handling", "1")
1146
1147     msg = {}
1148     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
1149     msg['da'] = dev[0].own_addr()
1150     msg['sa'] = bssid
1151     msg['bssid'] = bssid
1152
1153     logger.debug("WNM Sleep Mode Response - GTK subelem and IGTK subelem")
1154     keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
1155     keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
1156                            0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
1157     keydata += struct.pack("<BBHLH4L", WNM_SLEEP_SUBELEM_IGTK, 2 + 6 + 16, 0,
1158                            0x10203040, 0x5060,
1159                            0xf1f2f3f4, 0xf5f6f7f8, 0xf9f0fafb, 0xfcfdfeff)
1160     msg['payload'] = struct.pack("<BBBH",
1161                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1162                                  len(keydata))
1163     msg['payload'] += keydata
1164     msg['payload'] += struct.pack("<BBBBHBB",
1165                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1166                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1167                                   WLAN_EID_TFS_RESP, 0)
1168     hapd.mgmt_tx(msg)
1169     expect_ack(hapd)
1170
1171     ev = dev[0].wait_event(["WNM: Ignore Key Data"], timeout=5)
1172     if ev is None:
1173         raise Exception("Key Data not ignored")
1174
1175 def test_wnm_bss_tm_req_with_mbo_ie(dev, apdev):
1176     """WNM BSS transition request with MBO IE and reassociation delay attribute"""
1177     ssid = "test-wnm-mbo"
1178     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
1179     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1180     bssid = apdev[0]['bssid']
1181     if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
1182         raise Exception("Failed to set STA as cellular data capable")
1183
1184     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
1185                    proto="WPA2", ieee80211w="0", scan_freq="2412")
1186
1187     logger.debug("BTM request with MBO reassociation delay when disassoc imminent is not set")
1188     if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=3:2:1"):
1189         raise Exception("BSS transition management succeeded unexpectedly")
1190
1191     logger.debug("BTM request with invalid MBO transition reason code")
1192     if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=10:2:1"):
1193         raise Exception("BSS transition management succeeded unexpectedly")
1194
1195     logger.debug("BTM request with MBO reassociation retry delay of 5 seconds")
1196     if 'OK' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " disassoc_imminent=1 disassoc_timer=3 mbo=3:5:1"):
1197         raise Exception("BSS transition management command failed")
1198
1199     ev = dev[0].wait_event(['MBO-CELL-PREFERENCE'], 1)
1200     if ev is None or "preference=1" not in ev:
1201         raise Exception("Timeout waiting for MBO-CELL-PREFERENCE event")
1202
1203     ev = dev[0].wait_event(['MBO-TRANSITION-REASON'], 1)
1204     if ev is None or "reason=3" not in ev:
1205         raise Exception("Timeout waiting for MBO-TRANSITION-REASON event")
1206
1207     ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
1208     if ev is None:
1209         raise Exception("No BSS Transition Management Response")
1210     if dev[0].own_addr() not in ev:
1211         raise Exception("Unexpected BSS Transition Management Response address")
1212
1213     ev = dev[0].wait_event(['CTRL-EVENT-DISCONNECTED'], 5)
1214     if ev is None:
1215             raise Exception("Station did not disconnect although disassoc imminent was set")
1216
1217     # Set the scan interval to make dev[0] look for connections
1218     if 'OK' not in dev[0].request("SCAN_INTERVAL 1"):
1219             raise Exception("Failed to set scan interval")
1220
1221     # Make sure no connection is made during the retry delay
1222     ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
1223     if ev is not None:
1224             raise Exception("Station connected before assoc retry delay was over")
1225
1226     # After the assoc retry delay is over, we can reconnect
1227     ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
1228     if ev is None:
1229             raise Exception("Station did not connect after assoc retry delay is over")
1230
1231     if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
1232         raise Exception("Failed to set STA as cellular data not-capable")
1233
1234 def test_wnm_bss_transition_mgmt_query(dev, apdev):
1235     """WNM BSS Transition Management query"""
1236     params = { "ssid": "test-wnm",
1237                "bss_transition": "1" }
1238     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1239     params = { "ssid": "another" }
1240     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1241
1242     dev[0].scan_for_bss(apdev[1]['bssid'], 2412)
1243     dev[0].scan_for_bss(apdev[0]['bssid'], 2412)
1244
1245     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
1246     dev[0].request("WNM_BSS_QUERY 0 list")
1247
1248     ev = dev[0].wait_event(["WNM: BSS Transition Management Request"],
1249                            timeout=5)
1250     if ev is None:
1251         raise Exception("No BSS Transition Management Request frame seen")
1252
1253     ev = hapd.wait_event(["BSS-TM-RESP"], timeout=5)
1254     if ev is None:
1255         raise Exception("No BSS Transition Management Response frame seen")
1256
1257 def test_wnm_bss_tm_security_mismatch(dev, apdev):
1258     """WNM BSS Transition Management and security mismatch"""
1259     params = { "ssid": "test-wnm",
1260                "wpa": "2",
1261                "wpa_key_mgmt": "WPA-PSK",
1262                "rsn_pairwise": "CCMP",
1263                "wpa_passphrase": "12345678",
1264                "hw_mode": "g",
1265                "channel": "1",
1266                "bss_transition": "1" }
1267     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1268
1269     params = { "ssid": "test-wnm",
1270                "hw_mode": "g",
1271                "channel": "11",
1272                "bss_transition": "1" }
1273     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1274
1275     dev[0].scan_for_bss(apdev[1]['bssid'], 2462)
1276
1277     id = dev[0].connect("test-wnm", psk="12345678",
1278                         bssid=apdev[0]['bssid'], scan_freq="2412")
1279     dev[0].set_network(id, "scan_freq", "")
1280     dev[0].set_network(id, "bssid", "")
1281
1282     addr = dev[0].own_addr()
1283     dev[0].dump_monitor()
1284
1285     logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
1286     if "OK" not in hapd.request("BSS_TM_REQ " + addr + " pref=1 abridged=1 valid_int=255 neighbor=" + apdev[1]['bssid'] + ",0x0000,115,36,7,0301ff"):
1287         raise Exception("BSS_TM_REQ command failed")
1288     ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
1289     if ev is None:
1290         raise Exception("No BSS Transition Management Response")
1291     if "status_code=7" not in ev:
1292         raise Exception("Unexpected BSS transition request response: " + ev)