tests: WNM Sleep Mode - AP side OOM
[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 def test_wnm_bss_keep_alive(dev, apdev):
423     """WNM keep-alive"""
424     params = { "ssid": "test-wnm",
425                "ap_max_inactivity": "1" }
426     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
427
428     addr = dev[0].p2p_interface_addr()
429     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
430     start = hapd.get_sta(addr)
431     ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=2)
432     if ev is not None:
433         raise Exception("Unexpected disconnection")
434     end = hapd.get_sta(addr)
435     if int(end['rx_packets']) <= int(start['rx_packets']):
436         raise Exception("No keep-alive packets received")
437     try:
438         # Disable client keep-alive so that hostapd will verify connection
439         # with client poll
440         dev[0].request("SET no_keep_alive 1")
441         for i in range(60):
442             sta = hapd.get_sta(addr)
443             logger.info("timeout_next=%s rx_packets=%s tx_packets=%s" % (sta['timeout_next'], sta['rx_packets'], sta['tx_packets']))
444             if i > 1 and sta['timeout_next'] != "NULLFUNC POLL" and int(sta['tx_packets']) > int(end['tx_packets']):
445                 break
446             ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.5)
447             if ev is not None:
448                 raise Exception("Unexpected disconnection (client poll expected)")
449     finally:
450         dev[0].request("SET no_keep_alive 0")
451     if int(sta['tx_packets']) <= int(end['tx_packets']):
452         raise Exception("No client poll packet seen")
453
454 def test_wnm_bss_tm(dev, apdev):
455     """WNM BSS Transition Management"""
456     try:
457         hapd = None
458         hapd2 = None
459         params = { "ssid": "test-wnm",
460                    "country_code": "FI",
461                    "ieee80211d": "1",
462                    "hw_mode": "g",
463                    "channel": "1",
464                    "bss_transition": "1" }
465         hapd = hostapd.add_ap(apdev[0]['ifname'], params)
466
467         id = dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
468         dev[0].set_network(id, "scan_freq", "")
469
470         params = { "ssid": "test-wnm",
471                    "country_code": "FI",
472                    "ieee80211d": "1",
473                    "hw_mode": "a",
474                    "channel": "36",
475                    "bss_transition": "1" }
476         hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
477
478         addr = dev[0].p2p_interface_addr()
479         dev[0].dump_monitor()
480
481         logger.info("No neighbor list entries")
482         if "OK" not in hapd.request("BSS_TM_REQ " + addr):
483             raise Exception("BSS_TM_REQ command failed")
484         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
485         if ev is None:
486             raise Exception("No BSS Transition Management Response")
487         if addr not in ev:
488             raise Exception("Unexpected BSS Transition Management Response address")
489         if "status_code=0" in ev:
490             raise Exception("BSS transition accepted unexpectedly")
491         dev[0].dump_monitor()
492
493         logger.info("Neighbor list entry, but not claimed as Preferred Candidate List")
494         if "OK" not in hapd.request("BSS_TM_REQ " + addr + " neighbor=11:22:33:44:55:66,0x0000,81,3,7"):
495             raise Exception("BSS_TM_REQ command failed")
496         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
497         if ev is None:
498             raise Exception("No BSS Transition Management Response")
499         if "status_code=0" in ev:
500             raise Exception("BSS transition accepted unexpectedly")
501         dev[0].dump_monitor()
502
503         logger.info("Preferred Candidate List (no matching neighbor) without Disassociation Imminent")
504         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"):
505             raise Exception("BSS_TM_REQ command failed")
506         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
507         if ev is None:
508             raise Exception("No BSS Transition Management Response")
509         if "status_code=0" in ev:
510             raise Exception("BSS transition accepted unexpectedly")
511         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
512         if ev is None:
513             raise Exception("No scan started")
514         dev[0].dump_monitor()
515
516         logger.info("Preferred Candidate List (matching neighbor for another BSS) without Disassociation Imminent")
517         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"):
518             raise Exception("BSS_TM_REQ command failed")
519         ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
520         if ev is None:
521             raise Exception("No BSS Transition Management Response")
522         if "status_code=0" not in ev:
523             raise Exception("BSS transition request was not accepted: " + ev)
524         if "target_bssid=" + apdev[1]['bssid'] not in ev:
525             raise Exception("Unexpected target BSS: " + ev)
526         dev[0].wait_connected(timeout=15, error="No reassociation seen")
527         if apdev[1]['bssid'] not in ev:
528             raise Exception("Unexpected reassociation target: " + ev)
529         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
530         if ev is not None:
531             raise Exception("Unexpected scan started")
532         dev[0].dump_monitor()
533
534         logger.info("Preferred Candidate List with two matches, no roam needed")
535         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"):
536             raise Exception("BSS_TM_REQ command failed")
537         ev = hapd2.wait_event(['BSS-TM-RESP'], timeout=10)
538         if ev is None:
539             raise Exception("No BSS Transition Management Response")
540         if "status_code=0" not in ev:
541             raise Exception("BSS transition request was not accepted: " + ev)
542         if "target_bssid=" + apdev[1]['bssid'] not in ev:
543             raise Exception("Unexpected target BSS: " + ev)
544         ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=0.1)
545         if ev is not None:
546             raise Exception("Unexpected scan started")
547         ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.5)
548         if ev is not None:
549             raise Exception("Unexpected reassociation");
550     finally:
551         dev[0].request("DISCONNECT")
552         if hapd:
553             hapd.request("DISABLE")
554         if hapd2:
555             hapd2.request("DISABLE")
556         subprocess.call(['iw', 'reg', 'set', '00'])
557         dev[0].flush_scan_cache()
558
559 def start_wnm_tm(ap, country, dev):
560     params = { "ssid": "test-wnm",
561                "country_code": country,
562                "ieee80211d": "1",
563                "hw_mode": "g",
564                "channel": "1",
565                "bss_transition": "1" }
566     hapd = hostapd.add_ap(ap['ifname'], params)
567     id = dev.connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
568     dev.dump_monitor()
569     dev.set_network(id, "scan_freq", "")
570     return hapd, id
571
572 def stop_wnm_tm(hapd, dev):
573     dev.request("DISCONNECT")
574     try:
575         dev.wait_disconnected()
576     except:
577         pass
578     if hapd:
579         hapd.request("DISABLE")
580     subprocess.call(['iw', 'reg', 'set', '00'])
581     dev.flush_scan_cache()
582
583 def wnm_bss_tm_check(hapd, dev, data):
584     addr = dev.p2p_interface_addr()
585     if "OK" not in hapd.request("BSS_TM_REQ " + addr + " " + data):
586         raise Exception("BSS_TM_REQ command failed")
587     ev = dev.wait_event(["CTRL-EVENT-SCAN-STARTED"], timeout=5)
588     if ev is None:
589         raise Exception("No scan started")
590     ev = dev.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
591     if ev is None:
592         raise Exception("Scan did not complete")
593
594     ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
595     if ev is None:
596         raise Exception("No BSS Transition Management Response")
597     if "status_code=7" not in ev:
598         raise Exception("Unexpected response: " + ev)
599
600 def test_wnm_bss_tm_country_us(dev, apdev):
601     """WNM BSS Transition Management (US)"""
602     try:
603         hapd = None
604         hapd, id = start_wnm_tm(apdev[0], "US", dev[0])
605
606         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
607         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")
608
609         # Make the test take less time by limiting full scans
610         dev[0].set_network(id, "scan_freq", "2412")
611         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
612         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")
613
614         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
615         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")
616     finally:
617         stop_wnm_tm(hapd, dev[0])
618
619 def test_wnm_bss_tm_country_fi(dev, apdev):
620     """WNM BSS Transition Management (FI)"""
621     addr = dev[0].p2p_interface_addr()
622     try:
623         hapd = None
624         hapd, id = start_wnm_tm(apdev[0], "FI", dev[0])
625
626         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
627         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")
628
629         # Make the test take less time by limiting full scans
630         dev[0].set_network(id, "scan_freq", "2412")
631         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
632         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")
633
634         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
635         wnm_bss_tm_check(hapd, dev[0], "pref=1 neighbor=00:11:22:33:44:00,0x0000,0,0,7")
636     finally:
637         stop_wnm_tm(hapd, dev[0])
638
639 def test_wnm_bss_tm_country_jp(dev, apdev):
640     """WNM BSS Transition Management (JP)"""
641     addr = dev[0].p2p_interface_addr()
642     try:
643         hapd = None
644         hapd, id = start_wnm_tm(apdev[0], "JP", dev[0])
645
646         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
647         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")
648
649         # Make the test take less time by limiting full scans
650         dev[0].set_network(id, "scan_freq", "2412")
651         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
652         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")
653     finally:
654         stop_wnm_tm(hapd, dev[0])
655
656 def test_wnm_bss_tm_country_cn(dev, apdev):
657     """WNM BSS Transition Management (CN)"""
658     addr = dev[0].p2p_interface_addr()
659     try:
660         hapd = None
661         hapd, id = start_wnm_tm(apdev[0], "CN", dev[0])
662
663         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
664         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")
665
666         # Make the test take less time by limiting full scans
667         dev[0].set_network(id, "scan_freq", "2412")
668         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
669         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")
670     finally:
671         stop_wnm_tm(hapd, dev[0])
672
673 def test_wnm_bss_tm_global(dev, apdev):
674     """WNM BSS Transition Management (global)"""
675     addr = dev[0].p2p_interface_addr()
676     try:
677         hapd = None
678         hapd, id = start_wnm_tm(apdev[0], "XX", dev[0])
679
680         logger.info("Preferred Candidate List (no matching neighbor, known channels)")
681         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")
682
683         # Make the test take less time by limiting full scans
684         dev[0].set_network(id, "scan_freq", "2412")
685         logger.info("Preferred Candidate List (no matching neighbor, unknown channels)")
686         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")
687
688         logger.info("Preferred Candidate List (no matching neighbor, unknown channels 2)")
689         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")
690     finally:
691         stop_wnm_tm(hapd, dev[0])
692
693 def test_wnm_bss_tm_op_class_0(dev, apdev):
694     """WNM BSS Transition Management with invalid operating class"""
695     try:
696         hapd = None
697         hapd, id = start_wnm_tm(apdev[0], "US", dev[0])
698
699         logger.info("Preferred Candidate List (no matching neighbor, invalid op class specified for channels)")
700         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")
701     finally:
702         stop_wnm_tm(hapd, dev[0])
703
704 def test_wnm_action_proto(dev, apdev):
705     """WNM Action protocol testing"""
706     params = { "ssid": "test-wnm" }
707     params['wnm_sleep_mode'] = '1'
708     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
709     bssid = apdev[0]['bssid']
710     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
711     dev[0].request("WNM_SLEEP enter")
712     time.sleep(0.1)
713     hapd.set("ext_mgmt_frame_handling", "1")
714
715     msg = {}
716     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
717     msg['da'] = dev[0].own_addr()
718     msg['sa'] = bssid
719     msg['bssid'] = bssid
720
721     dialog_token = 1
722
723     logger.debug("Unexpected WNM-Notification Response")
724     # Note: This is actually not registered for user space processing in
725     # driver_nl80211.c nl80211_mgmt_subscribe_non_ap() and as such, won't make
726     # it to wpa_supplicant.
727     msg['payload'] = struct.pack("<BBBB",
728                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_RESP,
729                                  dialog_token, 0)
730     hapd.mgmt_tx(msg)
731     expect_ack(hapd)
732
733     logger.debug("Truncated WNM-Notification Request (no Type field)")
734     msg['payload'] = struct.pack("<BBB",
735                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
736                                  dialog_token)
737     hapd.mgmt_tx(msg)
738     expect_ack(hapd)
739
740     logger.debug("WFA WNM-Notification Request with truncated IE (min)")
741     msg['payload'] = struct.pack("<BBBBBB",
742                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
743                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 1)
744     hapd.mgmt_tx(msg)
745     expect_ack(hapd)
746
747     logger.debug("WFA WNM-Notification Request with truncated IE (max)")
748     msg['payload'] = struct.pack("<BBBBBB",
749                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
750                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 255)
751     hapd.mgmt_tx(msg)
752     expect_ack(hapd)
753
754     logger.debug("WFA WNM-Notification Request with too short IE")
755     msg['payload'] = struct.pack("<BBBBBB",
756                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
757                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0, 0)
758     hapd.mgmt_tx(msg)
759     expect_ack(hapd)
760
761     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL")
762     msg['payload'] = struct.pack(">BBBBBBLB",
763                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
764                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
765                                  0x506f9a00, 1)
766     hapd.mgmt_tx(msg)
767     expect_ack(hapd)
768
769     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(2)")
770     msg['payload'] = struct.pack(">BBBBBBLBB",
771                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
772                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 6,
773                                  0x506f9a00, 1, 0)
774     hapd.mgmt_tx(msg)
775     expect_ack(hapd)
776
777     logger.debug("WFA WNM-Notification Request with truncated Sub Rem URL(3)")
778     msg['payload'] = struct.pack(">BBBBBBLB",
779                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
780                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 5,
781                                  0x506f9a00, 0xff)
782     hapd.mgmt_tx(msg)
783     expect_ack(hapd)
784
785     logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(min)")
786     msg['payload'] = struct.pack(">BBBBBBLBHB",
787                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
788                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
789                                  0x506f9a01, 0, 0, 1)
790     hapd.mgmt_tx(msg)
791     expect_ack(hapd)
792
793     logger.debug("WFA WNM-Notification Request with truncated Deauth Imminent URL(max)")
794     msg['payload'] = struct.pack(">BBBBBBLBHB",
795                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
796                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 8,
797                                  0x506f9a01, 0, 0, 0xff)
798     hapd.mgmt_tx(msg)
799     expect_ack(hapd)
800
801     logger.debug("WFA WNM-Notification Request with unsupported IE")
802     msg['payload'] = struct.pack("<BBBBBBL",
803                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
804                                  dialog_token, WNM_NOTIF_TYPE_WFA, 0xdd, 4, 0)
805     hapd.mgmt_tx(msg)
806     expect_ack(hapd)
807
808     logger.debug("WNM-Notification Request with unknown WNM-Notification type 0")
809     msg['payload'] = struct.pack("<BBBB",
810                                  ACTION_CATEG_WNM, WNM_ACT_NOTIFICATION_REQ,
811                                  dialog_token, WNM_NOTIF_TYPE_FW_UPGRADE)
812     hapd.mgmt_tx(msg)
813     expect_ack(hapd)
814
815     logger.debug("Truncated WNM Sleep Mode Response - no Dialog Token")
816     msg['payload'] = struct.pack("<BB",
817                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP)
818     hapd.mgmt_tx(msg)
819     expect_ack(hapd)
820
821     logger.debug("Truncated WNM Sleep Mode Response - no Key Data Length")
822     msg['payload'] = struct.pack("<BBB",
823                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0)
824     hapd.mgmt_tx(msg)
825     expect_ack(hapd)
826
827     logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (min)")
828     msg['payload'] = struct.pack("<BBBH",
829                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
830                                  1)
831     hapd.mgmt_tx(msg)
832     expect_ack(hapd)
833
834     logger.debug("Truncated WNM Sleep Mode Response - truncated Key Data (max)")
835     msg['payload'] = struct.pack("<BBBH",
836                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
837                                  0xffff)
838     hapd.mgmt_tx(msg)
839     expect_ack(hapd)
840
841     logger.debug("WNM Sleep Mode Response - truncated IE header")
842     msg['payload'] = struct.pack("<BBBHB",
843                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
844                                  0, 0)
845     hapd.mgmt_tx(msg)
846     expect_ack(hapd)
847
848     logger.debug("WNM Sleep Mode Response - truncated IE")
849     msg['payload'] = struct.pack("<BBBHBB",
850                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
851                                  0, 0, 1)
852     hapd.mgmt_tx(msg)
853     expect_ack(hapd)
854
855     logger.debug("WNM Sleep Mode Response - Empty TFS Response")
856     msg['payload'] = struct.pack("<BBBHBB",
857                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
858                                  0, WLAN_EID_TFS_RESP, 0)
859     hapd.mgmt_tx(msg)
860     expect_ack(hapd)
861
862     logger.debug("WNM Sleep Mode Response - EID 0 not recognized")
863     msg['payload'] = struct.pack("<BBBHBB",
864                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
865                                  0, 0, 0)
866     hapd.mgmt_tx(msg)
867     expect_ack(hapd)
868
869     logger.debug("WNM Sleep Mode Response - Empty WNM Sleep Mode element and TFS Response element")
870     msg['payload'] = struct.pack("<BBBHBBBB",
871                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
872                                  0, WLAN_EID_WNMSLEEP, 0, WLAN_EID_TFS_RESP, 0)
873     hapd.mgmt_tx(msg)
874     expect_ack(hapd)
875
876     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element and empty TFS Response element")
877     msg['payload'] = struct.pack("<BBBHBBBBHBB",
878                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
879                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
880                                  WNM_STATUS_SLEEP_ACCEPT, 0,
881                                  WLAN_EID_TFS_RESP, 0)
882     hapd.mgmt_tx(msg)
883     expect_ack(hapd)
884
885     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(exit, deny key) and empty TFS Response element")
886     msg['payload'] = struct.pack("<BBBHBBBBHBB",
887                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
888                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
889                                  WNM_STATUS_DENIED_KEY, 0,
890                                  WLAN_EID_TFS_RESP, 0)
891     hapd.mgmt_tx(msg)
892     expect_ack(hapd)
893
894     logger.debug("WNM Sleep Mode Response - WNM Sleep Mode element(enter, deny key) and empty TFS Response element")
895     msg['payload'] = struct.pack("<BBBHBBBBHBB",
896                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
897                                  0, WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_ENTER,
898                                  WNM_STATUS_DENIED_KEY, 0,
899                                  WLAN_EID_TFS_RESP, 0)
900     hapd.mgmt_tx(msg)
901     expect_ack(hapd)
902
903 def test_wnm_action_proto_pmf(dev, apdev):
904     """WNM Action protocol testing (PMF enabled)"""
905     ssid = "test-wnm-pmf"
906     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
907     params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
908     params["ieee80211w"] = "2"
909     params['wnm_sleep_mode'] = '1'
910     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
911     bssid = apdev[0]['bssid']
912     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK-SHA256",
913                    proto="WPA2", ieee80211w="2", scan_freq="2412")
914     dev[0].request("WNM_SLEEP enter")
915     time.sleep(0.1)
916     hapd.set("ext_mgmt_frame_handling", "1")
917
918     msg = {}
919     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
920     msg['da'] = dev[0].own_addr()
921     msg['sa'] = bssid
922     msg['bssid'] = bssid
923
924     logger.debug("WNM Sleep Mode Response - Invalid Key Data element length")
925     keydata = struct.pack("<BB", 0, 1)
926     msg['payload'] = struct.pack("<BBBH",
927                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
928                                  len(keydata))
929     msg['payload'] += keydata
930     msg['payload'] += struct.pack("<BBBBHBB",
931                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
932                                   WNM_STATUS_SLEEP_ACCEPT, 0,
933                                   WLAN_EID_TFS_RESP, 0)
934     hapd.mgmt_tx(msg)
935     expect_ack(hapd)
936
937     logger.debug("WNM Sleep Mode Response - Too short GTK subelem")
938     keydata = struct.pack("<BB", WNM_SLEEP_SUBELEM_GTK, 0)
939     msg['payload'] = struct.pack("<BBBH",
940                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
941                                  len(keydata))
942     msg['payload'] += keydata
943     msg['payload'] += struct.pack("<BBBBHBB",
944                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
945                                   WNM_STATUS_SLEEP_ACCEPT, 0,
946                                   WLAN_EID_TFS_RESP, 0)
947     hapd.mgmt_tx(msg)
948     expect_ack(hapd)
949
950     logger.debug("WNM Sleep Mode Response - Invalid GTK subelem")
951     keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
952                           0, 17, 0, 0, 0, 0, 0, 0)
953     msg['payload'] = struct.pack("<BBBH",
954                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
955                                  len(keydata))
956     msg['payload'] += keydata
957     msg['payload'] += struct.pack("<BBBBHBB",
958                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
959                                   WNM_STATUS_SLEEP_ACCEPT, 0,
960                                   WLAN_EID_TFS_RESP, 0)
961     hapd.mgmt_tx(msg)
962     expect_ack(hapd)
963
964     logger.debug("WNM Sleep Mode Response - Invalid GTK subelem (2)")
965     keydata = struct.pack("<BBHB2L4L", WNM_SLEEP_SUBELEM_GTK, 11 + 16,
966                           0, 0, 0, 0, 0, 0, 0, 0)
967     msg['payload'] = struct.pack("<BBBH",
968                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
969                                  len(keydata))
970     msg['payload'] += keydata
971     msg['payload'] += struct.pack("<BBBBHBB",
972                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
973                                   WNM_STATUS_SLEEP_ACCEPT, 0,
974                                   WLAN_EID_TFS_RESP, 0)
975     hapd.mgmt_tx(msg)
976     expect_ack(hapd)
977
978     logger.debug("WNM Sleep Mode Response - GTK subelem and too short IGTK subelem")
979     keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
980     keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
981                            0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
982     keydata += struct.pack("<BB", WNM_SLEEP_SUBELEM_IGTK, 0)
983     msg['payload'] = struct.pack("<BBBH",
984                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
985                                  len(keydata))
986     msg['payload'] += keydata
987     msg['payload'] += struct.pack("<BBBBHBB",
988                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
989                                   WNM_STATUS_SLEEP_ACCEPT, 0,
990                                   WLAN_EID_TFS_RESP, 0)
991     hapd.mgmt_tx(msg)
992     expect_ack(hapd)
993
994     logger.debug("WNM Sleep Mode Response - Unknown subelem")
995     keydata = struct.pack("<BB", 255, 0)
996     msg['payload'] = struct.pack("<BBBH",
997                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
998                                  len(keydata))
999     msg['payload'] += keydata
1000     msg['payload'] += struct.pack("<BBBBHBB",
1001                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1002                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1003                                   WLAN_EID_TFS_RESP, 0)
1004     hapd.mgmt_tx(msg)
1005     expect_ack(hapd)
1006
1007 def test_wnm_action_proto_no_pmf(dev, apdev):
1008     """WNM Action protocol testing (PMF disabled)"""
1009     ssid = "test-wnm-no-pmf"
1010     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
1011     params['wnm_sleep_mode'] = '1'
1012     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1013     bssid = apdev[0]['bssid']
1014     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
1015                    proto="WPA2", ieee80211w="0", scan_freq="2412")
1016     dev[0].request("WNM_SLEEP enter")
1017     time.sleep(0.1)
1018     hapd.set("ext_mgmt_frame_handling", "1")
1019
1020     msg = {}
1021     msg['fc'] = MGMT_SUBTYPE_ACTION << 4
1022     msg['da'] = dev[0].own_addr()
1023     msg['sa'] = bssid
1024     msg['bssid'] = bssid
1025
1026     logger.debug("WNM Sleep Mode Response - GTK subelem and IGTK subelem")
1027     keydata = struct.pack("<BBHB", WNM_SLEEP_SUBELEM_GTK, 11 + 16, 0, 16)
1028     keydata += struct.pack(">2L4L", 0x01020304, 0x05060708,
1029                            0x11223344, 0x55667788, 0x9900aabb, 0xccddeeff)
1030     keydata += struct.pack("<BBHLH4L", WNM_SLEEP_SUBELEM_IGTK, 2 + 6 + 16, 0,
1031                            0x10203040, 0x5060,
1032                            0xf1f2f3f4, 0xf5f6f7f8, 0xf9f0fafb, 0xfcfdfeff)
1033     msg['payload'] = struct.pack("<BBBH",
1034                                  ACTION_CATEG_WNM, WNM_ACT_SLEEP_MODE_RESP, 0,
1035                                  len(keydata))
1036     msg['payload'] += keydata
1037     msg['payload'] += struct.pack("<BBBBHBB",
1038                                   WLAN_EID_WNMSLEEP, 4, WNM_SLEEP_MODE_EXIT,
1039                                   WNM_STATUS_SLEEP_ACCEPT, 0,
1040                                   WLAN_EID_TFS_RESP, 0)
1041     hapd.mgmt_tx(msg)
1042     expect_ack(hapd)
1043
1044     ev = dev[0].wait_event(["WNM: Ignore Key Data"], timeout=5)
1045     if ev is None:
1046         raise Exception("Key Data not ignored")
1047
1048 def test_wnm_bss_tm_req_with_mbo_ie(dev, apdev):
1049     """WNM BSS transition request with MBO IE and reassociation delay attribute"""
1050     ssid = "test-wnm-mbo"
1051     params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
1052     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1053     bssid = apdev[0]['bssid']
1054     if "OK" not in dev[0].request("SET mbo_cell_capa 1"):
1055         raise Exception("Failed to set STA as cellular data capable")
1056
1057     dev[0].connect(ssid, psk="12345678", key_mgmt="WPA-PSK",
1058                    proto="WPA2", ieee80211w="0", scan_freq="2412")
1059
1060     logger.debug("BTM request with MBO reassociation delay when disassoc imminent is not set")
1061     if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=3:2:1"):
1062         raise Exception("BSS transition management succeeded unexpectedly")
1063
1064     logger.debug("BTM request with invalid MBO transition reason code")
1065     if 'FAIL' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " mbo=10:2:1"):
1066         raise Exception("BSS transition management succeeded unexpectedly")
1067
1068     logger.debug("BTM request with MBO reassociation retry delay of 5 seconds")
1069     if 'OK' not in hapd.request("BSS_TM_REQ " + dev[0].own_addr() + " disassoc_imminent=1 disassoc_timer=3 mbo=3:5:1"):
1070         raise Exception("BSS transition management command failed")
1071
1072     ev = dev[0].wait_event(['MBO-CELL-PREFERENCE'], 1)
1073     if ev is None or "preference=1" not in ev:
1074         raise Exception("Timeout waiting for MBO-CELL-PREFERENCE event")
1075
1076     ev = dev[0].wait_event(['MBO-TRANSITION-REASON'], 1)
1077     if ev is None or "reason=3" not in ev:
1078         raise Exception("Timeout waiting for MBO-TRANSITION-REASON event")
1079
1080     ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
1081     if ev is None:
1082         raise Exception("No BSS Transition Management Response")
1083     if dev[0].own_addr() not in ev:
1084         raise Exception("Unexpected BSS Transition Management Response address")
1085
1086     ev = dev[0].wait_event(['CTRL-EVENT-DISCONNECTED'], 5)
1087     if ev is None:
1088             raise Exception("Station did not disconnect although disassoc imminent was set")
1089
1090     # Set the scan interval to make dev[0] look for connections
1091     if 'OK' not in dev[0].request("SCAN_INTERVAL 1"):
1092             raise Exception("Failed to set scan interval")
1093
1094     # Make sure no connection is made during the retry delay
1095     ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
1096     if ev is not None:
1097             raise Exception("Station connected before assoc retry delay was over")
1098
1099     # After the assoc retry delay is over, we can reconnect
1100     ev = dev[0].wait_event(['CTRL-EVENT-CONNECTED'], 5)
1101     if ev is None:
1102             raise Exception("Station did not connect after assoc retry delay is over")
1103
1104     if "OK" not in dev[0].request("SET mbo_cell_capa 3"):
1105         raise Exception("Failed to set STA as cellular data not-capable")
1106
1107 def test_wnm_bss_transition_mgmt_query(dev, apdev):
1108     """WNM BSS Transition Management query"""
1109     params = { "ssid": "test-wnm",
1110                "bss_transition": "1" }
1111     hapd = hostapd.add_ap(apdev[0]['ifname'], params)
1112     params = { "ssid": "another" }
1113     hapd2 = hostapd.add_ap(apdev[1]['ifname'], params)
1114
1115     dev[0].scan_for_bss(apdev[1]['bssid'], 2412)
1116     dev[0].scan_for_bss(apdev[0]['bssid'], 2412)
1117
1118     dev[0].connect("test-wnm", key_mgmt="NONE", scan_freq="2412")
1119     dev[0].request("WNM_BSS_QUERY 0 list")
1120
1121     ev = dev[0].wait_event(["WNM: BSS Transition Management Request"],
1122                            timeout=5)
1123     if ev is None:
1124         raise Exception("No BSS Transition Management Request frame seen")
1125
1126     ev = hapd.wait_event(["BSS-TM-RESP"], timeout=5)
1127     if ev is None:
1128         raise Exception("No BSS Transition Management Response frame seen")