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