blob: 24387ba7c5fa5c8d8b6878f82b38c63fb86679fb [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 Malinencc6c5092019-02-19 12:51:08 +02005 * Copyright (c) 2018-2019, The Linux Foundation
Jouni Malinencd4e3c32015-10-29 12:39:56 +02006 * All Rights Reserved.
7 * Licensed under the Clear BSD license. See README for more details.
8 */
9
10#include "sigma_dut.h"
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +053011#include "wpa_helpers.h"
Jouni Malinencd4e3c32015-10-29 12:39:56 +020012
13#define TG_MAX_CLIENTS_CONNECTIONS 1
14
Purushottam Kushwahab7f56d42018-06-11 12:59:45 +053015/* To send periodic data for VO-Enterprise tests */
16extern int sigma_periodic_data;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020017
Jouni Malinencc6c5092019-02-19 12:51:08 +020018static enum sigma_cmd_result cmd_traffic_agent_config(struct sigma_dut *dut,
19 struct sigma_conn *conn,
20 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +020021{
22 struct sigma_stream *s;
23 const char *val;
24 char buf[100];
25
26 if (dut->num_streams == MAX_SIGMA_STREAMS) {
27 send_resp(dut, conn, SIGMA_ERROR, "errorCode,No more "
28 "concurrent traffic streams supported");
Jouni Malinencc6c5092019-02-19 12:51:08 +020029 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020030 }
31
32 s = &dut->streams[dut->num_streams];
33 free(s->stats);
34 memset(s, 0, sizeof(*s));
35 s->sock = -1;
36 s->no_timestamps = dut->no_timestamps;
37
38 val = get_param(cmd, "profile");
39 if (!val)
Jouni Malinencc6c5092019-02-19 12:51:08 +020040 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020041
42 if (strcasecmp(val, "File_Transfer") == 0)
43 s->profile = SIGMA_PROFILE_FILE_TRANSFER;
44 else if (strcasecmp(val, "Multicast") == 0)
45 s->profile = SIGMA_PROFILE_MULTICAST;
46 else if (strcasecmp(val, "IPTV") == 0)
47 s->profile = SIGMA_PROFILE_IPTV;
48 else if (strcasecmp(val, "Transaction") == 0)
49 s->profile = SIGMA_PROFILE_TRANSACTION;
50 else if (strcasecmp(val, "Start_Sync") == 0)
51 s->profile = SIGMA_PROFILE_START_SYNC;
52 else if (strcasecmp(val, "Uapsd") == 0)
53 s->profile = SIGMA_PROFILE_UAPSD;
54 else {
55 send_resp(dut, conn, SIGMA_INVALID, "errorCode,Unsupported "
56 "profile");
Jouni Malinencc6c5092019-02-19 12:51:08 +020057 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020058 }
59
60 val = get_param(cmd, "direction");
61 if (!val)
Jouni Malinencc6c5092019-02-19 12:51:08 +020062 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020063 if (strcasecmp(val, "send") == 0)
64 s->sender = 1;
65 else if (strcasecmp(val, "receive") == 0)
66 s->sender = 0;
67 else
Jouni Malinencc6c5092019-02-19 12:51:08 +020068 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +020069
70 val = get_param(cmd, "destination");
71 if (val) {
Peng Xu1b70c322018-06-26 16:40:14 -070072 if (!is_ipv6_addr(val)) {
73 if (inet_aton(val, &s->dst) == 0)
Jouni Malinencc6c5092019-02-19 12:51:08 +020074 return INVALID_SEND_STATUS;
Peng Xu1b70c322018-06-26 16:40:14 -070075 } else {
76 if (inet_pton(AF_INET6, val, &s->dst) != 1)
Jouni Malinencc6c5092019-02-19 12:51:08 +020077 return INVALID_SEND_STATUS;
Peng Xu1b70c322018-06-26 16:40:14 -070078 }
Jouni Malinencd4e3c32015-10-29 12:39:56 +020079 }
80
81 val = get_param(cmd, "source");
82 if (val) {
Peng Xu1b70c322018-06-26 16:40:14 -070083 if (!is_ipv6_addr(val)) {
84 if (inet_aton(val, &s->src) == 0)
Jouni Malinencc6c5092019-02-19 12:51:08 +020085 return INVALID_SEND_STATUS;
Peng Xu1b70c322018-06-26 16:40:14 -070086 } else {
87 if (inet_pton(AF_INET6, val, &s->src) != 1)
Jouni Malinencc6c5092019-02-19 12:51:08 +020088 return INVALID_SEND_STATUS;
Peng Xu1b70c322018-06-26 16:40:14 -070089 }
Jouni Malinencd4e3c32015-10-29 12:39:56 +020090 }
91
92 val = get_param(cmd, "destinationPort");
93 if (val)
94 s->dst_port = atoi(val);
95
96 val = get_param(cmd, "sourcePort");
97 if (val)
98 s->src_port = atoi(val);
99
100 val = get_param(cmd, "frameRate");
101 if (val)
102 s->frame_rate = atoi(val);
103
104 val = get_param(cmd, "duration");
105 if (val)
106 s->duration = atoi(val);
107
108 val = get_param(cmd, "payloadSize");
109 if (val)
110 s->payload_size = atoi(val);
111
112 val = get_param(cmd, "startDelay");
113 if (val)
114 s->start_delay = atoi(val);
115
116 val = get_param(cmd, "maxCnt");
117 if (val)
118 s->max_cnt = atoi(val);
119
120 val = get_param(cmd, "trafficClass");
121 if (val) {
122 if (strcasecmp(val, "Voice") == 0)
123 s->tc = SIGMA_TC_VOICE;
124 else if (strcasecmp(val, "Video") == 0)
125 s->tc = SIGMA_TC_VIDEO;
126 else if (strcasecmp(val, "Background") == 0)
127 s->tc = SIGMA_TC_BACKGROUND;
128 else if (strcasecmp(val, "BestEffort") == 0)
129 s->tc = SIGMA_TC_BEST_EFFORT;
130 else
Jouni Malinencc6c5092019-02-19 12:51:08 +0200131 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200132 }
133
134 val = get_param(cmd, "userpriority");
135 if (val) {
136 s->user_priority_set = 1;
137 s->user_priority = atoi(val);
138 }
139
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530140 val = get_param(cmd, "tagName");
141 if (val) {
Peng Xub8fc5cc2017-05-10 17:27:28 -0700142 strlcpy(s->test_name, val, sizeof(s->test_name));
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530143 sigma_dut_print(dut, DUT_MSG_DEBUG,
144 "Traffic agent: U-APSD console tagname %s",
145 s->test_name);
146 }
147
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200148 if (dut->throughput_pktsize && s->frame_rate == 0 && s->sender &&
149 dut->throughput_pktsize != s->payload_size &&
150 (s->profile == SIGMA_PROFILE_FILE_TRANSFER ||
151 s->profile == SIGMA_PROFILE_IPTV ||
152 s->profile == SIGMA_PROFILE_UAPSD)) {
Jouni Malinenc2493f82016-06-05 18:01:33 +0300153 sigma_dut_print(dut, DUT_MSG_INFO,
154 "Traffic agent: Override throughput test payload size %u -> %u",
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200155 s->payload_size, dut->throughput_pktsize);
156 s->payload_size = dut->throughput_pktsize;
157 }
158
159 val = get_param(cmd, "transProtoType");
160 if (val) {
161 if (strcmp(val, "1") == 0)
162 s->trans_proto = IPPROTO_TCP;
163 else if (strcmp(val, "0") == 0)
164 s->trans_proto = IPPROTO_UDP;
165 else
Jouni Malinencc6c5092019-02-19 12:51:08 +0200166 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200167 } else {
168 s->trans_proto = IPPROTO_UDP;
169 }
170
171 if (s->profile == SIGMA_PROFILE_IPTV && !s->sender && !s->no_timestamps)
172 {
173 s->stats = calloc(MAX_SIGMA_STATS,
174 sizeof(struct sigma_frame_stats));
175 if (s->stats == NULL)
Jouni Malinencc6c5092019-02-19 12:51:08 +0200176 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200177 }
178
179 dut->stream_id++;
180 dut->num_streams++;
181
182 s->stream_id = dut->stream_id;
183 snprintf(buf, sizeof(buf), "streamID,%d", s->stream_id);
184 send_resp(dut, conn, SIGMA_COMPLETE, buf);
Jouni Malinencc6c5092019-02-19 12:51:08 +0200185 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200186}
187
188
189static void stop_stream(struct sigma_stream *s)
190{
191 if (s && s->started) {
192 pthread_join(s->thr, NULL);
193 if (s->sock != -1) {
194 close(s->sock);
195 s->sock = -1;
196 }
197
198 s->started = 0;
199 }
200}
201
202
Jouni Malinencc6c5092019-02-19 12:51:08 +0200203static enum sigma_cmd_result cmd_traffic_agent_reset(struct sigma_dut *dut,
204 struct sigma_conn *conn,
205 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200206{
207 int i;
208 for (i = 0; i < dut->num_streams; i++) {
209 struct sigma_stream *s = &dut->streams[i];
210 s->stop = 1;
211 stop_stream(s);
212 }
213 dut->num_streams = 0;
214 memset(&dut->streams, 0, sizeof(dut->streams));
Jouni Malinencc6c5092019-02-19 12:51:08 +0200215 return SUCCESS_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200216}
217
218
219static int get_stream_id(const char *str, int streams[MAX_SIGMA_STREAMS])
220{
221 int count;
222
223 count = 0;
224 for (;;) {
225 if (count == MAX_SIGMA_STREAMS)
226 return -1;
227 streams[count] = atoi(str);
228 if (streams[count] == 0)
229 return -1;
230 count++;
231 str = strchr(str, ' ');
232 if (str == NULL)
233 break;
234 while (*str == ' ')
235 str++;
236 }
237
238 return count;
239}
240
241
242static int open_socket_file_transfer(struct sigma_dut *dut,
243 struct sigma_stream *s)
244{
245 struct sockaddr_in addr;
246 int sock_opt_val = 1;
247
248 s->sock = socket(PF_INET, IPPROTO_UDP == s->trans_proto ? SOCK_DGRAM :
249 SOCK_STREAM, s->trans_proto);
250 if (s->sock < 0) {
251 perror("socket");
252 return -1;
253 }
254
255 if (setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &sock_opt_val,
256 sizeof(sock_opt_val)) < 0) {
257 perror("setsockopt");
258 close(s->sock);
259 s->sock = -1;
260 return -1;
261 }
262
263 memset(&addr, 0, sizeof(addr));
264 addr.sin_family = AF_INET;
265 addr.sin_port = htons(s->sender ? s->src_port : s->dst_port);
266 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: sender=%d "
267 "bind port %d", s->sender, ntohs(addr.sin_port));
268 if (bind(s->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
269 perror("bind");
270 close(s->sock);
271 s->sock = -1;
272 return -1;
273 }
274
275 if (s->profile == SIGMA_PROFILE_MULTICAST && !s->sender)
276 return 0;
277
278 if (s->trans_proto == IPPROTO_TCP && s->sender == 0) {
279 if (listen(s->sock, TG_MAX_CLIENTS_CONNECTIONS ) < 0) {
280 sigma_dut_print(dut, DUT_MSG_INFO,
281 "Listen failed with error %d: %s",
282 errno, strerror(errno));
283 close(s->sock);
284 s->sock = -1;
285 return -1;
286 }
287 } else {
288 memset(&addr, 0, sizeof(addr));
289 addr.sin_family = AF_INET;
290 addr.sin_addr.s_addr = s->sender ? s->dst.s_addr :
291 s->src.s_addr;
292 addr.sin_port = htons(s->sender ? s->dst_port : s->src_port);
293 sigma_dut_print(dut, DUT_MSG_DEBUG,
294 "Traffic agent: connect %s:%d",
295 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
296 if (connect(s->sock, (struct sockaddr *) &addr, sizeof(addr)) <
297 0) {
298 perror("connect");
299 close(s->sock);
300 s->sock = -1;
301 return -1;
302 }
303 }
304
305 return 0;
306}
307
308
309static int open_socket_multicast(struct sigma_dut *dut, struct sigma_stream *s)
310{
311 if (open_socket_file_transfer(dut, s) < 0)
312 return -1;
313
314 if (!s->sender) {
315 struct ip_mreq mr;
316 memset(&mr, 0, sizeof(mr));
317 mr.imr_multiaddr.s_addr = s->dst.s_addr;
318 mr.imr_interface.s_addr = htonl(INADDR_ANY);
319 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: "
320 "IP_ADD_MEMBERSHIP %s", inet_ntoa(s->dst));
321 if (setsockopt(s->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
322 (void *) &mr, sizeof(mr)) < 0) {
323 sigma_dut_print(dut, DUT_MSG_INFO,
324 "setsockopt[IP_ADD_MEMBERSHIP]: %s",
325 strerror(errno));
326 /*
327 * Continue anyway since this can happen, e.g., if the
328 * default route is missing. This is not critical for
329 * multicast RX testing.
330 */
331 }
332 }
333
334 return 0;
335}
336
337
338static int set_socket_prio(struct sigma_stream *s)
339{
340 int tos = 0x00;
341
342 switch (s->tc) {
343 case SIGMA_TC_VOICE:
344 if (s->user_priority_set) {
345 if (s->user_priority == 6)
Sunil Dutt6d7c88c2020-06-24 16:14:06 +0530346 tos = 46 << 2;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200347 else if (s->user_priority == 7)
348 tos = 56 << 2;
349 else
350 return -1;
351 } else
352 tos = 0xe0; /* DSCP = 56 */
353 break;
354 case SIGMA_TC_VIDEO:
355 if (s->user_priority_set) {
356 if (s->user_priority == 4)
357 tos = 32 << 2;
358 else if (s->user_priority == 5)
359 tos = 40 << 2;
360 else
361 return -1;
362 } else
363 tos = 0xa0; /* DSCP = 40 */
364 break;
365 case SIGMA_TC_BACKGROUND:
366 if (s->user_priority_set) {
367 if (s->user_priority == 1)
368 tos = 8 << 2;
369 else if (s->user_priority == 2)
370 tos = 16 << 2;
371 else
372 return -1;
373 } else
374 tos = 0x20; /* DSCP = 8 */
375 break;
376 case SIGMA_TC_BEST_EFFORT:
377 if (s->user_priority_set) {
378 if (s->user_priority == 0)
379 tos = 0 << 2;
380 else if (s->user_priority == 3)
381 tos = 20 << 2;
382 else
383 return -1;
384 } else
385 tos = 0x00; /* DSCP = 0 */
386 break;
387 }
388
389 if (setsockopt(s->sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) {
390 perror("setsockopt");
391 return -1;
392 }
393
394 return 0;
395}
396
397
398static int open_socket(struct sigma_dut *dut, struct sigma_stream *s)
399{
400 switch (s->profile) {
401 case SIGMA_PROFILE_FILE_TRANSFER:
402 return open_socket_file_transfer(dut, s);
403 case SIGMA_PROFILE_MULTICAST:
404 return open_socket_multicast(dut, s);
405 case SIGMA_PROFILE_IPTV:
406 if (open_socket_file_transfer(dut, s) < 0)
407 return -1;
408 return set_socket_prio(s);
409 case SIGMA_PROFILE_TRANSACTION:
410 return open_socket_file_transfer(dut, s);
411 case SIGMA_PROFILE_UAPSD:
412 return open_socket_file_transfer(dut, s);
413 case SIGMA_PROFILE_START_SYNC:
414 sigma_dut_print(dut, DUT_MSG_INFO, "Traffic stream profile %d "
415 "not yet supported", s->profile);
416 /* TODO */
417 break;
418 }
419
420 return -1;
421}
422
423
424static void send_file_fast(struct sigma_stream *s, char *pkt)
425{
426 struct timeval stop, now;
427 int res;
428 unsigned int counter = 0;
429
430 gettimeofday(&stop, NULL);
431 stop.tv_sec += s->duration;
432
433 while (!s->stop) {
434 counter++;
435 WPA_PUT_BE32(&pkt[8], counter);
436
437 if ((counter & 0xf) == 0) {
438 gettimeofday(&now, NULL);
439 if (now.tv_sec > stop.tv_sec ||
440 (now.tv_sec == stop.tv_sec &&
441 now.tv_usec >= stop.tv_usec))
442 break;
443 }
444
445 s->tx_act_frames++;
Arif Hussain04fbea72018-11-08 17:15:11 -0800446 res = send(s->sock, pkt, s->payload_size, MSG_DONTWAIT);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200447 if (res >= 0) {
448 s->tx_frames++;
449 s->tx_payload_bytes += res;
450 } else {
451 switch (errno) {
452 case EAGAIN:
453 case ENOBUFS:
454 usleep(1000);
455 break;
456 case ECONNRESET:
457 case EPIPE:
458 s->stop = 1;
459 break;
460 default:
461 perror("send");
462 break;
463 }
464 }
465 }
466}
467
468
469static void send_file(struct sigma_stream *s)
470{
471 char *pkt;
472 struct timeval stop, now, start;
473 int res;
vamsi krishna2c650812016-05-16 17:43:22 +0530474 unsigned int counter = 0, total_sleep_usec = 0, total_pkts;
475 int sleep_usec = 0;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200476
477 if (s->duration <= 0 || s->frame_rate < 0 || s->payload_size < 20)
478 return;
479
480 pkt = malloc(s->payload_size);
481 if (pkt == NULL)
482 return;
483 memset(pkt, 1, s->payload_size);
Peng Xub8fc5cc2017-05-10 17:27:28 -0700484 strlcpy(pkt, "1345678", s->payload_size);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200485
486 if (s->frame_rate == 0 && s->no_timestamps) {
487 send_file_fast(s, pkt);
488 free(pkt);
489 return;
490 }
491
492 gettimeofday(&stop, NULL);
493 stop.tv_sec += s->duration;
494
vamsi krishna2c650812016-05-16 17:43:22 +0530495 total_pkts = s->duration * s ->frame_rate;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200496
497 gettimeofday(&start, NULL);
498
499 while (!s->stop) {
500 counter++;
501 WPA_PUT_BE32(&pkt[8], counter);
502
vamsi krishna2c650812016-05-16 17:43:22 +0530503 if (sleep_usec) {
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200504 usleep(sleep_usec);
vamsi krishna2c650812016-05-16 17:43:22 +0530505 total_sleep_usec += sleep_usec;
506 }
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200507
508 gettimeofday(&now, NULL);
509 if (now.tv_sec > stop.tv_sec ||
510 (now.tv_sec == stop.tv_sec && now.tv_usec >= stop.tv_usec))
511 break;
512
vamsi krishna2c650812016-05-16 17:43:22 +0530513 if (s->frame_rate && (unsigned int) s->tx_frames >= total_pkts)
514 break;
515
516 if (s->frame_rate == 0 || s->tx_frames == 0)
517 sleep_usec = 0;
518 else if (sleep_usec || s->frame_rate < 10 ||
519 counter % (s->frame_rate / 10) == 0) {
520 /* Recalculate sleep_usec for every 100 ms approximately
521 */
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200522 struct timeval tmp;
vamsi krishna2c650812016-05-16 17:43:22 +0530523 int diff, duration;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200524
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200525 timersub(&now, &start, &tmp);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200526
vamsi krishna2c650812016-05-16 17:43:22 +0530527 diff = tmp.tv_sec * 1000000 + tmp.tv_usec;
528 duration = (1000000 / s->frame_rate) * s->tx_frames;
529
530 if (duration > diff)
531 sleep_usec = (total_sleep_usec +
532 (duration - diff)) / s->tx_frames;
533 else
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200534 sleep_usec = 0;
535 }
536
537 WPA_PUT_BE32(&pkt[12], now.tv_sec);
538 WPA_PUT_BE32(&pkt[16], now.tv_usec);
539
540 s->tx_act_frames++;
Arif Hussain04fbea72018-11-08 17:15:11 -0800541 res = send(s->sock, pkt, s->payload_size, MSG_DONTWAIT);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200542 if (res >= 0) {
543 s->tx_frames++;
544 s->tx_payload_bytes += res;
545 } else {
546 switch (errno) {
547 case EAGAIN:
548 case ENOBUFS:
549 usleep(1000);
550 break;
551 case ECONNRESET:
552 case EPIPE:
553 s->stop = 1;
554 break;
555 default:
556 perror("send");
557 break;
558 }
559 }
560 }
561
vamsi krishna2c650812016-05-16 17:43:22 +0530562 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
563 "send_file: counter %u s->tx_frames %d total_sleep_usec %u",
564 counter, s->tx_frames, total_sleep_usec);
565
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200566 free(pkt);
567}
568
Purushottam Kushwahab7f56d42018-06-11 12:59:45 +0530569static void send_periodic_data(struct sigma_stream *s)
570{
571 char *pkt;
572 struct timeval stop, now, start;
573 int res;
574 unsigned int counter = 0, total_sleep_usec = 0, total_pkts;
575 int sleep_usec = 0;
576
577 if (s->duration <= 0 || s->frame_rate < 0 || s->payload_size < 20)
578 return;
579
580 pkt = malloc(s->payload_size);
581 if (pkt == NULL)
582 return;
583 memset(pkt, 1, s->payload_size);
Purushottam Kushwaha74459f12018-06-29 11:32:52 +0530584 strlcpy(pkt, "1345678", s->payload_size);
Purushottam Kushwahab7f56d42018-06-11 12:59:45 +0530585
586 if (s->frame_rate == 0 && s->no_timestamps) {
587 send_file_fast(s, pkt);
588 free(pkt);
589 return;
590 }
591
592 gettimeofday(&stop, NULL);
593 stop.tv_sec += s->duration;
594
595 total_pkts = s->duration * s->frame_rate;
596
597 gettimeofday(&start, NULL);
598 while (!s->stop) {
599 counter++;
600 WPA_PUT_BE32(&pkt[8], counter);
601
602 if (sleep_usec) {
603 usleep(sleep_usec);
604 total_sleep_usec += sleep_usec;
605 }
606 gettimeofday(&now, NULL);
607
608 if (now.tv_sec > stop.tv_sec ||
609 (now.tv_sec == stop.tv_sec && now.tv_usec >= stop.tv_usec))
610 break;
611
612 if (s->frame_rate && (unsigned int) s->tx_frames >= total_pkts)
613 break;
614
615 WPA_PUT_BE32(&pkt[12], now.tv_sec);
616 WPA_PUT_BE32(&pkt[16], now.tv_usec);
617
618 s->tx_act_frames++;
619 res = send(s->sock, pkt, s->payload_size, 0);
620 if (res >= 0) {
621 s->tx_frames++;
622 s->tx_payload_bytes += res;
623 } else {
624 switch (errno) {
625 case EAGAIN:
626 case ENOBUFS:
627 usleep(1000);
628 break;
629 case ECONNRESET:
630 case EPIPE:
631 s->stop = 1;
632 break;
633 default:
634 perror("send");
635 break;
636 }
637 }
638
639 if (s->frame_rate == 0)
640 sleep_usec = 0;
641 else {
642 struct timeval tmp;
643 int diff, duration, pkt_spacing;
644
645 gettimeofday(&now, NULL);
646 timersub(&now, &start, &tmp);
647
648 pkt_spacing = 1000000 / s->frame_rate ;
649 diff = tmp.tv_sec * 1000000 + tmp.tv_usec;
650 duration = (pkt_spacing) * s->tx_frames;
651
652 if (duration > diff) {
653 if ((duration - diff) > pkt_spacing)
654 sleep_usec = (total_sleep_usec +
655 (duration - diff)) / s->tx_frames;
656 else
657 sleep_usec = duration - diff;
658 } else {
659 sleep_usec = 0;
660 }
661 }
662 }
663
664 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
665 "send_periodic_data: counter %u s->tx_frames %d total_sleep_usec %u",
666 counter, s->tx_frames, total_sleep_usec);
667
668 free(pkt);
669}
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200670
671static void send_transaction(struct sigma_stream *s)
672{
673 char *pkt, *rpkt;
674 struct timeval stop, now;
675 int res;
676 unsigned int counter = 0, rcounter;
677 int wait_time;
678 fd_set rfds;
679 struct timeval tv;
680
681 if (s->duration <= 0 || s->frame_rate <= 0 || s->payload_size < 20)
682 return;
683
684 pkt = malloc(s->payload_size);
685 if (pkt == NULL)
686 return;
687 rpkt = malloc(s->payload_size);
688 if (rpkt == NULL) {
689 free(pkt);
690 return;
691 }
692 memset(pkt, 1, s->payload_size);
Peng Xub8fc5cc2017-05-10 17:27:28 -0700693 strlcpy(pkt, "1345678", s->payload_size);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200694
695 gettimeofday(&stop, NULL);
696 stop.tv_sec += s->duration;
697
698 wait_time = 1000000 / s->frame_rate;
699
700 while (!s->stop) {
701 counter++;
702 if (s->max_cnt && (int) counter > s->max_cnt)
703 break;
704 WPA_PUT_BE32(&pkt[8], counter);
705
706 gettimeofday(&now, NULL);
707 if (now.tv_sec > stop.tv_sec ||
708 (now.tv_sec == stop.tv_sec && now.tv_usec >= stop.tv_usec))
709 break;
710 WPA_PUT_BE32(&pkt[12], now.tv_sec);
711 WPA_PUT_BE32(&pkt[16], now.tv_usec);
712
Arif Hussain04fbea72018-11-08 17:15:11 -0800713 res = send(s->sock, pkt, s->payload_size, MSG_DONTWAIT);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200714 if (res >= 0) {
715 s->tx_frames++;
716 s->tx_payload_bytes += res;
717 } else {
718 switch (errno) {
719 case EAGAIN:
720 case ENOBUFS:
721 usleep(1000);
722 break;
723 case ECONNRESET:
724 case EPIPE:
725 s->stop = 1;
726 break;
727 default:
728 perror("send");
729 break;
730 }
731 }
732
733 /* Wait for response */
734 tv.tv_sec = 0;
735 tv.tv_usec = wait_time;
736 FD_ZERO(&rfds);
737 FD_SET(s->sock, &rfds);
738 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
739 if (res < 0) {
740 if (errno == EINTR)
741 continue;
742 perror("select");
743 break;
744 }
745
746 if (res == 0) {
747 /* timeout */
748 continue;
749 }
750
751 if (FD_ISSET(s->sock, &rfds)) {
752 /* response received */
753 res = recv(s->sock, rpkt, s->payload_size, 0);
754 if (res < 0) {
755 perror("recv");
756 break;
757 }
758 rcounter = WPA_GET_BE32(&rpkt[8]);
759 if (rcounter != counter)
760 s->out_of_seq_frames++;
761 s->rx_frames++;
762 s->rx_payload_bytes += res;
763 }
764 }
765
766 free(pkt);
767 free(rpkt);
768}
769
770
771static void * send_thread(void *ctx)
772{
773 struct sigma_stream *s = ctx;
774
775 sleep(s->start_delay);
776
777 switch (s->profile) {
778 case SIGMA_PROFILE_FILE_TRANSFER:
779 send_file(s);
780 break;
781 case SIGMA_PROFILE_MULTICAST:
782 send_file(s);
783 break;
784 case SIGMA_PROFILE_IPTV:
Purushottam Kushwahab7f56d42018-06-11 12:59:45 +0530785 if (sigma_periodic_data)
786 send_periodic_data(s);
787 else
788 send_file(s);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200789 break;
790 case SIGMA_PROFILE_TRANSACTION:
791 send_transaction(s);
792 break;
793 case SIGMA_PROFILE_START_SYNC:
794 break;
795 case SIGMA_PROFILE_UAPSD:
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +0530796 send_uapsd_console(s);
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200797 break;
798 }
799
800 return NULL;
801}
802
803
804struct traffic_agent_send_data {
805 struct sigma_dut *dut;
806 struct sigma_conn *conn;
807 int streams[MAX_SIGMA_STREAMS];
808 int count;
809};
810
811
812static struct sigma_stream * get_stream(struct sigma_dut *dut, int id)
813{
814 int i;
815
816 for (i = 0; i < dut->num_streams; i++) {
817 if ((unsigned int) id == dut->streams[i].stream_id)
818 return &dut->streams[i];
819 }
820
821 return NULL;
822}
823
824
825static void * send_report_thread(void *ctx)
826{
827 struct traffic_agent_send_data *data = ctx;
828 struct sigma_dut *dut = data->dut;
829 struct sigma_conn *conn = data->conn;
830 int i, ret;
831 char buf[100 + MAX_SIGMA_STREAMS * 60], *pos;
832
833 for (i = 0; i < data->count; i++) {
834 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: waiting "
835 "for stream %d send to complete",
836 data->streams[i]);
837 stop_stream(get_stream(dut, data->streams[i]));
838 }
839
840 buf[0] = '\0';
841 pos = buf;
842
843 pos += snprintf(pos, buf + sizeof(buf) - pos, "streamID,");
844 for (i = 0; i < data->count; i++) {
845 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
846 i > 0 ? " " : "", data->streams[i]);
847 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
848 break;
849 pos += ret;
850 }
851
852 if (dut->program == PROGRAM_60GHZ) {
853 sigma_dut_print(dut, DUT_MSG_INFO, "reporting tx_act_frames");
854 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txActFrames,");
855 for (i = 0; i < data->count; i++) {
856 struct sigma_stream *s;
857
858 s = get_stream(dut, data->streams[i]);
859 if (!s)
860 continue;
861 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
862 i > 0 ? " " : "", s->tx_act_frames);
863 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
864 break;
865 pos += ret;
866 }
867 }
868
869 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txFrames,");
870 for (i = 0; i < data->count; i++) {
871 struct sigma_stream *s = get_stream(dut, data->streams[i]);
872
873 if (!s)
874 continue;
875 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
876 i > 0 ? " " : "", s->tx_frames);
877 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
878 break;
879 pos += ret;
880 }
881
882 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxFrames,");
883 for (i = 0; i < data->count; i++) {
884 struct sigma_stream *s = get_stream(dut, data->streams[i]);
885
886 if (!s)
887 continue;
888 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
889 i > 0 ? " " : "", s->rx_frames);
890 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
891 break;
892 pos += ret;
893 }
894
895 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txPayloadBytes,");
896 for (i = 0; i < data->count; i++) {
897 struct sigma_stream *s = get_stream(dut, data->streams[i]);
898
899 if (!s)
900 continue;
901 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
902 i > 0 ? " " : "", s->tx_payload_bytes);
903 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
904 break;
905 pos += ret;
906 }
907
908 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxPayloadBytes,");
909 for (i = 0; i < data->count; i++) {
910 struct sigma_stream *s = get_stream(dut, data->streams[i]);
911
912 if (!s)
913 continue;
914 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
915 i > 0 ? " " : "", s->rx_payload_bytes);
916 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
917 break;
918 pos += ret;
919 }
920
921 pos += snprintf(pos, buf + sizeof(buf) - pos, ",outOfSequenceFrames,");
922 for (i = 0; i < data->count; i++) {
923 struct sigma_stream *s = get_stream(dut, data->streams[i]);
924
925 if (!s)
926 continue;
927 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
928 i > 0 ? " " : "", s->out_of_seq_frames);
929 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
930 break;
931 pos += ret;
932 }
933
934 for (i = 0; i < data->count; i++) {
935 struct sigma_stream *s = get_stream(dut, data->streams[i]);
936 if (!s)
937 continue;
938 s->ta_send_in_progress = 0;
939 if (s->trans_proto == IPPROTO_TCP) {
940 /*
941 * Close the socket to make sure client side close the
942 * network before the server. Otherwise, the server
943 * might get "Address already in use" when trying to
944 * reuse the port.
945 */
946 close(s->sock);
947 s->sock = -1;
948 sigma_dut_print(dut, DUT_MSG_DEBUG,
949 "Closed the sender socket");
950 }
951 }
952
953 buf[sizeof(buf) - 1] = '\0';
954
955 if (conn->s < 0)
956 sigma_dut_print(dut, DUT_MSG_INFO, "Cannot send traffic_agent response since control socket has already been closed");
957 else
958 send_resp(dut, conn, SIGMA_COMPLETE, buf);
959 conn->waiting_completion = 0;
960
961 free(data);
962
963 return NULL;
964}
965
966
Jouni Malinencc6c5092019-02-19 12:51:08 +0200967static enum sigma_cmd_result cmd_traffic_agent_send(struct sigma_dut *dut,
968 struct sigma_conn *conn,
969 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200970{
971 const char *val;
972 int i, j, res;
973 char buf[100];
974 struct traffic_agent_send_data *data;
975
976 val = get_param(cmd, "streamID");
977 if (val == NULL)
Jouni Malinencc6c5092019-02-19 12:51:08 +0200978 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200979
980 data = calloc(1, sizeof(*data));
981 if (data == NULL)
Jouni Malinencc6c5092019-02-19 12:51:08 +0200982 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200983 data->dut = dut;
984 data->conn = conn;
985
986 data->count = get_stream_id(val, data->streams);
987 if (data->count < 0) {
988 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +0200989 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +0200990 }
991 for (i = 0; i < data->count; i++) {
992 struct sigma_stream *s = get_stream(dut, data->streams[i]);
993
994 if (!s) {
995 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
996 "not configured", data->streams[i]);
997 send_resp(dut, conn, SIGMA_INVALID, buf);
998 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +0200999 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001000 }
1001 for (j = 0; j < i; j++)
Srikanth Marepalliab1fbf72018-08-27 12:53:11 +05301002 if (data->streams[i] == data->streams[j]) {
1003 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001004 return ERROR_SEND_STATUS;
Srikanth Marepalliab1fbf72018-08-27 12:53:11 +05301005 }
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001006 if (!s->sender) {
1007 snprintf(buf, sizeof(buf), "errorCode,Not configured "
1008 "as sender for streamID %d", data->streams[i]);
1009 send_resp(dut, conn, SIGMA_INVALID, buf);
1010 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001011 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001012 }
1013 if (s->ta_send_in_progress) {
1014 send_resp(dut, conn, SIGMA_ERROR,
1015 "errorCode,Multiple concurrent send cmds on same streamID not supported");
1016 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001017 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001018 }
1019 }
1020
1021 for (i = 0; i < data->count; i++) {
1022 struct sigma_stream *s = get_stream(dut, data->streams[i]);
1023
1024 if (!s)
1025 continue;
1026 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: open "
1027 "socket for send stream %d", data->streams[i]);
1028 if (open_socket(dut, s) < 0) {
1029 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001030 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001031 }
1032 }
1033
1034 for (i = 0; i < data->count; i++) {
1035 struct sigma_stream *s = get_stream(dut, data->streams[i]);
1036
1037 if (!s)
1038 continue;
Pradeep Reddy POTTETI79594042015-11-23 12:59:12 +05301039
1040 /*
1041 * Provide dut context to the thread to support debugging and
1042 * returning of error messages.
1043 */
1044 s->dut = dut;
1045
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001046 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start "
1047 "send for stream %d", data->streams[i]);
1048 res = pthread_create(&s->thr, NULL, send_thread, s);
1049 if (res) {
1050 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create "
1051 "failed: %d", res);
1052 free(data);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001053 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001054 }
1055 s->started = 1;
1056 }
1057
1058 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start a thread to track sending streams");
1059 conn->waiting_completion = 1;
1060 res = pthread_create(&dut->thr, NULL, send_report_thread, data);
1061 if (res) {
1062 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create failed: %d",
1063 res);
1064 free(data);
1065 conn->waiting_completion = 0;
Jouni Malinencc6c5092019-02-19 12:51:08 +02001066 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001067 }
1068
1069 for (i = 0; i < data->count; i++) {
1070 struct sigma_stream *s = get_stream(dut, data->streams[i]);
1071
1072 if (s)
1073 s->ta_send_in_progress = 1;
1074 }
1075
1076 /* Command will be completed in send_report_thread() */
1077
Jouni Malinencc6c5092019-02-19 12:51:08 +02001078 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001079}
1080
1081
1082static void receive_file(struct sigma_stream *s)
1083{
1084 struct timeval tv, now;
1085 fd_set rfds;
1086 int res;
1087 char *pkt;
1088 int pktlen;
1089 unsigned int last_rx = 0, counter;
1090
1091 pktlen = 65536 + 1;
1092 pkt = malloc(pktlen);
1093 if (pkt == NULL)
1094 return;
1095
1096 while (!s->stop) {
1097 FD_ZERO(&rfds);
1098 FD_SET(s->sock, &rfds);
1099 tv.tv_sec = 0;
1100 tv.tv_usec = 300000;
1101 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
1102 if (res < 0) {
1103 perror("select");
1104 usleep(10000);
1105 } else if (FD_ISSET(s->sock, &rfds)) {
1106 res = recv(s->sock, pkt, pktlen, 0);
1107 if (res >= 0) {
1108 s->rx_frames++;
1109 s->rx_payload_bytes += res;
1110
1111 counter = WPA_GET_BE32(&pkt[8]);
1112 if (counter < last_rx)
1113 s->out_of_seq_frames++;
1114 last_rx = counter;
1115 } else {
1116 perror("recv");
1117 break;
1118 }
1119
1120 if (res >= 20 && s->stats &&
1121 s->num_stats < MAX_SIGMA_STATS) {
1122 struct sigma_frame_stats *stats;
1123 stats = &s->stats[s->num_stats];
1124 s->num_stats++;
1125 gettimeofday(&now, NULL);
1126 stats->seqnum = counter;
1127 stats->local_sec = now.tv_sec;
1128 stats->local_usec = now.tv_usec;
1129 stats->remote_sec = WPA_GET_BE32(&pkt[12]);
1130 stats->remote_usec = WPA_GET_BE32(&pkt[16]);
1131 }
1132 }
1133 }
1134
1135 free(pkt);
1136}
1137
1138
1139static void receive_transaction(struct sigma_stream *s)
1140{
1141 struct timeval tv;
1142 fd_set rfds;
1143 int res;
1144 char *pkt;
1145 int pktlen;
1146 unsigned int last_rx = 0, counter;
1147 struct sockaddr_in addr;
1148 socklen_t addrlen;
1149
1150 if (s->payload_size)
1151 pktlen = s->payload_size;
1152 else
1153 pktlen = 65536 + 1;
1154 pkt = malloc(pktlen);
1155 if (pkt == NULL)
1156 return;
1157
1158 while (!s->stop) {
1159 FD_ZERO(&rfds);
1160 FD_SET(s->sock, &rfds);
1161 tv.tv_sec = 0;
1162 tv.tv_usec = 300000;
1163 res = select(s->sock + 1, &rfds, NULL, NULL, &tv);
1164 if (res < 0) {
1165 perror("select");
1166 usleep(10000);
1167 } else if (FD_ISSET(s->sock, &rfds)) {
1168 addrlen = sizeof(addr);
1169 res = recvfrom(s->sock, pkt, pktlen, 0,
1170 (struct sockaddr *) &addr, &addrlen);
1171 if (res < 0) {
1172 perror("recv");
1173 break;
1174 }
1175
1176 s->rx_frames++;
1177 s->rx_payload_bytes += res;
1178
1179 counter = WPA_GET_BE32(&pkt[8]);
1180 if (counter < last_rx)
1181 s->out_of_seq_frames++;
1182 last_rx = counter;
1183
1184 /* send response */
1185 res = sendto(s->sock, pkt, pktlen, 0,
1186 (struct sockaddr *) &addr, addrlen);
1187 if (res < 0) {
1188 perror("sendto");
1189 } else {
1190 s->tx_frames++;
1191 s->tx_payload_bytes += res;
1192 }
1193 }
1194 }
1195
1196 free(pkt);
1197}
1198
1199
1200static void * receive_thread(void *ctx)
1201{
1202 struct sigma_stream *s = ctx;
1203
1204 if (s->trans_proto == IPPROTO_TCP) {
1205 /* Wait for socket to be accepted */
1206 struct sockaddr_in connected_addr;
1207 int connected_sock; /* returned from accept on sock */
1208 socklen_t connected_addr_len = sizeof(connected_addr);
1209
1210 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
1211 "Traffic agent: Waiting on accept");
1212 connected_sock = accept(s->sock,
1213 (struct sockaddr *) &connected_addr,
1214 &connected_addr_len);
1215 if (connected_sock < 0) {
1216 sigma_dut_print(s->dut, DUT_MSG_ERROR,
1217 "Traffic agent: Failed to accept: %s",
1218 strerror(errno));
1219 return NULL;
1220 }
1221
1222 sigma_dut_print(s->dut, DUT_MSG_DEBUG,
1223 "Traffic agent: Accepted client closing parent socket and talk over connected sock.");
1224 close(s->sock);
1225 s->sock = connected_sock;
1226 }
1227
1228 switch (s->profile) {
1229 case SIGMA_PROFILE_FILE_TRANSFER:
1230 receive_file(s);
1231 break;
1232 case SIGMA_PROFILE_MULTICAST:
1233 receive_file(s);
1234 break;
1235 case SIGMA_PROFILE_IPTV:
1236 receive_file(s);
1237 break;
1238 case SIGMA_PROFILE_TRANSACTION:
1239 receive_transaction(s);
1240 break;
1241 case SIGMA_PROFILE_START_SYNC:
1242 break;
1243 case SIGMA_PROFILE_UAPSD:
1244 receive_uapsd(s);
1245 break;
1246 }
1247
1248 return NULL;
1249}
1250
1251
Jouni Malinencc6c5092019-02-19 12:51:08 +02001252static enum sigma_cmd_result
1253cmd_traffic_agent_receive_start(struct sigma_dut *dut, struct sigma_conn *conn,
1254 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001255{
1256 const char *val;
1257 int streams[MAX_SIGMA_STREAMS];
1258 int i, j, count;
1259 char buf[100];
1260
1261 val = get_param(cmd, "streamID");
1262 if (val == NULL)
Jouni Malinencc6c5092019-02-19 12:51:08 +02001263 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001264 count = get_stream_id(val, streams);
1265 if (count < 0)
Jouni Malinencc6c5092019-02-19 12:51:08 +02001266 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001267 for (i = 0; i < count; i++) {
1268 struct sigma_stream *s = get_stream(dut, streams[i]);
1269
1270 if (!s) {
1271 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
1272 "not configured", streams[i]);
1273 send_resp(dut, conn, SIGMA_INVALID, buf);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001274 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001275 }
1276 for (j = 0; j < i; j++)
1277 if (streams[i] == streams[j])
Jouni Malinencc6c5092019-02-19 12:51:08 +02001278 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001279 if (s->sender) {
1280 snprintf(buf, sizeof(buf), "errorCode,Not configured "
1281 "as receiver for streamID %d", streams[i]);
1282 send_resp(dut, conn, SIGMA_INVALID, buf);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001283 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001284 }
1285 }
1286
1287 for (i = 0; i < count; i++) {
1288 struct sigma_stream *s = get_stream(dut, streams[i]);
1289
1290 if (!s)
1291 continue;
1292 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: open "
1293 "receive socket for stream %d", streams[i]);
1294 if (open_socket(dut, s) < 0)
Jouni Malinencc6c5092019-02-19 12:51:08 +02001295 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001296 }
1297
1298 for (i = 0; i < count; i++) {
1299 struct sigma_stream *s = get_stream(dut, streams[i]);
1300 int res;
1301
1302 if (!s)
1303 continue;
1304 /*
1305 * Provide dut context to the thread to support debugging and
1306 * returning of error messages. Similarly, provide interface
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +05301307 * information to the thread. If the Interface parameter is not
1308 * passed, get it from get_station_ifname() since the interface
1309 * name is needed for power save mode configuration for Uapsd
1310 * cases.
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001311 */
1312 s->dut = dut;
1313 val = get_param(cmd, "Interface");
Jouni Malinen016ae6c2019-11-04 17:00:01 +02001314 strlcpy(s->ifname, (val ? val : get_station_ifname(dut)),
Pradeep Reddy POTTETI3f8c0b32016-05-03 16:06:37 +05301315 sizeof(s->ifname));
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001316
1317 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: start "
1318 "receive for stream %d", streams[i]);
1319 res = pthread_create(&s->thr, NULL, receive_thread, s);
1320 if (res) {
1321 sigma_dut_print(dut, DUT_MSG_INFO, "pthread_create "
1322 "failed: %d", res);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001323 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001324 }
1325 s->started = 1;
1326 }
1327
Jouni Malinencc6c5092019-02-19 12:51:08 +02001328 return SUCCESS_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001329}
1330
1331
1332static void write_frame_stats(struct sigma_dut *dut, struct sigma_stream *s,
1333 int id)
1334{
1335 char fname[128];
1336 FILE *f;
1337 unsigned int i;
1338
Alexei Avshalom Lazarc9bc15d2020-01-29 10:52:13 +02001339 snprintf(fname, sizeof(fname), "%s/e2e%u-%d.txt",
1340 dut->sigma_tmpdir, (unsigned int) time(NULL), id);
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001341 f = fopen(fname, "w");
1342 if (f == NULL) {
1343 sigma_dut_print(dut, DUT_MSG_INFO, "Could not write %s",
1344 fname);
1345 return;
1346 }
1347 fprintf(f, "seqnum:local_sec:local_usec:remote_sec:remote_usec\n");
1348
1349 sigma_dut_print(dut, DUT_MSG_DEBUG, "Writing frame stats to %s",
1350 fname);
1351
1352 for (i = 0; i < s->num_stats; i++) {
1353 struct sigma_frame_stats *stats = &s->stats[i];
1354 fprintf(f, "%u:%u:%u:%u:%u\n", stats->seqnum,
1355 stats->local_sec, stats->local_usec,
1356 stats->remote_sec, stats->remote_usec);
1357 }
1358
1359 fclose(f);
1360}
1361
1362
Jouni Malinencc6c5092019-02-19 12:51:08 +02001363static enum sigma_cmd_result
1364cmd_traffic_agent_receive_stop(struct sigma_dut *dut, struct sigma_conn *conn,
1365 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001366{
1367 const char *val;
1368 int streams[MAX_SIGMA_STREAMS];
1369 int i, j, ret, count;
1370 char buf[100 + MAX_SIGMA_STREAMS * 60], *pos;
1371
1372 val = get_param(cmd, "streamID");
1373 if (val == NULL)
Jouni Malinencc6c5092019-02-19 12:51:08 +02001374 return INVALID_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001375 count = get_stream_id(val, streams);
1376 if (count < 0)
Jouni Malinencc6c5092019-02-19 12:51:08 +02001377 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001378 for (i = 0; i < count; i++) {
1379 struct sigma_stream *s = get_stream(dut, streams[i]);
1380
1381 if (!s) {
1382 snprintf(buf, sizeof(buf), "errorCode,StreamID %d "
1383 "not configured", streams[i]);
1384 send_resp(dut, conn, SIGMA_INVALID, buf);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001385 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001386 }
1387 for (j = 0; j < i; j++)
1388 if (streams[i] == streams[j])
Jouni Malinencc6c5092019-02-19 12:51:08 +02001389 return ERROR_SEND_STATUS;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001390 if (!s->started) {
1391 snprintf(buf, sizeof(buf), "errorCode,Receive not "
1392 "started for streamID %d", streams[i]);
1393 send_resp(dut, conn, SIGMA_INVALID, buf);
Jouni Malinencc6c5092019-02-19 12:51:08 +02001394 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001395 }
1396 }
1397
1398 for (i = 0; i < count; i++) {
1399 struct sigma_stream *s = get_stream(dut, streams[i]);
1400
1401 if (s)
1402 s->stop = 1;
1403 }
1404
1405 for (i = 0; i < count; i++) {
1406 struct sigma_stream *s = get_stream(dut, streams[i]);
1407
1408 if (!s)
1409 continue;
1410 sigma_dut_print(dut, DUT_MSG_DEBUG, "Traffic agent: stop "
1411 "receive for stream %d", streams[i]);
1412 stop_stream(s);
1413 }
1414
1415 buf[0] = '\0';
1416 pos = buf;
1417
1418 pos += snprintf(pos, buf + sizeof(buf) - pos, "streamID,");
1419 for (i = 0; i < count; i++) {
1420 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1421 i > 0 ? " " : "", streams[i]);
1422 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1423 break;
1424 pos += ret;
1425 }
1426
1427 if (dut->program == PROGRAM_60GHZ) {
1428 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txActFrames,");
1429 for (i = 0; i < count; i++) {
1430 struct sigma_stream *s = get_stream(dut, streams[i]);
1431
1432 if (!s)
1433 continue;
1434 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1435 i > 0 ? " " : "", s->tx_act_frames);
1436 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1437 break;
1438 pos += ret;
1439 }
1440 }
1441
1442 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txFrames,");
1443 for (i = 0; i < count; i++) {
1444 struct sigma_stream *s = get_stream(dut, streams[i]);
1445
1446 if (!s)
1447 continue;
1448 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1449 i > 0 ? " " : "", s->tx_frames);
1450 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1451 break;
1452 pos += ret;
1453 }
1454
1455 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxFrames,");
1456 for (i = 0; i < count; i++) {
1457 struct sigma_stream *s = get_stream(dut, streams[i]);
1458
1459 if (!s)
1460 continue;
1461 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1462 i > 0 ? " " : "", s->rx_frames);
1463 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1464 break;
1465 pos += ret;
1466 }
1467
1468 pos += snprintf(pos, buf + sizeof(buf) - pos, ",txPayloadBytes,");
1469 for (i = 0; i < count; i++) {
1470 struct sigma_stream *s = get_stream(dut, streams[i]);
1471
1472 if (!s)
1473 continue;
1474 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
1475 i > 0 ? " " : "", s->tx_payload_bytes);
1476 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1477 break;
1478 pos += ret;
1479 }
1480
1481 pos += snprintf(pos, buf + sizeof(buf) - pos, ",rxPayloadBytes,");
1482 for (i = 0; i < count; i++) {
1483 struct sigma_stream *s = get_stream(dut, streams[i]);
1484
1485 if (!s)
1486 continue;
1487 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%llu",
1488 i > 0 ? " " : "", s->rx_payload_bytes);
1489 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1490 break;
1491 pos += ret;
1492 }
1493
1494 pos += snprintf(pos, buf + sizeof(buf) - pos, ",outOfSequenceFrames,");
1495 for (i = 0; i < count; i++) {
1496 struct sigma_stream *s = get_stream(dut, streams[i]);
1497
1498 if (!s)
1499 continue;
1500 ret = snprintf(pos, buf + sizeof(buf) - pos, "%s%d",
1501 i > 0 ? " " : "", s->out_of_seq_frames);
1502 if (ret < 0 || ret >= buf + sizeof(buf) - pos)
1503 break;
1504 pos += ret;
1505 }
1506
1507 buf[sizeof(buf) - 1] = '\0';
1508
1509 send_resp(dut, conn, SIGMA_COMPLETE, buf);
1510
1511 for (i = 0; i < count; i++) {
1512 struct sigma_stream *s = get_stream(dut, streams[i]);
1513
1514 if (!s)
1515 continue;
1516 if (s->profile == SIGMA_PROFILE_IPTV && s->num_stats > 0 &&
1517 dut->write_stats)
1518 write_frame_stats(dut, s, streams[i]);
1519 free(s->stats);
1520 s->stats = NULL;
1521 s->num_stats = 0;
1522 }
1523
Jouni Malinencc6c5092019-02-19 12:51:08 +02001524 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001525}
1526
1527
Jouni Malinencc6c5092019-02-19 12:51:08 +02001528static enum sigma_cmd_result cmd_traffic_agent_version(struct sigma_dut *dut,
1529 struct sigma_conn *conn,
1530 struct sigma_cmd *cmd)
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001531{
1532 send_resp(dut, conn, SIGMA_COMPLETE, "version,1.0");
Jouni Malinencc6c5092019-02-19 12:51:08 +02001533 return STATUS_SENT;
Jouni Malinencd4e3c32015-10-29 12:39:56 +02001534}
1535
1536
1537void traffic_agent_register_cmds(void)
1538{
1539 sigma_dut_reg_cmd("traffic_agent_config", NULL,
1540 cmd_traffic_agent_config);
1541 sigma_dut_reg_cmd("traffic_agent_reset", NULL,
1542 cmd_traffic_agent_reset);
1543 sigma_dut_reg_cmd("traffic_agent_send", NULL,
1544 cmd_traffic_agent_send);
1545 sigma_dut_reg_cmd("traffic_agent_receive_start", NULL,
1546 cmd_traffic_agent_receive_start);
1547 sigma_dut_reg_cmd("traffic_agent_receive_stop", NULL,
1548 cmd_traffic_agent_receive_stop);
1549 sigma_dut_reg_cmd("traffic_agent_version", NULL,
1550 cmd_traffic_agent_version);
1551}