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