1# P2P helper functions 2# Copyright (c) 2013-2019, Jouni Malinen <j@w1.fi> 3# 4# This software may be distributed under the terms of the BSD license. 5# See README for more details. 6 7import logging 8logger = logging.getLogger() 9import threading 10import time 11try: 12 from Queue import Queue 13except ImportError: 14 from queue import Queue 15 16import hwsim_utils 17 18MGMT_SUBTYPE_PROBE_REQ = 4 19MGMT_SUBTYPE_ACTION = 13 20ACTION_CATEG_PUBLIC = 4 21 22P2P_GO_NEG_REQ = 0 23P2P_GO_NEG_RESP = 1 24P2P_GO_NEG_CONF = 2 25P2P_INVITATION_REQ = 3 26P2P_INVITATION_RESP = 4 27P2P_DEV_DISC_REQ = 5 28P2P_DEV_DISC_RESP = 6 29P2P_PROV_DISC_REQ = 7 30P2P_PROV_DISC_RESP = 8 31 32P2P_ATTR_STATUS = 0 33P2P_ATTR_MINOR_REASON_CODE = 1 34P2P_ATTR_CAPABILITY = 2 35P2P_ATTR_DEVICE_ID = 3 36P2P_ATTR_GROUP_OWNER_INTENT = 4 37P2P_ATTR_CONFIGURATION_TIMEOUT = 5 38P2P_ATTR_LISTEN_CHANNEL = 6 39P2P_ATTR_GROUP_BSSID = 7 40P2P_ATTR_EXT_LISTEN_TIMING = 8 41P2P_ATTR_INTENDED_INTERFACE_ADDR = 9 42P2P_ATTR_MANAGEABILITY = 10 43P2P_ATTR_CHANNEL_LIST = 11 44P2P_ATTR_NOTICE_OF_ABSENCE = 12 45P2P_ATTR_DEVICE_INFO = 13 46P2P_ATTR_GROUP_INFO = 14 47P2P_ATTR_GROUP_ID = 15 48P2P_ATTR_INTERFACE = 16 49P2P_ATTR_OPERATING_CHANNEL = 17 50P2P_ATTR_INVITATION_FLAGS = 18 51P2P_ATTR_OOB_GO_NEG_CHANNEL = 19 52P2P_ATTR_SERVICE_HASH = 21 53P2P_ATTR_SESSION_INFORMATION_DATA = 22 54P2P_ATTR_CONNECTION_CAPABILITY = 23 55P2P_ATTR_ADVERTISEMENT_ID = 24 56P2P_ATTR_ADVERTISED_SERVICE = 25 57P2P_ATTR_SESSION_ID = 26 58P2P_ATTR_FEATURE_CAPABILITY = 27 59P2P_ATTR_PERSISTENT_GROUP = 28 60P2P_ATTR_VENDOR_SPECIFIC = 221 61 62P2P_SC_SUCCESS = 0 63P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1 64P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2 65P2P_SC_FAIL_LIMIT_REACHED = 3 66P2P_SC_FAIL_INVALID_PARAMS = 4 67P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5 68P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6 69P2P_SC_FAIL_NO_COMMON_CHANNELS = 7 70P2P_SC_FAIL_UNKNOWN_GROUP = 8 71P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9 72P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10 73P2P_SC_FAIL_REJECTED_BY_USER = 11 74 75WSC_ATTR_CONFIG_METHODS = 0x1008 76 77WLAN_EID_SSID = 0 78WLAN_EID_SUPP_RATES = 1 79WLAN_EID_VENDOR_SPECIFIC = 221 80 81def go_neg_pin_authorized_persistent(i_dev, r_dev, i_intent=None, r_intent=None, 82 i_method='enter', r_method='display', 83 test_data=True, r_listen=True): 84 if r_listen: 85 r_dev.p2p_listen() 86 i_dev.p2p_listen() 87 pin = r_dev.wps_read_pin() 88 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 89 r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method, 90 go_intent=r_intent, persistent=True) 91 if r_listen: 92 r_dev.p2p_listen() 93 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, 94 timeout=20, go_intent=i_intent, 95 persistent=True) 96 r_res = r_dev.p2p_go_neg_auth_result() 97 if i_res and r_res and \ 98 i_res['result'] == 'success' and r_res['result'] == 'success': 99 if i_res['role'] == 'GO': 100 i_dev.wait_sta(addr=r_dev.p2p_interface_addr()) 101 if r_res['role'] == 'GO': 102 r_dev.wait_sta(addr=i_dev.p2p_interface_addr()) 103 logger.debug("i_res: " + str(i_res)) 104 logger.debug("r_res: " + str(r_res)) 105 r_dev.dump_monitor() 106 i_dev.dump_monitor() 107 logger.info("Group formed") 108 if test_data: 109 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 110 return [i_res, r_res] 111 112def terminate_group(go, cli): 113 logger.info("Terminate persistent group") 114 cli.close_monitor_group() 115 go.remove_group() 116 cli.wait_go_ending_session() 117 118def invite(inv, resp, extra=None, persistent_reconnect=True, use_listen=True): 119 addr = resp.p2p_dev_addr() 120 if persistent_reconnect: 121 resp.global_request("SET persistent_reconnect 1") 122 else: 123 resp.global_request("SET persistent_reconnect 0") 124 if use_listen: 125 resp.p2p_listen() 126 else: 127 resp.p2p_find(social=True) 128 if not inv.discover_peer(addr, social=True): 129 raise Exception("Peer " + addr + " not found") 130 inv.dump_monitor() 131 peer = inv.get_peer(addr) 132 cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr 133 if extra: 134 cmd = cmd + " " + extra 135 inv.global_request(cmd) 136 137def check_result(go, cli): 138 ev = go.wait_global_event(["P2P-GROUP-STARTED", 139 "Failed to start AP functionality"], timeout=30) 140 if ev is None: 141 raise Exception("Timeout on group re-invocation (on GO)") 142 if "P2P-GROUP-STARTED" not in ev: 143 raise Exception("GO failed to start the group for re-invocation") 144 if "[PERSISTENT]" not in ev: 145 raise Exception("Re-invoked group not marked persistent") 146 go_res = go.group_form_result(ev) 147 if go_res['role'] != 'GO': 148 raise Exception("Persistent group GO did not become GO") 149 if not go_res['persistent']: 150 raise Exception("Persistent group not re-invoked as persistent (GO)") 151 ev = cli.wait_global_event(["P2P-GROUP-STARTED"], timeout=30) 152 if ev is None: 153 raise Exception("Timeout on group re-invocation (on client)") 154 if "[PERSISTENT]" not in ev: 155 raise Exception("Re-invoked group not marked persistent") 156 cli_res = cli.group_form_result(ev) 157 if cli_res['role'] != 'client': 158 raise Exception("Persistent group client did not become client") 159 if not cli_res['persistent']: 160 raise Exception("Persistent group not re-invoked as persistent (cli)") 161 return [go_res, cli_res] 162 163def form(go, cli, test_data=True, reverse_init=False, r_listen=True): 164 logger.info("Form a persistent group") 165 if reverse_init: 166 [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=cli, i_intent=0, 167 r_dev=go, r_intent=15, 168 test_data=test_data, 169 r_listen=r_listen) 170 else: 171 [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=go, i_intent=15, 172 r_dev=cli, r_intent=0, 173 test_data=test_data, 174 r_listen=r_listen) 175 if not i_res['persistent'] or not r_res['persistent']: 176 raise Exception("Formed group was not persistent") 177 terminate_group(go, cli) 178 if reverse_init: 179 return r_res 180 else: 181 return i_res 182 183def invite_from_cli(go, cli, terminate=True): 184 logger.info("Re-invoke persistent group from client") 185 invite(cli, go) 186 [go_res, cli_res] = check_result(go, cli) 187 hwsim_utils.test_connectivity_p2p(go, cli) 188 if terminate: 189 terminate_group(go, cli) 190 return [go_res, cli_res] 191 192def invite_from_go(go, cli, terminate=True, extra=None): 193 logger.info("Re-invoke persistent group from GO") 194 invite(go, cli, extra=extra) 195 [go_res, cli_res] = check_result(go, cli) 196 hwsim_utils.test_connectivity_p2p(go, cli) 197 if terminate: 198 terminate_group(go, cli) 199 return [go_res, cli_res] 200 201def autogo(go, freq=None, persistent=None): 202 logger.info("Start autonomous GO " + go.ifname) 203 res = go.p2p_start_go(freq=freq, persistent=persistent) 204 logger.debug("res: " + str(res)) 205 return res 206 207def connect_cli(go, client, social=False, freq=None): 208 logger.info("Try to connect the client to the GO") 209 pin = client.wps_read_pin() 210 go.p2p_go_authorize_client(pin) 211 res = client.p2p_connect_group(go.p2p_dev_addr(), pin, timeout=60, 212 social=social, freq=freq) 213 logger.info("Client connected") 214 go.wait_sta(client.p2p_interface_addr()) 215 hwsim_utils.test_connectivity_p2p(go, client) 216 return res 217 218def check_grpform_results(i_res, r_res): 219 if i_res['result'] != 'success' or r_res['result'] != 'success': 220 raise Exception("Failed group formation") 221 if i_res['ssid'] != r_res['ssid']: 222 raise Exception("SSID mismatch") 223 if i_res['freq'] != r_res['freq']: 224 raise Exception("freq mismatch") 225 if 'go_neg_freq' in r_res and i_res['go_neg_freq'] != r_res['go_neg_freq']: 226 raise Exception("go_neg_freq mismatch") 227 if i_res['freq'] != i_res['go_neg_freq']: 228 raise Exception("freq/go_neg_freq mismatch") 229 if i_res['role'] != i_res['go_neg_role']: 230 raise Exception("role/go_neg_role mismatch") 231 if 'go_neg_role' in r_res and r_res['role'] != r_res['go_neg_role']: 232 raise Exception("role/go_neg_role mismatch") 233 if i_res['go_dev_addr'] != r_res['go_dev_addr']: 234 raise Exception("GO Device Address mismatch") 235 236def go_neg_init(i_dev, r_dev, pin, i_method, i_intent, res): 237 logger.debug("Initiate GO Negotiation from i_dev") 238 try: 239 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=20, go_intent=i_intent) 240 logger.debug("i_res: " + str(i_res)) 241 except Exception as e: 242 i_res = None 243 logger.info("go_neg_init thread caught an exception from p2p_go_neg_init: " + str(e)) 244 res.put(i_res) 245 246def go_neg_pin(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display'): 247 r_dev.p2p_listen() 248 i_dev.p2p_listen() 249 pin = r_dev.wps_read_pin() 250 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 251 r_dev.dump_monitor() 252 res = Queue() 253 t = threading.Thread(target=go_neg_init, args=(i_dev, r_dev, pin, i_method, i_intent, res)) 254 t.start() 255 logger.debug("Wait for GO Negotiation Request on r_dev") 256 ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15) 257 if ev is None: 258 t.join() 259 raise Exception("GO Negotiation timed out") 260 r_dev.dump_monitor() 261 logger.debug("Re-initiate GO Negotiation from r_dev") 262 try: 263 r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), pin, r_method, 264 go_intent=r_intent, timeout=20) 265 except Exception as e: 266 logger.info("go_neg_pin - r_dev.p2p_go_neg_init() exception: " + str(e)) 267 t.join() 268 raise 269 logger.debug("r_res: " + str(r_res)) 270 r_dev.dump_monitor() 271 t.join() 272 i_res = res.get() 273 if i_res is None: 274 raise Exception("go_neg_init thread failed") 275 logger.debug("i_res: " + str(i_res)) 276 logger.info("Group formed") 277 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 278 i_dev.dump_monitor() 279 return [i_res, r_res] 280 281def go_neg_pin_authorized(i_dev, r_dev, i_intent=None, r_intent=None, 282 expect_failure=False, i_go_neg_status=None, 283 i_method='enter', r_method='display', test_data=True, 284 i_freq=None, r_freq=None, 285 i_freq2=None, r_freq2=None, 286 i_max_oper_chwidth=None, r_max_oper_chwidth=None, 287 i_ht40=False, i_vht=False, r_ht40=False, r_vht=False): 288 i_dev.p2p_listen() 289 pin = r_dev.wps_read_pin() 290 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 291 r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method, 292 go_intent=r_intent, freq=r_freq, freq2=r_freq2, 293 max_oper_chwidth=r_max_oper_chwidth, ht40=r_ht40, 294 vht=r_vht) 295 r_dev.p2p_listen() 296 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, 297 timeout=20, go_intent=i_intent, 298 expect_failure=expect_failure, freq=i_freq, 299 freq2=i_freq2, 300 max_oper_chwidth=i_max_oper_chwidth, 301 ht40=i_ht40, vht=i_vht) 302 r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure) 303 logger.debug("i_res: " + str(i_res)) 304 logger.debug("r_res: " + str(r_res)) 305 if not expect_failure and i_res and r_res and \ 306 i_res['result'] == 'success' and r_res['result'] == 'success': 307 if i_res['role'] == 'GO': 308 i_dev.wait_sta(addr=r_dev.p2p_interface_addr()) 309 if r_res['role'] == 'GO': 310 r_dev.wait_sta(addr=i_dev.p2p_interface_addr()) 311 r_dev.dump_monitor() 312 i_dev.dump_monitor() 313 if i_go_neg_status: 314 if i_res['result'] != 'go-neg-failed': 315 raise Exception("Expected GO Negotiation failure not reported") 316 if i_res['status'] != i_go_neg_status: 317 raise Exception("Expected GO Negotiation status not seen") 318 if expect_failure: 319 return 320 logger.info("Group formed") 321 if test_data: 322 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 323 return [i_res, r_res] 324 325def go_neg_init_pbc(i_dev, r_dev, i_intent, res, freq, provdisc, timeout=20): 326 logger.debug("Initiate GO Negotiation from i_dev") 327 try: 328 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", 329 timeout=timeout, go_intent=i_intent, 330 freq=freq, provdisc=provdisc) 331 logger.debug("i_res: " + str(i_res)) 332 except Exception as e: 333 i_res = None 334 logger.info("go_neg_init_pbc thread caught an exception from p2p_go_neg_init: " + str(e)) 335 res.put(i_res) 336 337def go_neg_pbc(i_dev, r_dev, i_intent=None, r_intent=None, i_freq=None, 338 r_freq=None, provdisc=False, r_listen=False, timeout=30): 339 if r_listen: 340 r_dev.p2p_listen() 341 else: 342 r_dev.p2p_find(social=True) 343 i_dev.p2p_find(social=True) 344 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 345 r_dev.dump_monitor() 346 res = Queue() 347 t = threading.Thread(target=go_neg_init_pbc, args=(i_dev, r_dev, i_intent, 348 res, i_freq, provdisc, 349 timeout)) 350 t.start() 351 logger.debug("Wait for GO Negotiation Request on r_dev") 352 ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=timeout - 5) 353 if ev is None: 354 logger.debug("Wait for P2P-GO-NEG-REQUEST timed out on r_dev - wait for i_dev thread to complete") 355 t.join() 356 raise Exception("GO Negotiation timed out") 357 r_dev.dump_monitor() 358 # Allow some time for the GO Neg Resp to go out before initializing new 359 # GO Negotiation. 360 time.sleep(0.2) 361 logger.debug("Re-initiate GO Negotiation from r_dev") 362 try: 363 r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), None, "pbc", 364 go_intent=r_intent, timeout=timeout, 365 freq=r_freq) 366 except Exception as e: 367 logger.info("go_neg_pbc - r_dev.p2p_go_neg_init() exception: " + str(e)) 368 t.join() 369 raise 370 logger.debug("r_res: " + str(r_res)) 371 r_dev.dump_monitor() 372 t.join() 373 i_res = res.get() 374 if i_res is None: 375 raise Exception("go_neg_init_pbc thread failed") 376 logger.debug("i_res: " + str(i_res)) 377 logger.info("Group formed") 378 time.sleep(0.1) 379 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 380 i_dev.dump_monitor() 381 return [i_res, r_res] 382 383def go_neg_pbc_authorized(i_dev, r_dev, i_intent=None, r_intent=None, 384 expect_failure=False, i_freq=None, r_freq=None): 385 i_dev.p2p_listen() 386 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 387 r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), None, "pbc", 388 go_intent=r_intent, freq=r_freq) 389 r_dev.p2p_listen() 390 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=20, 391 go_intent=i_intent, 392 expect_failure=expect_failure, freq=i_freq) 393 r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure) 394 logger.debug("i_res: " + str(i_res)) 395 logger.debug("r_res: " + str(r_res)) 396 r_dev.dump_monitor() 397 i_dev.dump_monitor() 398 if expect_failure: 399 return 400 logger.info("Group formed") 401 return [i_res, r_res] 402 403def remove_group(dev1, dev2, allow_failure=False): 404 try: 405 dev1.remove_group() 406 except: 407 if not allow_failure: 408 raise 409 try: 410 dev2.remove_group() 411 except: 412 pass 413