]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_wmediumd.py
HE: MCS size is always a minimum of 4 bytes
[thirdparty/hostap.git] / tests / hwsim / test_wmediumd.py
1 # wmediumd sanity checks
2 # Copyright (c) 2015, Intel Deutschland GmbH
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import tempfile, os, subprocess, errno, hwsim_utils, time
8 from utils import HwsimSkip
9 from wpasupplicant import WpaSupplicant
10 from tshark import run_tshark
11 from test_ap_open import _test_ap_open
12 from test_wpas_mesh import check_mesh_support, check_mesh_group_added
13 from test_wpas_mesh import check_mesh_peer_connected, add_open_mesh_network
14 from test_wpas_mesh import check_mesh_group_removed
15
16 class LocalVariables:
17 revs = []
18
19 CFG = """
20 ifaces :
21 {
22 ids = ["%s", "%s"]
23 links = (
24 (0, 1, 30)
25 )
26 }
27 """
28
29 CFG2 = """
30 ifaces :
31 {
32 ids = ["%s", "%s", "%s"]
33 }
34
35 model:
36 {
37 type = "prob"
38
39 links = (
40 (0, 1, 0.000000),
41 (0, 2, 0.000000),
42 (1, 2, 1.000000)
43 )
44 }
45 """
46
47 CFG3 = """
48 ifaces :
49 {
50 ids = ["%s", "%s", "%s", "%s", "%s"]
51 }
52
53 model:
54 {
55 type = "prob"
56
57 default_prob = 1.0
58 links = (
59 (0, 1, 0.000000),
60 (1, 2, 0.000000),
61 (2, 3, 0.000000),
62 (3, 4, 0.000000)
63 )
64 }
65 """
66
67 def get_wmediumd_version():
68 if len(LocalVariables.revs) > 0:
69 return LocalVariables.revs
70
71 try:
72 verstr = subprocess.check_output(['wmediumd', '-V']).decode()
73 except OSError as e:
74 if e.errno == errno.ENOENT:
75 raise HwsimSkip('wmediumd not available')
76 raise
77
78 vernum = verstr.split(' ')[1][1:]
79 LocalVariables.revs = vernum.split('.')
80 for i in range(0, len(LocalVariables.revs)):
81 LocalVariables.revs[i] = int(LocalVariables.revs[i])
82 while len(LocalVariables.revs) < 3:
83 LocalVariables.revs += [0]
84
85 return LocalVariables.revs
86
87 def require_wmediumd_version(major, minor, patch):
88 revs = get_wmediumd_version()
89 if revs[0] < major or revs[1] < minor or revs[2] < patch:
90 raise HwsimSkip('wmediumd v%s.%s.%s is too old for this test' %
91 (revs[0], revs[1], revs[2]))
92
93 def output_wmediumd_log(p, params, data):
94 log_file = open(os.path.abspath(os.path.join(params['logdir'],
95 'wmediumd.log')), 'a')
96 log_file.write(data)
97 log_file.close()
98
99 def start_wmediumd(fn, params):
100 try:
101 p = subprocess.Popen(['wmediumd', '-c', fn],
102 stdout=subprocess.PIPE,
103 stderr=subprocess.STDOUT)
104 except OSError as e:
105 if e.errno == errno.ENOENT:
106 raise HwsimSkip('wmediumd not available')
107 raise
108
109 logs = ''
110 while True:
111 line = p.stdout.readline().decode()
112 if not line:
113 output_wmediumd_log(p, params, logs)
114 raise Exception('wmediumd was terminated unexpectedly')
115 if line.find('REGISTER SENT!') > -1:
116 break
117 logs += line
118 return p
119
120 def stop_wmediumd(p, params):
121 p.terminate()
122 p.wait()
123 stdoutdata, stderrdata = p.communicate()
124 output_wmediumd_log(p, params, stdoutdata.decode())
125
126 def test_wmediumd_simple(dev, apdev, params):
127 """test a simple wmediumd configuration"""
128 fd, fn = tempfile.mkstemp()
129 try:
130 f = os.fdopen(fd, 'w')
131 f.write(CFG % (apdev[0]['bssid'], dev[0].own_addr()))
132 f.close()
133 p = start_wmediumd(fn, params)
134 try:
135 _test_ap_open(dev, apdev)
136 finally:
137 stop_wmediumd(p, params)
138 # test that releasing hwsim works correctly
139 _test_ap_open(dev, apdev)
140 finally:
141 os.unlink(fn)
142
143 def test_wmediumd_path_simple(dev, apdev, params):
144 """test a mesh path"""
145 # 0 and 1 is connected
146 # 0 and 2 is connected
147 # 1 and 2 is not connected
148 # 1 --- 0 --- 2
149 # | |
150 # +-----X-----+
151 # This tests if 1 and 2 can communicate each other via 0.
152 require_wmediumd_version(0, 3, 1)
153 fd, fn = tempfile.mkstemp()
154 try:
155 f = os.fdopen(fd, 'w')
156 f.write(CFG2 % (dev[0].own_addr(), dev[1].own_addr(),
157 dev[2].own_addr()))
158 f.close()
159 p = start_wmediumd(fn, params)
160 try:
161 _test_wmediumd_path_simple(dev, apdev)
162 finally:
163 stop_wmediumd(p, params)
164 finally:
165 os.unlink(fn)
166
167 def _test_wmediumd_path_simple(dev, apdev):
168 for i in range(0, 3):
169 check_mesh_support(dev[i])
170 add_open_mesh_network(dev[i], freq="2462", basic_rates="60 120 240")
171
172 # Check for mesh joined
173 for i in range(0, 3):
174 check_mesh_group_added(dev[i])
175
176 state = dev[i].get_status_field("wpa_state")
177 if state != "COMPLETED":
178 raise Exception("Unexpected wpa_state on dev" + str(i) + ": " + state)
179
180 mode = dev[i].get_status_field("mode")
181 if mode != "mesh":
182 raise Exception("Unexpected mode: " + mode)
183
184 # Check for peer connected
185 check_mesh_peer_connected(dev[0])
186 check_mesh_peer_connected(dev[0])
187 check_mesh_peer_connected(dev[1])
188 check_mesh_peer_connected(dev[2])
189
190 # Test connectivity 1->2 and 2->1
191 hwsim_utils.test_connectivity(dev[1], dev[2])
192
193 # Check mpath table on 0
194 res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'mpath', 'dump'])
195 if res != 0:
196 raise Exception("iw command failed on dev0")
197 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) == -1 or \
198 data.find(dev[2].own_addr() + ' ' + dev[2].own_addr()) == -1:
199 raise Exception("mpath not found on dev0:\n" + data)
200 if data.find(dev[0].own_addr()) > -1:
201 raise Exception("invalid mpath found on dev0:\n" + data)
202
203 # Check mpath table on 1
204 res, data = dev[1].cmd_execute(['iw', dev[1].ifname, 'mpath', 'dump'])
205 if res != 0:
206 raise Exception("iw command failed on dev1")
207 if data.find(dev[0].own_addr() + ' ' + dev[0].own_addr()) == -1 or \
208 data.find(dev[2].own_addr() + ' ' + dev[0].own_addr()) == -1:
209 raise Exception("mpath not found on dev1:\n" + data)
210 if data.find(dev[2].own_addr() + ' ' + dev[2].own_addr()) > -1 or \
211 data.find(dev[1].own_addr()) > -1:
212 raise Exception("invalid mpath found on dev1:\n" + data)
213
214 # Check mpath table on 2
215 res, data = dev[2].cmd_execute(['iw', dev[2].ifname, 'mpath', 'dump'])
216 if res != 0:
217 raise Exception("iw command failed on dev2")
218 if data.find(dev[0].own_addr() + ' ' + dev[0].own_addr()) == -1 or \
219 data.find(dev[1].own_addr() + ' ' + dev[0].own_addr()) == -1:
220 raise Exception("mpath not found on dev2:\n" + data)
221 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) > -1 or \
222 data.find(dev[2].own_addr()) > -1:
223 raise Exception("invalid mpath found on dev2:\n" + data)
224
225 # remove mesh groups
226 for i in range(0, 3):
227 dev[i].mesh_group_remove()
228 check_mesh_group_removed(dev[i])
229 dev[i].dump_monitor()
230
231 def test_wmediumd_path_ttl(dev, apdev, params):
232 """Mesh path request TTL"""
233 # 0 --- 1 --- 2 --- 3 --- 4
234 # Test the TTL of mesh path request.
235 # If the TTL is shorter than path, the mesh path request should be dropped.
236 require_wmediumd_version(0, 3, 1)
237
238 local_dev = []
239 for i in range(0, 3):
240 local_dev.append(dev[i])
241
242 for i in range(5, 7):
243 wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
244 wpas.interface_add("wlan" + str(i))
245 check_mesh_support(wpas)
246 temp_dev = wpas.request("MESH_INTERFACE_ADD ifname=mesh" + str(i))
247 if "FAIL" in temp_dev:
248 raise Exception("MESH_INTERFACE_ADD failed")
249 local_dev.append(WpaSupplicant(ifname=temp_dev))
250
251 fd, fn = tempfile.mkstemp()
252 try:
253 f = os.fdopen(fd, 'w')
254 f.write(CFG3 % (local_dev[0].own_addr(), local_dev[1].own_addr(),
255 local_dev[2].own_addr(), local_dev[3].own_addr(),
256 local_dev[4].own_addr()))
257 f.close()
258 p = start_wmediumd(fn, params)
259 try:
260 _test_wmediumd_path_ttl(local_dev, True)
261 _test_wmediumd_path_ttl(local_dev, False)
262 finally:
263 stop_wmediumd(p, params)
264 finally:
265 os.unlink(fn)
266 for i in range(5, 7):
267 wpas.interface_remove("wlan" + str(i))
268
269 def _test_wmediumd_path_ttl(dev, ok):
270 for i in range(0, 5):
271 check_mesh_support(dev[i])
272 add_open_mesh_network(dev[i], freq="2462", basic_rates="60 120 240")
273
274 # Check for mesh joined
275 for i in range(0, 5):
276 check_mesh_group_added(dev[i])
277
278 state = dev[i].get_status_field("wpa_state")
279 if state != "COMPLETED":
280 raise Exception("Unexpected wpa_state on dev" + str(i) + ": " + state)
281
282 mode = dev[i].get_status_field("mode")
283 if mode != "mesh":
284 raise Exception("Unexpected mode: " + mode)
285
286 # set mesh path request ttl
287 subprocess.check_call(["iw", "dev", dev[0].ifname, "set", "mesh_param",
288 "mesh_element_ttl=" + ("4" if ok else "3")])
289
290 # Check for peer connected
291 for i in range(0, 5):
292 check_mesh_peer_connected(dev[i])
293 for i in range(1, 4):
294 check_mesh_peer_connected(dev[i])
295
296 # Test connectivity 0->4 and 0->4
297 hwsim_utils.test_connectivity(dev[0], dev[4], success_expected=ok)
298
299 # Check mpath table on 0
300 res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'mpath', 'dump'])
301 if res != 0:
302 raise Exception("iw command failed on dev0")
303 if ok:
304 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) == -1 or \
305 data.find(dev[4].own_addr() + ' ' + dev[1].own_addr()) == -1:
306 raise Exception("mpath not found on dev0:\n" + data)
307 else:
308 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) == -1 or \
309 data.find(dev[4].own_addr() + ' 00:00:00:00:00:00') == -1:
310 raise Exception("mpath not found on dev0:\n" + data)
311 if data.find(dev[0].own_addr()) > -1 or \
312 data.find(dev[2].own_addr()) > -1 or \
313 data.find(dev[3].own_addr()) > -1:
314 raise Exception("invalid mpath found on dev0:\n" + data)
315
316 # remove mesh groups
317 for i in range(0, 3):
318 dev[i].mesh_group_remove()
319 check_mesh_group_removed(dev[i])
320 dev[i].dump_monitor()
321
322 def test_wmediumd_path_rann(dev, apdev, params):
323 """Mesh path with RANN"""
324 # 0 and 1 is connected
325 # 0 and 2 is connected
326 # 1 and 2 is not connected
327 # 2 is mesh root and RANN enabled
328 # 1 --- 0 --- 2
329 # | |
330 # +-----X-----+
331 # This tests if 1 and 2 can communicate each other via 0.
332 require_wmediumd_version(0, 3, 1)
333 fd, fn = tempfile.mkstemp()
334 try:
335 f = os.fdopen(fd, 'w')
336 f.write(CFG2 % (dev[0].own_addr(), dev[1].own_addr(),
337 dev[2].own_addr()))
338 f.close()
339 p = start_wmediumd(fn, params)
340 try:
341 _test_wmediumd_path_rann(dev, apdev)
342 finally:
343 stop_wmediumd(p, params)
344 finally:
345 os.unlink(fn)
346
347 capfile = os.path.join(params['logdir'], "hwsim0.pcapng")
348
349 # check Root STA address in root announcement element
350 filt = "wlan.fc.type_subtype == 0x000d && " + \
351 "wlan_mgt.fixed.mesh_action == 0x01 && " + \
352 "wlan_mgt.tag.number == 126"
353 out = run_tshark(capfile, filt, ["wlan.rann.root_sta"])
354 if out is None:
355 raise Exception("No captured data found\n")
356 if out.find(dev[2].own_addr()) == -1 or \
357 out.find(dev[0].own_addr()) > -1 or \
358 out.find(dev[1].own_addr()) > -1:
359 raise Exception("RANN should be sent by dev2 only:\n" + out)
360
361 # check RANN interval is in range
362 filt = "wlan.sa == 02:00:00:00:02:00 && " + \
363 "wlan.fc.type_subtype == 0x000d && " + \
364 "wlan_mgt.fixed.mesh_action == 0x01 && " + \
365 "wlan_mgt.tag.number == 126"
366 out = run_tshark(capfile, filt, ["frame.time_relative"])
367 if out is None:
368 raise Exception("No captured data found\n")
369 lines = out.splitlines()
370 prev = float(lines[len(lines) - 1])
371 for i in reversed(list(range(1, len(lines) - 1))):
372 now = float(lines[i])
373 if prev - now < 1.0 or 3.0 < prev - now:
374 raise Exception("RANN interval " + str(prev - now) +
375 "(sec) should be close to 2.0(sec)\n")
376 prev = now
377
378 # check no one uses broadcast path request
379 filt = "wlan.da == ff:ff:ff:ff:ff:ff && " + \
380 "wlan.fc.type_subtype == 0x000d && " + \
381 "wlan_mgt.fixed.mesh_action == 0x01 && " + \
382 "wlan_mgt.tag.number == 130"
383 out = run_tshark(capfile, filt, ["wlan.sa", "wlan.da"])
384 if out is None:
385 raise Exception("No captured data found\n")
386 if len(out) > 0:
387 raise Exception("invalid broadcast path requests\n" + out)
388
389 def _test_wmediumd_path_rann(dev, apdev):
390 for i in range(0, 3):
391 check_mesh_support(dev[i])
392 add_open_mesh_network(dev[i], freq="2462", basic_rates="60 120 240")
393
394 # Check for mesh joined
395 for i in range(0, 3):
396 check_mesh_group_added(dev[i])
397
398 state = dev[i].get_status_field("wpa_state")
399 if state != "COMPLETED":
400 raise Exception("Unexpected wpa_state on dev" + str(i) + ": " + state)
401
402 mode = dev[i].get_status_field("mode")
403 if mode != "mesh":
404 raise Exception("Unexpected mode: " + mode)
405
406 # set node 2 as RANN supported root
407 subprocess.check_call(["iw", "dev", dev[0].ifname, "set", "mesh_param",
408 "mesh_hwmp_rootmode=0"])
409 subprocess.check_call(["iw", "dev", dev[1].ifname, "set", "mesh_param",
410 "mesh_hwmp_rootmode=0"])
411 subprocess.check_call(["iw", "dev", dev[2].ifname, "set", "mesh_param",
412 "mesh_hwmp_rootmode=4"])
413 subprocess.check_call(["iw", "dev", dev[2].ifname, "set", "mesh_param",
414 "mesh_hwmp_rann_interval=2000"])
415
416 # Check for peer connected
417 check_mesh_peer_connected(dev[0])
418 check_mesh_peer_connected(dev[0])
419 check_mesh_peer_connected(dev[1])
420 check_mesh_peer_connected(dev[2])
421
422 # Wait for RANN frame
423 time.sleep(10)
424
425 # Test connectivity 1->2 and 2->1
426 hwsim_utils.test_connectivity(dev[1], dev[2])
427
428 # Check mpath table on 0
429 res, data = dev[0].cmd_execute(['iw', dev[0].ifname, 'mpath', 'dump'])
430 if res != 0:
431 raise Exception("iw command failed on dev0")
432 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) == -1 or \
433 data.find(dev[2].own_addr() + ' ' + dev[2].own_addr()) == -1:
434 raise Exception("mpath not found on dev0:\n" + data)
435 if data.find(dev[0].own_addr()) > -1:
436 raise Exception("invalid mpath found on dev0:\n" + data)
437
438 # Check mpath table on 1
439 res, data = dev[1].cmd_execute(['iw', dev[1].ifname, 'mpath', 'dump'])
440 if res != 0:
441 raise Exception("iw command failed on dev1")
442 if data.find(dev[0].own_addr() + ' ' + dev[0].own_addr()) == -1 or \
443 data.find(dev[2].own_addr() + ' ' + dev[0].own_addr()) == -1:
444 raise Exception("mpath not found on dev1:\n" + data)
445 if data.find(dev[2].own_addr() + ' ' + dev[2].own_addr()) > -1 or \
446 data.find(dev[1].own_addr()) > -1:
447 raise Exception("invalid mpath found on dev1:\n" + data)
448
449 # Check mpath table on 2
450 res, data = dev[2].cmd_execute(['iw', dev[2].ifname, 'mpath', 'dump'])
451 if res != 0:
452 raise Exception("iw command failed on dev2")
453 if data.find(dev[0].own_addr() + ' ' + dev[0].own_addr()) == -1 or \
454 data.find(dev[1].own_addr() + ' ' + dev[0].own_addr()) == -1:
455 raise Exception("mpath not found on dev2:\n" + data)
456 if data.find(dev[1].own_addr() + ' ' + dev[1].own_addr()) > -1 or \
457 data.find(dev[2].own_addr()) > -1:
458 raise Exception("invalid mpath found on dev2:\n" + data)
459
460 # remove mesh groups
461 for i in range(0, 3):
462 dev[i].mesh_group_remove()
463 check_mesh_group_removed(dev[i])
464 dev[i].dump_monitor()