1 /* 2 * Sigma Control API DUT - Miracast interface 3 * Copyright (c) 2017, Qualcomm Atheros, Inc. 4 * Copyright (c) 2018, The Linux Foundation 5 * All Rights Reserved. 6 * Licensed under the Clear BSD license. See README for more details. 7 * 8 * Implementation of MIRACAST specific functionality. 9 * For example, starting wfd session. 10 */ 11 12 #include "sigma_dut.h" 13 #include <dlfcn.h> 14 #include <sys/ioctl.h> 15 #include <sys/select.h> 16 #include "wpa_ctrl.h" 17 #include "wpa_helpers.h" 18 #include "miracast.h" 19 #ifdef ANDROID 20 #include "properties.h" 21 #ifndef MIRACAST_DHCP_M 22 #include <netutils/ifc.h> 23 #endif /* MIRACAST_DHCP_M */ 24 #endif /* ANDROID */ 25 26 #define HUNDRED_SECOND_TIMEOUT 100 /* 100 seconds */ 27 #define DHCP_LEASE_FILE_PATH "/data/misc/dhcp/dnsmasq.leases" 28 #define MIRACAST_CMD_LEN 512 29 30 extern char *sigma_main_ifname; 31 extern char *sigma_station_ifname; 32 33 static int session_management_control_port = 7236; 34 /* Followingng stores p2p interface name after P2P group formation */ 35 static char wfd_ifname[32]; 36 37 #ifndef MIRACAST_DHCP_M 38 extern void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, 39 uint32_t *prefixLength, uint32_t *dns1, 40 uint32_t *dns2, uint32_t *server, 41 uint32_t *lease); 42 43 extern int do_dhcp(char *); 44 45 const char *ipaddr (in_addr_t addr) 46 { 47 struct in_addr in_addr; 48 in_addr.s_addr = addr; 49 return inet_ntoa(in_addr); 50 } 51 #endif /* MIRACAST_DHCP_M */ 52 53 54 55 56 static int miracast_load(struct sigma_dut *dut) 57 { 58 static int once = 1; 59 60 if (!once) 61 return 0; 62 63 once = 0; 64 dlerror(); 65 dut->miracast_lib = dlopen(dut->miracast_lib_path ? 66 dut->miracast_lib_path : "libmiracast.so", 67 RTLD_LAZY); 68 if (!dut->miracast_lib) { 69 sigma_dut_print(dut, DUT_MSG_INFO, 70 "Fail to load Miracast library %s", 71 dlerror()); 72 return -1; 73 } 74 sigma_dut_print(dut, DUT_MSG_INFO, 75 "Miracast Wi-Fi Display library found - starting service"); 76 return 0; 77 } 78 79 80 static int miracast_unload(struct sigma_dut *dut) 81 { 82 int err; 83 84 if (!dut->miracast_lib) 85 return -1; 86 87 dlerror(); 88 sigma_dut_print(dut, DUT_MSG_INFO, "Unloading Miracast library"); 89 err = dlclose(dut->miracast_lib); 90 dut->miracast_lib = NULL; 91 if (err == 0) { 92 sigma_dut_print(dut, DUT_MSG_INFO, 93 "Miracast library successfully unloaded"); 94 } else { 95 sigma_dut_print(dut, DUT_MSG_INFO, 96 "Failed to unload Miracast library"); 97 } 98 return err; 99 } 100 101 102 static int get_peer_ip_p2p_go(struct sigma_dut *dut, char *ipaddr, 103 const char *macaddr, unsigned int wait_limit) 104 { 105 106 FILE *fp; 107 108 fp = fopen(DHCP_LEASE_FILE_PATH, "r"); 109 if (!fp) { 110 sigma_dut_print(dut, DUT_MSG_ERROR, 111 "Could not open DHCP lease file"); 112 return -1; 113 } 114 115 sigma_dut_print(dut, DUT_MSG_INFO, "macaddress %s", macaddr); 116 while (wait_limit > 0) { 117 char line[100] = { 0 }; 118 char *str1 = NULL; 119 char *dummy_str = NULL; 120 char dummy_macaddress[32]; 121 int ip_found = 0; 122 int len; 123 124 fseek(fp, 0, SEEK_SET); 125 while (fgets(line, sizeof(line), fp) != NULL) { 126 len = strlen(line); 127 if (len == 0) 128 continue; 129 130 str1 = strtok_r(line, " ", &dummy_str); 131 if (str1 == NULL) 132 break; 133 134 /* Look for mac address */ 135 str1 = strtok_r(NULL, " ", &dummy_str); 136 if (str1 == NULL) 137 break; 138 139 strlcpy(dummy_macaddress, str1, 140 sizeof(dummy_macaddress)); 141 142 /* Look for ip address */ 143 str1 = strtok_r(NULL, " ", &dummy_str); 144 if (str1 == NULL) 145 break; 146 147 strlcpy(ipaddr,str1,32); 148 149 sigma_dut_print(dut, DUT_MSG_INFO, 150 "Peer IP Address obtained and mac %s %s", 151 ipaddr, dummy_macaddress); 152 153 /* 154 * The idea is that the p2p mac address may differ by 1 155 * nibble mostly it is the first byte, hence try the 156 * middle two octets. 157 */ 158 if (strncasecmp(macaddr + 6, dummy_macaddress + 6, 159 5) == 0) { 160 ip_found = 1; 161 sigma_dut_print(dut, DUT_MSG_INFO, 162 "Obtained the IP address %s", 163 ipaddr); 164 break; 165 } 166 } 167 168 if (ip_found) 169 break; 170 171 sigma_dut_print(dut, DUT_MSG_INFO, 172 "Failed to find IP from DHCP lease file"); 173 sleep(1); 174 wait_limit--; 175 } 176 fclose(fp); 177 return 0; 178 } 179 180 181 static int miracast_start_dhcp_client(struct sigma_dut *dut, const char *ifname) 182 { 183 #ifdef MIRACAST_DHCP_M 184 start_dhcp(dut, ifname, 0); 185 #else /* MIRACAST_DHCP_M */ 186 int ret = ifc_init(); 187 188 sigma_dut_print(dut, DUT_MSG_DEBUG, "ifc init returned %d", ret); 189 ret = do_dhcp((char *) ifname); 190 sigma_dut_print(dut, DUT_MSG_DEBUG, "do dhcp returned %d", ret); 191 #endif /* MIRACAST_DHCP_M */ 192 return 0; 193 } 194 195 196 static void miracast_stop_dhcp_client(struct sigma_dut *dut, char *ifname) 197 { 198 #ifdef MIRACAST_DHCP_M 199 stop_dhcp(dut, ifname, 0); 200 #else /* MIRACAST_DHCP_M */ 201 ifc_close(); 202 #endif /* MIRACAST_DHCP_M */ 203 } 204 205 206 #ifdef MIRACAST_DHCP_M 207 208 static int get_local_ip_address(struct sigma_dut *dut, 209 char *local_ip_addr, size_t buflen, 210 const char *intf, int size) 211 { 212 struct ifreq ifr; 213 int s; 214 215 memset(&ifr, 0, sizeof(struct ifreq)); 216 strlcpy(ifr.ifr_name, intf, IFNAMSIZ); 217 ifr.ifr_name[IFNAMSIZ-1] = 0; 218 219 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 220 sigma_dut_print(dut, DUT_MSG_INFO, 221 "%s: Error in creating socket", __func__); 222 return -1; 223 } 224 225 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { 226 sigma_dut_print(dut, DUT_MSG_INFO, "ioctl failed: %s", 227 strerror(errno)); 228 close(s); 229 return -1; 230 } 231 232 strlcpy(local_ip_addr, 233 inet_ntoa(((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr), 234 buflen); 235 close(s); 236 return 0; 237 } 238 239 240 static int get_peer_ip_p2p_client(struct sigma_dut *dut, char *ip_addr, 241 const char *intf, unsigned int wait_limit) 242 { 243 char prop_name[128]; 244 char prop_name_self[128]; 245 char self_ip[128]; 246 247 memset(self_ip, 0, sizeof(self_ip)); 248 /* For P2P Client read the server property */ 249 snprintf(prop_name, sizeof(prop_name), "%s.%s.server", "dhcp", "p2p"); 250 snprintf(prop_name_self, sizeof(prop_name_self), 251 "%s.%s.ipaddress", "dhcp", "p2p"); 252 253 while (wait_limit > 0) { 254 #ifdef ANDROID 255 property_get(prop_name, ip_addr, NULL); 256 #else /* ANDROID */ 257 ip_addr[0] = '\0'; 258 #endif /* ANDROID */ 259 get_local_ip_address(dut, self_ip, sizeof(self_ip), intf, 20); 260 sigma_dut_print(dut, DUT_MSG_INFO, "Peer IP, self IP: %s %s", 261 ip_addr, self_ip); 262 if (strlen(ip_addr) > 8 && 263 ip_addr[0] == '1' && ip_addr[1] == '9' && 264 self_ip[0] == '1' && self_ip[1] == '9') 265 break; /* connected */ 266 267 /* What if DHCP server was started before Client was started? 268 * Request DHCP yet again */ 269 miracast_start_dhcp_client(dut, intf); 270 sleep(5); /* Sleep always helps */ 271 wait_limit--; 272 } 273 274 return wait_limit > 0 ? 0 : -1; 275 } 276 277 #else /* MIRACAST_DHCP_M */ 278 279 static int get_peer_ip_p2p_client(struct sigma_dut *dut, char *ipAddr, 280 const char *intf, unsigned int wait_limit) 281 { 282 uint32_t ipaddress, gateway, prefixLength, 283 dns1, dns2, serveraddr, lease; 284 285 get_dhcp_info(&ipaddress, &gateway, &prefixLength, &dns1, &dns2, 286 &serveraddr, &lease); 287 while (wait_limit > 0) { 288 sigma_dut_print(dut, DUT_MSG_INFO, "Peer IP: %u", ipaddress); 289 if (strlen(ipaddr(serveraddr)) > 8) { 290 /* connected */ 291 strlcpy(ipAddr, ipaddr(serveraddr), 16); 292 break; 293 } 294 sleep(1); 295 wait_limit--; 296 } 297 return wait_limit == 0 ? -1 : 0; 298 } 299 300 #endif /* MIRACAST_DHCP_M */ 301 302 303 static int get_p2p_connection_event(struct sigma_dut *dut, 304 const char *input_intf, 305 char *output_intf, 306 int size_output_intf, 307 int *is_group_owner) 308 { 309 /* 310 * Poll for the P2P Connection 311 * Then poll for IP 312 * Then poll for WFD session ID and exit 313 * P2P connection done 314 * Loop till connection is ready 315 */ 316 struct wpa_ctrl *ctrl; 317 char *mode_string; 318 char event_buf[256]; 319 char *ifname; 320 char *pos; 321 int res = 0; 322 const char *events[] = { 323 "P2P-GROUP-STARTED", 324 "P2P-GO-NEG-FAILURE", 325 "P2P-GROUP-FORMATION-FAILURE", 326 NULL 327 }; 328 329 /* Wait for WPA CLI EVENTS */ 330 /* Default timeout is 120s */ 331 ctrl = open_wpa_mon(input_intf); 332 if (!ctrl) { 333 sigma_dut_print(dut, DUT_MSG_ERROR, 334 "Failed to open wpa_supplicant monitor connection"); 335 return -1; 336 } 337 338 res = get_wpa_cli_events(dut, ctrl, events, event_buf, 339 sizeof(event_buf)); 340 341 wpa_ctrl_detach(ctrl); 342 wpa_ctrl_close(ctrl); 343 344 if (res < 0) { 345 sigma_dut_print(dut, DUT_MSG_ERROR, 346 "Group formation did not complete"); 347 return -1; 348 } 349 350 sigma_dut_print(dut, DUT_MSG_DEBUG, "Received event %s", event_buf); 351 352 if (strstr(event_buf, "P2P-GROUP-FORMATION-FAILURE") || 353 strstr(event_buf, "P2P-GO-NEG-FAILURE")) 354 return -1; 355 356 sigma_dut_print(dut, DUT_MSG_INFO, "P2P connection done"); 357 ifname = strchr(event_buf, ' '); 358 if (!ifname) { 359 sigma_dut_print(dut, DUT_MSG_INFO, "No P2P interface found"); 360 return -1; 361 } 362 ifname++; 363 pos = strchr(ifname, ' '); 364 if (!pos) { 365 sigma_dut_print(dut, DUT_MSG_ERROR, "No P2P interface found"); 366 return -1; 367 } 368 *pos++ = '\0'; 369 sigma_dut_print(dut, DUT_MSG_DEBUG, "Group interface %s", ifname); 370 371 strlcpy(output_intf, ifname, size_output_intf); 372 373 mode_string = pos; 374 pos = strchr(mode_string, ' '); 375 if (!pos) { 376 sigma_dut_print(dut, DUT_MSG_ERROR, "No group role found"); 377 return -1; 378 } 379 380 *pos++ = '\0'; 381 sigma_dut_print(dut, DUT_MSG_DEBUG, "Group Role %s", mode_string); 382 383 if (strcmp(mode_string, "GO") == 0) 384 *is_group_owner = 1; 385 sigma_dut_print(dut, DUT_MSG_DEBUG, "Value of is_group_owner %d", 386 *is_group_owner); 387 return 0; 388 } 389 390 391 /* Following serves as an entry point function to perform rtsp tasks */ 392 static void * miracast_rtsp_thread_entry(void *ptr) 393 { 394 struct sigma_dut *dut = ptr; 395 char output_ifname[16]; 396 int is_group_owner = 0; 397 const char *intf = sigma_station_ifname; 398 unsigned int wait_limit; 399 char peer_ip_address[32]; 400 char rtsp_session_id[12]; 401 int (*extn_start_wfd_connection)(const char *, 402 const char *, /* Peer IP */ 403 int, /* RTSP port number */ 404 int, /* WFD Device Type; 0-Source, 405 1-P-Sink, 2-Secondary Sink */ 406 char *); /* for returning session ID */ 407 408 miracast_load(dut); 409 410 if (sigma_main_ifname) { 411 intf = sigma_main_ifname; 412 sigma_dut_print(dut, DUT_MSG_DEBUG, 413 "miracast_rtsp_thread_entry: sigma_main_ifname = [%s]", 414 intf); 415 } else { 416 sigma_dut_print(dut, DUT_MSG_DEBUG, 417 "miracast_rtsp_thread_entry: sigma_main_ifname is NULL"); 418 } 419 420 if (get_p2p_connection_event(dut, intf, output_ifname, 421 sizeof(output_ifname), 422 &is_group_owner) < 0) { 423 sigma_dut_print(dut, DUT_MSG_ERROR, "P2P connection failure"); 424 goto EXIT; 425 } 426 427 sigma_dut_print(dut, DUT_MSG_DEBUG, "Waiting to start dhcp"); 428 429 /* Calling WFD APIs now */ 430 /* If you are a source, go ahead and start the RTSP server */ 431 if (dut->wfd_device_type != 0) 432 wait_limit = HUNDRED_SECOND_TIMEOUT; 433 else 434 wait_limit = 500; 435 436 if (!is_group_owner) { 437 sigma_dut_print(dut, DUT_MSG_INFO, 438 "Waiting to start dhcp client"); 439 sleep(5); /* Wait for IP */ 440 miracast_start_dhcp_client(dut, output_ifname); 441 sleep(5); /* Wait for IP */ 442 if (get_peer_ip_p2p_client(dut, peer_ip_address, output_ifname, 443 wait_limit) < 0) { 444 sigma_dut_print(dut, DUT_MSG_ERROR, 445 "Could not get peer IP"); 446 goto EXIT; 447 } 448 } else { 449 stop_dhcp(dut, output_ifname, 1); 450 /* For GO read the DHCP Lease File */ 451 sigma_dut_print(dut, DUT_MSG_INFO, 452 "Waiting to start dhcp server"); 453 start_dhcp(dut, output_ifname, 1); 454 sleep(5); 455 if (get_peer_ip_p2p_go(dut, peer_ip_address, 456 dut->peer_mac_address, wait_limit) < 0) { 457 sigma_dut_print(dut, DUT_MSG_ERROR, 458 "Could not get peer IP"); 459 goto EXIT; 460 } 461 } 462 463 extn_start_wfd_connection = dlsym(dut->miracast_lib, 464 "start_wfd_connection"); 465 if (extn_start_wfd_connection) { 466 extn_start_wfd_connection(NULL, peer_ip_address, 467 session_management_control_port, 468 1 - dut->wfd_device_type, 469 rtsp_session_id); 470 } else { 471 sigma_dut_print(dut, DUT_MSG_INFO, 472 "dlsym seems to have error %p %p", 473 dut->miracast_lib, extn_start_wfd_connection); 474 } 475 476 EXIT: 477 sigma_dut_print(dut, DUT_MSG_INFO, "Reached Miracast thread exit"); 478 479 return NULL; 480 } 481 482 483 /*---------------------------------------------------------------------- 484 WFD Source IE: 000601101c440036 485 len WFD device info control port throughput 486 110] [00000 00100010 000] [00011 10001000 100] [00000 00000110 110] 487 = 7236 488 489 WFD Sink IE: 000601511c440036 490 len WFD device info control port throughput 491 110] [00000 00101010 001] [00011 10001000 100] [00000 00000110 110] 492 = 7236 493 494 WFD device info: 495 BITS NAME DESCRIPTION 496 ------------------------------------------- 497 1:0 WFD Device Type 0b00: WFD Source 498 0b01: Primary Sink 499 0b10: Secondary Sink 500 0b11: Dual Role, either WFD Source/Primary sink 501 502 5:4 WFD Session 0b00: Not available for WFD Session 503 Availibility 0b01: Available for WFD Session 504 0b10, 0b11: Reserved 505 506 6 WSD Support Bit 0b0: WFD Service Discovery not supported 507 0b1: WFD Service Discovery supported 508 509 8 CP Support Bit 0b0: Content Protection via HDCP not supported 510 0b1: Content Protection via HDCP supported 511 --------------------------------------------------------------------------- 512 */ 513 514 static void miracast_set_wfd_ie(struct sigma_dut *sigma_dut) 515 { 516 char *intf = sigma_station_ifname; 517 518 if (sigma_main_ifname != NULL) 519 intf = sigma_main_ifname; 520 521 sigma_dut_print(sigma_dut, DUT_MSG_DEBUG, "miracast_set_wfd_ie() = intf = %s", 522 intf); 523 wpa_command(intf, "SET wifi_display 1"); 524 525 if (sigma_dut->wfd_device_type == 0) { 526 wpa_command(intf, "WFD_SUBELEM_SET 0 000601101c440036"); 527 wpa_command(intf, "WFD_SUBELEM_SET 11 00020000"); 528 } else { 529 wpa_command(intf, "WFD_SUBELEM_SET 0 000601511c440036"); 530 wpa_command(intf, "WFD_SUBELEM_SET 11 00020001"); 531 } 532 } 533 534 535 void miracast_init(struct sigma_dut *dut) 536 { 537 sigma_dut_print(dut, DUT_MSG_DEBUG, "Create thread pool for VDS"); 538 miracast_set_wfd_ie(dut); 539 sigma_dut_print(dut, DUT_MSG_DEBUG, "Clear groupID @ start"); 540 } 541 542 543 void miracast_deinit(struct sigma_dut *dut) 544 { 545 (void) miracast_unload(dut); 546 } 547 548 549 static void miracast_generate_string_cmd(struct sigma_cmd *cmd, char *strcmd, 550 size_t size) 551 { 552 int i = 0; 553 char *pos, *end; 554 int ret; 555 556 if (!strcmd) 557 return; 558 strcmd[0] = '\0'; 559 pos = strcmd; 560 end = strcmd + size; 561 for (i = 0; i < cmd->count; i++) { 562 ret = snprintf(pos, end - pos, "%s,%s,", cmd->params[i], 563 cmd->values[i]); 564 if (ret < 0 || ret >= end - pos) 565 break; 566 pos += ret; 567 } 568 569 pos = strrchr(strcmd, ','); 570 if (pos) 571 *pos = '\0'; 572 printf("Miracast: generated command: %s\n", strcmd); 573 } 574 575 576 static void * auto_go_thread_entry(void *ptr) 577 { 578 struct sigma_dut *dut = ptr; 579 struct wpa_ctrl *ctrl; 580 char event_buf[64]; 581 char *peer = NULL; 582 int res = 0; 583 char macaddress[32]; 584 char peer_ip_address[32]; 585 char rtsp_session_id[12]; 586 int (*extn_start_wfd_connection)(const char *, 587 const char *, /* Peer IP */ 588 int, /* RTSP port number */ 589 int, /* WFD Device Type; 0-Source, 590 1-P-Sink, 2-Secondary Sink */ 591 char *); /* for returning session ID */ 592 593 stop_dhcp(dut, wfd_ifname, 1); 594 /* For auto-GO, start the DHCP server and wait for 5 seconds */ 595 start_dhcp(dut, wfd_ifname, 1); 596 sleep(5); /* Wait for IP */ 597 598 sigma_dut_print(dut, DUT_MSG_INFO, "Wait for AP-STA-CONNECTED"); 599 ctrl = open_wpa_mon(wfd_ifname); /* Refer to wfd_ifname */ 600 if (!ctrl) { 601 sigma_dut_print(dut, DUT_MSG_ERROR, 602 "Failed to open wpa_supplicant monitor connection"); 603 goto THR_EXIT; 604 } 605 res = get_wpa_cli_event(dut, ctrl, "AP-STA-CONNECTED", 606 event_buf, sizeof(event_buf)); 607 wpa_ctrl_detach(ctrl); 608 wpa_ctrl_close(ctrl); 609 610 if (res < 0) { 611 sigma_dut_print(dut, DUT_MSG_ERROR, 612 "Could not get event before timeout"); 613 goto THR_EXIT; 614 } 615 616 sigma_dut_print(dut, DUT_MSG_DEBUG, "STA Connected Event: '%s'", 617 event_buf); 618 peer = strchr(event_buf, ' '); 619 if (!peer) { 620 sigma_dut_print(dut, DUT_MSG_ERROR, "Could not find STA MAC"); 621 goto THR_EXIT; 622 } 623 624 peer++; 625 strlcpy(macaddress, peer, sizeof(macaddress)); 626 if (get_peer_ip_p2p_go(dut, peer_ip_address, macaddress, 30) < 0) { 627 sigma_dut_print(dut, DUT_MSG_ERROR, "Could not get peer IP"); 628 goto THR_EXIT; 629 } 630 631 sigma_dut_print(dut, DUT_MSG_INFO, "dlsym %p", dut->miracast_lib); 632 extn_start_wfd_connection = dlsym(dut->miracast_lib, 633 "start_wfd_connection"); 634 if (!extn_start_wfd_connection) 635 sigma_dut_print(dut, DUT_MSG_INFO, "dlsym function NULL"); 636 else 637 extn_start_wfd_connection(NULL, peer_ip_address, 638 session_management_control_port, 639 1 - dut->wfd_device_type, 640 rtsp_session_id); 641 642 THR_EXIT: 643 sigma_dut_print(dut, DUT_MSG_INFO, "Reached auto GO thread exit"); 644 return NULL; 645 } 646 647 648 void miracast_sta_reset_default(struct sigma_dut *dut, struct sigma_conn *conn, 649 struct sigma_cmd *cmd) 650 { 651 char *intf = sigma_station_ifname; 652 int (*extn_sta_reset_default)(char *); 653 char string_cmd[MIRACAST_CMD_LEN] = { 0 }; 654 655 if (sigma_main_ifname != NULL) 656 intf = sigma_main_ifname; 657 sigma_dut_print(dut, DUT_MSG_DEBUG, 658 "miracast_sta_reset_default() = intf = %s", intf); 659 stop_dhcp(dut, intf, 1); /* IFNAME argument is ignored */ 660 miracast_stop_dhcp_client(dut, intf); 661 662 /* This is where vendor Miracast library is loaded and function pointers 663 * to Miracast functions (defined by CAPI) are loaded. */ 664 665 if (miracast_load(dut) != 0) { 666 sigma_dut_print(dut, DUT_MSG_INFO, 667 "Fail to load Miracast library"); 668 return; 669 } 670 671 if (!dut->miracast_lib) { 672 sigma_dut_print(dut, DUT_MSG_ERROR, 673 "Miracast library is absent"); 674 return; 675 } 676 677 dlerror(); 678 679 miracast_generate_string_cmd(cmd, string_cmd, sizeof(string_cmd)); 680 extn_sta_reset_default = dlsym(dut->miracast_lib, "sta_reset_default"); 681 if (extn_sta_reset_default) 682 extn_sta_reset_default(string_cmd); 683 684 /* delete threads if any */ 685 /* TODO: if dut->rtsp_thread_handle running, call 686 * miracast_release_rtsp_thread_resources(dut); */ 687 } 688 689 690 void miracast_start_autonomous_go(struct sigma_dut *dut, 691 struct sigma_conn *conn, 692 struct sigma_cmd *cmd, char *ifname) 693 { 694 strlcpy(wfd_ifname, ifname, sizeof(wfd_ifname)); 695 (void) pthread_create(&dut->rtsp_thread_handle, NULL, 696 auto_go_thread_entry, dut); 697 } 698 699 700 static void miracast_rtsp_thread_create(struct sigma_dut *dut, 701 struct sigma_conn *conn, 702 struct sigma_cmd *cmd) 703 { 704 (void) pthread_create(&dut->rtsp_thread_handle, NULL, 705 miracast_rtsp_thread_entry, dut); 706 } 707 708 709 int miracast_dev_send_frame(struct sigma_dut *dut, struct sigma_conn *conn, 710 struct sigma_cmd *cmd) 711 { 712 const char *frame_name = get_param(cmd, "FrameName"); 713 /* const char *source = get_param(cmd, "Source"); */ 714 /* const char *destination = get_param(cmd, "Destination"); */ 715 /* const char *dev_type = get_param(cmd, "DevType"); */ 716 const char *rtsp_msg_type = get_param(cmd, "RtspMsgType"); 717 /* const char *wfd_session_id = get_param(cmd, "WfdSessionID"); */ 718 int (*dev_send_frame)(const char *); 719 char string_cmd[MIRACAST_CMD_LEN] = { 0 }; 720 721 dev_send_frame = dlsym(dut->miracast_lib, "dev_send_frame"); 722 if (!dev_send_frame) 723 return -1; 724 sigma_dut_print(dut, DUT_MSG_DEBUG, "miracast_dev_send_frame 1"); 725 miracast_generate_string_cmd(cmd, string_cmd, sizeof(string_cmd)); 726 if (!frame_name) 727 return 0; 728 if (strcasecmp(frame_name, "RTSP") != 0) 729 return 0; 730 731 if (!rtsp_msg_type) 732 return 0; 733 734 if (strcasecmp(rtsp_msg_type, "PAUSE") == 0 || 735 strcasecmp(rtsp_msg_type, "TRIGGER-PAUSE") == 0) { 736 /* Call RTSP Pause */ 737 dev_send_frame(string_cmd); 738 return 1; 739 } 740 741 if (strcasecmp(rtsp_msg_type, "PLAY") == 0 || 742 strcasecmp(rtsp_msg_type, "TRIGGER-PLAY") == 0) { 743 /* Call RTSP Play */; 744 dev_send_frame(string_cmd); /* Not for secure playback */ 745 return 1; 746 } 747 748 if (strcasecmp(rtsp_msg_type, "TEARDOWN") == 0 || 749 strcasecmp(rtsp_msg_type, "TRIGGER-TEARDOWN") == 0) { 750 dev_send_frame(string_cmd); /* RTSP Teardown */ 751 return 1; 752 } 753 754 if (strcasecmp(rtsp_msg_type,"SET_PARAMETER") == 0) { 755 const char *set_parameter = get_param(cmd, "SetParameter"); 756 const char *transportType = get_param(cmd, "TransportType"); 757 758 if (set_parameter == NULL && transportType == NULL) { 759 send_resp(dut, conn, SIGMA_ERROR, 760 "errorCode,Invalid Set Parameter value"); 761 return 0; 762 } 763 764 if (1) /* (strcasecmp(set_parameter, "Standby") == 0) */ { 765 dev_send_frame(string_cmd); 766 return 1; 767 } 768 /* TODO More needs to be implemented when the spec is clearer */ 769 return 1; 770 } 771 772 if (strcasecmp(rtsp_msg_type, "SETUP") == 0) { 773 dev_send_frame(string_cmd); 774 /* TODO More needs to be implemented when the spec is clearer */ 775 return 1; 776 } 777 778 if (strcasecmp(frame_name, "WFD_ProbeReq") == 0) { 779 send_resp(dut, conn, SIGMA_ERROR, 780 "errorCode,Unsupported WFD Probe Request"); 781 return 0; 782 } 783 784 if (strcasecmp(frame_name, "WFD_ServiceDiscReq") == 0) { 785 send_resp(dut, conn, SIGMA_ERROR, 786 "errorCode,Unsupported WFD Service Discovery"); 787 return 0; 788 } 789 790 send_resp(dut, conn, SIGMA_ERROR, 791 "errorCode,Unsupported dev_send_frame"); 792 return 0; 793 } 794 795 796 int miracast_dev_exec_action(struct sigma_dut *dut, struct sigma_conn *conn, 797 struct sigma_cmd *cmd) 798 { 799 const char *service_type = get_param(cmd,"ServiceType"); 800 int (*dev_exec_action)(const char *); 801 char string_cmd[MIRACAST_CMD_LEN] = { 0 }; 802 803 sigma_dut_print(dut, DUT_MSG_DEBUG, "miracast_dev_exec_frame"); 804 805 if (service_type) { 806 char resp_buf[128]; 807 808 sigma_dut_print(dut, DUT_MSG_DEBUG, "MDNS Instance Name = %s", 809 dut->mdns_instance_name); 810 strlcpy(resp_buf, "InstanceName,", sizeof(resp_buf)); 811 strlcat(resp_buf + strlen(resp_buf), dut->mdns_instance_name, 812 sizeof(resp_buf) - strlen(resp_buf)); 813 send_resp(dut, conn, SIGMA_COMPLETE, resp_buf); 814 return 0; 815 } 816 817 miracast_generate_string_cmd(cmd, string_cmd, sizeof(string_cmd)); 818 dev_exec_action = dlsym(dut->miracast_lib, "dev_exec_action"); 819 if (!dev_exec_action) 820 return -2; 821 return dev_exec_action(string_cmd); 822 } 823 824 825 int miracast_preset_testparameters(struct sigma_dut *dut, 826 struct sigma_conn *conn, 827 struct sigma_cmd *cmd) 828 { 829 const char *mdns_disc = get_param(cmd, "mdns_disc"); 830 const char *mdns_role = get_param(cmd, "mdns_role"); 831 char string_cmd[MIRACAST_CMD_LEN]; 832 int ret = 0; 833 char string_resp[64] = { 0 }; 834 int (*extn_sta_preset_test_parameter)(const char *, char *, int); 835 836 miracast_load(dut); 837 miracast_generate_string_cmd(cmd, string_cmd, sizeof(string_cmd)); 838 extn_sta_preset_test_parameter = 839 dlsym(dut->miracast_lib, "sta_preset_testparameters"); 840 if (!extn_sta_preset_test_parameter) 841 return -1; 842 ret = extn_sta_preset_test_parameter(string_cmd, string_resp, 843 sizeof(string_resp)); 844 if (ret == SIGMA_ERROR) { 845 send_resp(dut, conn, SIGMA_ERROR, 846 "Miracast extension reported error in the command sta_preset_testparameters"); 847 return 0; 848 } 849 850 if (mdns_disc && mdns_role) { 851 if (strlen(string_resp)) 852 strlcpy(dut->mdns_instance_name, string_resp, 853 sizeof(dut->mdns_instance_name)); 854 else 855 dut->mdns_instance_name[0] = '\0'; 856 } 857 858 return 1; 859 } 860 861 862 static int get_p2p_peers(char *respbuf, size_t bufsize) 863 { 864 char addr[1024], cmd[64]; 865 char *intf = get_main_ifname(); 866 int ret; 867 char *pos, *end; 868 869 pos = respbuf; 870 end = respbuf + bufsize; 871 872 if (wpa_command_resp(intf, "P2P_PEER FIRST", addr, 128) >= 0) { 873 addr[17] = '\0'; 874 strlcpy(respbuf, addr, bufsize); 875 pos += strlen(respbuf); 876 snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); 877 memset(addr, 0, sizeof(addr)); 878 while (wpa_command_resp(intf, cmd, addr, sizeof(addr)) >= 0) { 879 if (memcmp(addr, "FAIL", 4) == 0) 880 break; 881 addr[17] = '\0'; 882 ret = snprintf(pos, end - pos, " %s", addr); 883 if (ret < 0 || ret >= end - pos) 884 break; 885 pos += ret; 886 snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr); 887 memset(addr, 0, sizeof(addr)); 888 } 889 } 890 891 return 0; 892 } 893 894 895 int miracast_cmd_sta_get_parameter(struct sigma_dut *dut, 896 struct sigma_conn *conn, 897 struct sigma_cmd *cmd) 898 { 899 /* const char *intf = get_param(cmd, "Interface"); */ 900 /* const char *program = get_param(cmd, "Program"); */ 901 const char *parameter = get_param(cmd, "Parameter"); 902 char resp_buf[1024]; /* may need to change depending on number of peer 903 devices found */ 904 905 if (!parameter) { 906 send_resp(dut, conn, SIGMA_COMPLETE, "NULL"); 907 return 0; 908 } 909 910 if (strcasecmp(parameter, "DiscoveredDevList") == 0) { 911 int len = strlen("DeviceList,"); 912 913 snprintf(resp_buf, sizeof(resp_buf), "DeviceList,"); 914 get_p2p_peers(resp_buf + len, 1024 - len); 915 } else { 916 send_resp(dut, conn, SIGMA_ERROR, "Invalid Parameter"); 917 return 0; 918 } 919 920 send_resp(dut, conn, SIGMA_COMPLETE, resp_buf); 921 return 0; 922 } 923 924 925 int miracast_mdns_start_wfd_connection(struct sigma_dut *dut, 926 struct sigma_conn *conn, 927 struct sigma_cmd *cmd) 928 { 929 const char *init_wfd = get_param(cmd, "init_wfd"); 930 int int_init_wfd = -1; 931 char rtsp_session_id[12]; 932 char cmd_response[128]; 933 int (*extn_start_wfd_connection)(const char *, 934 const char *, /* Peer IP */ 935 int, /* RTSP port number */ 936 int, /* WFD Device Type; 0-Source, 937 1-P-Sink, 2-Secondary Sink */ 938 char *); /* for returning session ID */ 939 int count = 0; 940 char *sig_resp = NULL; 941 942 if (init_wfd) 943 int_init_wfd = atoi(init_wfd); 944 945 extn_start_wfd_connection = dlsym(dut->miracast_lib, 946 "start_wfd_connection"); 947 if (!extn_start_wfd_connection) 948 return -1; 949 rtsp_session_id[0] = '\0'; 950 if (int_init_wfd != 0) { 951 extn_start_wfd_connection(NULL, NULL, -100, 952 1 - dut->wfd_device_type, 953 rtsp_session_id); 954 while (strlen(rtsp_session_id) == 0 && count < 60) { 955 count++; 956 sleep(1); 957 } 958 snprintf(cmd_response, sizeof(cmd_response), 959 "result,NULL,GroupID,NULL,WFDSessionID,%s", 960 count == 60 ? "NULL" : rtsp_session_id); 961 sig_resp = cmd_response; 962 } else { 963 extn_start_wfd_connection(NULL, NULL, -100, 964 1 - dut->wfd_device_type, NULL); 965 sig_resp = "result,NULL,GroupID,NULL,WFDSessionID,NULL"; 966 } 967 968 send_resp(dut, conn, SIGMA_COMPLETE, sig_resp); 969 return 0; 970 } 971 972 973 static enum sigma_cmd_result cmd_start_wfd_connection(struct sigma_dut *dut, 974 struct sigma_conn *conn, 975 struct sigma_cmd *cmd) 976 { 977 const char *intf = get_param(cmd, "Interface"); 978 const char *peer_address = get_param(cmd, "PeerAddress"); 979 const char *init_wfd = get_param(cmd, "init_wfd"); 980 const char *intent_val = get_param(cmd, "intent_val"); 981 const char *oper_chan = get_param(cmd, "oper_chn"); 982 const char *coupled_session = get_param(cmd, "coupledSession"); 983 const char *tdls = get_param(cmd, "TDLS"); 984 const char *r2_connection = get_param(cmd, "R2ConnectionType"); 985 char ssid[128]; 986 char p2p_dev_address[18]; 987 char output_intf[16]; 988 char sig_resp_buf[1024]; 989 char cmd_buf[256]; /* Command buffer */ 990 char resp_buf[256]; /* Response buffer to UCC */ 991 int go_intent = 0; 992 int freq; 993 int res = 0; 994 char buf_peer[4096]; 995 char *availability = NULL; 996 char command[64]; 997 int avail_bit; 998 char ctemp[2]; 999 char rtspport[5] = { '7', '2', '3', '6', '\0' }; 1000 int is_group_owner = 0; 1001 char peer_ip_address[32]; 1002 int sm_control_port = 7236; 1003 char rtsp_session_id[12] = { '\0' }; 1004 int (*extn_start_wfd_connection)(const char *, 1005 const char *, /* Peer IP */ 1006 int, /* RTSP port number */ 1007 int, /* WFD Device Type; 0-Source, 1008 1-P-Sink, 2-Secondary Sink */ 1009 char *); /* for returning session ID */ 1010 int count = 0; 1011 1012 if (r2_connection) { 1013 if (strcasecmp(r2_connection, "Infrastructure") == 0) 1014 return miracast_mdns_start_wfd_connection(dut, conn, 1015 cmd); 1016 } 1017 1018 if (coupled_session && atoi(coupled_session) == 1) { 1019 send_resp(dut, conn, SIGMA_ERROR, 1020 "errorCode,Coupled Session is unsupported"); 1021 return 0; 1022 } 1023 1024 if (tdls && atoi(tdls) == 1) { 1025 send_resp(dut, conn, SIGMA_ERROR, 1026 "errorCode,TDLS is unsupported"); 1027 return 0; 1028 } 1029 1030 if (intent_val) { 1031 go_intent = atoi(intent_val); 1032 if (go_intent > 15) 1033 go_intent = 1; 1034 } 1035 1036 if (p2p_discover_peer(dut, intf, peer_address, 1) < 0) { 1037 send_resp(dut, conn, SIGMA_ERROR, 1038 "errorCode,Could not find peer"); 1039 return 0; 1040 } 1041 1042 snprintf(cmd_buf, sizeof(cmd_buf), "P2P_CONNECT %s", peer_address); 1043 1044 switch (dut->wps_method) { 1045 case WFA_CS_WPS_PIN_DISPLAY: 1046 snprintf(cmd_buf + strlen(cmd_buf), 1047 sizeof(cmd_buf) - strlen(cmd_buf), " %s display", 1048 dut->wps_pin); 1049 break; 1050 case WFA_CS_WPS_PIN_LABEL: 1051 snprintf(cmd_buf + strlen(cmd_buf), 1052 sizeof(cmd_buf) - strlen(cmd_buf), " pin label"); 1053 break; 1054 case WFA_CS_WPS_PIN_KEYPAD: 1055 snprintf(cmd_buf + strlen(cmd_buf), 1056 sizeof(cmd_buf) - strlen(cmd_buf), " %s keypad", 1057 dut->wps_pin); 1058 break; 1059 case WFA_CS_WPS_PBC: 1060 default: /* Configuring default to PBC */ 1061 snprintf(cmd_buf + strlen(cmd_buf), 1062 sizeof(cmd_buf) - strlen(cmd_buf), " pbc"); 1063 break; 1064 } 1065 1066 if (dut->persistent) { 1067 snprintf(cmd_buf + strlen(cmd_buf), 1068 sizeof(cmd_buf) - strlen(cmd_buf), " persistent"); 1069 } 1070 snprintf(cmd_buf + strlen(cmd_buf), sizeof(cmd_buf) - strlen(cmd_buf), 1071 " go_intent=%d", go_intent); 1072 1073 if (init_wfd && atoi(init_wfd) == 0) { 1074 snprintf(cmd_buf + strlen(cmd_buf), 1075 sizeof(cmd_buf) - strlen(cmd_buf), " auth"); 1076 } 1077 1078 if (oper_chan) { 1079 int chan; 1080 1081 chan = atoi(oper_chan); 1082 if (chan >= 1 && chan <= 13) 1083 freq = 2407 + chan * 5; 1084 else if (chan == 14) 1085 freq = 2484; 1086 else 1087 freq = 5000 + chan * 5; 1088 1089 snprintf(cmd_buf + strlen(cmd_buf), 1090 sizeof(cmd_buf) - strlen(cmd_buf), " freq=%d", freq); 1091 } 1092 1093 /* WFD SESSION AVAILABILITY CHECK */ 1094 1095 memset(buf_peer, 0, sizeof(buf_peer)); 1096 snprintf(command, sizeof(command), "P2P_PEER %s", peer_address); 1097 strlcpy(dut->peer_mac_address, peer_address, 1098 sizeof(dut->peer_mac_address)); 1099 if (wpa_command_resp(intf, command, buf_peer, sizeof(buf_peer)) >= 0 && 1100 strlen(buf_peer) != 0) 1101 availability = strstr(buf_peer, "wfd_subelems="); 1102 1103 if (!availability || strlen(availability) < 21) { 1104 sigma_dut_print(dut, DUT_MSG_INFO, "Did not get WFD SUBELEMS"); 1105 send_resp(dut, conn, SIGMA_COMPLETE, 1106 "result,NULL,GroupID,NULL,WFDSessionID,NULL"); 1107 return 0; 1108 } 1109 1110 /* Extracting Availability Bit */ 1111 ctemp[0] = availability[21]; 1112 ctemp[1] = '\0'; 1113 avail_bit = (int) strtol(ctemp, NULL, 16); 1114 1115 if ((avail_bit & 0x3) == 0) { 1116 send_resp(dut, conn, SIGMA_COMPLETE, 1117 "result,NULL,GroupID,NULL,WFDSessionID,NULL"); 1118 return 0; 1119 } 1120 1121 /* Extract RTSP Port for Sink */ 1122 1123 if (dut->wfd_device_type != 0) { 1124 if (strlen(availability) >= 23) { 1125 availability += 23; 1126 if (availability[0]) 1127 snprintf(rtspport, 5, "%s", availability); 1128 } 1129 sigma_dut_print(dut, DUT_MSG_INFO, 1130 "rtsp_port = %s, availability = %s ", 1131 rtspport, availability); 1132 session_management_control_port = (int) strtol(rtspport, NULL, 1133 16); 1134 sigma_dut_print(dut, DUT_MSG_INFO, 1135 "SessionManagementControlPort = %d", 1136 session_management_control_port); 1137 } 1138 1139 memset(resp_buf, 0, sizeof(resp_buf)); 1140 res = wpa_command_resp(intf, cmd_buf, resp_buf, sizeof(resp_buf)); 1141 if (res < 0) { 1142 sigma_dut_print(dut, DUT_MSG_ERROR, 1143 "wpa_command_resp failed"); 1144 return 1; 1145 } 1146 if (strncmp(resp_buf, "FAIL", 4) == 0) { 1147 sigma_dut_print(dut, DUT_MSG_INFO, 1148 "wpa_command: Command failed (FAIL received)"); 1149 return 1; 1150 } 1151 1152 if (init_wfd && atoi(init_wfd) == 0) { 1153 /* Start thread to wait for P2P connection */ 1154 miracast_rtsp_thread_create(dut, conn, cmd); 1155 send_resp(dut, conn, SIGMA_COMPLETE, 1156 "result,NULL,GroupID,NULL,WFDSessionID,NULL"); 1157 return 0; 1158 } 1159 1160 res = get_p2p_connection_event(dut, intf, output_intf, 1161 sizeof(output_intf), &is_group_owner); 1162 sigma_dut_print(dut, DUT_MSG_DEBUG, "p2p connection done %d", 1163 is_group_owner); 1164 if (res < 0) { 1165 sigma_dut_print(dut, DUT_MSG_ERROR, 1166 "Group Formation did not complete"); 1167 return 1; 1168 } 1169 1170 snprintf(sig_resp_buf, sizeof(sig_resp_buf), "result"); 1171 1172 if (is_group_owner) { 1173 stop_dhcp(dut, output_intf,1); 1174 snprintf(sig_resp_buf + strlen(sig_resp_buf), 1175 sizeof(sig_resp_buf) - strlen(sig_resp_buf), ",GO"); 1176 start_dhcp(dut, output_intf,1); 1177 sleep(5); 1178 } else { 1179 snprintf(sig_resp_buf + strlen(sig_resp_buf), 1180 sizeof(sig_resp_buf) - strlen(sig_resp_buf), 1181 ",CLIENT"); 1182 miracast_start_dhcp_client(dut, output_intf); 1183 sleep(5); 1184 } 1185 1186 snprintf(sig_resp_buf + strlen(sig_resp_buf), 1187 sizeof(sig_resp_buf) - strlen(sig_resp_buf), ",GroupID,"); 1188 1189 res = get_wpa_status(output_intf, "p2p_device_address", 1190 p2p_dev_address, sizeof(p2p_dev_address)); 1191 if (res < 0) 1192 return -1; 1193 sigma_dut_print(dut, DUT_MSG_INFO, "p2p_dev_address %s", 1194 p2p_dev_address); 1195 strlcpy(sig_resp_buf + strlen(sig_resp_buf), p2p_dev_address, 1196 sizeof(sig_resp_buf) - strlen(sig_resp_buf)); 1197 1198 res = get_wpa_status(output_intf, "ssid", ssid, sizeof(ssid)); 1199 if (res < 0) { 1200 sigma_dut_print(dut, DUT_MSG_DEBUG, 1201 "get_wpa_status failed to get ssid"); 1202 return -1; 1203 } 1204 1205 snprintf(sig_resp_buf + strlen(sig_resp_buf), 1206 sizeof(sig_resp_buf) - strlen(sig_resp_buf), 1207 " %s,WFDSessionId,", ssid); 1208 1209 if (!is_group_owner) { 1210 if (get_peer_ip_p2p_client(dut, peer_ip_address, output_intf, 1211 60) < 0) { 1212 send_resp(dut, conn, SIGMA_ERROR, 1213 "Could not get remote IP"); 1214 return 0; 1215 } 1216 } else { 1217 if (get_peer_ip_p2p_go(dut, peer_ip_address, peer_address, 1218 30) < 0) { 1219 send_resp(dut, conn, SIGMA_ERROR, 1220 "Could not get remote IP"); 1221 return 0; 1222 } 1223 } 1224 1225 if (dut->wfd_device_type != 0) 1226 sm_control_port = (int) strtol(rtspport, NULL, 16); 1227 else 1228 sm_control_port = 7236; 1229 1230 extn_start_wfd_connection = dlsym(dut->miracast_lib, 1231 "start_wfd_connection"); 1232 if (!extn_start_wfd_connection) 1233 return -1; 1234 extn_start_wfd_connection(NULL, peer_ip_address, sm_control_port, 1235 1 - dut->wfd_device_type, rtsp_session_id); 1236 1237 while (strlen(rtsp_session_id) == 0 && count < 60) { 1238 count++; 1239 sleep(1); 1240 } 1241 1242 if (count == 60) 1243 strlcpy(rtsp_session_id, "00000000", sizeof(rtsp_session_id)); 1244 1245 strlcat(sig_resp_buf, rtsp_session_id, 1246 sizeof(sig_resp_buf) - strlen(sig_resp_buf)); 1247 send_resp(dut, conn, SIGMA_COMPLETE, sig_resp_buf); 1248 return 0; 1249 } 1250 1251 1252 static enum sigma_cmd_result cmd_connect_go_start_wfd(struct sigma_dut *dut, 1253 struct sigma_conn *conn, 1254 struct sigma_cmd *cmd) 1255 { 1256 const char *intf = get_param(cmd, "Interface"); 1257 const char *p2p_dev_id = get_param(cmd, "P2PdevID"); 1258 /* const char *p2p_group_id = get_param(cmd, "GroupID"); */ 1259 char sig_resp_buf[1024]; 1260 char method[12]; 1261 char cmd_buf[256]; 1262 char buf[256]; 1263 char resp_buf[256]; 1264 int go = 0; 1265 int res = 0; 1266 char output_ifname[32]; 1267 char peer_ip_address[32]; 1268 char rtsp_session_id[12]; 1269 int (*extn_connect_go_start_wfd)(const char *, 1270 const char * /* Peer IP */, 1271 int /* RTSP port number */, 1272 int /* WFD Device Type; 0-Source, 1273 1-P-Sink, 2-Secondary Sink */, 1274 char *); /* for returning session ID */ 1275 1276 snprintf(cmd_buf, sizeof(cmd_buf), "P2P_CONNECT %s", p2p_dev_id); 1277 1278 switch (dut->wps_method) { 1279 case WFA_CS_WPS_PBC: 1280 snprintf(cmd_buf + strlen(cmd_buf), 1281 sizeof(cmd_buf) - strlen(cmd_buf), " pbc"); 1282 strlcpy(method, "pbc", sizeof(method)); 1283 break; 1284 case WFA_CS_WPS_PIN_DISPLAY: 1285 snprintf(cmd_buf + strlen(cmd_buf), 1286 sizeof(cmd_buf) - strlen(cmd_buf), " %s display", 1287 dut->wps_pin); 1288 strlcpy(method, "display", sizeof(method)); 1289 break; 1290 case WFA_CS_WPS_PIN_LABEL: 1291 snprintf(cmd_buf + strlen(cmd_buf), 1292 sizeof(cmd_buf) - strlen(cmd_buf), " pin label"); 1293 strlcpy(method, "label", sizeof(method)); 1294 break; 1295 case WFA_CS_WPS_PIN_KEYPAD: 1296 snprintf(cmd_buf + strlen(cmd_buf), 1297 sizeof(cmd_buf) - strlen(cmd_buf), " %s keypad", 1298 dut->wps_pin); 1299 strlcpy(method, "keypad", sizeof(method)); 1300 break; 1301 default: /* Configuring to PBC */ 1302 snprintf(cmd_buf + strlen(cmd_buf), 1303 sizeof(cmd_buf) - strlen(cmd_buf), " pbc"); 1304 strlcpy(method, "pbc", sizeof(method)); 1305 break; 1306 } 1307 snprintf(cmd_buf + strlen(cmd_buf), 1308 sizeof(cmd_buf) - strlen(cmd_buf), " join"); 1309 1310 /* run provisional discovery */ 1311 if (p2p_discover_peer(dut, intf, p2p_dev_id, 0) < 0) { 1312 send_resp(dut, conn, SIGMA_ERROR, 1313 "ErrorCode,Could not discover the requested peer"); 1314 return 0; 1315 } 1316 1317 snprintf(buf, sizeof(buf), "P2P_PROV_DISC %s %s", p2p_dev_id, method); 1318 if (wpa_command(intf, buf) < 0) { 1319 sigma_dut_print(dut, DUT_MSG_INFO, 1320 "Failed to send provision discovery request"); 1321 return -2; 1322 } 1323 1324 res = wpa_command_resp(intf, cmd_buf, resp_buf, sizeof(resp_buf)); 1325 if (res < 0) { 1326 sigma_dut_print(dut, DUT_MSG_ERROR, 1327 "wpa_command_resp failed"); 1328 return 1; 1329 } 1330 if (strncmp(resp_buf, "FAIL", 4) == 0) { 1331 send_resp(dut, conn, SIGMA_ERROR, 1332 "errorCode,failed P2P connection"); 1333 return 0; 1334 } 1335 1336 res = get_p2p_connection_event(dut, intf, output_ifname, 1337 sizeof(output_ifname), &go); 1338 if (res < 0) { 1339 send_resp(dut, conn, SIGMA_ERROR, 1340 "errorCode,failed P2P connection"); 1341 return 0; 1342 } 1343 1344 miracast_start_dhcp_client(dut, output_ifname); 1345 1346 if (get_peer_ip_p2p_client(dut, peer_ip_address, output_ifname, 1347 30) < 0) { 1348 send_resp(dut, conn, SIGMA_ERROR, "Could not get remote IP"); 1349 return 0; 1350 } 1351 1352 if (dut->wfd_device_type != 0) { 1353 char rtsp_buff[1000], cmd_buff[32]; 1354 char *sub_elem = NULL; 1355 char rtspport[5] = { '7', '2', '3', '6', '\0' }; 1356 1357 sigma_dut_print(dut, DUT_MSG_DEBUG, 1358 "Log --- p2p address = %s", p2p_dev_id); 1359 snprintf(cmd_buff, sizeof(cmd_buff), "P2P_PEER %s", p2p_dev_id); 1360 if (wpa_command_resp(output_ifname, cmd_buff, rtsp_buff, 1361 sizeof(rtsp_buff)) >= 0 && 1362 strlen(rtsp_buff) != 0) 1363 sub_elem = strstr(rtsp_buff, "wfd_subelems="); 1364 1365 /* Extract RTSP Port for Sink */ 1366 if (sub_elem && strlen(sub_elem) >= 23) { 1367 sub_elem += 23; 1368 snprintf(rtspport, 5, "%s", sub_elem); 1369 sigma_dut_print(dut, DUT_MSG_DEBUG, 1370 "rtsp_port = %s, subElem = %s", 1371 rtspport, sub_elem); 1372 } 1373 session_management_control_port = (int) strtol(rtspport, NULL, 1374 16); 1375 sigma_dut_print(dut, DUT_MSG_DEBUG, 1376 "SessionManagementControlPort = %d", 1377 session_management_control_port); 1378 1379 } else { 1380 session_management_control_port = 7236; 1381 } 1382 1383 extn_connect_go_start_wfd = dlsym(dut->miracast_lib, 1384 "connect_go_start_wfd"); 1385 if (!extn_connect_go_start_wfd) 1386 return -1; 1387 rtsp_session_id[0] = '\0'; 1388 extn_connect_go_start_wfd(NULL, peer_ip_address, 1389 session_management_control_port, 1390 1 - dut->wfd_device_type, rtsp_session_id); 1391 /* Null terminating regardless of what was returned */ 1392 rtsp_session_id[sizeof(rtsp_session_id) - 1] = '\0'; 1393 snprintf(sig_resp_buf, sizeof(sig_resp_buf), "WFDSessionId,%s", 1394 rtsp_session_id); 1395 1396 send_resp(dut, conn, SIGMA_COMPLETE, sig_resp_buf); 1397 return 0; 1398 } 1399 1400 1401 static enum sigma_cmd_result cmd_sta_generate_event(struct sigma_dut *dut, 1402 struct sigma_conn *conn, 1403 struct sigma_cmd *cmd) 1404 { 1405 1406 /* const char *intf = get_param(cmd, "Interface"); */ 1407 /* const char *program = get_param(cmd, "Program"); */ 1408 const char *type = get_param(cmd, "Type"); 1409 char string_cmd[MIRACAST_CMD_LEN]; 1410 int (*extn_sta_generate_event)(const char *); 1411 1412 if (!type) { 1413 send_resp(dut, conn, SIGMA_INVALID, 1414 "errorCode, Invalid Type for Generate Event"); 1415 return 0; 1416 } 1417 miracast_generate_string_cmd(cmd, string_cmd, sizeof(string_cmd)); 1418 extn_sta_generate_event = dlsym(dut->miracast_lib, 1419 "sta_generate_event"); 1420 if (!extn_sta_generate_event) 1421 return -1; 1422 if (strcasecmp(type, "UIBC_Gen") == 0 || 1423 strcasecmp(type, "UIBC_HID") == 0) { 1424 extn_sta_generate_event(string_cmd); 1425 } else if (strcasecmp(type, "FrameSkip") == 0) { 1426 return 1; 1427 } else if (strcasecmp(type, "InputContent") == 0) { 1428 send_resp(dut, conn, SIGMA_COMPLETE, NULL); 1429 return 0; 1430 } else if (strcasecmp(type, "I2cRead") == 0) { 1431 send_resp(dut, conn, SIGMA_ERROR, 1432 "errorCode,Unsupported Type for Generate Event"); 1433 return 0; 1434 } else if (strcasecmp(type, "I2cWrite") == 0) { 1435 send_resp(dut, conn, SIGMA_ERROR, 1436 "errorCode, Unsupported Type for Generate Event"); 1437 return 0; 1438 } else if (strcasecmp(type, "IdrReq") == 0) { 1439 if (dut->wfd_device_type == 0) { /* Source */ 1440 send_resp(dut, conn, SIGMA_ERROR, 1441 "errorCode, Unsupported Type for Generate Event"); 1442 } else { 1443 send_resp(dut, conn, SIGMA_COMPLETE, NULL); 1444 extn_sta_generate_event(string_cmd); 1445 } 1446 return 0; 1447 } 1448 return 1; 1449 } 1450 1451 1452 static enum sigma_cmd_result cmd_reinvoke_wfd_session(struct sigma_dut *dut, 1453 struct sigma_conn *conn, 1454 struct sigma_cmd *cmd) 1455 { 1456 const char *intf = get_param(cmd, "Interface"); 1457 const char *grp_id = get_param(cmd, "GroupID"); 1458 const char *peer_address = get_param(cmd, "peeraddress"); 1459 const char *invitation_action = get_param(cmd, "InvitationAction"); 1460 char buf[256]; 1461 struct wpa_ctrl *ctrl; 1462 int res, id; 1463 char *ssid, *pos; 1464 unsigned int wait_limit; 1465 char peer_ip_address[32]; 1466 char rtsp_session_id[12]; 1467 int (*extn_start_wfd_connection)(const char *, 1468 const char *, /* Peer IP */ 1469 int, /* RTSP port number */ 1470 int, /* WFD Device Type; 0-Source, 1471 1-P-Sink, 2-Secondary Sink */ 1472 char *); /* for returning session ID */ 1473 1474 /* All are compulsory parameters */ 1475 if (!intf || !grp_id || !invitation_action || !peer_address) { 1476 send_resp(dut, conn, SIGMA_INVALID, 1477 "errorCode,Invalid parameters for Reinvoke WFD Session"); 1478 return 0; 1479 } 1480 1481 if (strcmp(invitation_action, "accept") == 0) { 1482 /* 1483 * In a client-joining-a-running-group case, we need to 1484 * separately authorize the invitation. 1485 */ 1486 miracast_stop_dhcp_client(dut, NULL); 1487 sigma_dut_print(dut, DUT_MSG_DEBUG, "Trying to discover GO %s", 1488 peer_address); 1489 if (p2p_discover_peer(dut, intf, peer_address, 1) < 0) { 1490 send_resp(dut, conn, SIGMA_ERROR, 1491 "ErrorCode,Could not discover the requested peer"); 1492 return 0; 1493 } 1494 1495 snprintf(buf, sizeof(buf), "P2P_CONNECT %s %s join auth", 1496 peer_address, dut->wps_method == WFA_CS_WPS_PBC ? 1497 "pbc" : dut->wps_pin); 1498 if (wpa_command(intf, buf) < 0) 1499 return -2; 1500 1501 miracast_rtsp_thread_create(dut, conn, cmd); 1502 return 1; 1503 } 1504 1505 ssid = strchr(grp_id, ' '); 1506 if (!ssid) { 1507 sigma_dut_print(dut, DUT_MSG_INFO, "Invalid grpid"); 1508 return -1; 1509 } 1510 ssid++; 1511 sigma_dut_print(dut, DUT_MSG_DEBUG, 1512 "Search for persistent group credentials based on SSID: '%s'", 1513 ssid); 1514 if (wpa_command_resp(intf, "LIST_NETWORKS", buf, sizeof(buf)) < 0) 1515 return -2; 1516 pos = strstr(buf, ssid); 1517 if (!pos || pos == buf || pos[-1] != '\t' || 1518 pos[strlen(ssid)] != '\t') { 1519 send_resp(dut, conn, SIGMA_ERROR, 1520 "ErrorCode,Persistent group credentials not found"); 1521 return 0; 1522 } 1523 while (pos > buf && pos[-1] != '\n') 1524 pos--; 1525 id = atoi(pos); 1526 snprintf(buf, sizeof(buf), "P2P_INVITE persistent=%d peer=%s", 1527 id, peer_address); 1528 1529 sigma_dut_print(dut, DUT_MSG_DEBUG, 1530 "Trying to discover peer %s for invitation", 1531 peer_address); 1532 if (p2p_discover_peer(dut, intf, peer_address, 0) < 0) { 1533 send_resp(dut, conn, SIGMA_ERROR, 1534 "ErrorCode,Could not discover the requested peer"); 1535 return 0; 1536 } 1537 1538 ctrl = open_wpa_mon(intf); 1539 if (!ctrl) { 1540 sigma_dut_print(dut, DUT_MSG_ERROR, 1541 "Failed to open wpa_supplicant monitor connection"); 1542 return -2; 1543 } 1544 1545 if (wpa_command(intf, buf) < 0) { 1546 sigma_dut_print(dut, DUT_MSG_INFO, 1547 "Failed to send invitation request"); 1548 wpa_ctrl_detach(ctrl); 1549 wpa_ctrl_close(ctrl); 1550 return -2; 1551 } 1552 1553 res = get_wpa_cli_event(dut, ctrl, "P2P-INVITATION-RESULT", 1554 buf, sizeof(buf)); 1555 wpa_ctrl_detach(ctrl); 1556 wpa_ctrl_close(ctrl); 1557 if (res < 0) 1558 return -2; 1559 1560 miracast_load(dut); 1561 1562 sigma_dut_print(dut, DUT_MSG_DEBUG, "Waiting to start DHCP"); 1563 1564 /* Calling Miracast multimedia APIs */ 1565 if (dut->wfd_device_type != 0) 1566 wait_limit = HUNDRED_SECOND_TIMEOUT; 1567 else 1568 wait_limit = 500; 1569 1570 stop_dhcp(dut, intf, 1); 1571 /* For GO read the DHCP lease file */ 1572 sigma_dut_print(dut, DUT_MSG_INFO, "Waiting to start DHCP server"); 1573 start_dhcp(dut, intf, 1); 1574 sleep(5); 1575 if (get_peer_ip_p2p_go(dut, peer_ip_address, dut->peer_mac_address, 1576 wait_limit) < 0) { 1577 sigma_dut_print(dut, DUT_MSG_ERROR, "Could not get peer IP"); 1578 return -2; 1579 } 1580 1581 extn_start_wfd_connection = dlsym(dut->miracast_lib, 1582 "start_wfd_connection"); 1583 if (extn_start_wfd_connection) { 1584 extn_start_wfd_connection(NULL, peer_ip_address, 1585 session_management_control_port, 1586 1 - dut->wfd_device_type, 1587 rtsp_session_id); 1588 } else { 1589 sigma_dut_print(dut, DUT_MSG_INFO, 1590 "dlsym seems to have error %p %p", 1591 dut->miracast_lib, 1592 extn_start_wfd_connection); 1593 } 1594 1595 return 1; 1596 } 1597 1598 1599 static int req_intf_peer(struct sigma_cmd *cmd) 1600 { 1601 if (!get_param(cmd, "interface") || 1602 !get_param(cmd, "PeerAddress")) 1603 return -1; 1604 return 0; 1605 } 1606 1607 1608 static int req_intf_p2pdev_grpid(struct sigma_cmd *cmd) 1609 { 1610 if (!get_param(cmd, "interface") || 1611 !get_param(cmd, "P2pdevID") || 1612 !get_param(cmd, "GroupID")) 1613 return -1; 1614 return 0; 1615 } 1616 1617 1618 static int req_intf_prog_type(struct sigma_cmd *cmd) 1619 { 1620 const char *prog = get_param(cmd, "Program"); 1621 1622 if (!get_param(cmd, "interface") || 1623 !get_param(cmd, "Type") || 1624 !prog || strcmp(prog, "WFD") != 0) 1625 return -1; 1626 return 0; 1627 } 1628 1629 1630 static int req_intf_peeradd_inv(struct sigma_cmd *cmd) 1631 { 1632 if (!get_param(cmd, "interface") || 1633 !get_param(cmd, "peerAddress") || 1634 !get_param(cmd, "InvitationAction")) 1635 return -1; 1636 return 0; 1637 } 1638 1639 1640 void miracast_register_cmds(void) 1641 { 1642 sigma_dut_reg_cmd("start_wfd_connection", req_intf_peer, 1643 cmd_start_wfd_connection); 1644 sigma_dut_reg_cmd("connect_go_start_wfd", req_intf_p2pdev_grpid, 1645 cmd_connect_go_start_wfd); 1646 sigma_dut_reg_cmd("sta_generate_event", req_intf_prog_type, 1647 cmd_sta_generate_event); 1648 sigma_dut_reg_cmd("reinvoke_wfd_session", req_intf_peeradd_inv, 1649 cmd_reinvoke_wfd_session); 1650 } 1651