1# Test cases for Wi-Fi Aware unsynchronized service discovery (NAN USD) 2# Copyright (c) 2024, Qualcomm Innovation Center, Inc. 3# 4# This software may be distributed under the terms of the BSD license. 5# See README for more details. 6 7import time 8 9import logging 10logger = logging.getLogger() 11 12import hostapd 13from utils import * 14 15def check_nan_usd_capab(dev): 16 capa = dev.request("GET_CAPABILITY nan") 17 if "USD" not in capa: 18 raise HwsimSkip("NAN USD not supported") 19 20def test_nan_usd_publish_invalid_param(dev): 21 """NAN USD Publish with invalid parameters""" 22 check_nan_usd_capab(dev[0]) 23 24 # Both solicited and unsolicited disabled is invalid 25 cmd = "NAN_PUBLISH service_name=_test solicited=0 unsolicited=0" 26 id0 = dev[0].request(cmd) 27 if "FAIL" not in id0: 28 raise Exception("NAN_PUBLISH accepts both solicited=0 and unsolicited=0") 29 30def test_nan_usd_publish(dev, apdev): 31 """NAN USD Publish""" 32 check_nan_usd_capab(dev[0]) 33 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677" 34 id0 = dev[0].request(cmd) 35 if "FAIL" in id0: 36 raise Exception("NAN_PUBLISH failed") 37 38 cmd = "NAN_UPDATE_PUBLISH publish_id=" + id0 + " ssi=1122334455" 39 if "FAIL" in dev[0].request(cmd): 40 raise Exception("NAN_UPDATE_PUBLISH failed") 41 42 cmd = "NAN_CANCEL_PUBLISH publish_id=" + id0 43 if "FAIL" in dev[0].request(cmd): 44 raise Exception("NAN_CANCEL_PUBLISH failed") 45 46 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=1) 47 if ev is None: 48 raise Exception("PublishTerminated event not seen") 49 if "publish_id=" + id0 not in ev: 50 raise Exception("Unexpected publish_id: " + ev) 51 if "reason=user-request" not in ev: 52 raise Exception("Unexpected reason: " + ev) 53 54 cmd = "NAN_PUBLISH service_name=_test" 55 count = 0 56 for i in range(256): 57 if "FAIL" in dev[0].request(cmd): 58 break 59 count += 1 60 logger.info("Maximum services: %d" % count) 61 for i in range(count): 62 cmd = "NAN_CANCEL_PUBLISH publish_id=%s" % (i + 1) 63 if "FAIL" in dev[0].request(cmd): 64 raise Exception("NAN_CANCEL_PUBLISH failed") 65 66 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=1) 67 if ev is None: 68 raise Exception("PublishTerminated event not seen") 69 70def test_nan_usd_subscribe(dev, apdev): 71 """NAN USD Subscribe""" 72 check_nan_usd_capab(dev[0]) 73 cmd = "NAN_SUBSCRIBE service_name=_test active=1 srv_proto_type=2 ssi=1122334455" 74 id0 = dev[0].request(cmd) 75 if "FAIL" in id0: 76 raise Exception("NAN_SUBSCRIBE failed") 77 78 cmd = "NAN_CANCEL_SUBSCRIBE subscribe_id=" + id0 79 if "FAIL" in dev[0].request(cmd): 80 raise Exception("NAN_CANCEL_SUBSCRIBE failed") 81 82 ev = dev[0].wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=1) 83 if ev is None: 84 raise Exception("SubscribeTerminated event not seen") 85 if "subscribe_id=" + id0 not in ev: 86 raise Exception("Unexpected subscribe_id: " + ev) 87 if "reason=user-request" not in ev: 88 raise Exception("Unexpected reason: " + ev) 89 90def test_nan_usd_match(dev, apdev): 91 """NAN USD Publish/Subscribe match""" 92 check_nan_usd_capab(dev[0]) 93 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455" 94 id0 = dev[0].request(cmd) 95 if "FAIL" in id0: 96 raise Exception("NAN_SUBSCRIBE failed") 97 98 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 ttl=5" 99 id1 = dev[1].request(cmd) 100 if "FAIL" in id1: 101 raise Exception("NAN_PUBLISH failed") 102 103 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 104 if ev is None: 105 raise Exception("DiscoveryResult event not seen") 106 if "srv_proto_type=2" not in ev.split(' '): 107 raise Exception("Unexpected srv_proto_type: " + ev) 108 if "ssi=6677" not in ev.split(' '): 109 raise Exception("Unexpected ssi: " + ev) 110 111 dev[0].request("NAN_CANCEL_SUBSCRIBE id=" + id0) 112 dev[1].request("NAN_CANCEL_PUBLISH id=" + id1) 113 114def test_nan_usd_match2(dev, apdev): 115 """NAN USD Publish/Subscribe match (2)""" 116 check_nan_usd_capab(dev[0]) 117 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 ttl=10 fsd=0" 118 id0 = dev[1].request(cmd) 119 if "FAIL" in id0: 120 raise Exception("NAN_PUBLISH failed") 121 122 time.sleep(1) 123 124 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455 active=1" 125 id0 = dev[0].request(cmd) 126 if "FAIL" in id0: 127 raise Exception("NAN_SUBSCRIBE failed") 128 129 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 130 if ev is None: 131 raise Exception("DiscoveryResult event not seen") 132 if "srv_proto_type=2" not in ev.split(' '): 133 raise Exception("Unexpected srv_proto_type: " + ev) 134 if "ssi=6677" not in ev.split(' '): 135 raise Exception("Unexpected ssi: " + ev) 136 137 # Check for publisher and subscriber functionality to time out 138 ev = dev[0].wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=2) 139 if ev is None: 140 raise Exception("Subscribe not terminated") 141 ev = dev[1].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 142 if ev is None: 143 raise Exception("Publish not terminated") 144 145def test_nan_usd_match3(dev, apdev): 146 """NAN USD Publish/Subscribe match (3)""" 147 check_nan_usd_capab(dev[0]) 148 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455 active=1" 149 id0 = dev[0].request(cmd) 150 if "FAIL" in id0: 151 raise Exception("NAN_SUBSCRIBE failed") 152 153 time.sleep(0.05) 154 155 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 ttl=10" 156 id1 = dev[1].request(cmd) 157 if "FAIL" in id1: 158 raise Exception("NAN_PUBLISH failed") 159 160 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 161 if ev is None: 162 raise Exception("DiscoveryResult event not seen") 163 if "srv_proto_type=2" not in ev.split(' '): 164 raise Exception("Unexpected srv_proto_type: " + ev) 165 if "ssi=6677" not in ev.split(' '): 166 raise Exception("Unexpected ssi: " + ev) 167 168 dev[0].request("NAN_CANCEL_SUBSCRIBE id=" + id0) 169 dev[1].request("NAN_CANCEL_PUBLISH id=" + id1) 170 171def split_nan_event(ev): 172 vals = dict() 173 for p in ev.split(' ')[1:]: 174 name, val = p.split('=') 175 vals[name] = val 176 return vals 177 178def test_nan_usd_followup(dev, apdev): 179 """NAN USD Publish/Subscribe match and follow-up""" 180 check_nan_usd_capab(dev[0]) 181 run_nan_usd_followup(dev[0], dev[1]) 182 183def test_nan_usd_followup_multi_chan(dev, apdev): 184 """NAN USD Publish/Subscribe match and follow-up with multi channels""" 185 check_nan_usd_capab(dev[0]) 186 run_nan_usd_followup(dev[0], dev[1], multi_chan=True) 187 188def test_nan_usd_followup_hostapd(dev, apdev): 189 """NAN USD Publish/Subscribe match and follow-up with hostapd""" 190 check_nan_usd_capab(dev[0]) 191 hapd = hostapd.add_ap(apdev[0], {"ssid": "open", 192 "channel": "6"}) 193 run_nan_usd_followup(hapd, dev[1]) 194 195def run_nan_usd_followup(dev0, dev1, multi_chan=False): 196 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=3 ssi=1122334455" 197 if multi_chan: 198 cmd += " freq=2462" 199 id0 = dev0.request(cmd) 200 if "FAIL" in id0: 201 raise Exception("NAN_SUBSCRIBE failed") 202 203 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=3 ssi=6677 ttl=10" 204 if multi_chan: 205 cmd += " freq=2412 freq_list=2437,2462" 206 id1 = dev1.request(cmd) 207 if "FAIL" in id1: 208 raise Exception("NAN_PUBLISH failed") 209 210 ev = dev0.wait_event(["NAN-DISCOVERY-RESULT"], timeout=10) 211 if ev is None: 212 raise Exception("DiscoveryResult event not seen") 213 vals = split_nan_event(ev) 214 if vals['srv_proto_type'] != '3': 215 raise Exception("Unexpected srv_proto_type: " + ev) 216 if vals['ssi'] != '6677': 217 raise Exception("Unexpected ssi: " + ev) 218 if vals['subscribe_id'] != id0: 219 raise Exception("Unexpected subscribe_id: " + ev) 220 if vals['publish_id'] != id1: 221 raise Exception("Unexpected publish_id: " + ev) 222 addr1 = vals['address'] 223 224 # Automatically sent Follow-up message without ssi 225 ev = dev1.wait_event(["NAN-RECEIVE"], timeout=5) 226 if ev is None: 227 raise Exception("Receive event not seen") 228 vals2 = split_nan_event(ev) 229 if vals2['ssi'] != '': 230 raise Exception("Unexpected ssi in Follow-up: " + ev) 231 232 # Follow-up from subscriber to publisher 233 time.sleep(0.2) 234 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=8899".format(vals['subscribe_id'], vals['publish_id'], addr1) 235 if "FAIL" in dev0.request(cmd): 236 raise Exception("NAN_TRANSMIT failed") 237 238 ev = dev1.wait_event(["NAN-RECEIVE"], timeout=5) 239 if ev is None: 240 raise Exception("Receive event not seen") 241 vals = split_nan_event(ev) 242 if vals['ssi'] != '8899': 243 raise Exception("Unexpected ssi in Follow-up: " + ev) 244 if vals['id'] != id1: 245 raise Exception("Unexpected id: " + ev) 246 if vals['peer_instance_id'] != id0: 247 raise Exception("Unexpected peer_instance_id: " + ev) 248 addr0 = vals['address'] 249 250 # Follow-up from publisher to subscriber 251 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=aabbccdd".format(id1, vals['peer_instance_id'], addr0) 252 if "FAIL" in dev1.request(cmd): 253 raise Exception("NAN_TRANSMIT failed") 254 255 ev = dev0.wait_event(["NAN-RECEIVE"], timeout=5) 256 if ev is None: 257 raise Exception("Receive event not seen") 258 vals = split_nan_event(ev) 259 if vals['ssi'] != 'aabbccdd': 260 raise Exception("Unexpected ssi in Follow-up: " + ev) 261 if vals['id'] != id0: 262 raise Exception("Unexpected id: " + ev) 263 if vals['peer_instance_id'] != id1: 264 raise Exception("Unexpected peer_instance_id: " + ev) 265 266 # Another Follow-up message from publisher to subscriber 267 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=eeff".format(id1, vals['peer_instance_id'], addr0) 268 if "FAIL" in dev1.request(cmd): 269 raise Exception("NAN_TRANSMIT failed") 270 271 ev = dev0.wait_event(["NAN-RECEIVE"], timeout=5) 272 if ev is None: 273 raise Exception("Receive event not seen") 274 vals = split_nan_event(ev) 275 if vals['ssi'] != 'eeff': 276 raise Exception("Unexpected ssi in Follow-up: " + ev) 277 if vals['id'] != id0: 278 raise Exception("Unexpected id: " + ev) 279 if vals['peer_instance_id'] != id1: 280 raise Exception("Unexpected peer_instance_id: " + ev) 281 282 # And one more Follow-up message from publisher to subscriber after some 283 # delay. 284 time.sleep(0.5) 285 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=22334455".format(id1, vals['peer_instance_id'], addr0) 286 if "FAIL" in dev1.request(cmd): 287 raise Exception("NAN_TRANSMIT failed") 288 289 ev = dev0.wait_event(["NAN-RECEIVE"], timeout=5) 290 if ev is None: 291 raise Exception("Receive event not seen") 292 vals = split_nan_event(ev) 293 if vals['ssi'] != '22334455': 294 raise Exception("Unexpected ssi in Follow-up: " + ev) 295 if vals['id'] != id0: 296 raise Exception("Unexpected id: " + ev) 297 if vals['peer_instance_id'] != id1: 298 raise Exception("Unexpected peer_instance_id: " + ev) 299 300 dev0.request("NAN_CANCEL_SUBSCRIBE id=" + id0) 301 dev1.request("NAN_CANCEL_PUBLISH id=" + id1) 302 303def test_nan_usd_solicited_publisher(dev, apdev): 304 """NAN USD Publish/Subscribe match with solicited-only Publisher""" 305 check_nan_usd_capab(dev[0]) 306 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 srv_proto_type=2 ssi=6677" 307 id1 = dev[1].request(cmd) 308 if "FAIL" in id1: 309 raise Exception("NAN_PUBLISH failed") 310 311 cmd = "NAN_SUBSCRIBE service_name=_test active=1 srv_proto_type=2 ssi=1122334455" 312 id0 = dev[0].request(cmd) 313 if "FAIL" in id0: 314 raise Exception("NAN_SUBSCRIBE failed") 315 316 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 317 if ev is None: 318 raise Exception("DiscoveryResult event not seen") 319 vals = split_nan_event(ev) 320 if vals['srv_proto_type'] != "2": 321 raise Exception("Unexpected ssi: " + ev) 322 if vals['ssi'] != "6677": 323 raise Exception("Unexpected ssi: " + ev) 324 325 ev = dev[1].wait_event(["NAN-REPLIED"], timeout=5) 326 if ev is None: 327 raise Exception("Replied event not seen") 328 vals = split_nan_event(ev) 329 if vals['publish_id'] != id1: 330 raise Exception("Unexpected publish_id: " + ev) 331 if vals['subscribe_id'] != id0: 332 raise Exception("Unexpected subscribe_id: " + ev) 333 if vals['address'] != dev[0].own_addr(): 334 raise Exception("Unexpected address: " + ev) 335 if vals['srv_proto_type'] != "2": 336 raise Exception("Unexpected ssi: " + ev) 337 if vals['ssi'] != "1122334455": 338 raise Exception("Unexpected ssi: " + ev) 339 340def test_nan_usd_solicited_publisher_timeout(dev, apdev): 341 """NAN USD solicited Publisher timeout""" 342 check_nan_usd_capab(dev[0]) 343 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 ttl=10 srv_proto_type=2 ssi=6677" 344 id = dev[0].request(cmd) 345 if "FAIL" in id: 346 raise Exception("NAN_PUBLISH failed") 347 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=2) 348 if ev is not None: 349 raise Exception("Too quick Publish termination") 350 351 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 352 if ev is None: 353 raise Exception("Publish not terminated") 354 if "reason=timeout" not in ev: 355 raise Exception("Unexpected reason: " + ev) 356 357def test_nan_usd_unsolicited_publisher_timeout(dev, apdev): 358 """NAN USD unsolicited Publisher timeout""" 359 check_nan_usd_capab(dev[0]) 360 cmd = "NAN_PUBLISH service_name=_test solicited=0 ttl=10 srv_proto_type=2 ssi=6677" 361 id = dev[0].request(cmd) 362 if "FAIL" in id: 363 raise Exception("NAN_PUBLISH failed") 364 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=2) 365 if ev is not None: 366 raise Exception("Too quick Publish termination") 367 368 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 369 if ev is None: 370 raise Exception("Publish not terminated") 371 if "reason=timeout" not in ev: 372 raise Exception("Unexpected reason: " + ev) 373 374def test_nan_usd_publish_all_chans(dev, apdev): 375 """NAN USD Publish - all channels""" 376 check_nan_usd_capab(dev[0]) 377 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=all ttl=10" 378 id0 = dev[0].request(cmd) 379 if "FAIL" in id0: 380 raise Exception("NAN_PUBLISH failed") 381 382 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 383 if ev is None: 384 raise Exception("PublishTerminated event not seen") 385 386def test_nan_usd_publish_multi_chan(dev, apdev): 387 """NAN USD Publish - multi channel""" 388 check_nan_usd_capab(dev[0]) 389 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 390 id0 = dev[0].request(cmd) 391 if "FAIL" in id0: 392 raise Exception("NAN_PUBLISH failed") 393 394 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 395 if ev is None: 396 raise Exception("PublishTerminated event not seen") 397 398def test_nan_usd_publish_multi_chan_solicited(dev, apdev): 399 """NAN USD Publish - multi channel - solicited""" 400 check_nan_usd_capab(dev[0]) 401 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 402 id0 = dev[0].request(cmd) 403 if "FAIL" in id0: 404 raise Exception("NAN_PUBLISH failed") 405 406 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 407 if ev is None: 408 raise Exception("PublishTerminated event not seen") 409 410def test_nan_usd_publish_multi_chan_pause(dev, apdev): 411 """NAN USD Publish - multi channel""" 412 check_nan_usd_capab(dev[0]) 413 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 414 id0 = dev[0].request(cmd) 415 if "FAIL" in id0: 416 raise Exception("NAN_PUBLISH failed") 417 418 time.sleep(1) 419 420 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455" 421 id1 = dev[1].request(cmd) 422 if "FAIL" in id1: 423 raise Exception("NAN_SUBSCRIBE failed") 424 425 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=8899 active=1" 426 id2 = dev[2].request(cmd) 427 if "FAIL" in id2: 428 raise Exception("NAN_SUBSCRIBE failed") 429 430 ev = dev[0].wait_event(["NAN-RECEIVE"], timeout=10) 431 if ev is None: 432 raise Exception("Receive event not seen") 433 if "address=" + dev[1].own_addr() in ev.split(): 434 dev1 = dev[1] 435 dev2 = dev[2] 436 elif "address=" + dev[2].own_addr() in ev.split(): 437 dev1 = dev[2] 438 dev2 = dev[1] 439 else: 440 raise Exception("Unexpected address in NAN-RECEIVE: " + ev) 441 442 ev = dev1.wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 443 if ev is None: 444 raise Exception("DiscoveryResult event not seen (1)") 445 vals = split_nan_event(ev) 446 447 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=8899".format(vals['subscribe_id'], vals['publish_id'], dev[0].own_addr()) 448 if "FAIL" in dev1.request(cmd): 449 raise Exception("NAN_TRANSMIT failed") 450 ev = dev[0].wait_event(["NAN-RECEIVE"], timeout=5) 451 if ev is None: 452 raise Exception("Receive event not seen for follow-up (1)") 453 vals = split_nan_event(ev) 454 cmd = "NAN_UNPAUSE_PUBLISH publish_id={} peer_instance_id={} peer={}".format(vals['id'], vals['peer_instance_id'], vals['address']) 455 if "OK" not in dev[0].request(cmd): 456 raise Exception("NAN_UNPAUSE_PUBLISH failed") 457 458 ev = dev2.wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 459 if ev is None: 460 raise Exception("DiscoveryResult event not seen (2)") 461 vals = split_nan_event(ev) 462 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=8899".format(vals['subscribe_id'], vals['publish_id'], dev[0].own_addr()) 463 if "FAIL" in dev2.request(cmd): 464 raise Exception("NAN_TRANSMIT failed") 465 ev = dev[0].wait_event(["NAN-RECEIVE"], timeout=5) 466 if ev is None: 467 raise Exception("Receive event not seen for follow-up (2)") 468 469 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 470 if ev is None: 471 raise Exception("PublishTerminated event not seen") 472