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