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