ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_net.c
Go to the documentation of this file.
1
18
19#include "board_net.h"
20
21#include <stdint.h>
22#include <stdio.h>
23#include <string.h>
24
25#include "board_console.h"
27
29typedef enum : uint8_t {
35
37typedef enum : uint32_t {
40
42typedef enum : uint32_t {
43 k_net_peer_ip = 0xC0A80101UL,
44 k_net_fw_ip = 0xC0A8012AUL,
46 k_net_peer_port = 49152U,
48
50typedef enum : uint32_t {
51 k_eth_hdr = 14U,
52 k_eth_arp = 0x0806U,
53 k_eth_ipv4 = 0x0800U,
54 k_arp_len = 28U,
55 k_ip_hdr = 20U,
59 k_mac_len = 6U,
60 k_net_buf = 1600U,
62
99
101typedef enum : uint8_t {
110
112typedef enum : uint8_t {
113 k_tcp_fin = 0x01U,
114 k_tcp_syn = 0x02U,
115 k_tcp_rst = 0x04U,
116 k_tcp_psh = 0x08U,
117 k_tcp_ack = 0x10U,
119
120static const uint8_t s_peer_mac[k_mac_len] =
121 {0x02U, 0x00U, (uint8_t)k_peer_mac_b2, 0x00U, (uint8_t)k_peer_mac_b4, 0x01U};
122
123static bool s_trace;
124static uint8_t s_state;
125static uint8_t s_fw_mac[k_mac_len];
126static bool s_fw_mac_known;
127static uint32_t s_arp_replies;
128static uint32_t s_pings;
129static uint32_t s_wait;
130static uint16_t s_ping_seq;
131static uint32_t s_tx_frames;
132static uint32_t s_polls;
133static uint32_t s_delivered;
134static uint32_t s_tcp_our_seq;
135static uint32_t s_tcp_their_seq;
136static uint32_t s_tcp_echoed;
137static bool s_tcp_match;
138static bool s_tcp_need_data;
139static uint32_t s_tcp_estab_wait;
140
155static const uint8_t s_tcp_payload[] = "tcp echo probe payload\n";
156
158enum : uint32_t {
160};
161static_assert((sizeof(s_tcp_payload) - 1U) == (size_t)k_net_tcp_payload_len,
162 "EIL contract: threadx_netx_tcp_echo's hil.conf HIL_EXPECT names "
163 "this byte count -- update examples/ek_ra8d2/hw_validated/hil/"
164 "threadx_netx_tcp_echo/hil.conf in the same change");
165
166/* Ring of frames queued for the firmware to receive. The firmware's RX worker
167 * drains all available frames per poll, so a handshake burst (ACK + data) can
168 * queue several at once. */
169enum : uint32_t {
171};
172static uint8_t s_rxq[k_net_qdepth][k_net_buf];
173static uint16_t s_rxq_len[k_net_qdepth];
174static uint32_t s_rxq_head;
175static uint32_t s_rxq_tail;
176
177/* =============================================================================
178 * Byte / checksum helpers.
179 * =============================================================================
180 */
181
192RA8_INTERNAL static void internal_put16(uint8_t* p, uint16_t v)
193{
194 p[0] = (uint8_t)(v >> 8);
195 p[1] = (uint8_t)(v & (uint32_t)k_byte_mask);
196}
197
208RA8_INTERNAL static void internal_put32(uint8_t* p, uint32_t v)
209{
210 p[0] = (uint8_t)(v >> (uint32_t)k_shift24);
211 p[1] = (uint8_t)((v >> 16) & (uint32_t)k_byte_mask);
212 p[2] = (uint8_t)((v >> 8) & (uint32_t)k_byte_mask);
213 p[3] = (uint8_t)(v & (uint32_t)k_byte_mask);
214}
215
227RA8_INTERNAL static uint16_t internal_get16(const uint8_t* p)
228{
229 return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]);
230}
231
243RA8_INTERNAL static uint32_t internal_get32(const uint8_t* p)
244{
245 return ((uint32_t)p[0] << (uint32_t)k_shift24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) |
246 (uint32_t)p[3];
247}
248
262RA8_INTERNAL static uint16_t internal_net_checksum(const uint8_t* d, uint32_t len, uint32_t seed)
263{
264 uint32_t sum = seed;
265 for (uint32_t i = 0U; (i + 1U) < len; i += 2U) {
266 sum += ((uint32_t)d[i] << 8) | (uint32_t)d[i + 1U];
267 }
268 if ((len & 1U) != 0U) {
269 sum += (uint32_t)d[len - 1U] << 8;
270 }
271 while ((sum >> 16) != 0U) {
272 sum = (sum & (uint32_t)k_u16_mask) + (sum >> 16);
273 }
274 return (uint16_t)(~sum & (uint32_t)k_u16_mask);
275}
276
287RA8_INTERNAL static void internal_net_queue(const uint8_t* frame, uint32_t len)
288{
289 const uint32_t next = (s_rxq_tail + 1U) % (uint32_t)k_net_qdepth;
290 if ((next == s_rxq_head) || (len > (uint32_t)k_net_buf)) {
291 return;
292 }
293 (void)memcpy(s_rxq[s_rxq_tail], frame, len);
294 s_rxq_len[s_rxq_tail] = (uint16_t)len;
295 s_rxq_tail = next;
296}
297
309RA8_INTERNAL static void internal_net_eth_hdr(uint8_t* f, const uint8_t* dst, uint16_t ethertype)
310{
311 (void)memcpy(&f[0], dst, k_mac_len);
312 (void)memcpy(&f[6], s_peer_mac, k_mac_len);
313 internal_put16(&f[k_eth_ethertype_off], ethertype);
314}
315
316/* =============================================================================
317 * ARP -- resolve the firmware's MAC.
318 * =============================================================================
319 */
320
330{
331 static const uint8_t bcast[k_mac_len] = {(uint8_t)k_byte_mask,
332 (uint8_t)k_byte_mask,
333 (uint8_t)k_byte_mask,
334 (uint8_t)k_byte_mask,
335 (uint8_t)k_byte_mask,
336 (uint8_t)k_byte_mask};
337 uint8_t f[k_eth_hdr + k_arp_len];
338 (void)memset(f, 0, sizeof(f));
339 internal_net_eth_hdr(f, bcast, (uint16_t)k_eth_arp);
340 uint8_t* a = &f[k_eth_hdr];
341 internal_put16(&a[0], 1U); /* htype = Ethernet. */
342 internal_put16(&a[2], (uint16_t)k_eth_ipv4); /* ptype = IPv4. */
343 a[4] = (uint8_t)k_mac_len;
344 a[k_arp_plen_off] = (uint8_t)k_arp_plen;
345 internal_put16(&a[6], 1U); /* op = request. */
346 (void)memcpy(&a[8], s_peer_mac, k_mac_len);
349 internal_net_queue(f, sizeof(f));
350}
351
362RA8_INTERNAL static void internal_net_send_arp_reply(const uint8_t* to_mac, uint32_t to_ip)
363{
364 uint8_t f[k_eth_hdr + k_arp_len];
365 (void)memset(f, 0, sizeof(f));
366 internal_net_eth_hdr(f, to_mac, (uint16_t)k_eth_arp);
367 uint8_t* a = &f[k_eth_hdr];
368 internal_put16(&a[0], 1U);
369 internal_put16(&a[2], (uint16_t)k_eth_ipv4);
370 a[4] = (uint8_t)k_mac_len;
371 a[k_arp_plen_off] = (uint8_t)k_arp_plen;
372 internal_put16(&a[6], 2U); /* op = reply. */
373 (void)memcpy(&a[8], s_peer_mac, k_mac_len);
375 (void)memcpy(&a[k_arp_tha_off], to_mac, k_mac_len);
376 internal_put32(&a[k_arp_tpa_off], to_ip);
377 internal_net_queue(f, sizeof(f));
378}
379
380/* =============================================================================
381 * ICMP -- ping the firmware.
382 * =============================================================================
383 */
384
396RA8_INTERNAL static void internal_net_ip_hdr(uint8_t* ip, uint8_t proto, uint16_t payload_len)
397{
398 (void)memset(ip, 0, k_ip_hdr);
399 ip[0] = (uint8_t)k_ipv4_ver_ihl; /* version 4, IHL 5. */
400 internal_put16(&ip[2], (uint16_t)(k_ip_hdr + payload_len));
401 internal_put16(&ip[4], (uint16_t)k_ip_ident); /* identification. */
402 internal_put16(&ip[6], (uint16_t)k_ip_flag_df); /* don't fragment. */
403 ip[8] = (uint8_t)k_ip_ttl; /* TTL. */
404 ip[k_ip_proto_off] = proto;
406 internal_put32(&ip[k_ip_dst_off], (uint32_t)k_net_fw_ip);
408}
409
419{
420 if (!s_fw_mac_known) {
421 return;
422 }
423 uint8_t f[k_eth_hdr + k_ip_hdr + k_icmp_hdr + 16U];
424 (void)memset(f, 0, sizeof(f));
426 const uint16_t icmp_len = (uint16_t)(k_icmp_hdr + 16U);
427 internal_net_ip_hdr(&f[k_eth_hdr], (uint8_t)k_ip_proto_icmp, icmp_len);
428 uint8_t* ic = &f[k_eth_hdr + k_ip_hdr];
429 ic[0] = 8U; /* echo request. */
430 s_ping_seq++;
431 internal_put16(&ic[4], (uint16_t)k_icmp_ident); /* identifier. */
432 internal_put16(&ic[6], s_ping_seq);
433 for (uint32_t i = 0U; i < 16U; i++) {
434 ic[k_icmp_hdr + i] = (uint8_t)((uint32_t)k_icmp_pat_base + i); /* payload pattern. */
435 }
436 internal_put16(&ic[2], internal_net_checksum(ic, icmp_len, 0U));
437 internal_net_queue(f, sizeof(f));
438}
439
440/* =============================================================================
441 * TCP -- connect to the firmware's echo server, send a payload, verify the echo.
442 * =============================================================================
443 */
444
456RA8_INTERNAL static void
457internal_net_send_tcp(uint8_t flags, const uint8_t* payload, uint16_t payload_len)
458{
459 if (!s_fw_mac_known) {
460 return;
461 }
463 const uint16_t tcp_len = (uint16_t)((uint16_t)k_tcp_hdr + payload_len);
464 if (((uint32_t)k_eth_hdr + (uint32_t)k_ip_hdr + (uint32_t)tcp_len) > sizeof(f)) {
465 return;
466 }
467 (void)memset(f, 0, sizeof(f));
469 internal_net_ip_hdr(&f[k_eth_hdr], (uint8_t)k_ip_proto_tcp, tcp_len);
470 uint8_t* t = &f[k_eth_hdr + k_ip_hdr];
471 internal_put16(&t[0], (uint16_t)k_net_peer_port);
472 internal_put16(&t[2], (uint16_t)k_net_echo_port);
475 t[k_tcp_off_dataoff] = (uint8_t)k_tcp_data_off; /* data offset = 5 32-bit words. */
476 t[k_tcp_off_flags] = flags;
477 internal_put16(&t[k_tcp_off_window], (uint16_t)k_tcp_window); /* window. */
478 if (payload_len > 0U) {
479 (void)memcpy(&t[k_tcp_off_payload], payload, payload_len);
480 }
481 /* TCP checksum covers the IPv4 pseudo-header + the segment. */
482 const uint32_t pseudo =
483 ((uint32_t)k_net_peer_ip >> 16) + ((uint32_t)k_net_peer_ip & (uint32_t)k_u16_mask) +
484 ((uint32_t)k_net_fw_ip >> 16) + ((uint32_t)k_net_fw_ip & (uint32_t)k_u16_mask) +
485 (uint32_t)k_ip_proto_tcp + (uint32_t)tcp_len;
486 internal_put16(&t[16], internal_net_checksum(t, tcp_len, pseudo));
487 internal_net_queue(f, (uint32_t)k_eth_hdr + (uint32_t)k_ip_hdr + (uint32_t)tcp_len);
488}
489
499{
500 s_tcp_our_seq = (uint32_t)k_tcp_isn; /* deterministic ISN. */
501 internal_net_send_tcp((uint8_t)k_tcp_syn, nullptr, 0U);
502}
503
513{
514 const uint16_t n = (uint16_t)(sizeof(s_tcp_payload) - 1U);
516 s_tcp_our_seq += (uint32_t)n;
517}
518
530RA8_INTERNAL static void
531internal_net_tcp_on_estab(uint32_t seq, const uint8_t* pdata, uint32_t plen)
532{
533 s_tcp_echoed = plen;
535 (plen == (uint32_t)(sizeof(s_tcp_payload) - 1U)) && (memcmp(pdata, s_tcp_payload, plen) == 0);
536 s_tcp_their_seq = seq + plen;
537 internal_net_send_tcp((uint8_t)k_tcp_ack, nullptr, 0U);
538 internal_net_send_tcp((uint8_t)(k_tcp_fin | k_tcp_ack), nullptr, 0U);
539 s_tcp_our_seq += 1U; /* FIN consumes one. */
540 s_state = (uint8_t)k_net_fin;
541 if (s_trace) {
542 (void)priv_emu_io_errf(" [net] TCP echo %u byte(s) match=%s\n", plen, s_tcp_match ? "Y" : "N");
543 }
544}
545
556RA8_INTERNAL static void internal_net_rx_tcp(const uint8_t* t, uint32_t len)
557{
558 if (len < (uint32_t)k_tcp_hdr) {
559 return;
560 }
561 if ((internal_get16(&t[0]) != (uint16_t)k_net_echo_port) ||
562 (internal_get16(&t[2]) != (uint16_t)k_net_peer_port)) {
563 return;
564 }
565 const uint32_t seq = internal_get32(&t[4]);
566 const uint8_t flags = t[13];
567 const uint32_t doff =
568 (uint32_t)((t[k_tcp_off_dataoff] >> (uint32_t)k_tcp_doff_shift) & (uint32_t)k_ip_ihl_mask) *
569 (uint32_t)k_ihl_word;
570 if ((doff < (uint32_t)k_tcp_hdr) || (doff > len)) {
571 return;
572 }
573 const uint32_t plen = len - doff;
574 const uint8_t* pdata = &t[doff];
575 if (s_trace) {
576 (void)priv_emu_io_errf(" [net] RX TCP flags=0x%02X seq=%u ack=%u plen=%u (state %u)\n",
577 (unsigned)flags,
578 seq,
579 internal_get32(&t[8]),
580 plen,
581 (unsigned)s_state);
582 }
583
584 if ((s_state == (uint8_t)k_net_syn) && ((flags & (uint8_t)k_tcp_syn) != 0U) &&
585 ((flags & (uint8_t)k_tcp_ack) != 0U)) {
586 s_tcp_their_seq = seq + 1U; /* their SYN consumes one sequence number. */
587 s_tcp_our_seq += 1U; /* our SYN consumed one. */
588 internal_net_send_tcp((uint8_t)k_tcp_ack, nullptr, 0U);
589 /* Defer the payload a few ticks so the firmware's accept() binds the socket
590 * and the echo thread is waiting in receive() before the data arrives. */
591 s_tcp_need_data = true;
592 s_tcp_estab_wait = 0U;
593 s_state = (uint8_t)k_net_estab;
594 return;
595 }
596 if ((s_state == (uint8_t)k_net_estab) && (plen > 0U)) {
597 internal_net_tcp_on_estab(seq, pdata, plen);
598 return;
599 }
600 if ((s_state == (uint8_t)k_net_fin) && ((flags & (uint8_t)k_tcp_fin) != 0U)) {
601 s_tcp_their_seq = seq + plen + 1U; /* their FIN consumes one. */
602 internal_net_send_tcp((uint8_t)k_tcp_ack, nullptr, 0U);
603 s_state = (uint8_t)k_net_done;
604 return;
605 }
606}
607
608/* =============================================================================
609 * RX parsing + the peer state machine.
610 * =============================================================================
611 */
612
623RA8_INTERNAL static void internal_net_rx_arp(const uint8_t* a, uint32_t len)
624{
625 if (len < (uint32_t)k_arp_len) {
626 return;
627 }
628 const uint16_t op = internal_get16(&a[6]);
629 const uint32_t spa = internal_get32(&a[14]);
630 const uint32_t tpa = internal_get32(&a[24]);
631 if (spa == (uint32_t)k_net_fw_ip) {
632 (void)memcpy(s_fw_mac, &a[8], k_mac_len); /* sender HW = firmware MAC. */
633 s_fw_mac_known = true;
634 if (op == 2U) {
636 }
637 }
638 if ((op == 1U) && (tpa == (uint32_t)k_net_peer_ip)) {
639 internal_net_send_arp_reply(&a[8], spa); /* firmware asked who-has us. */
640 }
641 if (s_fw_mac_known && (s_state == (uint8_t)k_net_arp)) {
643 s_state = (uint8_t)k_net_ping;
644 s_wait = 0U;
645 }
646}
647
658RA8_INTERNAL static void internal_net_rx_icmp(const uint8_t* ic, uint32_t len)
659{
660 if ((len >= (uint32_t)k_icmp_hdr) && (ic[0] == 0U)) { /* echo reply. */
661 s_pings++;
662 if (s_state == (uint8_t)k_net_ping) {
663 if (s_trace) {
664 (void)priv_emu_io_errf(
665 " [net] ICMP echo reply from 192.168.1.42 -- ping ok; opening TCP\n");
666 }
667 internal_net_send_syn(); /* ping proven; connect to the echo server. */
668 s_state = (uint8_t)k_net_syn;
669 s_wait = 0U;
670 }
671 }
672}
673
684RA8_INTERNAL static void internal_net_rx_ipv4(const uint8_t* ip, uint32_t len)
685{
686 if (len < (uint32_t)k_ip_hdr) {
687 return;
688 }
689 const uint32_t ihl = (uint32_t)(ip[0] & (uint32_t)k_ip_ihl_mask) * (uint32_t)k_ihl_word;
690 if ((ihl < (uint32_t)k_ip_hdr) || (ihl > len)) {
691 return;
692 }
693 /* Use the IP total-length field, not the frame length: a short frame is padded
694 * to the 60-byte Ethernet minimum, and that padding must not be mistaken for
695 * upper-layer payload (e.g. a bare TCP ACK would otherwise look like 6 data
696 * bytes). */
697 uint32_t actual = len;
698 const uint16_t ip_total = internal_get16(&ip[2]);
699 if (((uint32_t)ip_total >= ihl) && ((uint32_t)ip_total <= len)) {
700 actual = (uint32_t)ip_total;
701 }
702 const uint8_t proto = ip[9];
703 if (proto == (uint8_t)k_ip_proto_icmp) {
704 internal_net_rx_icmp(&ip[ihl], actual - ihl);
705 } else if (proto == (uint8_t)k_ip_proto_tcp) {
706 internal_net_rx_tcp(&ip[ihl], actual - ihl);
707 }
708}
709
710void board_net_on_tx(const uint8_t* frame, uint32_t len)
711{
712 s_tx_frames++;
713 if (len < (uint32_t)k_eth_hdr) {
714 return;
715 }
716 if (s_trace) {
717 (void)priv_emu_io_errf(" [net] firmware TX %u bytes ethertype 0x%04X\n",
718 len,
719 (unsigned)internal_get16(&frame[k_eth_ethertype_off]));
720 }
721 const uint16_t ethertype = internal_get16(&frame[k_eth_ethertype_off]);
722 /* Console NET tab: one line per frame the firmware transmits. */
723 char ln[k_net_console_line_cap];
724 (void)snprintf(ln, sizeof(ln), "NET tx eth=0x%04X %uB", (unsigned)ethertype, (unsigned)len);
726 if (ethertype == (uint16_t)k_eth_arp) {
727 internal_net_rx_arp(&frame[k_eth_hdr], len - (uint32_t)k_eth_hdr);
728 } else if (ethertype == (uint16_t)k_eth_ipv4) {
729 internal_net_rx_ipv4(&frame[k_eth_hdr], len - (uint32_t)k_eth_hdr);
730 }
731}
732
733uint32_t board_net_poll_rx(uint8_t* buf, uint32_t max)
734{
735 s_polls++;
736 if (s_rxq_head == s_rxq_tail) {
737 return 0U; /* ring empty. */
738 }
739 const uint32_t n = s_rxq_len[s_rxq_head];
740 if (n > max) {
741 return 0U;
742 }
743 (void)memcpy(buf, s_rxq[s_rxq_head], n);
744 s_rxq_head = (s_rxq_head + 1U) % (uint32_t)k_net_qdepth;
745 s_delivered++;
746 /* Console NET tab: one line per frame the peer delivers to the firmware. */
747 char ln[k_net_console_line_cap];
748 (void)snprintf(ln, sizeof(ln), "NET rx %uB (#%u)", (unsigned)n, (unsigned)s_delivered);
750 return n;
751}
752
754{
755 s_wait++;
756 if (s_state == (uint8_t)k_net_init) {
758 s_state = (uint8_t)k_net_arp;
759 s_wait = 0U;
760 return;
761 }
762 if ((s_state == (uint8_t)k_net_estab) && s_tcp_need_data) {
763 enum : uint32_t { k_net_data_delay = 800U };
765 if (s_tcp_estab_wait > k_net_data_delay) {
766 internal_net_send_data(); /* connection settled; send the echo payload. */
767 s_tcp_need_data = false;
768 }
769 return;
770 }
771 /* Retransmit the pending step if the firmware has not answered for a while
772 * (the stack may still be bringing the interface up on the first attempts). */
773 enum : uint32_t { k_net_retry = 2000U };
774 if (s_wait > k_net_retry) {
775 s_wait = 0U;
776 if (s_state == (uint8_t)k_net_arp) {
778 } else if (s_state == (uint8_t)k_net_ping) {
780 } else if (s_state == (uint8_t)k_net_syn) {
782 }
783 }
784}
785
786void board_net_init(bool trace)
787{
788 s_trace = trace;
789 s_state = (uint8_t)k_net_init;
790 s_fw_mac_known = false;
791 s_arp_replies = 0U;
792 s_pings = 0U;
793 s_wait = 0U;
794 s_ping_seq = 0U;
795 s_rxq_head = 0U;
796 s_rxq_tail = 0U;
797 s_tx_frames = 0U;
798 s_polls = 0U;
799 s_delivered = 0U;
800 s_tcp_our_seq = 0U;
801 s_tcp_their_seq = 0U;
802 s_tcp_echoed = 0U;
803 s_tcp_match = false;
804 s_tcp_need_data = false;
805 s_tcp_estab_wait = 0U;
806 (void)memset(s_fw_mac, 0, sizeof(s_fw_mac));
807}
808
818RA8_INTERNAL static const char* internal_net_echo_state(void)
819{
820 if (s_tcp_match) {
821 return "MATCH";
822 }
823 if (s_tcp_echoed > 0U) {
824 return "MISMATCH";
825 }
826 return "pending";
827}
828
830{
831 if (s_state == (uint8_t)k_net_init) {
832 return; /* networking never came up in this run. */
833 }
834 (void)priv_emu_io_errf(" NET peer : 192.168.1.1 <-> 192.168.1.42 ARP %s ping %s (%u)\n",
835 s_fw_mac_known ? "resolved" : "--",
836 (s_pings > 0U) ? "ok" : "--",
837 s_pings);
838 (void)priv_emu_io_errf(" NET activity : fw TX %u frame(s), RX polls %u, delivered %u\n",
840 s_polls,
842 if (s_state >= (uint8_t)k_net_syn) {
843 (void)priv_emu_io_errf(" NET TCP : port 7 %s; echo %s (%u byte(s))\n",
844 (s_state >= (uint8_t)k_net_estab) ? "established + data sent"
845 : "SYN sent",
848 }
849}
Multi-channel console log store backing the board view's tabbed console.
void board_console_push(board_console_ch_t ch, const char *line)
Append one completed line to a channel ring and the ALL ring.
@ k_board_console_ch_net
Ethernet / IPv4 / TCP packet summaries.
static RA8_INTERNAL void internal_net_rx_icmp(const uint8_t *ic, uint32_t len)
Handle an inbound ICMP echo reply (count a successful ping).
Definition board_net.c:658
static uint16_t s_ping_seq
ICMP echo sequence.
Definition board_net.c:130
static uint32_t s_wait
Ticks since the last send.
Definition board_net.c:129
static uint8_t s_fw_mac[k_mac_len]
Learned from ARP.
Definition board_net.c:125
static uint32_t s_arp_replies
ARP replies received.
Definition board_net.c:127
static uint32_t s_delivered
Frames delivered to firmware.
Definition board_net.c:133
static RA8_INTERNAL void internal_net_ip_hdr(uint8_t *ip, uint8_t proto, uint16_t payload_len)
Fill a 20-byte IPv4 header (no options) + compute its checksum.
Definition board_net.c:396
static uint8_t s_rxq[k_net_qdepth][k_net_buf]
Definition board_net.c:172
static uint32_t s_tcp_estab_wait
Ticks since the connection established.
Definition board_net.c:139
static uint32_t s_rxq_tail
Definition board_net.c:175
static RA8_INTERNAL void internal_net_send_ping(void)
Build + queue an ICMP echo request to the firmware.
Definition board_net.c:418
static RA8_INTERNAL void internal_net_rx_arp(const uint8_t *a, uint32_t len)
Handle an inbound ARP frame (learn the firmware MAC / answer who-has).
Definition board_net.c:623
static RA8_INTERNAL void internal_net_send_arp_reply(const uint8_t *to_mac, uint32_t to_ip)
Build + queue an ARP reply giving the peer's MAC to the firmware.
Definition board_net.c:362
static uint32_t s_polls
ra8_eth_read polls served.
Definition board_net.c:132
net_state_t
Peer state machine: ARP -> ping -> TCP connect / echo / close.
Definition board_net.c:101
@ k_net_init
Nothing sent yet.
Definition board_net.c:102
@ k_net_fin
FIN out; awaiting close.
Definition board_net.c:107
@ k_net_estab
Connected; data out, awaiting echo.
Definition board_net.c:106
@ k_net_syn
TCP SYN out; awaiting SYN-ACK.
Definition board_net.c:105
@ k_net_done
Connection closed.
Definition board_net.c:108
@ k_net_arp
ARP request out; awaiting reply.
Definition board_net.c:103
@ k_net_ping
ICMP echo out; awaiting reply.
Definition board_net.c:104
static RA8_INTERNAL void internal_net_tcp_on_estab(uint32_t seq, const uint8_t *pdata, uint32_t plen)
ESTAB state: echo-match the payload, then start our active (FIN) close.
Definition board_net.c:531
net_proto_t
Protocol field offsets, masks, and well-known values for the frames board_net builds/parses (Ethernet...
Definition board_net.c:68
@ k_tcp_window
TCP advertised window.
Definition board_net.c:95
@ k_ip_dst_off
IPv4 destination-address offset.
Definition board_net.c:84
@ k_ip_ihl_mask
IHL / data-offset nibble mask.
Definition board_net.c:85
@ k_ip_src_off
IPv4 source-address offset.
Definition board_net.c:83
@ k_peer_mac_b4
Peer MAC octet 4.
Definition board_net.c:73
@ k_arp_tpa_off
ARP target-protocol-address offset.
Definition board_net.c:76
@ k_ipv4_ver_ihl
IPv4 version 4, IHL 5.
Definition board_net.c:77
@ k_tcp_isn
Deterministic initial seq number.
Definition board_net.c:96
@ k_icmp_ident
ICMP echo identifier (fixed).
Definition board_net.c:87
@ k_peer_mac_b2
Peer MAC octet 2 (locally admin).
Definition board_net.c:72
@ k_ihl_word
IHL/data-offset word size (bytes).
Definition board_net.c:86
@ k_tcp_off_window
TCP window field position.
Definition board_net.c:93
@ k_ip_ident
IPv4 identification (fixed).
Definition board_net.c:78
@ k_ip_csum_off
IPv4 header-checksum offset.
Definition board_net.c:82
@ k_tcp_data_off
TCP data offset = 5 words.
Definition board_net.c:94
@ k_tcp_off_flags
TCP flags byte position.
Definition board_net.c:92
@ k_shift24
Byte-3 position in a 32-bit word.
Definition board_net.c:71
@ k_ip_proto_off
IPv4 protocol-field offset.
Definition board_net.c:81
@ k_ip_flag_df
IPv4 don't-fragment flag.
Definition board_net.c:79
@ k_arp_plen
ARP protocol-address length (IPv4).
Definition board_net.c:75
@ k_tcp_doff_shift
TCP data-offset high-nibble shift.
Definition board_net.c:97
@ k_u16_mask
16-bit field.
Definition board_net.c:70
@ k_tcp_hdr
TCP header bytes (no options).
Definition board_net.c:89
@ k_tcp_payload_max
Max TCP payload board_net sends.
Definition board_net.c:90
@ k_tcp_off_dataoff
TCP data-offset byte position.
Definition board_net.c:91
@ k_eth_ethertype_off
EtherType offset in the eth header.
Definition board_net.c:74
@ k_icmp_pat_base
ICMP payload byte-pattern base.
Definition board_net.c:88
@ k_ip_ttl
IPv4 default TTL.
Definition board_net.c:80
void board_net_report(void)
Print the end-of-run network summary (link / ARP / ping / TCP).
Definition board_net.c:829
void board_net_init(bool trace)
Reset the virtual network peer to its initial state.
Definition board_net.c:786
static uint16_t s_rxq_len[k_net_qdepth]
Definition board_net.c:173
static RA8_INTERNAL uint32_t internal_get32(const uint8_t *p)
Read a big-endian 32-bit value from p.
Definition board_net.c:243
static const uint8_t s_tcp_payload[]
Payload the peer sends to the firmware's TCP echo server.
Definition board_net.c:155
static uint32_t s_pings
ICMP echo replies received.
Definition board_net.c:128
static const uint8_t s_peer_mac[k_mac_len]
Definition board_net.c:120
static RA8_INTERNAL uint16_t internal_get16(const uint8_t *p)
Read a big-endian 16-bit value from p.
Definition board_net.c:227
uint32_t board_net_poll_rx(uint8_t *buf, uint32_t max)
Fetch the next frame the peer wants the firmware to receive.
Definition board_net.c:733
static uint32_t s_tcp_our_seq
Our next TCP send sequence.
Definition board_net.c:134
static RA8_INTERNAL void internal_net_send_syn(void)
Open the TCP connection: send SYN with our initial sequence number.
Definition board_net.c:498
static RA8_INTERNAL void internal_net_send_data(void)
Send the test payload to the established echo connection.
Definition board_net.c:512
static uint32_t s_tcp_echoed
Echo payload bytes received.
Definition board_net.c:136
static RA8_INTERNAL void internal_net_rx_ipv4(const uint8_t *ip, uint32_t len)
Handle an inbound IPv4 frame, dispatching by protocol.
Definition board_net.c:684
board_net_frame_off_t
Offsets into the frames this stub synthesises (RFC 826 / RFC 793).
Definition board_net.c:29
@ k_arp_tha_off
ARP target-hardware-address offset.
Definition board_net.c:32
@ k_tcp_off_payload
TCP payload offset (no options here).
Definition board_net.c:33
@ k_arp_plen_off
ARP protocol-address-length field offset.
Definition board_net.c:30
@ k_arp_spa_off
ARP sender-protocol-address offset.
Definition board_net.c:31
net_frame_t
Frame offsets / sizes (Ethernet II + ARP + IPv4 + ICMP + TCP).
Definition board_net.c:50
@ k_icmp_hdr
ICMP echo header.
Definition board_net.c:56
@ k_eth_hdr
dst[6] src[6] type[2].
Definition board_net.c:51
@ k_arp_len
ARP payload length.
Definition board_net.c:54
@ k_net_buf
Staging buffer size.
Definition board_net.c:60
@ k_ip_proto_tcp
IPv4 protocol = TCP.
Definition board_net.c:58
@ k_ip_hdr
IPv4 header (no options).
Definition board_net.c:55
@ k_ip_proto_icmp
IPv4 protocol = ICMP.
Definition board_net.c:57
@ k_eth_ipv4
IPv4 ethertype.
Definition board_net.c:53
@ k_mac_len
Ethernet address length.
Definition board_net.c:59
@ k_eth_arp
ARP ethertype.
Definition board_net.c:52
net_tcp_flag_t
TCP control-bit flags.
Definition board_net.c:112
@ k_tcp_syn
TCP syn.
Definition board_net.c:114
@ k_tcp_rst
TCP rst.
Definition board_net.c:115
@ k_tcp_fin
TCP fin.
Definition board_net.c:113
@ k_tcp_ack
TCP ack.
Definition board_net.c:117
@ k_tcp_psh
TCP psh.
Definition board_net.c:116
@ k_net_qdepth
Net qdepth.
Definition board_net.c:170
@ k_net_tcp_payload_len
sizeof(s_tcp_payload) - 1, pinned.
Definition board_net.c:159
static bool s_tcp_need_data
Payload queued to send post-handshake.
Definition board_net.c:138
static RA8_INTERNAL void internal_put16(uint8_t *p, uint16_t v)
Store a 16-bit value big-endian (network order) at p.
Definition board_net.c:192
static RA8_INTERNAL uint16_t internal_net_checksum(const uint8_t *d, uint32_t len, uint32_t seed)
16-bit one's-complement checksum over len bytes at d.
Definition board_net.c:262
void board_net_on_tx(const uint8_t *frame, uint32_t len)
Hand one frame the firmware transmitted to the peer (ra8_eth_write).
Definition board_net.c:710
static RA8_INTERNAL void internal_net_rx_tcp(const uint8_t *t, uint32_t len)
Handle an inbound TCP segment: drive the connect / echo / close FSM.
Definition board_net.c:556
static uint32_t s_rxq_head
Definition board_net.c:174
static RA8_INTERNAL void internal_net_queue(const uint8_t *frame, uint32_t len)
Queue a built frame for the firmware to receive (drops if ring full).
Definition board_net.c:287
static RA8_INTERNAL void internal_net_send_tcp(uint8_t flags, const uint8_t *payload, uint16_t payload_len)
Build + queue a TCP segment to the firmware echo port (flags+payload).
Definition board_net.c:457
static uint32_t s_tx_frames
Frames the firmware sent.
Definition board_net.c:131
net_addr_t
Addressing + protocol constants for the peer and the firmware.
Definition board_net.c:42
@ k_net_echo_port
Firmware TCP echo server port.
Definition board_net.c:45
@ k_net_peer_ip
192.168.1.1 (the peer).
Definition board_net.c:43
@ k_net_peer_port
Peer ephemeral source port.
Definition board_net.c:46
@ k_net_fw_ip
192.168.1.42 (the firmware).
Definition board_net.c:44
static uint32_t s_tcp_their_seq
Their next seq (our ack).
Definition board_net.c:135
static bool s_fw_mac_known
Definition board_net.c:126
static RA8_INTERNAL void internal_net_send_arp_request(void)
Build + queue an ARP request asking who-has the firmware's IP.
Definition board_net.c:329
static RA8_INTERNAL const char * internal_net_echo_state(void)
One-word verdict for the TCP echo leg of the run report.
Definition board_net.c:818
static bool s_tcp_match
Echo matched what we sent.
Definition board_net.c:137
net_console_t
Console-tap line buffer capacity for a network packet summary.
Definition board_net.c:37
@ k_net_console_line_cap
Max chars in a "NET tx eth=.." line.
Definition board_net.c:38
void board_net_tick(void)
Advance the peer's state machine one tick (ARP -> ping -> TCP echo).
Definition board_net.c:753
static RA8_INTERNAL void internal_put32(uint8_t *p, uint32_t v)
Store a 32-bit value big-endian at p.
Definition board_net.c:208
static RA8_INTERNAL void internal_net_eth_hdr(uint8_t *f, const uint8_t *dst, uint16_t ethertype)
Fill the 14-byte Ethernet header into f.
Definition board_net.c:309
Virtual network peer for ra8_emulator – talks TCP/IP to the firmware.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
@ k_byte_mask
Byte mask.
static uint32_t s_state
static volatile uint32_t s_trace[k_dcd_trace_entries]
JLink-readable ring of packed transfer/SETUP events.