xref: /wlan-dirver/utils/sigma-dut/traffic.c (revision c9bc15d17a819fcb399b5df722c4227d26799eb3)
1 /*
2  * Sigma Control API DUT (station/AP)
3  * Copyright (c) 2010, Atheros Communications, Inc.
4  * Copyright (c) 2011-2013, 2016-2017 Qualcomm Atheros, Inc.
5  * Copyright (c) 2018-2019, The Linux Foundation
6  * All Rights Reserved.
7  * Licensed under the Clear BSD license. See README for more details.
8  */
9 
10 #include "sigma_dut.h"
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <ctype.h>
16 
17 #include "wpa_helpers.h"
18 
19 #ifdef ANDROID
20 #define SHELL "/system/bin/sh"
21 #else /* ANDROID */
22 #define SHELL "/bin/sh"
23 #endif /* ANDROID */
24 
25 
26 static enum sigma_cmd_result cmd_traffic_send_ping(struct sigma_dut *dut,
27 						   struct sigma_conn *conn,
28 						   struct sigma_cmd *cmd)
29 {
30 	const char *dst, *val;
31 	int size, dur, pkts;
32 	int id;
33 	char resp[100];
34 	float interval;
35 	double rate;
36 	FILE *f;
37 	char buf[100];
38 	int type = 1;
39 	int dscp = 0, use_dscp = 0;
40 	char extra[100], int_arg[100], intf_arg[100], ip_dst[100], ping[100];
41 
42 	val = get_param(cmd, "Type");
43 	if (!val)
44 		val = get_param(cmd, "IPType");
45 	if (val)
46 		type = atoi(val);
47 	if (type != 1 && type != 2) {
48 		send_resp(dut, conn, SIGMA_ERROR,
49 			  "ErrorCode,Unsupported address type");
50 		return STATUS_SENT;
51 	}
52 
53 	dst = get_param(cmd, "destination");
54 	if (dst == NULL || (type == 1 && !is_ip_addr(dst)) ||
55 	    (type == 2 && !is_ipv6_addr(dst)))
56 		return INVALID_SEND_STATUS;
57 	if (dut->ndp_enable && type == 2) {
58 		snprintf(ip_dst, sizeof(ip_dst), "%s%%nan0", dst);
59 		dst = ip_dst;
60 	}
61 
62 	val = get_param(cmd, "frameSize");
63 	if (val == NULL)
64 		return INVALID_SEND_STATUS;
65 	size = atoi(val);
66 
67 	val = get_param(cmd, "frameRate");
68 	if (val == NULL)
69 		return INVALID_SEND_STATUS;
70 	rate = atof(val);
71 	if (rate <= 0)
72 		return INVALID_SEND_STATUS;
73 
74 	val = get_param(cmd, "duration");
75 	if (val == NULL)
76 		return INVALID_SEND_STATUS;
77 	dur = atoi(val);
78 	if (dur <= 0 || dur > 3600)
79 		dur = 3600;
80 
81 	pkts = dur * rate;
82 	interval = (float) 1 / rate;
83 	if (interval > 100000)
84 		return INVALID_SEND_STATUS;
85 
86 	val = get_param(cmd, "DSCP");
87 	if (val) {
88 		dscp = atoi(val);
89 		if (dscp < 0 || dscp > 63) {
90 			send_resp(dut, conn, SIGMA_ERROR,
91 				  "ErrorCode,Invalid DSCP value");
92 			return STATUS_SENT;
93 		}
94 		use_dscp = 1;
95 	}
96 
97 	id = dut->next_streamid++;
98 	snprintf(buf, sizeof(buf), "%s/sigma_dut-ping.%d",
99 		 dut->sigma_tmpdir, id);
100 	unlink(buf);
101 	snprintf(buf, sizeof(buf), "%s/sigma_dut-ping-pid.%d",
102 		 dut->sigma_tmpdir, id);
103 	unlink(buf);
104 
105 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Send ping: pkts=%d interval=%f "
106 			"streamid=%d",
107 			pkts, interval, id);
108 
109 	f = fopen(concat_sigma_tmpdir(dut, "/sigma_dut-ping.sh", ping,
110 				      sizeof(ping)), "w");
111 	if (f == NULL)
112 		return ERROR_SEND_STATUS;
113 
114 	extra[0] = '\0';
115 	if (use_dscp) {
116 		snprintf(extra, sizeof(extra), " -Q 0x%02x",
117 			 dscp << 2);
118 	}
119 
120 	int_arg[0] = '\0';
121 	if (rate != 1)
122 		snprintf(int_arg, sizeof(int_arg), " -i %f", interval);
123 	if (!dut->ndp_enable && type == 2)
124 		snprintf(intf_arg, sizeof(intf_arg), " -I %s",
125 			 get_station_ifname(dut));
126 	else
127 		intf_arg[0] = '\0';
128 	fprintf(f, "#!" SHELL "\n"
129 		"ping%s -c %d%s -s %d%s -q%s %s > %s"
130 		"/sigma_dut-ping.%d &\n"
131 		"echo $! > %s/sigma_dut-ping-pid.%d\n",
132 		type == 2 ? "6" : "", pkts, int_arg, size, extra,
133 		intf_arg, dst, dut->sigma_tmpdir, id, dut->sigma_tmpdir, id);
134 
135 	fclose(f);
136 	if (chmod(concat_sigma_tmpdir(dut, "/sigma_dut-ping.sh", ping,
137 				      sizeof(ping)),
138 		  S_IRUSR | S_IWUSR | S_IXUSR) < 0)
139 		return ERROR_SEND_STATUS;
140 
141 	if (system(concat_sigma_tmpdir(dut, "/sigma_dut-ping.sh", ping,
142 				       sizeof(ping))) != 0) {
143 		sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to start ping");
144 		return ERROR_SEND_STATUS;
145 	}
146 
147 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-ping.sh", ping,
148 				   sizeof(ping)));
149 
150 	snprintf(resp, sizeof(resp), "streamID,%d", id);
151 	send_resp(dut, conn, SIGMA_COMPLETE, resp);
152 	return STATUS_SENT;
153 }
154 
155 
156 static enum sigma_cmd_result cmd_traffic_stop_ping(struct sigma_dut *dut,
157 						   struct sigma_conn *conn,
158 						   struct sigma_cmd *cmd)
159 {
160 	const char *val;
161 	int id, pid;
162 	FILE *f;
163 	char buf[100];
164 	int res_found = 0, sent = 0, received = 0;
165 
166 	val = get_param(cmd, "streamID");
167 	if (val == NULL)
168 		return INVALID_SEND_STATUS;
169 	id = atoi(val);
170 
171 	snprintf(buf, sizeof(buf), "%s/sigma_dut-ping-pid.%d",
172 		 dut->sigma_tmpdir, id);
173 	f = fopen(buf, "r");
174 	if (f == NULL) {
175 		send_resp(dut, conn, SIGMA_ERROR,
176 			  "ErrorCode,Unknown streamID");
177 		return STATUS_SENT;
178 	}
179 	if (fscanf(f, "%d", &pid) != 1 || pid <= 0) {
180 		sigma_dut_print(dut, DUT_MSG_ERROR, "No PID for ping process");
181 		fclose(f);
182 		unlink(buf);
183 		return ERROR_SEND_STATUS;
184 	}
185 
186 	fclose(f);
187 	unlink(buf);
188 
189 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Ping process pid %d", pid);
190 	if (kill(pid, SIGINT) < 0 && errno != ESRCH) {
191 		sigma_dut_print(dut, DUT_MSG_DEBUG, "kill failed: %s",
192 				strerror(errno));
193 	}
194 	usleep(250000);
195 
196 	snprintf(buf, sizeof(buf), "%s/sigma_dut-ping.%d",
197 		 dut->sigma_tmpdir, id);
198 	f = fopen(buf, "r");
199 	if (f == NULL) {
200 		sigma_dut_print(dut, DUT_MSG_DEBUG,
201 				"No ping result file found");
202 		send_resp(dut, conn, SIGMA_COMPLETE, "sent,0,replies,0");
203 		return STATUS_SENT;
204 	}
205 
206 	while (fgets(buf, sizeof(buf), f)) {
207 		char *pos;
208 
209 		pos = strstr(buf, " packets transmitted");
210 		if (pos) {
211 			pos--;
212 			while (pos > buf && isdigit(pos[-1]))
213 				pos--;
214 			sent = atoi(pos);
215 			res_found = 1;
216 		}
217 
218 		pos = strstr(buf, " packets received");
219 		if (pos == NULL)
220 			pos = strstr(buf, " received");
221 		if (pos) {
222 			pos--;
223 			while (pos > buf && isdigit(pos[-1]))
224 				pos--;
225 			received = atoi(pos);
226 			res_found = 1;
227 		}
228 	}
229 	fclose(f);
230 	snprintf(buf, sizeof(buf), "%s/sigma_dut-ping.%d",
231 		 dut->sigma_tmpdir, id);
232 	unlink(buf);
233 
234 	if (!res_found) {
235 		sigma_dut_print(dut, DUT_MSG_DEBUG,
236 				"No ping results found");
237 		send_resp(dut, conn, SIGMA_COMPLETE, "sent,0,replies,0");
238 		return STATUS_SENT;
239 	}
240 
241 	snprintf(buf, sizeof(buf), "sent,%d,replies,%d", sent, received);
242 	send_resp(dut, conn, SIGMA_COMPLETE, buf);
243 	return STATUS_SENT;
244 }
245 
246 
247 static enum sigma_cmd_result cmd_traffic_start_iperf(struct sigma_dut *dut,
248 						     struct sigma_conn *conn,
249 						     struct sigma_cmd *cmd)
250 {
251 	const char *val, *dst;
252 	const char *iptype;
253 	int port, duration;
254 	const char *proto;
255 	char buf[256];
256 	const char *ifname;
257 	char port_str[20], iperf[100];
258 	FILE *f;
259 	int server, ipv6 = 0;
260 
261 	val = get_param(cmd, "mode");
262 	if (!val) {
263 		send_resp(dut, conn, SIGMA_ERROR,
264 			  "errorCode,Missing mode parameter");
265 		return STATUS_SENT;
266 	}
267 	server = strcasecmp(val, "server") == 0;
268 
269 	iptype = "";
270 	val = get_param(cmd, "iptype");
271 	if (val) {
272 		if (strcasecmp(val, "ipv6") == 0) {
273 			iptype = "-6";
274 			ipv6 = 1;
275 		} else {
276 			iptype = "-4";
277 			ipv6 = 0;
278 		}
279 	}
280 
281 	port_str[0] = '\0';
282 	val = get_param(cmd, "port");
283 	if (val) {
284 		port = atoi(val);
285 		snprintf(port_str, sizeof(port_str), "-p %d", port);
286 	}
287 
288 	proto = "";
289 	val = get_param(cmd, "transproto");
290 	if (val && strcasecmp(val, "udp") == 0)
291 		proto = "-u";
292 
293 	dst = get_param(cmd, "destination");
294 	if (!server && (!dst || (!is_ip_addr(dst) && !is_ipv6_addr(dst)))) {
295 		send_resp(dut, conn, SIGMA_ERROR,
296 			  "errorCode,Invalid destination address");
297 		return STATUS_SENT;
298 	}
299 
300 	if (dut->ndpe)
301 		ifname = "nan0";
302 	else
303 		ifname = get_station_ifname(dut);
304 
305 	val = get_param(cmd, "duration");
306 	if (val)
307 		duration = atoi(val);
308 	else
309 		duration = 0;
310 
311 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf", iperf,
312 				   sizeof(iperf)));
313 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf-pid", iperf,
314 				   sizeof(iperf)));
315 
316 	f = fopen(concat_sigma_tmpdir(dut, "/sigma_dut-iperf.sh", iperf,
317 				      sizeof(iperf)), "w");
318 	if (!f) {
319 		send_resp(dut, conn, SIGMA_ERROR,
320 			  "errorCode,Can not write sigma_dut-iperf.sh");
321 		return STATUS_SENT;
322 	}
323 
324 	if (server) {
325 		/* write server side command to shell file */
326 		fprintf(f, "#!" SHELL "\n"
327 			"iperf3 -s %s %s > %s"
328 			"/sigma_dut-iperf &\n"
329 			"echo $! > %s/sigma_dut-iperf-pid\n",
330 			port_str, iptype, dut->sigma_tmpdir, dut->sigma_tmpdir);
331 	} else {
332 		/* write client side command to shell file */
333 		if (!dst)
334 			return INVALID_SEND_STATUS;
335 		if (ipv6)
336 			snprintf(buf, sizeof(buf), "%s%%%s", dst, ifname);
337 		else
338 			snprintf(buf, sizeof(buf), "%s", dst);
339 		fprintf(f, "#!" SHELL "\n"
340 			"iperf3 -c %s -t %d %s %s %s > %s"
341 			"/sigma_dut-iperf &\n"
342 			"echo $! > %s/sigma_dut-iperf-pid\n",
343 			buf, duration, iptype, proto, port_str,
344 			dut->sigma_tmpdir, dut->sigma_tmpdir);
345 	}
346 
347 	fclose(f);
348 
349 	if (chmod(concat_sigma_tmpdir(dut, "/sigma_dut-iperf.sh", iperf,
350 				      sizeof(iperf)),
351 		  S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
352 		send_resp(dut, conn, SIGMA_ERROR,
353 			  "errorCode,Can not chmod sigma_dut-iperf.sh");
354 		return STATUS_SENT;
355 	}
356 
357 	sigma_dut_print(dut, DUT_MSG_DEBUG, "Starting iperf");
358 	if (system(concat_sigma_tmpdir(dut, "/sigma_dut-iperf.sh", iperf,
359 				       sizeof(iperf))) != 0) {
360 		sigma_dut_print(dut, DUT_MSG_ERROR, "Failed to start iperf");
361 		send_resp(dut, conn, SIGMA_ERROR,
362 			  "errorCode,Failed to run sigma_dut-iperf.sh");
363 		return STATUS_SENT;
364 	}
365 
366 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf.sh", iperf,
367 				   sizeof(iperf)));
368 	return SUCCESS_SEND_STATUS;
369 }
370 
371 
372 static enum sigma_cmd_result cmd_traffic_stop_iperf(struct sigma_dut *dut,
373 						    struct sigma_conn *conn,
374 						    struct sigma_cmd *cmd)
375 {
376 	int pid;
377 	FILE *f;
378 	char buf[100], summary_buf[100], iperf[100];
379 	float bandwidth, totalbytes, factor;
380 	char *pos;
381 	long l_bandwidth, l_totalbytes;
382 
383 	f = fopen(concat_sigma_tmpdir(dut, "/sigma_dut-iperf-pid", iperf,
384 				      sizeof(iperf)), "r");
385 	if (!f) {
386 		send_resp(dut, conn, SIGMA_ERROR,
387 			  "errorCode,PID file does not exist");
388 		return STATUS_SENT;
389 	}
390 	if (fscanf(f, "%d", &pid) != 1 || pid <= 0) {
391 		sigma_dut_print(dut, DUT_MSG_ERROR, "No PID for iperf process");
392 		fclose(f);
393 		unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf-pid", iperf,
394 					   sizeof(iperf)));
395 		return ERROR_SEND_STATUS;
396 	}
397 
398 	fclose(f);
399 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf-pid", iperf,
400 				   sizeof(iperf)));
401 
402 	if (kill(pid, SIGINT) < 0 && errno != ESRCH) {
403 		sigma_dut_print(dut, DUT_MSG_DEBUG, "kill failed: %s",
404 				strerror(errno));
405 	}
406 	usleep(250000);
407 
408 	/* parse iperf output which is stored in sigma_dut-iperf */
409 	summary_buf[0] = '\0';
410 	f = fopen(concat_sigma_tmpdir(dut, "/sigma_dut-iperf", iperf,
411 				      sizeof(iperf)), "r");
412 	if (!f) {
413 		sigma_dut_print(dut, DUT_MSG_DEBUG,
414 				"No iperf result file found");
415 		send_resp(dut, conn, SIGMA_COMPLETE,
416 			  "bandwidth,0,totalbytes,0");
417 		return STATUS_SENT;
418 	}
419 
420 	/* find the last line which has the received bytes summary */
421 	while (fgets(buf, sizeof(buf), f)) {
422 		char *pos;
423 
424 		pos = strchr(buf, '\n');
425 		if (pos)
426 			*pos = '\0';
427 		sigma_dut_print(dut, DUT_MSG_DEBUG, "iperf: %s", buf);
428 		pos = strstr(buf, "  sec  ");
429 		if (pos)
430 			strlcpy(summary_buf, buf, sizeof(summary_buf));
431 	}
432 
433 	fclose(f);
434 	unlink(concat_sigma_tmpdir(dut, "/sigma_dut-iperf", iperf,
435 				   sizeof(iperf)));
436 
437 	pos = strstr(summary_buf, "Bytes");
438 	if (!pos || pos == summary_buf) {
439 		sigma_dut_print(dut, DUT_MSG_DEBUG,
440 				"Can not parse iperf results");
441 		send_resp(dut, conn, SIGMA_COMPLETE,
442 			  "bandwidth,0,totalbytes,0");
443 		return STATUS_SENT;
444 	}
445 
446 	if (pos[-1] == 'G')
447 		factor = 1024 * 1024 * 1024;
448 	else if (pos[-1] == 'M')
449 		factor = 1024 * 1024;
450 	else if (pos[-1] == 'K')
451 		factor = 1024;
452 	else
453 		factor = 1;
454 
455 	if (pos) {
456 		pos -= 2;
457 		while (pos > summary_buf && (pos[-1] != ' '))
458 			pos--;
459 		totalbytes = atof(pos);
460 	} else
461 		totalbytes = 0;
462 	l_totalbytes = totalbytes * factor;
463 
464 	pos = strstr(summary_buf, "bits/sec");
465 	if (!pos || pos == summary_buf) {
466 		sigma_dut_print(dut, DUT_MSG_DEBUG,
467 				"Can not parse iperf results");
468 		send_resp(dut, conn, SIGMA_COMPLETE,
469 			  "bandwidth,0,totalbytes,0");
470 		return STATUS_SENT;
471 	}
472 
473 	if (pos[-1] == 'G')
474 		factor = 1024 * 1024 * 1024 / 8;
475 	else if (pos[-1] == 'M')
476 		factor = 1024 * 1024 / 8;
477 	else if (pos[-1] == 'K')
478 		factor = 1024 / 8;
479 	else
480 		factor = 1 / 8;
481 
482 	if (pos && pos - summary_buf > 2) {
483 		pos -= 2;
484 		while (pos > summary_buf && (pos[-1] != ' '))
485 			pos--;
486 		bandwidth = atof(pos);
487 	} else
488 		bandwidth = 0;
489 	l_bandwidth = bandwidth * factor;
490 
491 	snprintf(buf, sizeof(buf), "bandwidth,%lu,totalbytes,%lu",
492 		 l_bandwidth, l_totalbytes);
493 	send_resp(dut, conn, SIGMA_COMPLETE, buf);
494 	return STATUS_SENT;
495 }
496 
497 
498 void traffic_register_cmds(void)
499 {
500 	sigma_dut_reg_cmd("traffic_send_ping", NULL, cmd_traffic_send_ping);
501 	sigma_dut_reg_cmd("traffic_stop_ping", NULL, cmd_traffic_stop_ping);
502 	sigma_dut_reg_cmd("traffic_start_iperf", NULL, cmd_traffic_start_iperf);
503 	sigma_dut_reg_cmd("traffic_stop_iperf", NULL, cmd_traffic_stop_iperf);
504 }
505