• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * trace-msg.c : define message protocol for communication between clients and
4  *               a server
5  *
6  * Copyright (C) 2013 Hitachi, Ltd.
7  * Created by Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com>
8  *
9  */
10 
11 #include <errno.h>
12 #include <poll.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stddef.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <arpa/inet.h>
22 #include <sys/types.h>
23 #include <linux/types.h>
24 
25 #include "trace-write-local.h"
26 #include "trace-cmd-local.h"
27 #include "trace-local.h"
28 #include "trace-msg.h"
29 #include "trace-cmd.h"
30 
31 typedef __u32 u32;
32 typedef __be32 be32;
33 
34 #define dprint(fmt, ...)	tracecmd_debug(fmt, ##__VA_ARGS__)
35 
36 /* Two (4k) pages is the max transfer for now */
37 #define MSG_MAX_LEN			8192
38 
39 #define MSG_HDR_LEN			sizeof(struct tracecmd_msg_header)
40 
41 #define MSG_MAX_DATA_LEN		(MSG_MAX_LEN - MSG_HDR_LEN)
42 
43 unsigned int page_size;
44 
45 struct tracecmd_msg_tinit {
46 	be32 cpus;
47 	be32 page_size;
48 	be32 opt_num;
49 } __packed;
50 
51 struct tracecmd_msg_rinit {
52 	be32 cpus;
53 } __packed;
54 
55 #define TRACE_REQ_PARAM_SIZE  (2 * sizeof(int))
56 enum trace_req_params {
57 	TRACE_REQUEST_ARGS,
58 	TRACE_REQUEST_TSYNC_PROTOS,
59 };
60 
61 struct tracecmd_msg_trace_req_param {
62 	int id;
63 	int length;
64 	char *value;
65 };
66 
67 struct tracecmd_msg_trace_req {
68 	be32 flags;
69 	be32 argc;
70 	u64 trace_id;
71 } __packed;
72 
73 struct tracecmd_msg_trace_resp {
74 	be32 flags;
75 	be32 cpus;
76 	be32 page_size;
77 	u64 trace_id;
78 	char tsync_proto_name[TRACECMD_TSYNC_PNAME_LENGTH];
79 	be32 tsync_port;
80 } __packed;
81 
82 struct tracecmd_msg_tsync {
83 	char sync_protocol_name[TRACECMD_TSYNC_PNAME_LENGTH];
84 	be32 sync_msg_id;
85 } __packed;
86 
87 struct tracecmd_msg_header {
88 	be32	size;
89 	be32	cmd;
90 	be32	cmd_size;
91 } __packed;
92 
93 #define MSG_MAP								\
94 	C(CLOSE,	0,	0),					\
95 	C(TINIT,	1,	sizeof(struct tracecmd_msg_tinit)),	\
96 	C(RINIT,	2,	sizeof(struct tracecmd_msg_rinit)),	\
97 	C(SEND_DATA,	3,	0),					\
98 	C(FIN_DATA,	4,	0),					\
99 	C(NOT_SUPP,	5,	0),					\
100 	C(TRACE_REQ,	6,	sizeof(struct tracecmd_msg_trace_req)),	\
101 	C(TRACE_RESP,	7,	sizeof(struct tracecmd_msg_trace_resp)),\
102 	C(CLOSE_RESP,	8,	0),					\
103 	C(TIME_SYNC,	9,	sizeof(struct tracecmd_msg_tsync)),
104 
105 #undef C
106 #define C(a,b,c)	MSG_##a = b
107 
108 enum tracecmd_msg_cmd {
109 	MSG_MAP
110 	MSG_NR_COMMANDS
111 };
112 
113 #undef C
114 #define C(a,b,c)	c
115 
116 static be32 msg_cmd_sizes[] = { MSG_MAP };
117 
118 #undef C
119 #define C(a,b,c)	#a
120 
121 static const char *msg_names[] = { MSG_MAP };
122 
cmd_to_name(int cmd)123 static const char *cmd_to_name(int cmd)
124 {
125 	if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
126 		return "Unknown";
127 	return msg_names[cmd];
128 }
129 
130 struct tracecmd_msg {
131 	struct tracecmd_msg_header		hdr;
132 	union {
133 		struct tracecmd_msg_tinit	tinit;
134 		struct tracecmd_msg_rinit	rinit;
135 		struct tracecmd_msg_trace_req	trace_req;
136 		struct tracecmd_msg_trace_resp	trace_resp;
137 		struct tracecmd_msg_tsync	tsync;
138 	};
139 	char					*buf;
140 } __packed;
141 
msg_buf_len(struct tracecmd_msg * msg)142 static inline int msg_buf_len(struct tracecmd_msg *msg)
143 {
144 	return ntohl(msg->hdr.size) - MSG_HDR_LEN - ntohl(msg->hdr.cmd_size);
145 }
146 
__msg_write(int fd,struct tracecmd_msg * msg,bool network)147 static int __msg_write(int fd, struct tracecmd_msg *msg, bool network)
148 {
149 	int msg_size, data_size;
150 	int ret;
151 	int cmd;
152 
153 	if (network) {
154 		cmd = ntohl(msg->hdr.cmd);
155 		if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
156 			return -EINVAL;
157 		dprint("msg send: %d (%s) [%d]\n",
158 		       cmd, cmd_to_name(cmd), ntohl(msg->hdr.size));
159 	}
160 	msg_size = MSG_HDR_LEN + ntohl(msg->hdr.cmd_size);
161 	data_size = ntohl(msg->hdr.size) - msg_size;
162 	if (data_size < 0)
163 		return -EINVAL;
164 
165 	if (network) {
166 		ret = __do_write_check(fd, msg, msg_size);
167 		if (ret < 0)
168 			return ret;
169 	}
170 	if (!data_size)
171 		return 0;
172 
173 	return __do_write_check(fd, msg->buf, data_size);
174 }
175 
msg_lseek(struct tracecmd_msg_handle * msg_handle,off64_t offset,int whence)176 __hidden off64_t msg_lseek(struct tracecmd_msg_handle *msg_handle, off64_t offset, int whence)
177 {
178 	/*
179 	 * lseek works only if the handle is in cache mode,
180 	 * cannot seek on a network socket
181 	 */
182 	if (!msg_handle->cache || msg_handle->cfd < 0)
183 		return (off64_t)-1;
184 	return lseek64(msg_handle->cfd, offset, whence);
185 }
186 
msg_write(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)187 static int msg_write(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
188 {
189 	if (msg_handle->cache && msg_handle->cfd >= 0)
190 		return __msg_write(msg_handle->cfd, msg, false);
191 
192 
193 	return __msg_write(msg_handle->fd, msg, true);
194 }
195 
196 enum msg_trace_flags {
197 	MSG_TRACE_USE_FIFOS = 1 << 0,
198 };
199 
make_tinit(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)200 static int make_tinit(struct tracecmd_msg_handle *msg_handle,
201 		      struct tracecmd_msg *msg)
202 {
203 	int cpu_count = msg_handle->cpu_count;
204 	int opt_num = 0;
205 	int data_size = 0;
206 
207 	if (msg_handle->flags & (TRACECMD_MSG_FL_USE_TCP |
208 				 TRACECMD_MSG_FL_USE_VSOCK)) {
209 		msg->buf = msg_handle->flags & TRACECMD_MSG_FL_USE_TCP ?
210 			strdup("tcp") : strdup("vsock");
211 		if (!msg->buf)
212 			return -1;
213 		opt_num++;
214 		data_size += strlen(msg->buf) + 1;
215 	}
216 
217 	msg->tinit.cpus = htonl(cpu_count);
218 	msg->tinit.page_size = htonl(page_size);
219 	msg->tinit.opt_num = htonl(opt_num);
220 
221 	msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
222 
223 	return 0;
224 }
225 
226 /* test a to u */
tatou(const char * s,unsigned int * res)227 static int tatou(const char *s, unsigned int *res)
228 {
229         long r;
230 
231         r = atol(s);
232         if (r >= 0 && r <= UINT_MAX) {
233                 *res = (unsigned int)r;
234                 return 0;
235         }
236         return -1;
237 }
238 
write_uints(char * buf,size_t buf_len,unsigned int * arr,int arr_len)239 static int write_uints(char *buf, size_t buf_len,
240 		       unsigned int *arr, int arr_len)
241 {
242 	int i, ret, tot = 0;
243 
244 	for (i = 0; i < arr_len; i++) {
245 		ret = snprintf(buf, buf_len, "%u", arr[i]);
246 		if (ret < 0)
247 			return ret;
248 
249 		/* Count the '\0' byte */
250 		ret++;
251 		tot += ret;
252 		if (buf)
253 			buf += ret;
254 		if (buf_len >= ret)
255 			buf_len -= ret;
256 		else
257 			buf_len = 0;
258 	}
259 
260 	return tot;
261 }
262 
make_rinit(struct tracecmd_msg * msg,int cpus,unsigned int * ports)263 static int make_rinit(struct tracecmd_msg *msg, int cpus, unsigned int *ports)
264 {
265 	int data_size;
266 
267 	data_size = write_uints(NULL, 0, ports, cpus);
268 	msg->buf = malloc(data_size);
269 	if (!msg->buf)
270 		return -ENOMEM;
271 	write_uints(msg->buf, data_size, ports, cpus);
272 
273 	msg->rinit.cpus = htonl(cpus);
274 	msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
275 
276 	return 0;
277 }
278 
tracecmd_msg_init(u32 cmd,struct tracecmd_msg * msg)279 static void tracecmd_msg_init(u32 cmd, struct tracecmd_msg *msg)
280 {
281 	memset(msg, 0, sizeof(*msg));
282 	msg->hdr.size = htonl(MSG_HDR_LEN + msg_cmd_sizes[cmd]);
283 	msg->hdr.cmd = htonl(cmd);
284 	msg->hdr.cmd_size = htonl(msg_cmd_sizes[cmd]);
285 }
286 
msg_free(struct tracecmd_msg * msg)287 static void msg_free(struct tracecmd_msg *msg)
288 {
289 	free(msg->buf);
290 	memset(msg, 0, sizeof(*msg));
291 }
292 
tracecmd_msg_send(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)293 static int tracecmd_msg_send(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
294 {
295 	int ret = 0;
296 
297 	ret = msg_write(msg_handle, msg);
298 	if (ret < 0)
299 		ret = -ECOMM;
300 
301 	msg_free(msg);
302 
303 	return ret;
304 }
305 
msg_send_nofree(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)306 static int msg_send_nofree(struct tracecmd_msg_handle *msg_handle, struct tracecmd_msg *msg)
307 {
308 	int ret = 0;
309 
310 	ret = msg_write(msg_handle, msg);
311 	if (ret < 0)
312 		ret = -ECOMM;
313 
314 	return ret;
315 }
316 
msg_read(int fd,void * buf,u32 size,int * n)317 static int msg_read(int fd, void *buf, u32 size, int *n)
318 {
319 	ssize_t r;
320 
321 	while (size) {
322 		r = read(fd, buf + *n, size);
323 		if (r < 0) {
324 			if (errno == EINTR)
325 				continue;
326 			return -errno;
327 		} else if (!r)
328 			return -ENOTCONN;
329 		size -= r;
330 		*n += r;
331 	}
332 
333 	return 0;
334 }
335 
336 static char scratch_buf[MSG_MAX_LEN];
337 
msg_read_extra(int fd,struct tracecmd_msg * msg,int * n,int size)338 static int msg_read_extra(int fd, struct tracecmd_msg *msg,
339 			  int *n, int size)
340 {
341 	int cmd, cmd_size, rsize;
342 	int ret;
343 
344 	cmd = ntohl(msg->hdr.cmd);
345 	if (cmd < 0 || cmd >= MSG_NR_COMMANDS)
346 		return -EINVAL;
347 
348 	cmd_size = ntohl(msg->hdr.cmd_size);
349 	if (cmd_size < 0)
350 		return -EINVAL;
351 
352 	if (cmd_size > 0) {
353 		rsize = cmd_size;
354 		if (rsize > msg_cmd_sizes[cmd])
355 			rsize = msg_cmd_sizes[cmd];
356 
357 		ret = msg_read(fd, msg, rsize, n);
358 		if (ret < 0)
359 			return ret;
360 
361 		ret = msg_read(fd, scratch_buf, cmd_size - rsize, n);
362 		if (ret < 0)
363 			return ret;
364 	}
365 
366 	if (size > *n) {
367 		size -= *n;
368 		msg->buf = malloc(size);
369 		if (!msg->buf)
370 			return -ENOMEM;
371 
372 		*n = 0;
373 		return msg_read(fd, msg->buf, size, n);
374 	}
375 
376 	return 0;
377 }
378 
379 /*
380  * Read header information of msg first, then read all data
381  */
tracecmd_msg_recv(int fd,struct tracecmd_msg * msg)382 static int tracecmd_msg_recv(int fd, struct tracecmd_msg *msg)
383 {
384 	u32 size = 0;
385 	int n = 0;
386 	int ret;
387 
388 	ret = msg_read(fd, msg, MSG_HDR_LEN, &n);
389 	if (ret < 0)
390 		return ret;
391 
392 	dprint("msg received: %d (%s) [%d]\n",
393 	       ntohl(msg->hdr.cmd), cmd_to_name(ntohl(msg->hdr.cmd)),
394 	       ntohl(msg->hdr.size));
395 
396 	size = ntohl(msg->hdr.size);
397 	if (size > MSG_MAX_LEN)
398 		/* too big */
399 		goto error;
400 	else if (size < MSG_HDR_LEN)
401 		/* too small */
402 		goto error;
403 	else if (size > MSG_HDR_LEN)
404 		return msg_read_extra(fd, msg, &n, size);
405 
406 	return 0;
407 error:
408 	tracecmd_plog("Receive an invalid message(size=%d)\n", size);
409 	return -ENOMSG;
410 }
411 
412 #define MSG_WAIT_MSEC	5000
413 static int msg_wait_to = MSG_WAIT_MSEC;
414 
tracecmd_msg_done(struct tracecmd_msg_handle * msg_handle)415 bool tracecmd_msg_done(struct tracecmd_msg_handle *msg_handle)
416 {
417 	return (volatile int)msg_handle->done;
418 }
419 
tracecmd_msg_set_done(struct tracecmd_msg_handle * msg_handle)420 void tracecmd_msg_set_done(struct tracecmd_msg_handle *msg_handle)
421 {
422 	msg_handle->done = true;
423 }
424 
error_operation(struct tracecmd_msg * msg)425 static void error_operation(struct tracecmd_msg *msg)
426 {
427 	tracecmd_warning("Message: cmd=%d size=%d", ntohl(msg->hdr.cmd), ntohl(msg->hdr.size));
428 }
429 
430 /*
431  * A return value of 0 indicates time-out
432  */
tracecmd_msg_recv_wait(int fd,struct tracecmd_msg * msg)433 static int tracecmd_msg_recv_wait(int fd, struct tracecmd_msg *msg)
434 {
435 	struct pollfd pfd;
436 	int ret;
437 
438 	pfd.fd = fd;
439 	pfd.events = POLLIN;
440 	ret = poll(&pfd, 1, tracecmd_get_debug() ? -1 : msg_wait_to);
441 	if (ret < 0)
442 		return -errno;
443 	else if (ret == 0)
444 		return -ETIMEDOUT;
445 
446 	return tracecmd_msg_recv(fd, msg);
447 }
448 
tracecmd_msg_wait_for_msg(int fd,struct tracecmd_msg * msg)449 static int tracecmd_msg_wait_for_msg(int fd, struct tracecmd_msg *msg)
450 {
451 	u32 cmd;
452 	int ret;
453 
454 	ret = tracecmd_msg_recv_wait(fd, msg);
455 	if (ret < 0) {
456 		if (ret == -ETIMEDOUT)
457 			tracecmd_warning("Connection timed out");
458 		return ret;
459 	}
460 
461 	cmd = ntohl(msg->hdr.cmd);
462 	if (cmd == MSG_CLOSE)
463 		return -ECONNABORTED;
464 
465 	return 0;
466 }
467 
tracecmd_msg_send_notsupp(struct tracecmd_msg_handle * msg_handle)468 static int tracecmd_msg_send_notsupp(struct tracecmd_msg_handle *msg_handle)
469 {
470 	struct tracecmd_msg msg;
471 
472 	tracecmd_msg_init(MSG_NOT_SUPP, &msg);
473 	return tracecmd_msg_send(msg_handle, &msg);
474 }
475 
handle_unexpected_msg(struct tracecmd_msg_handle * msg_handle,struct tracecmd_msg * msg)476 static int handle_unexpected_msg(struct tracecmd_msg_handle *msg_handle,
477 				 struct tracecmd_msg *msg)
478 {
479 	/* Don't send MSG_NOT_SUPP back if we just received one */
480 	if (ntohl(msg->hdr.cmd) == MSG_NOT_SUPP)
481 		return 0;
482 
483 	return tracecmd_msg_send_notsupp(msg_handle);
484 
485 }
486 
tracecmd_msg_send_init_data(struct tracecmd_msg_handle * msg_handle,unsigned int ** client_ports)487 int tracecmd_msg_send_init_data(struct tracecmd_msg_handle *msg_handle,
488 				unsigned int **client_ports)
489 {
490 	struct tracecmd_msg msg;
491 	unsigned int *ports;
492 	int i, cpus, ret;
493 	char *p, *buf_end;
494 	ssize_t buf_len;
495 
496 	*client_ports = NULL;
497 
498 	tracecmd_msg_init(MSG_TINIT, &msg);
499 	ret = make_tinit(msg_handle, &msg);
500 	if (ret < 0)
501 		goto out;
502 
503 	ret = tracecmd_msg_send(msg_handle, &msg);
504 	if (ret < 0)
505 		goto out;
506 
507 	msg_free(&msg);
508 
509 	ret = tracecmd_msg_wait_for_msg(msg_handle->fd, &msg);
510 	if (ret < 0)
511 		goto out;
512 
513 	if (ntohl(msg.hdr.cmd) != MSG_RINIT) {
514 		ret = -EOPNOTSUPP;
515 		goto error;
516 	}
517 
518 	buf_len = msg_buf_len(&msg);
519 	if (buf_len <= 0) {
520 		ret = -EINVAL;
521 		goto error;
522 	}
523 
524 	if (msg.buf[buf_len-1] != '\0') {
525 		ret = -EINVAL;
526 		goto error;
527 	}
528 
529 	cpus = ntohl(msg.rinit.cpus);
530 	ports = malloc(sizeof(*ports) * cpus);
531 	if (!ports) {
532 		ret = -ENOMEM;
533 		goto out;
534 	}
535 
536 	buf_end = msg.buf + buf_len;
537 	for (i = 0, p = msg.buf; i < cpus; i++, p++) {
538 		if (p >= buf_end || tatou(p, &ports[i])) {
539 			free(ports);
540 			ret = -EINVAL;
541 			goto error;
542 		}
543 		p = strchr(p, '\0');
544 	}
545 
546 	*client_ports = ports;
547 
548 	msg_free(&msg);
549 	return 0;
550 
551 error:
552 	error_operation(&msg);
553 	if (ret == -EOPNOTSUPP)
554 		handle_unexpected_msg(msg_handle, &msg);
555 out:
556 	msg_free(&msg);
557 	return ret;
558 }
559 
process_option(struct tracecmd_msg_handle * msg_handle,const char * opt)560 static bool process_option(struct tracecmd_msg_handle *msg_handle,
561 			   const char *opt)
562 {
563 	if (strcmp(opt, "tcp") == 0) {
564 		msg_handle->flags |= TRACECMD_MSG_FL_USE_TCP;
565 		return true;
566 	}
567 	if (strcmp(opt, "vsock") == 0) {
568 		msg_handle->flags |= TRACECMD_MSG_FL_USE_VSOCK;
569 		return true;
570 	}
571 	return false;
572 }
573 
574 struct tracecmd_msg_handle *
tracecmd_msg_handle_alloc(int fd,unsigned long flags)575 tracecmd_msg_handle_alloc(int fd, unsigned long flags)
576 {
577 	struct tracecmd_msg_handle *handle;
578 
579 	handle = calloc(1, sizeof(struct tracecmd_msg_handle));
580 	if (!handle)
581 		return NULL;
582 
583 	handle->fd = fd;
584 	handle->flags = flags;
585 	handle->cfd = -1;
586 	handle->cache = false;
587 	return handle;
588 }
589 
tracecmd_msg_handle_cache(struct tracecmd_msg_handle * msg_handle)590 int tracecmd_msg_handle_cache(struct tracecmd_msg_handle *msg_handle)
591 {
592 	if (msg_handle->cfd < 0) {
593 		strcpy(msg_handle->cfile, MSG_CACHE_FILE);
594 		msg_handle->cfd = mkstemp(msg_handle->cfile);
595 		if (msg_handle->cfd < 0)
596 			return -1;
597 		unlink(msg_handle->cfile);
598 	}
599 	msg_handle->cache = true;
600 	return 0;
601 }
602 
flush_cache(struct tracecmd_msg_handle * msg_handle)603 static int flush_cache(struct tracecmd_msg_handle *msg_handle)
604 {
605 	char buf[MSG_MAX_DATA_LEN];
606 	int ret;
607 
608 	if (!msg_handle->cache || msg_handle->cfd < 0)
609 		return 0;
610 	msg_handle->cache = false;
611 	if (lseek64(msg_handle->cfd, 0, SEEK_SET) == (off64_t)-1)
612 		return -1;
613 	do {
614 		ret = read(msg_handle->cfd, buf, MSG_MAX_DATA_LEN);
615 		if (ret <= 0)
616 			break;
617 		ret = tracecmd_msg_data_send(msg_handle, buf, ret);
618 		if (ret < 0)
619 			break;
620 	} while (ret >= 0);
621 
622 	close(msg_handle->cfd);
623 	msg_handle->cfd = -1;
624 	return ret;
625 }
626 
tracecmd_msg_handle_close(struct tracecmd_msg_handle * msg_handle)627 void tracecmd_msg_handle_close(struct tracecmd_msg_handle *msg_handle)
628 {
629 	if (msg_handle->fd >= 0)
630 		close(msg_handle->fd);
631 	if (msg_handle->cfd >= 0)
632 		close(msg_handle->cfd);
633 	free(msg_handle);
634 }
635 
636 #define MAX_OPTION_SIZE 4096
637 
tracecmd_msg_initial_setting(struct tracecmd_msg_handle * msg_handle)638 int tracecmd_msg_initial_setting(struct tracecmd_msg_handle *msg_handle)
639 {
640 	struct tracecmd_msg msg;
641 	char *p, *buf_end;
642 	ssize_t buf_len;
643 	int pagesize;
644 	int options, i;
645 	int cpus;
646 	int ret;
647 
648 	memset(&msg, 0, sizeof(msg));
649 	ret = tracecmd_msg_recv_wait(msg_handle->fd, &msg);
650 	if (ret < 0) {
651 		if (ret == -ETIMEDOUT)
652 			tracecmd_warning("Connection timed out");
653 		return ret;
654 	}
655 
656 	if (ntohl(msg.hdr.cmd) != MSG_TINIT) {
657 		ret = -EOPNOTSUPP;
658 		goto error;
659 	}
660 
661 	cpus = ntohl(msg.tinit.cpus);
662 	tracecmd_plog("cpus=%d\n", cpus);
663 	if (cpus < 0) {
664 		ret = -EINVAL;
665 		goto error;
666 	}
667 
668 	msg_handle->cpu_count = cpus;
669 
670 	pagesize = ntohl(msg.tinit.page_size);
671 	tracecmd_plog("pagesize=%d\n", pagesize);
672 	if (pagesize <= 0) {
673 		ret = -EINVAL;
674 		goto error;
675 	}
676 
677 	buf_len = msg_buf_len(&msg);
678 	if (buf_len < 0) {
679 		ret = -EINVAL;
680 		goto error;
681 	}
682 
683 	if (buf_len == 0)
684 		goto no_options;
685 
686 	if (msg.buf[buf_len-1] != '\0') {
687 		ret = -EINVAL;
688 		goto error;
689 	}
690 
691 	buf_end = msg.buf + buf_len;
692 	options = ntohl(msg.tinit.opt_num);
693 	for (i = 0, p = msg.buf; i < options; i++, p++) {
694 		if (p >= buf_end) {
695 			ret = -EINVAL;
696 			goto error;
697 		}
698 
699 		/* do we understand this option? */
700 		if (!process_option(msg_handle, p))
701 			tracecmd_plog("Cannot understand option '%s'\n", p);
702 
703 		p = strchr(p, '\0');
704 	}
705 
706 no_options:
707 	msg_free(&msg);
708 	return pagesize;
709 
710 error:
711 	error_operation(&msg);
712 	if (ret == -EOPNOTSUPP)
713 		handle_unexpected_msg(msg_handle, &msg);
714 	msg_free(&msg);
715 	return ret;
716 }
717 
tracecmd_msg_send_port_array(struct tracecmd_msg_handle * msg_handle,unsigned int * ports)718 int tracecmd_msg_send_port_array(struct tracecmd_msg_handle *msg_handle,
719 				 unsigned int *ports)
720 {
721 	struct tracecmd_msg msg;
722 	int ret;
723 
724 	tracecmd_msg_init(MSG_RINIT, &msg);
725 	ret = make_rinit(&msg, msg_handle->cpu_count, ports);
726 	if (ret < 0)
727 		return ret;
728 
729 	ret = tracecmd_msg_send(msg_handle, &msg);
730 	if (ret < 0)
731 		return ret;
732 
733 	return 0;
734 }
735 
tracecmd_msg_send_close_msg(struct tracecmd_msg_handle * msg_handle)736 int tracecmd_msg_send_close_msg(struct tracecmd_msg_handle *msg_handle)
737 {
738 	struct tracecmd_msg msg;
739 
740 	tracecmd_msg_init(MSG_CLOSE, &msg);
741 	return tracecmd_msg_send(msg_handle, &msg);
742 }
743 
tracecmd_msg_send_close_resp_msg(struct tracecmd_msg_handle * msg_handle)744 int tracecmd_msg_send_close_resp_msg(struct tracecmd_msg_handle *msg_handle)
745 {
746 	struct tracecmd_msg msg;
747 
748 	tracecmd_msg_init(MSG_CLOSE_RESP, &msg);
749 	return tracecmd_msg_send(msg_handle, &msg);
750 }
751 
tracecmd_msg_data_send(struct tracecmd_msg_handle * msg_handle,const char * buf,int size)752 int tracecmd_msg_data_send(struct tracecmd_msg_handle *msg_handle,
753 			   const char *buf, int size)
754 {
755 	struct tracecmd_msg msg;
756 	int n;
757 	int ret;
758 	int count = 0;
759 
760 	/* Don't bother doing anything if there's nothing to do */
761 	if (!size)
762 		return 0;
763 
764 	tracecmd_msg_init(MSG_SEND_DATA, &msg);
765 
766 	msg.buf = malloc(MSG_MAX_DATA_LEN);
767 	if (!msg.buf)
768 		return -ENOMEM;
769 
770 	msg.hdr.size = htonl(MSG_MAX_LEN);
771 
772 	n = size;
773 	while (n) {
774 		if (n > MSG_MAX_DATA_LEN) {
775 			memcpy(msg.buf, buf + count, MSG_MAX_DATA_LEN);
776 			n -= MSG_MAX_DATA_LEN;
777 			count += MSG_MAX_DATA_LEN;
778 		} else {
779 			msg.hdr.size = htonl(MSG_HDR_LEN + n);
780 			memcpy(msg.buf, buf + count, n);
781 			n = 0;
782 		}
783 		ret = msg_write(msg_handle, &msg);
784 		if (ret < 0)
785 			break;
786 	}
787 
788 	msg_free(&msg);
789 	return ret;
790 }
791 
tracecmd_msg_finish_sending_data(struct tracecmd_msg_handle * msg_handle)792 int tracecmd_msg_finish_sending_data(struct tracecmd_msg_handle *msg_handle)
793 {
794 	struct tracecmd_msg msg;
795 	int ret;
796 
797 	flush_cache(msg_handle);
798 	tracecmd_msg_init(MSG_FIN_DATA, &msg);
799 	ret = tracecmd_msg_send(msg_handle, &msg);
800 	if (ret < 0)
801 		return ret;
802 	return 0;
803 }
804 
tracecmd_msg_read_data(struct tracecmd_msg_handle * msg_handle,int ofd)805 int tracecmd_msg_read_data(struct tracecmd_msg_handle *msg_handle, int ofd)
806 {
807 	struct tracecmd_msg msg;
808 	int t, n, cmd;
809 	ssize_t s;
810 	int ret;
811 
812 	while (!tracecmd_msg_done(msg_handle)) {
813 		ret = tracecmd_msg_recv_wait(msg_handle->fd, &msg);
814 		if (ret < 0) {
815 			tracecmd_warning("reading client %d (%s)", ret, strerror(ret));
816 			return ret;
817 		}
818 
819 		cmd = ntohl(msg.hdr.cmd);
820 		if (cmd == MSG_FIN_DATA) {
821 			/* Finish receiving data */
822 			break;
823 		} else if (cmd != MSG_SEND_DATA) {
824 			ret = handle_unexpected_msg(msg_handle, &msg);
825 			if (ret < 0)
826 				goto error;
827 			goto next;
828 		}
829 
830 		n = msg_buf_len(&msg);
831 		t = n;
832 		s = 0;
833 		while (t > 0) {
834 			s = write(ofd, msg.buf+s, t);
835 			if (s < 0) {
836 				if (errno == EINTR)
837 					continue;
838 				tracecmd_warning("writing to file");
839 				ret = -errno;
840 				goto error;
841 			}
842 			t -= s;
843 			s = n - t;
844 		}
845 
846 next:
847 		msg_free(&msg);
848 	}
849 
850 	return 0;
851 
852 error:
853 	error_operation(&msg);
854 	msg_free(&msg);
855 	return ret;
856 }
857 
tracecmd_msg_collect_data(struct tracecmd_msg_handle * msg_handle,int ofd)858 int tracecmd_msg_collect_data(struct tracecmd_msg_handle *msg_handle, int ofd)
859 {
860 	int ret;
861 
862 	ret = tracecmd_msg_read_data(msg_handle, ofd);
863 	if (ret)
864 		return ret;
865 
866 	return tracecmd_msg_wait_close(msg_handle);
867 }
868 
tracecmd_msg_wait_for_cmd(struct tracecmd_msg_handle * msg_handle,enum tracecmd_msg_cmd cmd)869 static int tracecmd_msg_wait_for_cmd(struct tracecmd_msg_handle *msg_handle, enum tracecmd_msg_cmd cmd)
870 {
871 	struct tracecmd_msg msg;
872 	int ret = -1;
873 
874 	memset(&msg, 0, sizeof(msg));
875 	while (!tracecmd_msg_done(msg_handle)) {
876 		ret = tracecmd_msg_recv(msg_handle->fd, &msg);
877 		if (ret < 0)
878 			goto error;
879 
880 		if (ntohl(msg.hdr.cmd) == cmd)
881 			return 0;
882 
883 		error_operation(&msg);
884 		ret = handle_unexpected_msg(msg_handle, &msg);
885 		if (ret < 0)
886 			goto error;
887 
888 		msg_free(&msg);
889 	}
890 
891 error:
892 	msg_free(&msg);
893 	return ret;
894 }
895 
tracecmd_msg_wait_close(struct tracecmd_msg_handle * msg_handle)896 int tracecmd_msg_wait_close(struct tracecmd_msg_handle *msg_handle)
897 {
898 	return tracecmd_msg_wait_for_cmd(msg_handle, MSG_CLOSE);
899 }
900 
tracecmd_msg_wait_close_resp(struct tracecmd_msg_handle * msg_handle)901 int tracecmd_msg_wait_close_resp(struct tracecmd_msg_handle *msg_handle)
902 {
903 	return tracecmd_msg_wait_for_cmd(msg_handle, MSG_CLOSE_RESP);
904 }
905 
make_trace_req_protos(char ** buf,int * size,struct tracecmd_tsync_protos * protos)906 static int make_trace_req_protos(char **buf, int *size,
907 				 struct tracecmd_tsync_protos *protos)
908 {
909 	int protos_size = 1;
910 	size_t buf_size;
911 	char **names;
912 	char *nbuf;
913 	char *p;
914 
915 	names = protos->names;
916 	while (*names) {
917 		protos_size += strlen(*names) + 1;
918 		names++;
919 	}
920 
921 	buf_size = TRACE_REQ_PARAM_SIZE + protos_size;
922 	nbuf = realloc(*buf, *size + buf_size);
923 	if (!nbuf)
924 		return -1;
925 
926 	p = nbuf + *size;
927 	memset(p, 0, buf_size);
928 
929 	*(unsigned int *)p = htonl(TRACE_REQUEST_TSYNC_PROTOS);
930 	p += sizeof(int);
931 	*(unsigned int *)p = htonl(protos_size);
932 	p += sizeof(int);
933 
934 	names = protos->names;
935 	while (*names) {
936 		strcpy(p, *names);
937 		p += strlen(*names) + 1;
938 		names++;
939 	}
940 	p = NULL;
941 
942 	*size += buf_size;
943 	*buf = nbuf;
944 	return 0;
945 }
946 
make_trace_req_args(char ** buf,int * size,int argc,char ** argv)947 static int make_trace_req_args(char **buf, int *size, int argc, char **argv)
948 {
949 	size_t args_size;
950 	size_t buf_size;
951 	char *nbuf;
952 	char *p;
953 	int i;
954 
955 	args_size = sizeof(int);
956 	for (i = 0; i < argc; i++)
957 		args_size += strlen(argv[i]) + 1;
958 
959 	buf_size = TRACE_REQ_PARAM_SIZE + args_size;
960 	nbuf = realloc(*buf, *size + buf_size);
961 	if (!nbuf)
962 		return -1;
963 
964 	p = nbuf + *size;
965 	memset(p, 0, buf_size);
966 
967 	*(unsigned int *)p = htonl(TRACE_REQUEST_ARGS);
968 	p += sizeof(int);
969 	*(unsigned int *)p = htonl(args_size);
970 	p += sizeof(int);
971 
972 	*(unsigned int *)p = htonl(argc);
973 	p += sizeof(int);
974 	for (i = 0; i < argc; i++)
975 		p = stpcpy(p, argv[i]) + 1;
976 
977 	*size += buf_size;
978 	*buf = nbuf;
979 	return 0;
980 }
981 
make_trace_req(struct tracecmd_msg * msg,int argc,char ** argv,bool use_fifos,unsigned long long trace_id,struct tracecmd_tsync_protos * protos)982 static int make_trace_req(struct tracecmd_msg *msg, int argc, char **argv,
983 			  bool use_fifos, unsigned long long trace_id,
984 			  struct tracecmd_tsync_protos *protos)
985 {
986 	int size = 0;
987 	char *buf = NULL;
988 
989 	msg->trace_req.flags = 0;
990 	if (use_fifos)
991 		msg->trace_req.flags |= MSG_TRACE_USE_FIFOS;
992 	msg->trace_req.flags = htonl(msg->trace_req.flags);
993 	msg->trace_req.trace_id = htonll(trace_id);
994 
995 	if (argc && argv)
996 		make_trace_req_args(&buf, &size, argc, argv);
997 	if (protos && protos->names)
998 		make_trace_req_protos(&buf, &size, protos);
999 
1000 	msg->buf = buf;
1001 	msg->hdr.size = htonl(ntohl(msg->hdr.size) + size);
1002 
1003 	return 0;
1004 }
1005 
tracecmd_msg_send_trace_req(struct tracecmd_msg_handle * msg_handle,int argc,char ** argv,bool use_fifos,unsigned long long trace_id,struct tracecmd_tsync_protos * protos)1006 int tracecmd_msg_send_trace_req(struct tracecmd_msg_handle *msg_handle,
1007 				int argc, char **argv, bool use_fifos,
1008 				unsigned long long trace_id,
1009 				struct tracecmd_tsync_protos *protos)
1010 {
1011 	struct tracecmd_msg msg;
1012 	int ret;
1013 
1014 	tracecmd_msg_init(MSG_TRACE_REQ, &msg);
1015 	ret = make_trace_req(&msg, argc, argv, use_fifos, trace_id, protos);
1016 	if (ret < 0)
1017 		return ret;
1018 
1019 	return tracecmd_msg_send(msg_handle, &msg);
1020 }
1021 
get_trace_req_protos(char * buf,int length,struct tracecmd_tsync_protos ** protos)1022 static int get_trace_req_protos(char *buf, int length,
1023 				struct tracecmd_tsync_protos **protos)
1024 {
1025 	struct tracecmd_tsync_protos *plist = NULL;
1026 	int count = 0;
1027 	char *p;
1028 	int i, j;
1029 
1030 	i = length;
1031 	p = buf;
1032 	while (i > 0) {
1033 		i -= strlen(p) + 1;
1034 		count++;
1035 		p += strlen(p) + 1;
1036 	}
1037 
1038 	plist = calloc(1, sizeof(struct tracecmd_tsync_protos));
1039 	if (!plist)
1040 		goto error;
1041 	plist->names = calloc(count + 1, sizeof(char *));
1042 	if (!plist->names)
1043 		goto error;
1044 	i = length;
1045 	p = buf;
1046 	j = 0;
1047 	while (i > 0 && j < (count - 1)) {
1048 		i -= strlen(p) + 1;
1049 		plist->names[j++] = strdup(p);
1050 		p += strlen(p) + 1;
1051 	}
1052 
1053 	*protos = plist;
1054 	return 0;
1055 error:
1056 	if (plist) {
1057 		free(plist->names);
1058 		free(plist);
1059 	}
1060 	return -1;
1061 }
1062 
get_trace_req_args(char * buf,int length,int * argc,char *** argv)1063 static int get_trace_req_args(char *buf, int length, int *argc, char ***argv)
1064 {
1065 	unsigned int nr_args;
1066 	char *p, *buf_end;
1067 	char **args = NULL;
1068 	char *vagrs = NULL;
1069 	int ret;
1070 	int i;
1071 
1072 	if (length <= sizeof(int) || buf[length - 1] != '\0') {
1073 		ret = -EINVAL;
1074 		goto out;
1075 	}
1076 
1077 	nr_args = ntohl(*(unsigned int *)buf);
1078 	buf += sizeof(int);
1079 	length -= sizeof(int);
1080 
1081 	args = calloc(nr_args, sizeof(*args));
1082 	if (!args) {
1083 		ret = -ENOMEM;
1084 		goto out;
1085 	}
1086 
1087 	vagrs = calloc(length, sizeof(char));
1088 	if (!vagrs) {
1089 		ret = -ENOMEM;
1090 		goto out;
1091 	}
1092 
1093 	memcpy(vagrs, buf, length);
1094 	buf_end = vagrs + length;
1095 	for (i = 0, p = vagrs; i < nr_args; i++, p++) {
1096 		if (p >= buf_end) {
1097 			ret = -EINVAL;
1098 			goto out;
1099 		}
1100 		args[i] = p;
1101 		p = strchr(p, '\0');
1102 	}
1103 
1104 	*argc = nr_args;
1105 	*argv = args;
1106 	return 0;
1107 
1108 out:
1109 	free(args);
1110 	free(vagrs);
1111 	return ret;
1112 
1113 }
1114 
1115 /*
1116  * NOTE: On success, the returned `argv` should be freed with:
1117  *     free(argv[0]);
1118  *     free(argv);
1119  * and `tsync_protos` with free(tsync_protos);
1120  */
tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle * msg_handle,int * argc,char *** argv,bool * use_fifos,unsigned long long * trace_id,struct tracecmd_tsync_protos ** protos)1121 int tracecmd_msg_recv_trace_req(struct tracecmd_msg_handle *msg_handle,
1122 				int *argc, char ***argv, bool *use_fifos,
1123 				unsigned long long *trace_id,
1124 				struct tracecmd_tsync_protos **protos)
1125 {
1126 	struct tracecmd_msg msg;
1127 	unsigned int param_id;
1128 	int param_length;
1129 	ssize_t buf_len;
1130 	char *p;
1131 	int ret;
1132 
1133 	ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1134 	if (ret < 0)
1135 		return ret;
1136 
1137 	if (ntohl(msg.hdr.cmd) != MSG_TRACE_REQ) {
1138 		ret = -ENOTSUP;
1139 		goto out;
1140 	}
1141 
1142 	buf_len = ntohl(msg.hdr.size) - MSG_HDR_LEN - ntohl(msg.hdr.cmd_size);
1143 	if (buf_len < 0) {
1144 		ret = -EINVAL;
1145 		goto out;
1146 	}
1147 
1148 	*use_fifos = ntohl(msg.trace_req.flags) & MSG_TRACE_USE_FIFOS;
1149 	*trace_id = ntohll(msg.trace_req.trace_id);
1150 	p = msg.buf;
1151 	while (buf_len > 2 * sizeof(int)) {
1152 		param_id = ntohl(*((unsigned int *)p));
1153 		p += sizeof(int);
1154 		buf_len -= sizeof(int);
1155 		param_length = ntohl(*((unsigned int *)p));
1156 		p += sizeof(int);
1157 		buf_len -= sizeof(int);
1158 		if (buf_len < param_length)
1159 			break;
1160 		ret = 0;
1161 		switch (param_id) {
1162 		case TRACE_REQUEST_ARGS:
1163 			ret = get_trace_req_args(p, param_length, argc, argv);
1164 			break;
1165 		case TRACE_REQUEST_TSYNC_PROTOS:
1166 			ret = get_trace_req_protos(p, param_length, protos);
1167 			break;
1168 		default:
1169 			break;
1170 		}
1171 		if (ret)
1172 			break;
1173 		buf_len -= param_length;
1174 		p += param_length;
1175 	}
1176 
1177 	msg_free(&msg);
1178 	return 0;
1179 
1180 out:
1181 	error_operation(&msg);
1182 	if (ret == -EOPNOTSUPP)
1183 		handle_unexpected_msg(msg_handle, &msg);
1184 	msg_free(&msg);
1185 	return ret;
1186 }
1187 
1188 /**
1189  * tracecmd_msg_send_time_sync - Send a time sync packet
1190  * @msg_handle: message handle, holding the communication context
1191  * @sync_protocol: name of the time synch protocol, string up to
1192  *		   TRACECMD_TSYNC_PNAME_LENGTH characters length.
1193  * @sync_msg_id: id if the time synch message, protocol dependent
1194  * @payload_size: size of the packet payload, 0 in case of no payload
1195  * @payload: pointer to the packet payload, or NULL in case of no payload
1196  *
1197  * Returns 0 if packet is sent successfully, or negative error otherwise.
1198  */
tracecmd_msg_send_time_sync(struct tracecmd_msg_handle * msg_handle,char * sync_protocol,unsigned int sync_msg_id,unsigned int payload_size,char * payload)1199 int tracecmd_msg_send_time_sync(struct tracecmd_msg_handle *msg_handle,
1200 				char *sync_protocol, unsigned int sync_msg_id,
1201 				unsigned int payload_size, char *payload)
1202 {
1203 	struct tracecmd_msg msg;
1204 
1205 	tracecmd_msg_init(MSG_TIME_SYNC, &msg);
1206 	strncpy(msg.tsync.sync_protocol_name, sync_protocol, TRACECMD_TSYNC_PNAME_LENGTH);
1207 	msg.tsync.sync_msg_id = htonl(sync_msg_id);
1208 	msg.hdr.size = htonl(ntohl(msg.hdr.size) + payload_size);
1209 
1210 	msg.buf = payload;
1211 	return msg_send_nofree(msg_handle, &msg);
1212 }
1213 
1214 /**
1215  * tracecmd_msg_recv_time_sync - Receive a time sync packet
1216  * @msg_handle: message handle, holding the communication context
1217  * @sync_protocol: return the name of the packet's time synch protocol.
1218  *		   It must point to a prealocated buffer with size
1219  *		   TRACECMD_TSYNC_PNAME_LENGTH
1220  * @sync_msg_id: return the id of the packet's time synch message
1221  * @payload_size: size of the packet's payload, can be:
1222  *		 NULL - the payload is not interested and should be ignored
1223  *		 pointer to int, with value 0 - update with the size of the payload
1224  *						allocate memory and cpy the payload
1225  *						into it
1226  *		 pointer to int, with value greater than 0 - expected size of the
1227  *							     payload, preallocated
1228  *							     memory is passed to the API
1229  *							     with that size
1230  *@payload: pointer to the packet payload, can be:
1231  *	     NULL - the payload is not interested and should be ignored
1232  *	     pointer to char *, with value NULL - a new memory is allocated and returned
1233  *						  here, containing the packet's payload
1234  *						  the @payload_size is updated with the
1235  *						  size of the allocated memory. It must be
1236  *						  freed by free()
1237  *	     pointer to char *, with no-NULL value - A prealocated array is passed, with size
1238  *						     @payload_size. If payload's size is equal
1239  *						     or less, it will be copied here.
1240  *
1241  * Returns 0 if packet is received successfully, or negative error otherwise.
1242  */
tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle * msg_handle,char * sync_protocol,unsigned int * sync_msg_id,unsigned int * payload_size,char ** payload)1243 int tracecmd_msg_recv_time_sync(struct tracecmd_msg_handle *msg_handle,
1244 				char *sync_protocol,
1245 				unsigned int *sync_msg_id,
1246 				unsigned int *payload_size, char **payload)
1247 {
1248 	struct tracecmd_msg msg;
1249 	int ret = -1;
1250 	int buf_size;
1251 
1252 	memset(&msg, 0, sizeof(msg));
1253 	ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1254 	if (ret < 0)
1255 		goto out;
1256 
1257 	if (ntohl(msg.hdr.cmd) != MSG_TIME_SYNC) {
1258 		ret = -EOPNOTSUPP;
1259 		goto out;
1260 	}
1261 
1262 	if (sync_protocol)
1263 		strncpy(sync_protocol, msg.tsync.sync_protocol_name,
1264 				TRACECMD_TSYNC_PNAME_LENGTH);
1265 	if (sync_msg_id)
1266 		*sync_msg_id = ntohl(msg.tsync.sync_msg_id);
1267 
1268 	buf_size = msg_buf_len(&msg);
1269 	if (buf_size < 0) {
1270 		ret = -EINVAL;
1271 		goto out;
1272 	}
1273 
1274 	if (buf_size && payload && payload_size) {
1275 		if (*payload_size) {
1276 			if (*payload_size < buf_size || *payload == NULL) {
1277 				ret = -ENOMEM;
1278 				goto out;
1279 			}
1280 			memcpy(*payload, msg.buf, buf_size);
1281 			goto out;
1282 		}
1283 
1284 		*payload = malloc(buf_size);
1285 		if (*payload == NULL) {
1286 			ret = -ENOMEM;
1287 			goto out;
1288 		}
1289 		*payload_size = buf_size;
1290 		memcpy(*payload, msg.buf, buf_size);
1291 	}
1292 
1293 out:
1294 	msg_free(&msg);
1295 	return ret;
1296 }
1297 
make_trace_resp(struct tracecmd_msg * msg,int page_size,int nr_cpus,unsigned int * ports,bool use_fifos,unsigned long long trace_id,const char * tsync_proto,unsigned int tsync_port)1298 static int make_trace_resp(struct tracecmd_msg *msg, int page_size, int nr_cpus,
1299 			   unsigned int *ports, bool use_fifos,
1300 			   unsigned long long trace_id,
1301 			   const char *tsync_proto,
1302 			   unsigned int tsync_port)
1303 {
1304 	int data_size;
1305 
1306 	if (!tsync_proto)
1307 		tsync_proto = "";
1308 
1309 	data_size = write_uints(NULL, 0, ports, nr_cpus);
1310 	msg->buf = malloc(data_size);
1311 	if (!msg->buf)
1312 		return -ENOMEM;
1313 	write_uints(msg->buf, data_size, ports, nr_cpus);
1314 
1315 	msg->hdr.size = htonl(ntohl(msg->hdr.size) + data_size);
1316 	msg->trace_resp.flags = use_fifos ? MSG_TRACE_USE_FIFOS : 0;
1317 	msg->trace_resp.flags = htonl(msg->trace_resp.flags);
1318 	strncpy(msg->trace_resp.tsync_proto_name, tsync_proto, TRACECMD_TSYNC_PNAME_LENGTH);
1319 	msg->trace_resp.tsync_port = htonl(tsync_port);
1320 
1321 	msg->trace_resp.cpus = htonl(nr_cpus);
1322 	msg->trace_resp.page_size = htonl(page_size);
1323 	msg->trace_resp.trace_id = htonll(trace_id);
1324 
1325 	return 0;
1326 }
1327 
tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle * msg_handle,int nr_cpus,int page_size,unsigned int * ports,bool use_fifos,unsigned long long trace_id,const char * tsync_proto,unsigned int tsync_port)1328 int tracecmd_msg_send_trace_resp(struct tracecmd_msg_handle *msg_handle,
1329 				 int nr_cpus, int page_size,
1330 				 unsigned int *ports, bool use_fifos,
1331 				 unsigned long long trace_id,
1332 				 const char *tsync_proto, unsigned int tsync_port)
1333 {
1334 	struct tracecmd_msg msg;
1335 	int ret;
1336 
1337 	tracecmd_msg_init(MSG_TRACE_RESP, &msg);
1338 	ret = make_trace_resp(&msg, page_size, nr_cpus, ports,
1339 			      use_fifos, trace_id, tsync_proto, tsync_port);
1340 	if (ret < 0)
1341 		return ret;
1342 
1343 	return tracecmd_msg_send(msg_handle, &msg);
1344 }
1345 
tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle * msg_handle,int * nr_cpus,int * page_size,unsigned int ** ports,bool * use_fifos,unsigned long long * trace_id,char ** tsync_proto,unsigned int * tsync_port)1346 int tracecmd_msg_recv_trace_resp(struct tracecmd_msg_handle *msg_handle,
1347 				 int *nr_cpus, int *page_size,
1348 				 unsigned int **ports, bool *use_fifos,
1349 				 unsigned long long *trace_id,
1350 				 char **tsync_proto,
1351 				 unsigned int *tsync_port)
1352 {
1353 	struct tracecmd_msg msg;
1354 	char *p, *buf_end;
1355 	ssize_t buf_len;
1356 	int i, ret;
1357 
1358 	ret = tracecmd_msg_recv(msg_handle->fd, &msg);
1359 	if (ret < 0)
1360 		return ret;
1361 
1362 	if (ntohl(msg.hdr.cmd) != MSG_TRACE_RESP) {
1363 		ret = -ENOTSUP;
1364 		goto out;
1365 	}
1366 
1367 	buf_len = msg_buf_len(&msg);
1368 	if (buf_len <= 0) {
1369 		ret = -EINVAL;
1370 		goto out;
1371 	}
1372 
1373 	*use_fifos = ntohl(msg.trace_resp.flags) & MSG_TRACE_USE_FIFOS;
1374 	*nr_cpus = ntohl(msg.trace_resp.cpus);
1375 	*page_size = ntohl(msg.trace_resp.page_size);
1376 	*trace_id = ntohll(msg.trace_resp.trace_id);
1377 	*tsync_proto = strdup(msg.trace_resp.tsync_proto_name);
1378 	*tsync_port = ntohl(msg.trace_resp.tsync_port);
1379 	*ports = calloc(*nr_cpus, sizeof(**ports));
1380 	if (!*ports) {
1381 		ret = -ENOMEM;
1382 		goto out;
1383 	}
1384 
1385 	buf_end = msg.buf + buf_len;
1386 	for (i = 0, p = msg.buf; i < *nr_cpus; i++, p++) {
1387 		if (p >= buf_end || tatou(p, &(*ports)[i])) {
1388 			free(*ports);
1389 			ret = -EINVAL;
1390 			goto out;
1391 		}
1392 		p = strchr(p, '\0');
1393 	}
1394 
1395 	msg_free(&msg);
1396 	return 0;
1397 
1398 out:
1399 	error_operation(&msg);
1400 	if (ret == -EOPNOTSUPP)
1401 		handle_unexpected_msg(msg_handle, &msg);
1402 	msg_free(&msg);
1403 	return ret;
1404 }
1405