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