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