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