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 (false)
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