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