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