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 id0 = dev[1].request(cmd) 100 if "FAIL" in id0: 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 # Check for publisher and subscriber functionality to time out 112 ev = dev[0].wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=5) 113 if ev is None: 114 raise Exception("Subscribe not terminated") 115 ev = dev[1].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=5) 116 if ev is None: 117 raise Exception("Publish not terminated") 118 119def test_nan_usd_match2(dev, apdev): 120 """NAN USD Publish/Subscribe match (2)""" 121 check_nan_usd_capab(dev[0]) 122 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 ttl=10 fsd=0" 123 id0 = dev[1].request(cmd) 124 if "FAIL" in id0: 125 raise Exception("NAN_PUBLISH failed") 126 127 time.sleep(1) 128 129 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455 active=1" 130 id0 = dev[0].request(cmd) 131 if "FAIL" in id0: 132 raise Exception("NAN_SUBSCRIBE failed") 133 134 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 135 if ev is None: 136 raise Exception("DiscoveryResult event not seen") 137 if "srv_proto_type=2" not in ev.split(' '): 138 raise Exception("Unexpected srv_proto_type: " + ev) 139 if "ssi=6677" not in ev.split(' '): 140 raise Exception("Unexpected ssi: " + ev) 141 142 # Check for publisher and subscriber functionality to time out 143 ev = dev[0].wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=2) 144 if ev is None: 145 raise Exception("Subscribe not terminated") 146 ev = dev[1].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 147 if ev is None: 148 raise Exception("Publish not terminated") 149 150def test_nan_usd_match3(dev, apdev): 151 """NAN USD Publish/Subscribe match (3)""" 152 check_nan_usd_capab(dev[0]) 153 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455 active=1" 154 id0 = dev[0].request(cmd) 155 if "FAIL" in id0: 156 raise Exception("NAN_SUBSCRIBE failed") 157 158 time.sleep(0.05) 159 160 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 ttl=10" 161 id0 = dev[1].request(cmd) 162 if "FAIL" in id0: 163 raise Exception("NAN_PUBLISH failed") 164 165 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 166 if ev is None: 167 raise Exception("DiscoveryResult event not seen") 168 if "srv_proto_type=2" not in ev.split(' '): 169 raise Exception("Unexpected srv_proto_type: " + ev) 170 if "ssi=6677" not in ev.split(' '): 171 raise Exception("Unexpected ssi: " + ev) 172 173 # Check for publisher and subscriber functionality to time out 174 ev = dev[0].wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=2) 175 if ev is None: 176 raise Exception("Subscribe not terminated") 177 ev = dev[1].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 178 if ev is None: 179 raise Exception("Publish not terminated") 180 181def split_nan_event(ev): 182 vals = dict() 183 for p in ev.split(' ')[1:]: 184 name, val = p.split('=') 185 vals[name] = val 186 return vals 187 188def test_nan_usd_followup(dev, apdev): 189 """NAN USD Publish/Subscribe match and follow-up""" 190 check_nan_usd_capab(dev[0]) 191 run_nan_usd_followup(dev[0], dev[1]) 192 193def test_nan_usd_followup_multi_chan(dev, apdev): 194 """NAN USD Publish/Subscribe match and follow-up with multi channels""" 195 check_nan_usd_capab(dev[0]) 196 run_nan_usd_followup(dev[0], dev[1], multi_chan=True) 197 198def test_nan_usd_followup_hostapd(dev, apdev): 199 """NAN USD Publish/Subscribe match and follow-up with hostapd""" 200 check_nan_usd_capab(dev[0]) 201 hapd = hostapd.add_ap(apdev[0], {"ssid": "open", 202 "channel": "6"}) 203 run_nan_usd_followup(hapd, dev[1]) 204 205def run_nan_usd_followup(dev0, dev1, multi_chan=False): 206 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=3 ssi=1122334455" 207 if multi_chan: 208 cmd += " freq=2462" 209 id0 = dev0.request(cmd) 210 if "FAIL" in id0: 211 raise Exception("NAN_SUBSCRIBE failed") 212 213 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=3 ssi=6677 ttl=10" 214 if multi_chan: 215 cmd += " freq=2412 freq_list=2437,2462" 216 id1 = dev1.request(cmd) 217 if "FAIL" in id1: 218 raise Exception("NAN_PUBLISH failed") 219 220 ev = dev0.wait_event(["NAN-DISCOVERY-RESULT"], timeout=10) 221 if ev is None: 222 raise Exception("DiscoveryResult event not seen") 223 vals = split_nan_event(ev) 224 if vals['srv_proto_type'] != '3': 225 raise Exception("Unexpected srv_proto_type: " + ev) 226 if vals['ssi'] != '6677': 227 raise Exception("Unexpected ssi: " + ev) 228 if vals['subscribe_id'] != id0: 229 raise Exception("Unexpected subscribe_id: " + ev) 230 if vals['publish_id'] != id1: 231 raise Exception("Unexpected publish_id: " + ev) 232 addr1 = vals['address'] 233 234 # Automatically sent Follow-up message without ssi 235 ev = dev1.wait_event(["NAN-RECEIVE"], timeout=5) 236 if ev is None: 237 raise Exception("Receive event not seen") 238 vals2 = split_nan_event(ev) 239 if vals2['ssi'] != '': 240 raise Exception("Unexpected ssi in Follow-up: " + ev) 241 242 # Follow-up from subscriber to publisher 243 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=8899".format(vals['subscribe_id'], vals['publish_id'], addr1) 244 if "FAIL" in dev0.request(cmd): 245 raise Exception("NAN_TRANSMIT failed") 246 247 ev = dev1.wait_event(["NAN-RECEIVE"], timeout=5) 248 if ev is None: 249 raise Exception("Receive event not seen") 250 vals = split_nan_event(ev) 251 if vals['ssi'] != '8899': 252 raise Exception("Unexpected ssi in Follow-up: " + ev) 253 if vals['id'] != id1: 254 raise Exception("Unexpected id: " + ev) 255 if vals['peer_instance_id'] != id0: 256 raise Exception("Unexpected peer_instance_id: " + ev) 257 addr0 = vals['address'] 258 259 # Follow-up from publisher to subscriber 260 cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=aabbccdd".format(id1, vals['peer_instance_id'], addr0) 261 if "FAIL" in dev1.request(cmd): 262 raise Exception("NAN_TRANSMIT failed") 263 264 ev = dev0.wait_event(["NAN-RECEIVE"], timeout=5) 265 if ev is None: 266 raise Exception("Receive event not seen") 267 vals = split_nan_event(ev) 268 if vals['ssi'] != 'aabbccdd': 269 raise Exception("Unexpected ssi in Follow-up: " + ev) 270 if vals['id'] != id0: 271 raise Exception("Unexpected id: " + ev) 272 if vals['peer_instance_id'] != id1: 273 raise Exception("Unexpected peer_instance_id: " + ev) 274 275 # Check for publisher and subscriber functionality to time out 276 ev = dev0.wait_event(["NAN-SUBSCRIBE-TERMINATED"], timeout=10) 277 if ev is None: 278 raise Exception("Subscribe not terminated") 279 ev = dev1.wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 280 if ev is None: 281 raise Exception("Publish not terminated") 282 283def test_nan_usd_solicited_publisher(dev, apdev): 284 """NAN USD Publish/Subscribe match with solicited-only Publisher""" 285 check_nan_usd_capab(dev[0]) 286 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 srv_proto_type=2 ssi=6677" 287 id1 = dev[1].request(cmd) 288 if "FAIL" in id1: 289 raise Exception("NAN_PUBLISH failed") 290 291 cmd = "NAN_SUBSCRIBE service_name=_test active=1 srv_proto_type=2 ssi=1122334455" 292 id0 = dev[0].request(cmd) 293 if "FAIL" in id0: 294 raise Exception("NAN_SUBSCRIBE failed") 295 296 ev = dev[0].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 297 if ev is None: 298 raise Exception("DiscoveryResult event not seen") 299 vals = split_nan_event(ev) 300 if vals['srv_proto_type'] != "2": 301 raise Exception("Unexpected ssi: " + ev) 302 if vals['ssi'] != "6677": 303 raise Exception("Unexpected ssi: " + ev) 304 305 ev = dev[1].wait_event(["NAN-REPLIED"], timeout=5) 306 if ev is None: 307 raise Exception("Replied event not seen") 308 vals = split_nan_event(ev) 309 if vals['publish_id'] != id1: 310 raise Exception("Unexpected publish_id: " + ev) 311 if vals['subscribe_id'] != id0: 312 raise Exception("Unexpected subscribe_id: " + ev) 313 if vals['address'] != dev[0].own_addr(): 314 raise Exception("Unexpected address: " + ev) 315 if vals['srv_proto_type'] != "2": 316 raise Exception("Unexpected ssi: " + ev) 317 if vals['ssi'] != "1122334455": 318 raise Exception("Unexpected ssi: " + ev) 319 320def test_nan_usd_solicited_publisher_timeout(dev, apdev): 321 """NAN USD solicited Publisher timeout""" 322 check_nan_usd_capab(dev[0]) 323 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 ttl=10 srv_proto_type=2 ssi=6677" 324 id = dev[0].request(cmd) 325 if "FAIL" in id: 326 raise Exception("NAN_PUBLISH failed") 327 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=2) 328 if ev is not None: 329 raise Exception("Too quick Publish termination") 330 331 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 332 if ev is None: 333 raise Exception("Publish not terminated") 334 if "reason=timeout" not in ev: 335 raise Exception("Unexpected reason: " + ev) 336 337def test_nan_usd_unsolicited_publisher_timeout(dev, apdev): 338 """NAN USD unsolicited Publisher timeout""" 339 check_nan_usd_capab(dev[0]) 340 cmd = "NAN_PUBLISH service_name=_test solicited=0 ttl=10 srv_proto_type=2 ssi=6677" 341 id = dev[0].request(cmd) 342 if "FAIL" in id: 343 raise Exception("NAN_PUBLISH failed") 344 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=2) 345 if ev is not None: 346 raise Exception("Too quick Publish termination") 347 348 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=10) 349 if ev is None: 350 raise Exception("Publish not terminated") 351 if "reason=timeout" not in ev: 352 raise Exception("Unexpected reason: " + ev) 353 354def test_nan_usd_publish_all_chans(dev, apdev): 355 """NAN USD Publish - all channels""" 356 check_nan_usd_capab(dev[0]) 357 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=all ttl=10" 358 id0 = dev[0].request(cmd) 359 if "FAIL" in id0: 360 raise Exception("NAN_PUBLISH failed") 361 362 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 363 if ev is None: 364 raise Exception("PublishTerminated event not seen") 365 366def test_nan_usd_publish_multi_chan(dev, apdev): 367 """NAN USD Publish - multi channel""" 368 check_nan_usd_capab(dev[0]) 369 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 370 id0 = dev[0].request(cmd) 371 if "FAIL" in id0: 372 raise Exception("NAN_PUBLISH failed") 373 374 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 375 if ev is None: 376 raise Exception("PublishTerminated event not seen") 377 378def test_nan_usd_publish_multi_chan_solicited(dev, apdev): 379 """NAN USD Publish - multi channel - solicited""" 380 check_nan_usd_capab(dev[0]) 381 cmd = "NAN_PUBLISH service_name=_test unsolicited=0 srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 382 id0 = dev[0].request(cmd) 383 if "FAIL" in id0: 384 raise Exception("NAN_PUBLISH failed") 385 386 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 387 if ev is None: 388 raise Exception("PublishTerminated event not seen") 389 390def test_nan_usd_publish_multi_chan_pause(dev, apdev): 391 """NAN USD Publish - multi channel""" 392 check_nan_usd_capab(dev[0]) 393 cmd = "NAN_PUBLISH service_name=_test srv_proto_type=2 ssi=6677 freq_list=2412,2462 ttl=10" 394 id0 = dev[0].request(cmd) 395 if "FAIL" in id0: 396 raise Exception("NAN_PUBLISH failed") 397 398 time.sleep(1) 399 400 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=1122334455" 401 id1 = dev[1].request(cmd) 402 if "FAIL" in id1: 403 raise Exception("NAN_SUBSCRIBE failed") 404 405 cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=2 ssi=8899 active=1" 406 id2 = dev[2].request(cmd) 407 if "FAIL" in id2: 408 raise Exception("NAN_SUBSCRIBE failed") 409 410 ev = dev[1].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 411 if ev is None: 412 raise Exception("DiscoveryResult event not seen (1)") 413 414 ev = dev[2].wait_event(["NAN-DISCOVERY-RESULT"], timeout=5) 415 if ev is None: 416 raise Exception("DiscoveryResult event not seen (2)") 417 418 ev = dev[0].wait_event(["NAN-PUBLISH-TERMINATED"], timeout=15) 419 if ev is None: 420 raise Exception("PublishTerminated event not seen") 421