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