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