1 /*
2  * Copyright (c) 2018-2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "tp.h"
10 #include "tp_priv.h"
11 #include "ipv4.h"
12 #include "ipv6.h"
13 #include "udp_internal.h"
14 
15 static sys_slist_t tp_mem = SYS_SLIST_STATIC_INIT(&tp_mem);
16 static sys_slist_t tp_nbufs = SYS_SLIST_STATIC_INIT(&tp_nbufs);
17 static sys_slist_t tp_pkts = SYS_SLIST_STATIC_INIT(&tp_pkts);
18 static sys_slist_t tp_seq = SYS_SLIST_STATIC_INIT(&tp_seq);
19 
20 bool tp_trace;
21 enum tp_type tp_state = TP_NONE;
22 
tp_basename(char * path)23 char *tp_basename(char *path)
24 {
25 	char *filename = strrchr(path, '/');
26 
27 	return filename ? (filename + 1) : path;
28 }
29 
tp_str_to_hex(void * buf,size_t bufsize,const char * s)30 size_t tp_str_to_hex(void *buf, size_t bufsize, const char *s)
31 {
32 	size_t i, j, len = strlen(s);
33 
34 	tp_assert((len % 2) == 0, "Invalid string: %s", s);
35 
36 	for (i = 0, j = 0; i < len; i += 2, j++) {
37 
38 		uint8_t byte = (s[i] - '0') << 4 | (s[i + 1] - '0');
39 
40 		((uint8_t *) buf)[j] = byte;
41 	}
42 
43 	return j;
44 }
45 
tp_malloc(size_t size,const char * file,int line,const char * func)46 void *tp_malloc(size_t size, const char *file, int line, const char *func)
47 {
48 	struct tp_mem *mem = k_malloc(sizeof(struct tp_mem) + size +
49 					sizeof(*mem->footer));
50 
51 	mem->file = file;
52 	mem->line = line;
53 	mem->func = func;
54 
55 	mem->size = size;
56 
57 	mem->header = TP_MEM_HEADER_COOKIE;
58 
59 	mem->footer = (void *) ((uint8_t *) &mem->mem + size);
60 	*mem->footer = TP_MEM_FOOTER_COOKIE;
61 
62 	sys_slist_append(&tp_mem, (sys_snode_t *) mem);
63 
64 	return &mem->mem;
65 }
66 
dump(void * data,size_t len)67 static void dump(void *data, size_t len)
68 {
69 	uint8_t *buf = data;
70 	size_t i, width = 8;
71 
72 	for (i = 0; i < len; i++) {
73 
74 		if ((i % width) == 0) {
75 			printk("0x%08lx\t", POINTER_TO_INT(buf + i));
76 		}
77 
78 		printk("%02x ", buf[i]);
79 
80 		if (((i + 1) % width) == 0 || i == (len - 1)) {
81 			printk("\n");
82 		}
83 	}
84 }
85 
tp_mem_chk(struct tp_mem * mem)86 void tp_mem_chk(struct tp_mem *mem)
87 {
88 	if (mem->header != TP_MEM_HEADER_COOKIE ||
89 		*mem->footer != TP_MEM_FOOTER_COOKIE) {
90 
91 		tp_dbg("%s:%d %s() %p size: %zu",
92 			mem->file, mem->line, mem->func, mem->mem, mem->size);
93 
94 		dump(&mem->header, sizeof(mem->header));
95 		dump(mem->mem, mem->size);
96 		dump(mem->footer, sizeof(*mem->footer));
97 
98 		tp_assert(mem->header == TP_MEM_HEADER_COOKIE,
99 				"%s:%d %s() %p Corrupt header cookie: 0x%x",
100 				mem->file, mem->line, mem->func, mem->mem,
101 				mem->header);
102 
103 		tp_assert(*mem->footer == TP_MEM_FOOTER_COOKIE,
104 				"%s:%d %s() %p Corrupt footer cookie: 0x%x",
105 				mem->file, mem->line, mem->func, mem->mem,
106 				*mem->footer);
107 	}
108 }
109 
tp_free(void * ptr,const char * file,int line,const char * func)110 void tp_free(void *ptr, const char *file, int line, const char *func)
111 {
112 	struct tp_mem *mem = (void *)((uint8_t *) ptr - sizeof(struct tp_mem));
113 
114 	tp_mem_chk(mem);
115 
116 	if (!sys_slist_find_and_remove(&tp_mem, (sys_snode_t *) mem)) {
117 		tp_assert(false, "%s:%d %s() Invalid free(%p)",
118 				file, line, func, ptr);
119 	}
120 
121 	memset(mem, 0, sizeof(tp_mem) + mem->size + sizeof(*mem->footer));
122 	k_free(mem);
123 }
124 
tp_calloc(size_t nmemb,size_t size,const char * file,int line,const char * func)125 void *tp_calloc(size_t nmemb, size_t size, const char *file, int line,
126 		const char *func)
127 {
128 	size_t bytes = size * nmemb;
129 	void *ptr = tp_malloc(bytes, file, line, func);
130 
131 	memset(ptr, 0, bytes);
132 
133 	return ptr;
134 }
135 
tp_mem_stat(void)136 void tp_mem_stat(void)
137 {
138 	struct tp_mem *mem;
139 
140 	SYS_SLIST_FOR_EACH_CONTAINER(&tp_mem, mem, next) {
141 		tp_dbg("len=%zu %s:%d", mem->size, mem->file, mem->line);
142 		tp_mem_chk(mem);
143 	}
144 }
145 
tp_nbuf_alloc(struct net_buf_pool * pool,size_t len,const char * file,int line,const char * func)146 struct net_buf *tp_nbuf_alloc(struct net_buf_pool *pool, size_t len,
147 				const char *file, int line, const char *func)
148 {
149 	struct net_buf *nbuf = net_buf_alloc_len(pool, len, K_NO_WAIT);
150 	struct tp_nbuf *tp_nbuf = k_malloc(sizeof(struct tp_nbuf));
151 
152 	tp_assert(len, "");
153 	tp_assert(nbuf, "Out of nbufs");
154 
155 	tp_dbg("size=%d %p %s:%d %s()", nbuf->size, nbuf, file, line, func);
156 
157 	tp_nbuf->nbuf = nbuf;
158 	tp_nbuf->file = file;
159 	tp_nbuf->line = line;
160 
161 	sys_slist_append(&tp_nbufs, (sys_snode_t *) tp_nbuf);
162 
163 	return nbuf;
164 }
165 
tp_nbuf_clone(struct net_buf * buf,const char * file,int line,const char * func)166 struct net_buf *tp_nbuf_clone(struct net_buf *buf, const char *file, int line,
167 				const char *func)
168 {
169 	struct net_buf *clone = net_buf_clone(buf, K_NO_WAIT);
170 	struct tp_nbuf *tb = k_malloc(sizeof(struct tp_nbuf));
171 
172 	tp_dbg("size=%d %p %s:%d %s()", clone->size, clone, file, line, func);
173 
174 	tb->nbuf = clone;
175 	tb->file = file;
176 	tb->line = line;
177 
178 	sys_slist_append(&tp_nbufs, &tb->next);
179 
180 	return clone;
181 
182 }
183 
tp_nbuf_unref(struct net_buf * nbuf,const char * file,int line,const char * func)184 void tp_nbuf_unref(struct net_buf *nbuf, const char *file, int line,
185 			const char *func)
186 {
187 	bool found = false;
188 	struct tp_nbuf *tp_nbuf;
189 
190 	tp_dbg("len=%d %p %s:%d %s()", nbuf->len, nbuf, file, line, func);
191 
192 	SYS_SLIST_FOR_EACH_CONTAINER(&tp_nbufs, tp_nbuf, next) {
193 		if (tp_nbuf->nbuf == nbuf) {
194 			found = true;
195 			break;
196 		}
197 	}
198 
199 	tp_assert(found, "Invalid %s(%p): %s:%d", __func__, nbuf, file, line);
200 
201 	sys_slist_find_and_remove(&tp_nbufs, (sys_snode_t *) tp_nbuf);
202 
203 	net_buf_unref(nbuf);
204 
205 	k_free(tp_nbuf);
206 }
207 
tp_nbuf_stat(void)208 void tp_nbuf_stat(void)
209 {
210 	struct tp_nbuf *tp_nbuf;
211 
212 	SYS_SLIST_FOR_EACH_CONTAINER(&tp_nbufs, tp_nbuf, next) {
213 		tp_dbg("%s:%d len=%d", tp_nbuf->file, tp_nbuf->line,
214 			tp_nbuf->nbuf->len);
215 	}
216 }
217 
tp_pkt_alloc(struct net_pkt * pkt,const char * file,int line)218 void tp_pkt_alloc(struct net_pkt *pkt,
219 		  const char *file, int line)
220 {
221 	struct tp_pkt *tp_pkt = k_malloc(sizeof(struct tp_pkt));
222 
223 	tp_assert(tp_pkt, "");
224 	tp_assert(pkt, "");
225 
226 	tp_pkt->pkt = pkt;
227 	tp_pkt->file = file;
228 	tp_pkt->line = line;
229 
230 	sys_slist_append(&tp_pkts, (sys_snode_t *) tp_pkt);
231 }
232 
tp_pkt_clone(struct net_pkt * pkt,const char * file,int line)233 struct net_pkt *tp_pkt_clone(struct net_pkt *pkt, const char *file, int line)
234 {
235 	struct tp_pkt *tp_pkt = k_malloc(sizeof(struct tp_pkt));
236 
237 	pkt = net_pkt_clone(pkt, K_NO_WAIT);
238 
239 	tp_pkt->pkt = pkt;
240 	tp_pkt->file = file;
241 	tp_pkt->line = line;
242 
243 	sys_slist_append(&tp_pkts, (sys_snode_t *) tp_pkt);
244 
245 	return pkt;
246 }
247 
tp_pkt_unref(struct net_pkt * pkt,const char * file,int line)248 void tp_pkt_unref(struct net_pkt *pkt, const char *file, int line)
249 {
250 	bool found = false;
251 	struct tp_pkt *tp_pkt;
252 
253 	SYS_SLIST_FOR_EACH_CONTAINER(&tp_pkts, tp_pkt, next) {
254 		if (tp_pkt->pkt == pkt) {
255 			found = true;
256 			break;
257 		}
258 	}
259 
260 	tp_assert(found, "Invalid %s(%p): %s:%d", __func__, pkt, file, line);
261 
262 	sys_slist_find_and_remove(&tp_pkts, (sys_snode_t *) tp_pkt);
263 
264 	net_pkt_unref(tp_pkt->pkt);
265 
266 	k_free(tp_pkt);
267 }
268 
tp_pkt_stat(void)269 void tp_pkt_stat(void)
270 {
271 	struct tp_pkt *pkt;
272 
273 	SYS_SLIST_FOR_EACH_CONTAINER(&tp_pkts, pkt, next) {
274 		tp_dbg("%s:%d %p", pkt->file, pkt->line, pkt->pkt);
275 	}
276 }
277 
278 #define tp_seq_dump(_seq)						\
279 {									\
280 	tp_dbg("%s %u->%u (%s%d) %s:%d %s() %s",			\
281 		(_seq)->kind == TP_SEQ ? "SEQ" : "ACK",			\
282 		(_seq)->old_value, (_seq)->value,			\
283 		(_seq)->req >= 0 ? "+" : "", (_seq)->req,		\
284 		(_seq)->file, (_seq)->line, (_seq)->func,		\
285 		(_seq)->of ? "OF" : "");				\
286 }
287 
tp_seq_track(int kind,uint32_t * pvalue,int req,const char * file,int line,const char * func)288 uint32_t tp_seq_track(int kind, uint32_t *pvalue, int req,
289 			const char *file, int line, const char *func)
290 {
291 	struct tp_seq *seq = k_calloc(1, sizeof(struct tp_seq));
292 
293 	seq->file = file;
294 	seq->line = line;
295 	seq->func = func;
296 
297 	seq->kind = kind;
298 
299 	seq->req = req;
300 	seq->old_value = *pvalue;
301 
302 	if (req > 0) {
303 		seq->of = __builtin_uadd_overflow(seq->old_value, seq->req,
304 							&seq->value);
305 	} else {
306 		seq->value += req;
307 	}
308 
309 	*pvalue = seq->value;
310 
311 	sys_slist_append(&tp_seq, (sys_snode_t *) seq);
312 
313 	tp_seq_dump(seq);
314 
315 	return seq->value;
316 }
317 
tp_seq_stat(void)318 void tp_seq_stat(void)
319 {
320 	struct tp_seq *seq;
321 
322 	while ((seq = (struct tp_seq *) sys_slist_get(&tp_seq))) {
323 		tp_seq_dump(seq);
324 		k_free(seq);
325 	}
326 }
327 
tp_msg_to_type(const char * s)328 enum tp_type tp_msg_to_type(const char *s)
329 {
330 	enum tp_type type = TP_NONE;
331 
332 #define is_tp(_s, _type) do {		\
333 	if (is(#_type, _s)) {		\
334 		type = _type;		\
335 		goto out;		\
336 	}				\
337 } while (0)
338 
339 	is_tp(s, TP_COMMAND);
340 	is_tp(s, TP_CONFIG_REQUEST);
341 	is_tp(s, TP_INTROSPECT_REQUEST);
342 	is_tp(s, TP_DEBUG_STOP);
343 	is_tp(s, TP_DEBUG_STEP);
344 	is_tp(s, TP_DEBUG_CONTINUE);
345 
346 #undef is_tp
347 
348 out:
349 	tp_assert(type != TP_NONE, "Invalid message: %s", s);
350 
351 	return type;
352 }
353 
udp_finalize_pkt(struct net_pkt * pkt)354 static void udp_finalize_pkt(struct net_pkt *pkt)
355 {
356 	int ret = 0;
357 
358 	net_pkt_cursor_init(pkt);
359 
360 	if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
361 		ret = net_ipv4_finalize(pkt, IPPROTO_UDP);
362 	}
363 
364 	if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
365 		ret = net_ipv6_finalize(pkt, IPPROTO_UDP);
366 	}
367 
368 	NET_ASSERT(ret == 0);
369 }
370 
ip_header_add(struct net_pkt * pkt)371 static int ip_header_add(struct net_pkt *pkt)
372 {
373 	if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
374 		struct in_addr src;
375 		struct in_addr dst;
376 
377 		net_addr_pton(AF_INET, CONFIG_NET_CONFIG_MY_IPV4_ADDR, &src);
378 		net_addr_pton(AF_INET, CONFIG_NET_CONFIG_PEER_IPV4_ADDR, &dst);
379 
380 		return net_ipv4_create(pkt, &src, &dst);
381 	}
382 
383 	if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
384 		struct in6_addr src;
385 		struct in6_addr dst;
386 
387 		net_addr_pton(AF_INET6, CONFIG_NET_CONFIG_MY_IPV6_ADDR, &src);
388 		net_addr_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, &dst);
389 
390 		return net_ipv6_create(pkt, &src, &dst);
391 	}
392 
393 	return -EINVAL;
394 }
395 
tp_pkt_send(struct net_pkt * pkt)396 static void tp_pkt_send(struct net_pkt *pkt)
397 {
398 	net_pkt_ref(pkt);
399 
400 	if (net_send_data(pkt) < 0) {
401 		tp_err("net_send_data()");
402 	}
403 
404 	tp_pkt_unref(pkt, tp_basename(__FILE__), __LINE__);
405 }
406 
tp_output_pkt_alloc(sa_family_t af,struct net_if * iface,size_t len,const char * file,int line)407 static struct net_pkt *tp_output_pkt_alloc(sa_family_t af,
408 					   struct net_if *iface,
409 					   size_t len,
410 					   const char *file, int line)
411 {
412 	struct tp_pkt *tp_pkt = k_malloc(sizeof(struct tp_pkt));
413 
414 	tp_assert(tp_pkt, "");
415 
416 	tp_pkt->pkt = net_pkt_alloc_with_buffer(iface,
417 					sizeof(struct net_udp_hdr) + len,
418 					af, IPPROTO_UDP, K_NO_WAIT);
419 	tp_assert(tp_pkt->pkt, "");
420 
421 	tp_pkt->file = file;
422 	tp_pkt->line = line;
423 
424 	sys_slist_append(&tp_pkts, (sys_snode_t *) tp_pkt);
425 
426 	return tp_pkt->pkt;
427 }
428 
_tp_output(sa_family_t af,struct net_if * iface,void * data,size_t data_len,const char * file,int line)429 void _tp_output(sa_family_t af, struct net_if *iface, void *data,
430 		size_t data_len, const char *file, int line)
431 {
432 	struct net_pkt *pkt = tp_output_pkt_alloc(af, iface, data_len,
433 						  file, line);
434 	int ret;
435 
436 	ret = ip_header_add(pkt);
437 	if (ret < 0) {
438 		goto fail;
439 	}
440 
441 	ret = net_udp_create(pkt, htons(4242), htons(4242));
442 	if (ret < 0) {
443 		goto fail;
444 	}
445 
446 	ret = net_pkt_write(pkt, data, data_len);
447 	if (ret < 0) {
448 		goto fail;
449 	}
450 
451 	udp_finalize_pkt(pkt);
452 
453 	NET_ASSERT(net_pkt_get_len(pkt) <= net_if_get_mtu(pkt->iface));
454 
455 	tp_pkt_send(pkt);
456 
457 	return;
458 fail:
459 	NET_ASSERT(false);
460 }
461 
json_to_tp(void * data,size_t data_len)462 struct tp *json_to_tp(void *data, size_t data_len)
463 {
464 	static struct tp tp;
465 
466 	memset(&tp, 0, sizeof(tp));
467 
468 	if (json_obj_parse(data, data_len, tp_descr, ARRAY_SIZE(tp_descr),
469 			&tp) < 0) {
470 		tp_err("json_obj_parse()");
471 	}
472 
473 	tp.type = tp_msg_to_type(tp.msg);
474 
475 	return &tp;
476 }
477 
tp_new_find_and_apply(struct tp_new * tp,const char * key,void * value,int type)478 void tp_new_find_and_apply(struct tp_new *tp, const char *key, void *value,
479 				int type)
480 {
481 	bool found = false;
482 	int i;
483 
484 	for (i = 0; i < tp->num_entries; i++) {
485 		if (is(key, tp->data[i].key)) {
486 			found = true;
487 			break;
488 		}
489 	}
490 
491 	if (found) {
492 		switch (type) {
493 		case TP_BOOL: {
494 			bool new_value, old = *((bool *) value);
495 
496 			new_value = atoi(tp->data[i].value);
497 			*((bool *) value) = new_value;
498 			tp_dbg("%s %d->%d", key, old, new_value);
499 			break;
500 		}
501 		case TP_INT: {
502 			int new_value, old_value = *((int *) value);
503 
504 			new_value = atoi(tp->data[i].value);
505 			*((int *) value) = new_value;
506 			tp_dbg("%s %d->%d", key, old_value, new_value);
507 			break;
508 		}
509 		default:
510 			tp_err("Unimplemented");
511 		}
512 	}
513 }
514 
json_decode_msg(void * data,size_t data_len)515 enum tp_type json_decode_msg(void *data, size_t data_len)
516 {
517 	int decoded;
518 	struct tp_msg tp;
519 
520 	memset(&tp, 0, sizeof(tp));
521 
522 	decoded = json_obj_parse(data, data_len, tp_msg_dsc,
523 					ARRAY_SIZE(tp_msg_dsc), &tp);
524 #if 0
525 	if ((decoded & 1) == false) { /* TODO: this fails, why? */
526 		tp_err("json_obj_parse()");
527 	}
528 #endif
529 	tp_dbg("%s", tp.msg);
530 
531 	return tp.msg ? tp_msg_to_type(tp.msg) : TP_NONE;
532 }
533 
json_to_tp_new(void * data,size_t data_len)534 struct tp_new *json_to_tp_new(void *data, size_t data_len)
535 {
536 	static struct tp_new tp;
537 	int i;
538 
539 	memset(&tp, 0, sizeof(tp));
540 
541 	if (json_obj_parse(data, data_len, tp_new_dsc, ARRAY_SIZE(tp_new_dsc),
542 				&tp) < 0) {
543 		tp_err("json_obj_parse()");
544 	}
545 
546 	tp_dbg("%s", tp.msg);
547 
548 	for (i = 0; i < tp.num_entries; i++) {
549 		tp_dbg("%s=%s", tp.data[i].key, tp.data[i].value);
550 	}
551 
552 	return &tp;
553 }
554 
tp_encode(struct tp * tp,void * data,size_t * data_len)555 void tp_encode(struct tp *tp, void *data, size_t *data_len)
556 {
557 	int error;
558 
559 	error = json_obj_encode_buf(tp_descr, ARRAY_SIZE(tp_descr), tp,
560 					data, *data_len);
561 	if (error) {
562 		tp_err("json_obj_encode_buf()");
563 	}
564 
565 	*data_len = error ? 0 : strlen(data);
566 }
567 
568 
tp_new_to_json(struct tp_new * tp,void * data,size_t * data_len)569 void tp_new_to_json(struct tp_new *tp, void *data, size_t *data_len)
570 {
571 	int error = json_obj_encode_buf(tp_new_dsc, ARRAY_SIZE(tp_new_dsc), tp,
572 					data, *data_len);
573 	if (error) {
574 		tp_err("json_obj_encode_buf()");
575 	}
576 
577 	*data_len = error ? 0 : strlen(data);
578 }
579 
tp_out(sa_family_t af,struct net_if * iface,const char * msg,const char * key,const char * value)580 void tp_out(sa_family_t af, struct net_if *iface, const char *msg,
581 	    const char *key, const char *value)
582 {
583 	if (tp_trace) {
584 		size_t json_len;
585 		static uint8_t buf[128]; /* TODO: Merge all static buffers and
586 				       * eventually drop them
587 				       */
588 		struct tp_new tp = {
589 			.msg = msg,
590 			.data = { { .key = key, .value = value } },
591 			.num_entries = 1
592 		};
593 		json_len = sizeof(buf);
594 		tp_new_to_json(&tp, buf, &json_len);
595 		if (json_len) {
596 			tp_output(af, iface, buf, json_len);
597 		}
598 	}
599 }
600 
tp_tap_input(struct net_pkt * pkt)601 bool tp_tap_input(struct net_pkt *pkt)
602 {
603 	bool tap = tp_state != TP_NONE;
604 
605 	if (tap) {
606 		net_pkt_ref(pkt);
607 		/* STAILQ_INSERT_HEAD(&tp_q, pkt, stq_next); */
608 	}
609 
610 	return tap;
611 }
612