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