blob: ffc45b4edb36e41d5b1b2dffc7326f3203c9c82f [file] [log] [blame]
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001/*
2 * Sigma Control API DUT (station/AP)
3 * Copyright (c) 2010, Atheros Communications, Inc.
Jouni Malinen9d7e31d2017-12-22 18:55:04 +02004 * Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
Jouni Malinencd4e3c32015-10-29 12:39:56 +02005 * All Rights Reserved.
6 * Licensed under the Clear BSD license. See README for more details.
7 */
8
9#include "sigma_dut.h"
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +053010#include "wpa_helpers.h"
Jouni Malinencd4e3c32015-10-29 12:39:56 +020011
12#define TG_MAX_CLIENTS_CONNECTIONS 1
13
14
15static int cmd_traffic_agent_config(struct sigma_dut *dut,
16 struct sigma_conn *conn,
17 struct sigma_cmd *cmd)
18{
19 struct sigma_stream *s;
20 const char *val;
21 char buf[100];
22
23 if (dut->num_streams == MAX_SIGMA_STREAMS) {
24 send_resp(dut, conn, SIGMA_ERROR, "errorCode,No more "
25 "concurrent traffic streams supported");
26 return 0;
27 }
28
29 s = &dut->streams[dut->num_streams];
30 free(s->stats);
31 memset(s, 0, sizeof(*s));
32 s->sock = -1;
33 s->no_timestamps = dut->no_timestamps;
34
35 val = get_param(cmd, "profile");
36 if (!val)
37 return -1;
38
39 if (strcasecmp(val, "File_Transfer") == 0)
40 s->profile = SIGMA_PROFILE_FILE_TRANSFER;
41 else if (strcasecmp(val, "Multicast") == 0)
42 s->profile = SIGMA_PROFILE_MULTICAST;
43 else if (strcasecmp(val, "IPTV") == 0)
44 s->profile = SIGMA_PROFILE_IPTV;
45 else if (strcasecmp(val, "Transaction") == 0)
46 s->profile = SIGMA_PROFILE_TRANSACTION;
47 else if (strcasecmp(val, "Start_Sync") == 0)
48 s->profile = SIGMA_PROFILE_START_SYNC;
49 else if (strcasecmp(val, "Uapsd") == 0)
50 s->profile = SIGMA_PROFILE_UAPSD;
51 else {
52 send_resp(dut, conn, SIGMA_INVALID, "errorCode,Unsupported "
53 "profile");
54 return 0;
55 }
56
57 val = get_param(cmd, "direction");
58 if (!val)
59 return -1;
60 if (strcasecmp(val, "send") == 0)
61 s->sender = 1;
62 else if (strcasecmp(val, "receive") == 0)
63 s->sender = 0;
64 else
65 return -1;
66
67 val = get_param(cmd, "destination");
68 if (val) {
69 if (inet_aton(val, &s->dst) == 0)
70 return -1;
71 }
72
73 val = get_param(cmd, "source");
74 if (val) {
75 if (inet_aton(val, &s->src) == 0)
76 return -1;
77 }
78
79 val = get_param(cmd, "destinationPort");
80 if (val)
81 s->dst_port = atoi(val);
82
83 val = get_param(cmd, "sourcePort");
84 if (val)
85 s->src_port = atoi(val);
86
87 val = get_param(cmd, "frameRate");
88 if (val)
89 s->frame_rate = atoi(val);
90
91 val = get_param(cmd, "duration");
92 if (val)
93 s->duration = atoi(val);
94
95 val = get_param(cmd, "payloadSize");
96 if (val)
97 s->payload_size = atoi(val);
98
99 val = get_param(cmd, "startDelay");
100 if (val)
101 s->start_delay = atoi(val);
102
103 val = get_param(cmd, "maxCnt");
104 if (val)
105 s->max_cnt = atoi(val);
106
107 val = get_param(cmd, "trafficClass");
108 if (val) {
109 if (strcasecmp(val, "Voice") == 0)
110 s->tc = SIGMA_TC_VOICE;
111 else if (strcasecmp(val, "Video") == 0)
112 s->tc = SIGMA_TC_VIDEO;
113 else if (strcasecmp(val, "Background") == 0)
114 s->tc = SIGMA_TC_BACKGROUND;
115 else if (strcasecmp(val, "BestEffort") == 0)
116 s->tc = SIGMA_TC_BEST_EFFORT;
117 else
118 return -1;
119 }
120
121 val = get_param(cmd, "userpriority");
122 if (val) {
123 s->user_priority_set = 1;
124 s->user_priority = atoi(val);
125 }
126
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530127 val = get_param(cmd, "tagName");
128 if (val) {
Peng Xub8fc5cc2017-05-10 17:27:28 -0700129 strlcpy(s->test_name, val, sizeof(s->test_name));
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530130 sigma_dut_print(dut, DUT_MSG_DEBUG,
131 "Traffic agent: U-APSD console tagname %s",
132 s->test_name);
133 }
134
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200135 if (dut->throughput_pktsize && s->frame_rate == 0 && s->sender &&
136 dut->throughput_pktsize != s->payload_size &&
137 (s->profile == SIGMA_PROFILE_FILE_TRANSFER ||
138 s->profile == SIGMA_PROFILE_IPTV ||
139 s->profile == SIGMA_PROFILE_UAPSD)) {
Jouni Malinenc2493f82016-06-05 18:01:33 +0300140 sigma_dut_print(dut, DUT_MSG_INFO,
141 "Traffic agent: Override throughput test payload size %u -> %u",
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200142 s->payload_size, dut->throughput_pktsize);
143 s->payload_size = dut->throughput_pktsize;
144 }
145
146 val = get_param(cmd, "transProtoType");
147 if (val) {
148 if (strcmp(val, "1") == 0)
149 s->trans_proto = IPPROTO_TCP;
150 else if (strcmp(val, "0") == 0)
151 s->trans_proto = IPPROTO_UDP;
152 else
153 return -1;
154 } else {
155 s->trans_proto = IPPROTO_UDP;
156 }
157
158 if (s->profile == SIGMA_PROFILE_IPTV && !s->sender && !s->no_timestamps)
159 {
160 s->stats = calloc(MAX_SIGMA_STATS,
161 sizeof(struct sigma_frame_stats));
162 if (s->stats == NULL)
163 return -1;
164 }
165
166 dut->stream_id++;
167 dut->num_streams++;
168
169 s->stream_id = dut->stream_id;
170 snprintf(buf, sizeof(buf), "streamID,%d", s->stream_id);
171 send_resp(dut, conn, SIGMA_COMPLETE, buf);
172 return 0;
173}
174
175
176static void stop_stream(struct sigma_stream *s)
177{
178 if (s && s->started) {
179 pthread_join(s->thr, NULL);
180 if (s->sock != -1) {
181 close(s->sock);
182 s->sock = -1;
183 }
184
185 s->started = 0;
186 }
187}
188
189
190static int cmd_traffic_agent_reset(struct sigma_dut *dut,
191 struct sigma_conn *conn,
192 struct sigma_cmd *cmd)
193{
194 int i;
195 for (i = 0; i < dut->num_streams; i++) {
196 struct sigma_stream *s = &dut->streams[i];
197 s->stop = 1;
198 stop_stream(s);
199 }
200 dut->num_streams = 0;
201 memset(&dut->streams, 0, sizeof(dut->streams));
202 return 1;
203}
204
205
206static int get_stream_id(const char *str, int streams[MAX_SIGMA_STREAMS])
207{
208 int count;
209
210 count = 0;
211 for (;;) {
212 if (count == MAX_SIGMA_STREAMS)
213 return -1;
214 streams[count] = atoi(str);
215 if (streams[count] == 0)
216 return -1;
217 count++;
218 str = strchr(str, ' ');
219 if (str == NULL)
220 break;
221 while (*str == ' ')
222 str++;
223 }
224
225 return count;
226}
227
228
229static int open_socket_file_transfer(struct sigma_dut *dut,
230 struct sigma_stream *s)
231{
232 struct sockaddr_in addr;
233 int sock_opt_val = 1;
234
235 s->sock = socket(PF_INET, IPPROTO_UDP == s->trans_proto ? SOCK_DGRAM :
236 SOCK_STREAM, s->trans_proto);
237 if (s->sock < 0) {
238 perror("socket");
239 return -1;
240 }
241
242 if (setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &sock_opt_val,
243 sizeof(sock_opt_val)) < 0) {
244 perror("setsockopt");
245 close(s->sock);
246 s->sock = -1;
247 return -1;
248 }
249
250 memset(&addr, 0, sizeof(addr));
251 addr.sin_family = AF_INET;
252 addr.sin_port = htons(s->sender ? s->src_port : s->dst_port);
253 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: sender=%d "
254 "bind port %d", s->sender, ntohs(addr.sin_port));
255 if (bind(s->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
256 perror("bind");
257 close(s->sock);
258 s->sock = -1;
259 return -1;
260 }
261
262 if (s->profile == SIGMA_PROFILE_MULTICAST && !s->sender)
263 return 0;
264
265 if (s->trans_proto == IPPROTO_TCP && s->sender == 0) {
266 if (listen(s->sock, TG_MAX_CLIENTS_CONNECTIONS ) < 0) {
267 sigma_dut_print(dut, DUT_MSG_INFO,
268 "Listen failed with error %d: %s",
269 errno, strerror(errno));
270 close(s->sock);
271 s->sock = -1;
272 return -1;
273 }
274 } else {
275 memset(&addr, 0, sizeof(addr));
276 addr.sin_family = AF_INET;
277 addr.sin_addr.s_addr = s->sender ? s->dst.s_addr :
278 s->src.s_addr;
279 addr.sin_port = htons(s->sender ? s->dst_port : s->src_port);
280 sigma_dut_print(dut, DUT_MSG_DEBUG,
281 "Traffic agent: connect %s:%d",
282 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
283 if (connect(s->sock, (struct sockaddr *) &addr, sizeof(addr)) <
284 0) {
285 perror("connect");
286 close(s->sock);
287 s->sock = -1;
288 return -1;
289 }
290 }
291
292 return 0;
293}
294
295
296static int open_socket_multicast(struct sigma_dut *dut, struct sigma_stream *s)
297{
298 if (open_socket_file_transfer(dut, s) < 0)
299 return -1;
300
301 if (!s->sender) {
302 struct ip_mreq mr;
303 memset(&mr, 0, sizeof(mr));
304 mr.imr_multiaddr.s_addr = s->dst.s_addr;
305 mr.imr_interface.s_addr = htonl(INADDR_ANY);
306 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: "
307 "IP_ADD_MEMBERSHIP %s", inet_ntoa(s->dst));
308 if (setsockopt(s->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
309 (void *) &mr, sizeof(mr)) < 0) {
310 sigma_dut_print(dut, DUT_MSG_INFO,
311 "setsockopt[IP_ADD_MEMBERSHIP]: %s",
312 strerror(errno));
313 /*
314 * Continue anyway since this can happen, e.g., if the
315 * default route is missing. This is not critical for
316 * multicast RX testing.
317 */
318 }
319 }
320
321 return 0;
322}
323
324
325static int set_socket_prio(struct sigma_stream *s)
326{
327 int tos = 0x00;
328
329 switch (s->tc) {
330 case SIGMA_TC_VOICE:
331 if (s->user_priority_set) {
332 if (s->user_priority == 6)
333 tos = 48 << 2;
334 else if (s->user_priority == 7)
335 tos = 56 << 2;
336 else
337 return -1;
338 } else
339 tos = 0xe0; /* DSCP = 56 */
340 break;
341 case SIGMA_TC_VIDEO:
342 if (s->user_priority_set) {
343 if (s->user_priority == 4)
344 tos = 32 << 2;
345 else if (s->user_priority == 5)
346 tos = 40 << 2;
347 else
348 return -1;
349 } else
350 tos = 0xa0; /* DSCP = 40 */
351 break;
352 case SIGMA_TC_BACKGROUND:
353 if (s->user_priority_set) {
354 if (s->user_priority == 1)
355 tos = 8 << 2;
356 else if (s->user_priority == 2)
357 tos = 16 << 2;
358 else
359 return -1;
360 } else
361 tos = 0x20; /* DSCP = 8 */
362 break;
363 case SIGMA_TC_BEST_EFFORT:
364 if (s->user_priority_set) {
365 if (s->user_priority == 0)
366 tos = 0 << 2;
367 else if (s->user_priority == 3)
368 tos = 20 << 2;
369 else
370 return -1;
371 } else
372 tos = 0x00; /* DSCP = 0 */
373 break;
374 }
375
376 if (setsockopt(s->sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
377 perror("setsockopt");
378 return -1;
379 }
380
381 return 0;
382}
383
384
385static int open_socket(struct sigma_dut *dut, struct sigma_stream *s)
386{
387 switch (s->profile) {
388 case SIGMA_PROFILE_FILE_TRANSFER:
389 return open_socket_file_transfer(dut, s);
390 case SIGMA_PROFILE_MULTICAST:
391 return open_socket_multicast(dut, s);
392 case SIGMA_PROFILE_IPTV:
393 if (open_socket_file_transfer(dut, s) < 0)
394 return -1;
395 return set_socket_prio(s);
396 case SIGMA_PROFILE_TRANSACTION:
397 return open_socket_file_transfer(dut, s);
398 case SIGMA_PROFILE_UAPSD:
399 return open_socket_file_transfer(dut, s);
400 case SIGMA_PROFILE_START_SYNC:
401 sigma_dut_print(dut, DUT_MSG_INFO, "Traffic stream profile %d "
402 "not yet supported", s->profile);
403 /* TODO */
404 break;
405 }
406
407 return -1;
408}
409
410
411static void send_file_fast(struct sigma_stream *s, char *pkt)
412{
413 struct timeval stop, now;
414 int res;
415 unsigned int counter = 0;
416
417 gettimeofday(&stop, NULL);
418 stop.tv_sec += s->duration;
419
420 while (!s->stop) {
421 counter++;
422 WPA_PUT_BE32(&pkt[8], counter);
423
424 if ((counter & 0xf) == 0) {
425 gettimeofday(&now, NULL);
426 if (now.tv_sec > stop.tv_sec ||
427 (now.tv_sec == stop.tv_sec &&
428 now.tv_usec >= stop.tv_usec))
429 break;
430 }
431
432 s->tx_act_frames++;
433 res = send(s->sock, pkt, s->payload_size, 0);
434 if (res >= 0) {
435 s->tx_frames++;
436 s->tx_payload_bytes += res;
437 } else {
438 switch (errno) {
439 case EAGAIN:
440 case ENOBUFS:
441 usleep(1000);
442 break;
443 case ECONNRESET:
444 case EPIPE:
445 s->stop = 1;
446 break;
447 default:
448 perror("send");
449 break;
450 }
451 }
452 }
453}
454
455
456static void send_file(struct sigma_stream *s)
457{
458 char *pkt;
459 struct timeval stop, now, start;
460 int res;
vamsi krishna2c650812016-05-16 17:43:22 +0530461 unsigned int counter = 0, total_sleep_usec = 0, total_pkts;
462 int sleep_usec = 0;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200463
464 if (s->duration <= 0 || s->frame_rate < 0 || s->payload_size < 20)
465 return;
466
467 pkt = malloc(s->payload_size);
468 if (pkt == NULL)
469 return;
470 memset(pkt, 1, s->payload_size);
Peng Xub8fc5cc2017-05-10 17:27:28 -0700471 strlcpy(pkt, "1345678", s->payload_size);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200472
473 if (s->frame_rate == 0 && s->no_timestamps) {
474 send_file_fast(s, pkt);
475 free(pkt);
476 return;
477 }
478
479 gettimeofday(&stop, NULL);
480 stop.tv_sec += s->duration;
481
vamsi krishna2c650812016-05-16 17:43:22 +0530482 total_pkts = s->duration * s ->frame_rate;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200483
484 gettimeofday(&start, NULL);
485
486 while (!s->stop) {
487 counter++;
488 WPA_PUT_BE32(&pkt[8], counter);
489
vamsi krishna2c650812016-05-16 17:43:22 +0530490 if (sleep_usec) {
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200491 usleep(sleep_usec);
vamsi krishna2c650812016-05-16 17:43:22 +0530492 total_sleep_usec += sleep_usec;
493 }
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200494
495 gettimeofday(&now, NULL);
496 if (now.tv_sec > stop.tv_sec ||
497 (now.tv_sec == stop.tv_sec && now.tv_usec >= stop.tv_usec))
498 break;
499
vamsi krishna2c650812016-05-16 17:43:22 +0530500 if (s->frame_rate && (unsigned int) s->tx_frames >= total_pkts)
501 break;
502
503 if (s->frame_rate == 0 || s->tx_frames == 0)
504 sleep_usec = 0;
505 else if (sleep_usec || s->frame_rate < 10 ||
506 counter % (s->frame_rate / 10) == 0) {
507 /* Recalculate sleep_usec for every 100 ms approximately
508 */
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200509 struct timeval tmp;
vamsi krishna2c650812016-05-16 17:43:22 +0530510 int diff, duration;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200511
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200512 timersub(&now, &start, &tmp);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200513
vamsi krishna2c650812016-05-16 17:43:22 +0530514 diff = tmp.tv_sec * 1000000 + tmp.tv_usec;
515 duration = (1000000 / s->frame_rate) * s->tx_frames;
516
517 if (duration > diff)
518 sleep_usec = (total_sleep_usec +
519 (duration - diff)) / s->tx_frames;
520 else
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200521 sleep_usec = 0;
522 }
523
524 WPA_PUT_BE32(&pkt[12], now.tv_sec);
525 WPA_PUT_BE32(&pkt[16], now.tv_usec);
526
527 s->tx_act_frames++;
528 res = send(s->sock, pkt, s->payload_size, 0);
529 if (res >= 0) {
530 s->tx_frames++;
531 s->tx_payload_bytes += res;
532 } else {
533 switch (errno) {
534 case EAGAIN:
535 case ENOBUFS:
536 usleep(1000);
537 break;
538 case ECONNRESET:
539 case EPIPE:
540 s->stop = 1;
541 break;
542 default:
543 perror("send");
544 break;
545 }
546 }
547 }
548
vamsi krishna2c650812016-05-16 17:43:22 +0530549 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
550 "send_file: counter %u s->tx_frames %d total_sleep_usec %u",
551 counter, s->tx_frames, total_sleep_usec);
552
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200553 free(pkt);
554}
555
556
557static void send_transaction(struct sigma_stream *s)
558{
559 char *pkt, *rpkt;
560 struct timeval stop, now;
561 int res;
562 unsigned int counter = 0, rcounter;
563 int wait_time;
564 fd_set rfds;
565 struct timeval tv;
566
567 if (s->duration <= 0 || s->frame_rate <= 0 || s->payload_size < 20)
568 return;
569
570 pkt = malloc(s->payload_size);
571 if (pkt == NULL)
572 return;
573 rpkt = malloc(s->payload_size);
574 if (rpkt == NULL) {
575 free(pkt);
576 return;
577 }
578 memset(pkt, 1, s->payload_size);
Peng Xub8fc5cc2017-05-10 17:27:28 -0700579 strlcpy(pkt, "1345678", s->payload_size);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200580
581 gettimeofday(&stop, NULL);
582 stop.tv_sec += s->duration;
583
584 wait_time = 1000000 / s->frame_rate;
585
586 while (!s->stop) {
587 counter++;
588 if (s->max_cnt && (int) counter > s->max_cnt)
589 break;
590 WPA_PUT_BE32(&pkt[8], counter);
591
592 gettimeofday(&now, NULL);
593 if (now.tv_sec > stop.tv_sec ||
594 (now.tv_sec == stop.tv_sec && now.tv_usec >= stop.tv_usec))
595 break;
596 WPA_PUT_BE32(&pkt[12], now.tv_sec);
597 WPA_PUT_BE32(&pkt[16], now.tv_usec);
598
599 res = send(s->sock, pkt, s->payload_size, 0);
600 if (res >= 0) {
601 s->tx_frames++;
602 s->tx_payload_bytes += res;
603 } else {
604 switch (errno) {
605 case EAGAIN:
606 case ENOBUFS:
607 usleep(1000);
608 break;
609 case ECONNRESET:
610 case EPIPE:
611 s->stop = 1;
612 break;
613 default:
614 perror("send");
615 break;
616 }
617 }
618
619 /* Wait for response */
620 tv.tv_sec = 0;
621 tv.tv_usec = wait_time;
622 FD_ZERO(&rfds);
623 FD_SET(s->sock, &rfds);
624 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
625 if (res < 0) {
626 if (errno == EINTR)
627 continue;
628 perror("select");
629 break;
630 }
631
632 if (res == 0) {
633 /* timeout */
634 continue;
635 }
636
637 if (FD_ISSET(s->sock, &rfds)) {
638 /* response received */
639 res = recv(s->sock, rpkt, s->payload_size, 0);
640 if (res < 0) {
641 perror("recv");
642 break;
643 }
644 rcounter = WPA_GET_BE32(&rpkt[8]);
645 if (rcounter != counter)
646 s->out_of_seq_frames++;
647 s->rx_frames++;
648 s->rx_payload_bytes += res;
649 }
650 }
651
652 free(pkt);
653 free(rpkt);
654}
655
656
657static void * send_thread(void *ctx)
658{
659 struct sigma_stream *s = ctx;
660
661 sleep(s->start_delay);
662
663 switch (s->profile) {
664 case SIGMA_PROFILE_FILE_TRANSFER:
665 send_file(s);
666 break;
667 case SIGMA_PROFILE_MULTICAST:
668 send_file(s);
669 break;
670 case SIGMA_PROFILE_IPTV:
671 send_file(s);
672 break;
673 case SIGMA_PROFILE_TRANSACTION:
674 send_transaction(s);
675 break;
676 case SIGMA_PROFILE_START_SYNC:
677 break;
678 case SIGMA_PROFILE_UAPSD:
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530679 send_uapsd_console(s);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200680 break;
681 }
682
683 return NULL;
684}
685
686
687struct traffic_agent_send_data {
688 struct sigma_dut *dut;
689 struct sigma_conn *conn;
690 int streams[MAX_SIGMA_STREAMS];
691 int count;
692};
693
694
695static struct sigma_stream * get_stream(struct sigma_dut *dut, int id)
696{
697 int i;
698
699 for (i = 0; i < dut->num_streams; i++) {
700 if ((unsigned int) id == dut->streams[i].stream_id)
701 return &dut->streams[i];
702 }
703
704 return NULL;
705}
706
707
708static void * send_report_thread(void *ctx)
709{
710 struct traffic_agent_send_data *data = ctx;
711 struct sigma_dut *dut = data->dut;
712 struct sigma_conn *conn = data->conn;
713 int i, ret;
714 char buf[100 + MAX_SIGMA_STREAMS * 60], *pos;
715
716 for (i = 0; i < data->count; i++) {
717 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: waiting "
718 "for stream %d send to complete",
719 data->streams[i]);
720 stop_stream(get_stream(dut, data->streams[i]));
721 }
722
723 buf[0] = '\0';
724 pos = buf;
725
726 pos += snprintf(pos, buf + sizeof(buf) - pos, "streamID,");
727 for (i = 0; i < data->count; i++) {
728 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
729 i > 0 ? " " : "", data->streams[i]);
730 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
731 break;
732 pos += ret;
733 }
734
735 if (dut->program == PROGRAM_60GHZ) {
736 sigma_dut_print(dut, DUT_MSG_INFO, "reporting tx_act_frames");
737 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txActFrames,");
738 for (i = 0; i < data->count; i++) {
739 struct sigma_stream *s;
740
741 s = get_stream(dut, data->streams[i]);
742 if (!s)
743 continue;
744 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
745 i > 0 ? " " : "", s->tx_act_frames);
746 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
747 break;
748 pos += ret;
749 }
750 }
751
752 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txFrames,");
753 for (i = 0; i < data->count; i++) {
754 struct sigma_stream *s = get_stream(dut, data->streams[i]);
755
756 if (!s)
757 continue;
758 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
759 i > 0 ? " " : "", s->tx_frames);
760 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
761 break;
762 pos += ret;
763 }
764
765 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxFrames,");
766 for (i = 0; i < data->count; i++) {
767 struct sigma_stream *s = get_stream(dut, data->streams[i]);
768
769 if (!s)
770 continue;
771 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
772 i > 0 ? " " : "", s->rx_frames);
773 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
774 break;
775 pos += ret;
776 }
777
778 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txPayloadBytes,");
779 for (i = 0; i < data->count; i++) {
780 struct sigma_stream *s = get_stream(dut, data->streams[i]);
781
782 if (!s)
783 continue;
784 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
785 i > 0 ? " " : "", s->tx_payload_bytes);
786 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
787 break;
788 pos += ret;
789 }
790
791 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxPayloadBytes,");
792 for (i = 0; i < data->count; i++) {
793 struct sigma_stream *s = get_stream(dut, data->streams[i]);
794
795 if (!s)
796 continue;
797 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
798 i > 0 ? " " : "", s->rx_payload_bytes);
799 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
800 break;
801 pos += ret;
802 }
803
804 pos += snprintf(pos, buf + sizeof(buf) - pos, ",outOfSequenceFrames,");
805 for (i = 0; i < data->count; i++) {
806 struct sigma_stream *s = get_stream(dut, data->streams[i]);
807
808 if (!s)
809 continue;
810 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
811 i > 0 ? " " : "", s->out_of_seq_frames);
812 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
813 break;
814 pos += ret;
815 }
816
817 for (i = 0; i < data->count; i++) {
818 struct sigma_stream *s = get_stream(dut, data->streams[i]);
819 if (!s)
820 continue;
821 s->ta_send_in_progress = 0;
822 if (s->trans_proto == IPPROTO_TCP) {
823 /*
824 * Close the socket to make sure client side close the
825 * network before the server. Otherwise, the server
826 * might get "Address already in use" when trying to
827 * reuse the port.
828 */
829 close(s->sock);
830 s->sock = -1;
831 sigma_dut_print(dut, DUT_MSG_DEBUG,
832 "Closed the sender socket");
833 }
834 }
835
836 buf[sizeof(buf) - 1] = '\0';
837
838 if (conn->s < 0)
839 sigma_dut_print(dut, DUT_MSG_INFO, "Cannot send traffic_agent response since control socket has already been closed");
840 else
841 send_resp(dut, conn, SIGMA_COMPLETE, buf);
842 conn->waiting_completion = 0;
843
844 free(data);
845
846 return NULL;
847}
848
849
850static int cmd_traffic_agent_send(struct sigma_dut *dut,
851 struct sigma_conn *conn,
852 struct sigma_cmd *cmd)
853{
854 const char *val;
855 int i, j, res;
856 char buf[100];
857 struct traffic_agent_send_data *data;
858
859 val = get_param(cmd, "streamID");
860 if (val == NULL)
861 return -1;
862
863 data = calloc(1, sizeof(*data));
864 if (data == NULL)
865 return -1;
866 data->dut = dut;
867 data->conn = conn;
868
869 data->count = get_stream_id(val, data->streams);
870 if (data->count < 0) {
871 free(data);
872 return -1;
873 }
874 for (i = 0; i < data->count; i++) {
875 struct sigma_stream *s = get_stream(dut, data->streams[i]);
876
877 if (!s) {
878 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
879 "not configured", data->streams[i]);
880 send_resp(dut, conn, SIGMA_INVALID, buf);
881 free(data);
882 return 0;
883 }
884 for (j = 0; j < i; j++)
885 if (data->streams[i] == data->streams[j])
886 return -1;
887 if (!s->sender) {
888 snprintf(buf, sizeof(buf), "errorCode,Not configured "
889 "as sender for streamID %d", data->streams[i]);
890 send_resp(dut, conn, SIGMA_INVALID, buf);
891 free(data);
892 return 0;
893 }
894 if (s->ta_send_in_progress) {
895 send_resp(dut, conn, SIGMA_ERROR,
896 "errorCode,Multiple concurrent send cmds on same streamID not supported");
897 free(data);
898 return 0;
899 }
900 }
901
902 for (i = 0; i < data->count; i++) {
903 struct sigma_stream *s = get_stream(dut, data->streams[i]);
904
905 if (!s)
906 continue;
907 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: open "
908 "socket for send stream %d", data->streams[i]);
909 if (open_socket(dut, s) < 0) {
910 free(data);
911 return -2;
912 }
913 }
914
915 for (i = 0; i < data->count; i++) {
916 struct sigma_stream *s = get_stream(dut, data->streams[i]);
917
918 if (!s)
919 continue;
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530920
921 /*
922 * Provide dut context to the thread to support debugging and
923 * returning of error messages.
924 */
925 s->dut = dut;
926
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200927 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start "
928 "send for stream %d", data->streams[i]);
929 res = pthread_create(&s->thr, NULL, send_thread, s);
930 if (res) {
931 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create "
932 "failed: %d", res);
933 free(data);
934 return -2;
935 }
936 s->started = 1;
937 }
938
939 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start a thread to track sending streams");
940 conn->waiting_completion = 1;
941 res = pthread_create(&dut->thr, NULL, send_report_thread, data);
942 if (res) {
943 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create failed: %d",
944 res);
945 free(data);
946 conn->waiting_completion = 0;
947 return -2;
948 }
949
950 for (i = 0; i < data->count; i++) {
951 struct sigma_stream *s = get_stream(dut, data->streams[i]);
952
953 if (s)
954 s->ta_send_in_progress = 1;
955 }
956
957 /* Command will be completed in send_report_thread() */
958
959 return 0;
960}
961
962
963static void receive_file(struct sigma_stream *s)
964{
965 struct timeval tv, now;
966 fd_set rfds;
967 int res;
968 char *pkt;
969 int pktlen;
970 unsigned int last_rx = 0, counter;
971
972 pktlen = 65536 + 1;
973 pkt = malloc(pktlen);
974 if (pkt == NULL)
975 return;
976
977 while (!s->stop) {
978 FD_ZERO(&rfds);
979 FD_SET(s->sock, &rfds);
980 tv.tv_sec = 0;
981 tv.tv_usec = 300000;
982 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
983 if (res < 0) {
984 perror("select");
985 usleep(10000);
986 } else if (FD_ISSET(s->sock, &rfds)) {
987 res = recv(s->sock, pkt, pktlen, 0);
988 if (res >= 0) {
989 s->rx_frames++;
990 s->rx_payload_bytes += res;
991
992 counter = WPA_GET_BE32(&pkt[8]);
993 if (counter < last_rx)
994 s->out_of_seq_frames++;
995 last_rx = counter;
996 } else {
997 perror("recv");
998 break;
999 }
1000
1001 if (res >= 20 && s->stats &&
1002 s->num_stats < MAX_SIGMA_STATS) {
1003 struct sigma_frame_stats *stats;
1004 stats = &s->stats[s->num_stats];
1005 s->num_stats++;
1006 gettimeofday(&now, NULL);
1007 stats->seqnum = counter;
1008 stats->local_sec = now.tv_sec;
1009 stats->local_usec = now.tv_usec;
1010 stats->remote_sec = WPA_GET_BE32(&pkt[12]);
1011 stats->remote_usec = WPA_GET_BE32(&pkt[16]);
1012 }
1013 }
1014 }
1015
1016 free(pkt);
1017}
1018
1019
1020static void receive_transaction(struct sigma_stream *s)
1021{
1022 struct timeval tv;
1023 fd_set rfds;
1024 int res;
1025 char *pkt;
1026 int pktlen;
1027 unsigned int last_rx = 0, counter;
1028 struct sockaddr_in addr;
1029 socklen_t addrlen;
1030
1031 if (s->payload_size)
1032 pktlen = s->payload_size;
1033 else
1034 pktlen = 65536 + 1;
1035 pkt = malloc(pktlen);
1036 if (pkt == NULL)
1037 return;
1038
1039 while (!s->stop) {
1040 FD_ZERO(&rfds);
1041 FD_SET(s->sock, &rfds);
1042 tv.tv_sec = 0;
1043 tv.tv_usec = 300000;
1044 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
1045 if (res < 0) {
1046 perror("select");
1047 usleep(10000);
1048 } else if (FD_ISSET(s->sock, &rfds)) {
1049 addrlen = sizeof(addr);
1050 res = recvfrom(s->sock, pkt, pktlen, 0,
1051 (struct sockaddr *) &addr, &addrlen);
1052 if (res < 0) {
1053 perror("recv");
1054 break;
1055 }
1056
1057 s->rx_frames++;
1058 s->rx_payload_bytes += res;
1059
1060 counter = WPA_GET_BE32(&pkt[8]);
1061 if (counter < last_rx)
1062 s->out_of_seq_frames++;
1063 last_rx = counter;
1064
1065 /* send response */
1066 res = sendto(s->sock, pkt, pktlen, 0,
1067 (struct sockaddr *) &addr, addrlen);
1068 if (res < 0) {
1069 perror("sendto");
1070 } else {
1071 s->tx_frames++;
1072 s->tx_payload_bytes += res;
1073 }
1074 }
1075 }
1076
1077 free(pkt);
1078}
1079
1080
1081static void * receive_thread(void *ctx)
1082{
1083 struct sigma_stream *s = ctx;
1084
1085 if (s->trans_proto == IPPROTO_TCP) {
1086 /* Wait for socket to be accepted */
1087 struct sockaddr_in connected_addr;
1088 int connected_sock; /* returned from accept on sock */
1089 socklen_t connected_addr_len = sizeof(connected_addr);
1090
1091 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
1092 "Traffic agent: Waiting on accept");
1093 connected_sock = accept(s->sock,
1094 (struct sockaddr *) &connected_addr,
1095 &connected_addr_len);
1096 if (connected_sock < 0) {
1097 sigma_dut_print(s->dut, DUT_MSG_ERROR,
1098 "Traffic agent: Failed to accept: %s",
1099 strerror(errno));
1100 return NULL;
1101 }
1102
1103 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
1104 "Traffic agent: Accepted client closing parent socket and talk over connected sock.");
1105 close(s->sock);
1106 s->sock = connected_sock;
1107 }
1108
1109 switch (s->profile) {
1110 case SIGMA_PROFILE_FILE_TRANSFER:
1111 receive_file(s);
1112 break;
1113 case SIGMA_PROFILE_MULTICAST:
1114 receive_file(s);
1115 break;
1116 case SIGMA_PROFILE_IPTV:
1117 receive_file(s);
1118 break;
1119 case SIGMA_PROFILE_TRANSACTION:
1120 receive_transaction(s);
1121 break;
1122 case SIGMA_PROFILE_START_SYNC:
1123 break;
1124 case SIGMA_PROFILE_UAPSD:
1125 receive_uapsd(s);
1126 break;
1127 }
1128
1129 return NULL;
1130}
1131
1132
1133static int cmd_traffic_agent_receive_start(struct sigma_dut *dut,
1134 struct sigma_conn *conn,
1135 struct sigma_cmd *cmd)
1136{
1137 const char *val;
1138 int streams[MAX_SIGMA_STREAMS];
1139 int i, j, count;
1140 char buf[100];
1141
1142 val = get_param(cmd, "streamID");
1143 if (val == NULL)
1144 return -1;
1145 count = get_stream_id(val, streams);
1146 if (count < 0)
1147 return -1;
1148 for (i = 0; i < count; i++) {
1149 struct sigma_stream *s = get_stream(dut, streams[i]);
1150
1151 if (!s) {
1152 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
1153 "not configured", streams[i]);
1154 send_resp(dut, conn, SIGMA_INVALID, buf);
1155 return 0;
1156 }
1157 for (j = 0; j < i; j++)
1158 if (streams[i] == streams[j])
1159 return -1;
1160 if (s->sender) {
1161 snprintf(buf, sizeof(buf), "errorCode,Not configured "
1162 "as receiver for streamID %d", streams[i]);
1163 send_resp(dut, conn, SIGMA_INVALID, buf);
1164 return 0;
1165 }
1166 }
1167
1168 for (i = 0; i < count; i++) {
1169 struct sigma_stream *s = get_stream(dut, streams[i]);
1170
1171 if (!s)
1172 continue;
1173 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: open "
1174 "receive socket for stream %d", streams[i]);
1175 if (open_socket(dut, s) < 0)
1176 return -2;
1177 }
1178
1179 for (i = 0; i < count; i++) {
1180 struct sigma_stream *s = get_stream(dut, streams[i]);
1181 int res;
1182
1183 if (!s)
1184 continue;
1185 /*
1186 * Provide dut context to the thread to support debugging and
1187 * returning of error messages. Similarly, provide interface
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +05301188 * information to the thread. If the Interface parameter is not
1189 * passed, get it from get_station_ifname() since the interface
1190 * name is needed for power save mode configuration for Uapsd
1191 * cases.
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001192 */
1193 s->dut = dut;
1194 val = get_param(cmd, "Interface");
Peng Xub8fc5cc2017-05-10 17:27:28 -07001195 strlcpy(s->ifname, (val ? val : get_station_ifname()),
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +05301196 sizeof(s->ifname));
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001197
1198 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start "
1199 "receive for stream %d", streams[i]);
1200 res = pthread_create(&s->thr, NULL, receive_thread, s);
1201 if (res) {
1202 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create "
1203 "failed: %d", res);
1204 return -2;
1205 }
1206 s->started = 1;
1207 }
1208
1209 return 1;
1210}
1211
1212
1213static void write_frame_stats(struct sigma_dut *dut, struct sigma_stream *s,
1214 int id)
1215{
1216 char fname[128];
1217 FILE *f;
1218 unsigned int i;
1219
1220 snprintf(fname, sizeof(fname), SIGMA_TMPDIR "/e2e%u-%d.txt",
1221 (unsigned int) time(NULL), id);
1222 f = fopen(fname, "w");
1223 if (f == NULL) {
1224 sigma_dut_print(dut, DUT_MSG_INFO, "Could not write %s",
1225 fname);
1226 return;
1227 }
1228 fprintf(f, "seqnum:local_sec:local_usec:remote_sec:remote_usec\n");
1229
1230 sigma_dut_print(dut, DUT_MSG_DEBUG, "Writing frame stats to %s",
1231 fname);
1232
1233 for (i = 0; i < s->num_stats; i++) {
1234 struct sigma_frame_stats *stats = &s->stats[i];
1235 fprintf(f, "%u:%u:%u:%u:%u\n", stats->seqnum,
1236 stats->local_sec, stats->local_usec,
1237 stats->remote_sec, stats->remote_usec);
1238 }
1239
1240 fclose(f);
1241}
1242
1243
1244static int cmd_traffic_agent_receive_stop(struct sigma_dut *dut,
1245 struct sigma_conn *conn,
1246 struct sigma_cmd *cmd)
1247{
1248 const char *val;
1249 int streams[MAX_SIGMA_STREAMS];
1250 int i, j, ret, count;
1251 char buf[100 + MAX_SIGMA_STREAMS * 60], *pos;
1252
1253 val = get_param(cmd, "streamID");
1254 if (val == NULL)
1255 return -1;
1256 count = get_stream_id(val, streams);
1257 if (count < 0)
1258 return -1;
1259 for (i = 0; i < count; i++) {
1260 struct sigma_stream *s = get_stream(dut, streams[i]);
1261
1262 if (!s) {
1263 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
1264 "not configured", streams[i]);
1265 send_resp(dut, conn, SIGMA_INVALID, buf);
1266 return 0;
1267 }
1268 for (j = 0; j < i; j++)
1269 if (streams[i] == streams[j])
1270 return -1;
1271 if (!s->started) {
1272 snprintf(buf, sizeof(buf), "errorCode,Receive not "
1273 "started for streamID %d", streams[i]);
1274 send_resp(dut, conn, SIGMA_INVALID, buf);
1275 return 0;
1276 }
1277 }
1278
1279 for (i = 0; i < count; i++) {
1280 struct sigma_stream *s = get_stream(dut, streams[i]);
1281
1282 if (s)
1283 s->stop = 1;
1284 }
1285
1286 for (i = 0; i < count; i++) {
1287 struct sigma_stream *s = get_stream(dut, streams[i]);
1288
1289 if (!s)
1290 continue;
1291 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: stop "
1292 "receive for stream %d", streams[i]);
1293 stop_stream(s);
1294 }
1295
1296 buf[0] = '\0';
1297 pos = buf;
1298
1299 pos += snprintf(pos, buf + sizeof(buf) - pos, "streamID,");
1300 for (i = 0; i < count; i++) {
1301 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1302 i > 0 ? " " : "", streams[i]);
1303 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1304 break;
1305 pos += ret;
1306 }
1307
1308 if (dut->program == PROGRAM_60GHZ) {
1309 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txActFrames,");
1310 for (i = 0; i < count; i++) {
1311 struct sigma_stream *s = get_stream(dut, streams[i]);
1312
1313 if (!s)
1314 continue;
1315 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1316 i > 0 ? " " : "", s->tx_act_frames);
1317 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1318 break;
1319 pos += ret;
1320 }
1321 }
1322
1323 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txFrames,");
1324 for (i = 0; i < count; i++) {
1325 struct sigma_stream *s = get_stream(dut, streams[i]);
1326
1327 if (!s)
1328 continue;
1329 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1330 i > 0 ? " " : "", s->tx_frames);
1331 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1332 break;
1333 pos += ret;
1334 }
1335
1336 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxFrames,");
1337 for (i = 0; i < count; i++) {
1338 struct sigma_stream *s = get_stream(dut, streams[i]);
1339
1340 if (!s)
1341 continue;
1342 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1343 i > 0 ? " " : "", s->rx_frames);
1344 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1345 break;
1346 pos += ret;
1347 }
1348
1349 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txPayloadBytes,");
1350 for (i = 0; i < count; i++) {
1351 struct sigma_stream *s = get_stream(dut, streams[i]);
1352
1353 if (!s)
1354 continue;
1355 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
1356 i > 0 ? " " : "", s->tx_payload_bytes);
1357 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1358 break;
1359 pos += ret;
1360 }
1361
1362 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxPayloadBytes,");
1363 for (i = 0; i < count; i++) {
1364 struct sigma_stream *s = get_stream(dut, streams[i]);
1365
1366 if (!s)
1367 continue;
1368 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
1369 i > 0 ? " " : "", s->rx_payload_bytes);
1370 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1371 break;
1372 pos += ret;
1373 }
1374
1375 pos += snprintf(pos, buf + sizeof(buf) - pos, ",outOfSequenceFrames,");
1376 for (i = 0; i < count; i++) {
1377 struct sigma_stream *s = get_stream(dut, streams[i]);
1378
1379 if (!s)
1380 continue;
1381 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1382 i > 0 ? " " : "", s->out_of_seq_frames);
1383 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1384 break;
1385 pos += ret;
1386 }
1387
1388 buf[sizeof(buf) - 1] = '\0';
1389
1390 send_resp(dut, conn, SIGMA_COMPLETE, buf);
1391
1392 for (i = 0; i < count; i++) {
1393 struct sigma_stream *s = get_stream(dut, streams[i]);
1394
1395 if (!s)
1396 continue;
1397 if (s->profile == SIGMA_PROFILE_IPTV && s->num_stats > 0 &&
1398 dut->write_stats)
1399 write_frame_stats(dut, s, streams[i]);
1400 free(s->stats);
1401 s->stats = NULL;
1402 s->num_stats = 0;
1403 }
1404
1405 return 0;
1406}
1407
1408
1409static int cmd_traffic_agent_version(struct sigma_dut *dut,
1410 struct sigma_conn *conn,
1411 struct sigma_cmd *cmd)
1412{
1413 send_resp(dut, conn, SIGMA_COMPLETE, "version,1.0");
1414 return 0;
1415}
1416
1417
1418void traffic_agent_register_cmds(void)
1419{
1420 sigma_dut_reg_cmd("traffic_agent_config", NULL,
1421 cmd_traffic_agent_config);
1422 sigma_dut_reg_cmd("traffic_agent_reset", NULL,
1423 cmd_traffic_agent_reset);
1424 sigma_dut_reg_cmd("traffic_agent_send", NULL,
1425 cmd_traffic_agent_send);
1426 sigma_dut_reg_cmd("traffic_agent_receive_start", NULL,
1427 cmd_traffic_agent_receive_start);
1428 sigma_dut_reg_cmd("traffic_agent_receive_stop", NULL,
1429 cmd_traffic_agent_receive_stop);
1430 sigma_dut_reg_cmd("traffic_agent_version", NULL,
1431 cmd_traffic_agent_version);
1432}