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 logger.debug("i_res: " + str(i_res)) 98 logger.debug("r_res: " + str(r_res)) 99 r_dev.dump_monitor() 100 i_dev.dump_monitor() 101 logger.info("Group formed") 102 if test_data: 103 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 104 return [i_res, r_res] 105 106def terminate_group(go, cli): 107 logger.info("Terminate persistent group") 108 cli.close_monitor_group() 109 go.remove_group() 110 cli.wait_go_ending_session() 111 112def invite(inv, resp, extra=None, persistent_reconnect=True, use_listen=True): 113 addr = resp.p2p_dev_addr() 114 if persistent_reconnect: 115 resp.global_request("SET persistent_reconnect 1") 116 else: 117 resp.global_request("SET persistent_reconnect 0") 118 if use_listen: 119 resp.p2p_listen() 120 else: 121 resp.p2p_find(social=True) 122 if not inv.discover_peer(addr, social=True): 123 raise Exception("Peer " + addr + " not found") 124 inv.dump_monitor() 125 peer = inv.get_peer(addr) 126 cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr 127 if extra: 128 cmd = cmd + " " + extra 129 inv.global_request(cmd) 130 131def check_result(go, cli): 132 ev = go.wait_global_event(["P2P-GROUP-STARTED", 133 "Failed to start AP functionality"], timeout=30) 134 if ev is None: 135 raise Exception("Timeout on group re-invocation (on GO)") 136 if "P2P-GROUP-STARTED" not in ev: 137 raise Exception("GO failed to start the group for re-invocation") 138 if "[PERSISTENT]" not in ev: 139 raise Exception("Re-invoked group not marked persistent") 140 go_res = go.group_form_result(ev) 141 if go_res['role'] != 'GO': 142 raise Exception("Persistent group GO did not become GO") 143 if not go_res['persistent']: 144 raise Exception("Persistent group not re-invoked as persistent (GO)") 145 ev = cli.wait_global_event(["P2P-GROUP-STARTED"], timeout=30) 146 if ev is None: 147 raise Exception("Timeout on group re-invocation (on client)") 148 if "[PERSISTENT]" not in ev: 149 raise Exception("Re-invoked group not marked persistent") 150 cli_res = cli.group_form_result(ev) 151 if cli_res['role'] != 'client': 152 raise Exception("Persistent group client did not become client") 153 if not cli_res['persistent']: 154 raise Exception("Persistent group not re-invoked as persistent (cli)") 155 return [go_res, cli_res] 156 157def form(go, cli, test_data=True, reverse_init=False, r_listen=True): 158 logger.info("Form a persistent group") 159 if reverse_init: 160 [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=cli, i_intent=0, 161 r_dev=go, r_intent=15, 162 test_data=test_data, 163 r_listen=r_listen) 164 else: 165 [i_res, r_res] = go_neg_pin_authorized_persistent(i_dev=go, i_intent=15, 166 r_dev=cli, r_intent=0, 167 test_data=test_data, 168 r_listen=r_listen) 169 if not i_res['persistent'] or not r_res['persistent']: 170 raise Exception("Formed group was not persistent") 171 terminate_group(go, cli) 172 if reverse_init: 173 return r_res 174 else: 175 return i_res 176 177def invite_from_cli(go, cli, terminate=True): 178 logger.info("Re-invoke persistent group from client") 179 invite(cli, go) 180 [go_res, cli_res] = check_result(go, cli) 181 hwsim_utils.test_connectivity_p2p(go, cli) 182 if terminate: 183 terminate_group(go, cli) 184 return [go_res, cli_res] 185 186def invite_from_go(go, cli, terminate=True, extra=None): 187 logger.info("Re-invoke persistent group from GO") 188 invite(go, cli, extra=extra) 189 [go_res, cli_res] = check_result(go, cli) 190 hwsim_utils.test_connectivity_p2p(go, cli) 191 if terminate: 192 terminate_group(go, cli) 193 return [go_res, cli_res] 194 195def autogo(go, freq=None, persistent=None): 196 logger.info("Start autonomous GO " + go.ifname) 197 res = go.p2p_start_go(freq=freq, persistent=persistent) 198 logger.debug("res: " + str(res)) 199 return res 200 201def connect_cli(go, client, social=False, freq=None): 202 logger.info("Try to connect the client to the GO") 203 pin = client.wps_read_pin() 204 go.p2p_go_authorize_client(pin) 205 res = client.p2p_connect_group(go.p2p_dev_addr(), pin, timeout=60, 206 social=social, freq=freq) 207 logger.info("Client connected") 208 hwsim_utils.test_connectivity_p2p(go, client) 209 return res 210 211def check_grpform_results(i_res, r_res): 212 if i_res['result'] != 'success' or r_res['result'] != 'success': 213 raise Exception("Failed group formation") 214 if i_res['ssid'] != r_res['ssid']: 215 raise Exception("SSID mismatch") 216 if i_res['freq'] != r_res['freq']: 217 raise Exception("freq mismatch") 218 if 'go_neg_freq' in r_res and i_res['go_neg_freq'] != r_res['go_neg_freq']: 219 raise Exception("go_neg_freq mismatch") 220 if i_res['freq'] != i_res['go_neg_freq']: 221 raise Exception("freq/go_neg_freq mismatch") 222 if i_res['role'] != i_res['go_neg_role']: 223 raise Exception("role/go_neg_role mismatch") 224 if 'go_neg_role' in r_res and r_res['role'] != r_res['go_neg_role']: 225 raise Exception("role/go_neg_role mismatch") 226 if i_res['go_dev_addr'] != r_res['go_dev_addr']: 227 raise Exception("GO Device Address mismatch") 228 229def go_neg_init(i_dev, r_dev, pin, i_method, i_intent, res): 230 logger.debug("Initiate GO Negotiation from i_dev") 231 try: 232 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, timeout=20, go_intent=i_intent) 233 logger.debug("i_res: " + str(i_res)) 234 except Exception as e: 235 i_res = None 236 logger.info("go_neg_init thread caught an exception from p2p_go_neg_init: " + str(e)) 237 res.put(i_res) 238 239def go_neg_pin(i_dev, r_dev, i_intent=None, r_intent=None, i_method='enter', r_method='display'): 240 r_dev.p2p_listen() 241 i_dev.p2p_listen() 242 pin = r_dev.wps_read_pin() 243 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 244 r_dev.dump_monitor() 245 res = Queue() 246 t = threading.Thread(target=go_neg_init, args=(i_dev, r_dev, pin, i_method, i_intent, res)) 247 t.start() 248 logger.debug("Wait for GO Negotiation Request on r_dev") 249 ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15) 250 if ev is None: 251 t.join() 252 raise Exception("GO Negotiation timed out") 253 r_dev.dump_monitor() 254 logger.debug("Re-initiate GO Negotiation from r_dev") 255 try: 256 r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), pin, r_method, 257 go_intent=r_intent, timeout=20) 258 except Exception as e: 259 logger.info("go_neg_pin - r_dev.p2p_go_neg_init() exception: " + str(e)) 260 t.join() 261 raise 262 logger.debug("r_res: " + str(r_res)) 263 r_dev.dump_monitor() 264 t.join() 265 i_res = res.get() 266 if i_res is None: 267 raise Exception("go_neg_init thread failed") 268 logger.debug("i_res: " + str(i_res)) 269 logger.info("Group formed") 270 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 271 i_dev.dump_monitor() 272 return [i_res, r_res] 273 274def go_neg_pin_authorized(i_dev, r_dev, i_intent=None, r_intent=None, 275 expect_failure=False, i_go_neg_status=None, 276 i_method='enter', r_method='display', test_data=True, 277 i_freq=None, r_freq=None, 278 i_freq2=None, r_freq2=None, 279 i_max_oper_chwidth=None, r_max_oper_chwidth=None, 280 i_ht40=False, i_vht=False, r_ht40=False, r_vht=False): 281 i_dev.p2p_listen() 282 pin = r_dev.wps_read_pin() 283 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 284 r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), pin, r_method, 285 go_intent=r_intent, freq=r_freq, freq2=r_freq2, 286 max_oper_chwidth=r_max_oper_chwidth, ht40=r_ht40, 287 vht=r_vht) 288 r_dev.p2p_listen() 289 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), pin, i_method, 290 timeout=20, go_intent=i_intent, 291 expect_failure=expect_failure, freq=i_freq, 292 freq2=i_freq2, 293 max_oper_chwidth=i_max_oper_chwidth, 294 ht40=i_ht40, vht=i_vht) 295 r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure) 296 logger.debug("i_res: " + str(i_res)) 297 logger.debug("r_res: " + str(r_res)) 298 r_dev.dump_monitor() 299 i_dev.dump_monitor() 300 if i_go_neg_status: 301 if i_res['result'] != 'go-neg-failed': 302 raise Exception("Expected GO Negotiation failure not reported") 303 if i_res['status'] != i_go_neg_status: 304 raise Exception("Expected GO Negotiation status not seen") 305 if expect_failure: 306 return 307 logger.info("Group formed") 308 if test_data: 309 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 310 return [i_res, r_res] 311 312def go_neg_init_pbc(i_dev, r_dev, i_intent, res, freq, provdisc): 313 logger.debug("Initiate GO Negotiation from i_dev") 314 try: 315 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", 316 timeout=20, go_intent=i_intent, freq=freq, 317 provdisc=provdisc) 318 logger.debug("i_res: " + str(i_res)) 319 except Exception as e: 320 i_res = None 321 logger.info("go_neg_init_pbc thread caught an exception from p2p_go_neg_init: " + str(e)) 322 res.put(i_res) 323 324def go_neg_pbc(i_dev, r_dev, i_intent=None, r_intent=None, i_freq=None, r_freq=None, provdisc=False, r_listen=False): 325 if r_listen: 326 r_dev.p2p_listen() 327 else: 328 r_dev.p2p_find(social=True) 329 i_dev.p2p_find(social=True) 330 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 331 r_dev.dump_monitor() 332 res = Queue() 333 t = threading.Thread(target=go_neg_init_pbc, args=(i_dev, r_dev, i_intent, res, i_freq, provdisc)) 334 t.start() 335 logger.debug("Wait for GO Negotiation Request on r_dev") 336 ev = r_dev.wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15) 337 if ev is None: 338 t.join() 339 raise Exception("GO Negotiation timed out") 340 r_dev.dump_monitor() 341 # Allow some time for the GO Neg Resp to go out before initializing new 342 # GO Negotiation. 343 time.sleep(0.2) 344 logger.debug("Re-initiate GO Negotiation from r_dev") 345 try: 346 r_res = r_dev.p2p_go_neg_init(i_dev.p2p_dev_addr(), None, "pbc", 347 go_intent=r_intent, timeout=20, 348 freq=r_freq) 349 except Exception as e: 350 logger.info("go_neg_pbc - r_dev.p2p_go_neg_init() exception: " + str(e)) 351 t.join() 352 raise 353 logger.debug("r_res: " + str(r_res)) 354 r_dev.dump_monitor() 355 t.join() 356 i_res = res.get() 357 if i_res is None: 358 raise Exception("go_neg_init_pbc thread failed") 359 logger.debug("i_res: " + str(i_res)) 360 logger.info("Group formed") 361 hwsim_utils.test_connectivity_p2p(r_dev, i_dev) 362 i_dev.dump_monitor() 363 return [i_res, r_res] 364 365def go_neg_pbc_authorized(i_dev, r_dev, i_intent=None, r_intent=None, 366 expect_failure=False, i_freq=None, r_freq=None): 367 i_dev.p2p_listen() 368 logger.info("Start GO negotiation " + i_dev.ifname + " -> " + r_dev.ifname) 369 r_dev.p2p_go_neg_auth(i_dev.p2p_dev_addr(), None, "pbc", 370 go_intent=r_intent, freq=r_freq) 371 r_dev.p2p_listen() 372 i_res = i_dev.p2p_go_neg_init(r_dev.p2p_dev_addr(), None, "pbc", timeout=20, 373 go_intent=i_intent, 374 expect_failure=expect_failure, freq=i_freq) 375 r_res = r_dev.p2p_go_neg_auth_result(expect_failure=expect_failure) 376 logger.debug("i_res: " + str(i_res)) 377 logger.debug("r_res: " + str(r_res)) 378 r_dev.dump_monitor() 379 i_dev.dump_monitor() 380 if expect_failure: 381 return 382 logger.info("Group formed") 383 return [i_res, r_res] 384 385def remove_group(dev1, dev2, allow_failure=False): 386 try: 387 dev1.remove_group() 388 except: 389 if not allow_failure: 390 raise 391 try: 392 dev2.remove_group() 393 except: 394 pass 395