From b8b1e10cf8673ea368f5fd609f67543c5689a1ef Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 07:24:58 +0100 Subject: [PATCH 01/25] Improve error handling --- src/http/httpd.c | 127 ++++++++++++++++++++++++++++--------- src/port/posix/linux_tap.c | 1 + 2 files changed, 99 insertions(+), 29 deletions(-) diff --git a/src/http/httpd.c b/src/http/httpd.c index 8ff8d2f1..510e7982 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -20,6 +20,7 @@ */ #include "wolfip.h" #include "httpd.h" +#include static const char *http_status_text(int status_code) { switch (status_code) { @@ -55,7 +56,9 @@ static struct http_client *http_client_find(struct httpd *httpd, int sd) { int httpd_register_handler(struct httpd *httpd, const char *path, int (*handler)(struct httpd *httpd, struct http_client *hc, struct http_request *req)) { for (int i = 0; i < HTTPD_MAX_URLS; i++) { if (httpd->urls[i].handler == NULL) { + /* Copy path and guarantee null termination */ strncpy(httpd->urls[i].path, path, HTTP_PATH_LEN); + httpd->urls[i].path[HTTP_PATH_LEN-1] = '\0'; httpd->urls[i].handler = handler; return 0; } @@ -66,7 +69,9 @@ int httpd_register_handler(struct httpd *httpd, const char *path, int (*handler) int httpd_register_static_page(struct httpd *httpd, const char *path, const char *content) { for (int i = 0; i < HTTPD_MAX_URLS; i++) { if (httpd->urls[i].handler == NULL) { + /* Copy path and guarantee null termination */ strncpy(httpd->urls[i].path, path, HTTP_PATH_LEN); + httpd->urls[i].path[HTTP_PATH_LEN-1] = '\0'; httpd->urls[i].handler = NULL; httpd->urls[i].static_content = content; return 0; @@ -104,18 +109,39 @@ void http_send_response_headers(struct http_client *hc, int status_code, const c status_code, status_text, content_type, content_length); } if (hc->ssl) { - wolfSSL_write(hc->ssl, txt_response, strlen(txt_response)); + int rc = wolfSSL_write(hc->ssl, txt_response, strlen(txt_response)); + if (rc <= 0) { + /* Error – close connection */ + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + } } else { - wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, txt_response, strlen(txt_response), 0); + int rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, txt_response, strlen(txt_response), 0); + if (rc <= 0) { + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + } } } void http_send_response_body(struct http_client *hc, const void *body, size_t len) { if (!hc) return; if (hc->ssl) { - wolfSSL_write(hc->ssl, body, len); + int rc = wolfSSL_write(hc->ssl, body, len); + if (rc <= 0) { + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + } } else { - wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, body, len, 0); + int rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, body, len, 0); + if (rc <= 0) { + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + } } } @@ -125,23 +151,52 @@ void http_send_response_chunk(struct http_client *hc, const void *chunk, size_t if (!hc) return; snprintf(txt_chunk, sizeof(txt_chunk), "%zx\r\n", len); if (hc->ssl) { - wolfSSL_write(hc->ssl, txt_chunk, strlen(txt_chunk)); - wolfSSL_write(hc->ssl, chunk, len); - wolfSSL_write(hc->ssl, "\r\n", 2); + int rc = wolfSSL_write(hc->ssl, txt_chunk, strlen(txt_chunk)); + if (rc <= 0) + goto close_conn; + rc = wolfSSL_write(hc->ssl, chunk, len); + if (rc <= 0) + goto close_conn; + rc = wolfSSL_write(hc->ssl, "\r\n", 2); + if (rc <= 0) + goto close_conn; } else { struct wolfIP *s = hc->httpd->ipstack; - wolfIP_sock_send(s, hc->client_sd, txt_chunk, strlen(txt_chunk), 0); - wolfIP_sock_send(s, hc->client_sd, chunk, len, 0); - wolfIP_sock_send(s, hc->client_sd, "\r\n", 2, 0); + int rc = wolfIP_sock_send(s, hc->client_sd, txt_chunk, strlen(txt_chunk), 0); + if (rc <= 0) + goto close_conn; + rc = wolfIP_sock_send(s, hc->client_sd, chunk, len, 0); + if (rc <= 0) + goto close_conn; + rc = wolfIP_sock_send(s, hc->client_sd, "\r\n", 2, 0); + if (rc <= 0) + goto close_conn; + } + return; +close_conn: + if (hc->ssl) { + wolfSSL_free(hc->ssl); + hc->ssl = NULL; } + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; } void http_send_response_chunk_end(struct http_client *hc) { if (!hc) return; if (hc->ssl) { - wolfSSL_write(hc->ssl, "0\r\n\r\n", 5); + if (wolfSSL_write(hc->ssl, "0\r\n\r\n", 5) <= 0) { + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + return; + } } else { - wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0); + if (wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0) <= 0) { + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; + } } } @@ -173,7 +228,12 @@ int http_url_decode(char *buf, size_t len) { if (!q) { break; } + /* Ensure we have two more hex digits */ if (q + 2 >= buf + len) { + break; /* Malformed escape */ + } + /* Validate hex characters before conversion */ + if (!isxdigit((unsigned char)q[1]) || !isxdigit((unsigned char)q[2])) { break; } *q = (char) strtol(q + 1, NULL, 16); @@ -194,13 +254,14 @@ int http_url_encode(char *buf, size_t len, size_t max_len) { if (len + 2 >= max_len) { return -1; /* Not enough space */ } + /* Shift memory to create space for %20 */ memmove(q + 3, q + 1, len - (q + 1 - buf)); *q = '%'; *(q + 1) = '2'; *(q + 2) = '0'; len += 2; } - if (q) + if (q && (len < max_len)) q[len] = '\0'; return len; } @@ -215,39 +276,51 @@ static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len) struct http_url *url = NULL; memset(&req, 0, sizeof(struct http_request)); http_url_decode(p, len); /* Decode can be done in place */ - if (len < 4) goto bad_request; + if (len < 4) + goto bad_request; /* Parse the request line */ q = strchr(p, ' '); - if (!q) goto bad_request; + if (!q) + goto bad_request; n = q - p; - if (n >= sizeof(req.method)) goto bad_request; + if (n >= sizeof(req.method)) + goto bad_request; memcpy(req.method, p, n); req.method[n] = '\0'; p = q + 1; q = strchr(p, ' '); - if (!q) goto bad_request; + if (!q) + goto bad_request; n = q - p; - if (n >= sizeof(req.path)) goto bad_request; + if (n >= sizeof(req.path)) + goto bad_request; memcpy(req.path, p, n); req.path[n] = '\0'; p = q + 1; q = strchr(p, '\r'); - if (!q) goto bad_request; + if (!q) + goto bad_request; n = q - p; - if (n >= sizeof(req.query)) goto bad_request; + if (n >= sizeof(req.query)) + goto bad_request; memcpy(req.query, p, n); req.query[n] = '\0'; p = q + 2; /* Parse the headers */ + /* Parse headers – keep them in a single buffer to avoid allocations */ while (p < end) { q = strstr(p, "\r\n"); - if (!q) goto bad_request; + if (!q) + goto bad_request; n = q - p; if (n == 0) { - break; + break; /* End of headers */ } - if (n >= sizeof(req.headers)) goto bad_request; + /* Enforce header maximum length */ + if (n >= sizeof(req.headers)) + goto bad_request; + /* Copy header and terminate */ memcpy(req.headers, p, n); req.headers[n] = '\0'; p = q + 2; @@ -266,7 +339,8 @@ static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len) if ((strcmp(req.method, "GET") != 0) && (strcmp(req.method, "POST") != 0)) goto bad_request; url = http_find_url(hc->httpd, req.path); - if (!url) goto not_found; + if (!url) + goto not_found; if ((url->handler == NULL) && (url->static_content == NULL)) goto service_unavailable; @@ -422,8 +496,3 @@ int httpd_init(struct httpd *httpd, struct wolfIP *s, uint16_t port, void *ssl_c wolfIP_register_callback(s, httpd->listen_sd, http_accept_cb, httpd); return 0; } - - - - - diff --git a/src/port/posix/linux_tap.c b/src/port/posix/linux_tap.c index 65cc824c..ca2207ab 100644 --- a/src/port/posix/linux_tap.c +++ b/src/port/posix/linux_tap.c @@ -83,6 +83,7 @@ int tap_init(struct ll *ll, const char *ifname, uint32_t host_ip) memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; if (ioctl(tap_fd, TUNSETIFF, (void *)&ifr) < 0) { perror("ioctl TUNSETIFF"); close(tap_fd); From 6183710653703403f25794e5020ed415182bf8e8 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 07:36:39 +0100 Subject: [PATCH 02/25] Renamed constants and interfaces --- config.h | 4 ++-- src/http/httpd.c | 4 ++-- src/port/wolfssl_io.c | 4 ++-- src/test/test_native_wolfssl.c | 8 ++++---- src/test/unit/unit.c | 8 ++++---- src/wolfip.c | 32 ++++++++++++++++---------------- wolfip.h | 5 ++--- 7 files changed, 32 insertions(+), 33 deletions(-) diff --git a/config.h b/config.h index 6455142b..a0bdafad 100644 --- a/config.h +++ b/config.h @@ -6,8 +6,8 @@ #define MAX_TCPSOCKETS 4 #define MAX_UDPSOCKETS 2 -#define RXBUF_SIZE LINK_MTU * 4 -#define TXBUF_SIZE LINK_MTU * 4 +#define RXBUF_SIZE LINK_MTU * 16 +#define TXBUF_SIZE LINK_MTU * 16 #define MAX_NEIGHBORS 16 diff --git a/src/http/httpd.c b/src/http/httpd.c index 510e7982..1a2e433c 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -418,7 +418,7 @@ static void http_accept_cb(int sd, uint16_t event, void *arg) { if (httpd->ssl_ctx) { httpd->clients[i].ssl = wolfSSL_new(httpd->ssl_ctx); if (httpd->clients[i].ssl) { - wolfSSL_SetIO_FT(httpd->clients[i].ssl, client_sd); + wolfSSL_SetIO_wolfIP(httpd->clients[i].ssl, client_sd); } else { /* Failed to create SSL object */ wolfIP_sock_close(httpd->ipstack, client_sd); @@ -491,7 +491,7 @@ int httpd_init(struct httpd *httpd, struct wolfIP *s, uint16_t port, void *ssl_c } if (ssl_ctx) { httpd->ssl_ctx = (WOLFSSL_CTX *) ssl_ctx; - wolfSSL_SetIO_FT_CTX(httpd->ssl_ctx, httpd->ipstack); + wolfSSL_SetIO_wolfIP_CTX(httpd->ssl_ctx, httpd->ipstack); } wolfIP_register_callback(s, httpd->listen_sd, http_accept_cb, httpd); return 0; diff --git a/src/port/wolfssl_io.c b/src/port/wolfssl_io.c index 83c50c55..83625c78 100644 --- a/src/port/wolfssl_io.c +++ b/src/port/wolfssl_io.c @@ -54,7 +54,7 @@ static int wolfIP_io_send(WOLFSSL* ssl, char* buf, int sz, void* ctx) return ret; } -int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX* ctx, struct wolfIP *s) +int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX* ctx, struct wolfIP *s) { wolfSSL_SetIORecv(ctx, wolfIP_io_recv); wolfSSL_SetIOSend(ctx, wolfIP_io_send); @@ -62,7 +62,7 @@ int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX* ctx, struct wolfIP *s) return 0; } -int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd) +int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd) { wolfSSL_SetIOReadCtx(ssl, (void*)(intptr_t)fd); wolfSSL_SetIOWriteCtx(ssl, (void*)(intptr_t)fd); diff --git a/src/test/test_native_wolfssl.c b/src/test/test_native_wolfssl.c index f2b3ad5b..cda8efb0 100644 --- a/src/test/test_native_wolfssl.c +++ b/src/test/test_native_wolfssl.c @@ -53,8 +53,8 @@ static WOLFSSL *server_ssl = NULL; /* Defined in wolfssl_io.c */ -int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd); -int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); +int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd); +int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); /* wolfIP: server side callback. */ static void server_cb(int fd, uint16_t event, void *arg) @@ -70,7 +70,7 @@ static void server_cb(int fd, uint16_t event, void *arg) printf("Failed to create server SSL object\n"); return; } - wolfSSL_SetIO_FT(server_ssl, client_fd); + wolfSSL_SetIO_wolfIP(server_ssl, client_fd); /* Accepting the TLS session is not necessary here, as the * first read will trigger the handshake. */ @@ -285,7 +285,7 @@ void test_wolfip_echoserver(struct wolfIP *s, uint32_t srv_ip) return; } printf("Associating server context with wolfIP\n"); - wolfSSL_SetIO_FT_CTX(server_ctx, s); + wolfSSL_SetIO_wolfIP_CTX(server_ctx, s); printf("Importing server certificate\n"); ret = wolfSSL_CTX_use_certificate_buffer(server_ctx, server_der, diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 0aeca382..2307a050 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -612,7 +612,7 @@ START_TEST(test_transport_checksum) { // Set up pseudo-header values for test ph.ph.src = 0xc0a80101; // 192.168.1.1 ph.ph.dst = 0xc0a80102; // 192.168.1.2 - ph.ph.proto = FT_IPPROTO_TCP; + ph.ph.proto = WI_IPPROTO_TCP; ph.ph.len = ee16(20); // TCP header length (without options) // Test with a simple TCP header with src/dst ports and no data @@ -640,7 +640,7 @@ START_TEST(test_iphdr_set_checksum) { ip.id = ee16(1); ip.flags_fo = 0; ip.ttl = 64; - ip.proto = FT_IPPROTO_TCP; + ip.proto = WI_IPPROTO_TCP; ip.src = ee32(0xc0a80101); // 192.168.1.1 ip.dst = ee32(0xc0a80102); // 192.168.1.2 @@ -682,13 +682,13 @@ START_TEST(test_ip_output_add_header) { t.S = &S; // Run the function for a TCP packet - int result = ip_output_add_header(&t, &ip, FT_IPPROTO_TCP, 40); + int result = ip_output_add_header(&t, &ip, WI_IPPROTO_TCP, 40); ck_assert_int_eq(result, 0); // Validate IP header fields ck_assert_uint_eq(ip.ver_ihl, 0x45); ck_assert_uint_eq(ip.ttl, 64); - ck_assert_uint_eq(ip.proto, FT_IPPROTO_TCP); + ck_assert_uint_eq(ip.proto, WI_IPPROTO_TCP); ck_assert_uint_eq(ip.src, ee32(t.local_ip)); ck_assert_uint_eq(ip.dst, ee32(t.remote_ip)); ck_assert_msg(ip.csum != 0, "IP header checksum should not be zero"); diff --git a/src/wolfip.c b/src/wolfip.c index fd97fab6..7ffbfa8f 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -32,9 +32,9 @@ #define ICMP_ECHO_REQUEST 8 #define ICMP_TTL_EXCEEDED 11 -#define FT_IPPROTO_ICMP 0x01 -#define FT_IPPROTO_TCP 0x06 -#define FT_IPPROTO_UDP 0x11 +#define WI_IPPROTO_ICMP 0x01 +#define WI_IPPROTO_TCP 0x06 +#define WI_IPPROTO_UDP 0x11 #define IPADDR_ANY 0x00000000 #define TCP_OPTION_MSS 0x02 @@ -62,8 +62,8 @@ #define NO_TIMER 0 -#define FT_IP_MTU 1500 -#define TCP_MSS (FT_IP_MTU - (IP_HEADER_LEN + TCP_HEADER_LEN)) +#define WI_IP_MTU 1500 +#define TCP_MSS (WI_IP_MTU - (IP_HEADER_LEN + TCP_HEADER_LEN)) /* Macros */ #define IS_IP_BCAST(ip) (ip == 0xFFFFFFFF) @@ -663,7 +663,7 @@ static struct tsocket *udp_new_socket(struct wolfIP *s) for (int i = 0; i < MAX_UDPSOCKETS; i++) { t = &s->udpsockets[i]; if (t->proto == 0) { - t->proto = FT_IPPROTO_UDP; + t->proto = WI_IPPROTO_UDP; t->S = s; fifo_init(&t->sock.udp.rxbuf, t->rxmem, RXBUF_SIZE); fifo_init(&t->sock.udp.txbuf, t->txmem, TXBUF_SIZE); @@ -699,7 +699,7 @@ static struct tsocket *tcp_new_socket(struct wolfIP *s) for (int i = 0; i < MAX_TCPSOCKETS; i++) { t = &s->tcpsockets[i]; if (t->proto == 0) { - t->proto = FT_IPPROTO_TCP; + t->proto = WI_IPPROTO_TCP; t->S = s; t->sock.tcp.state = TCP_CLOSED; t->sock.tcp.rto = 1000; @@ -907,11 +907,11 @@ static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, ph.ph.zero = 0; ph.ph.proto = proto; ph.ph.len = ee16(len - IP_HEADER_LEN); - if (proto == FT_IPPROTO_TCP) { + if (proto == WI_IPPROTO_TCP) { struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)ip; tcp->csum = 0; tcp->csum = ee16(transport_checksum(&ph, &tcp->src_port)); - } else if (proto == FT_IPPROTO_UDP) { + } else if (proto == WI_IPPROTO_UDP) { struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)ip; udp->csum = 0; udp->csum = ee16(transport_checksum(&ph, &udp->src_port)); @@ -1079,7 +1079,7 @@ static void tcp_input(struct wolfIP *S, struct wolfIP_tcp_seg *tcp, uint32_t fra icmp.csum = ee16(icmp_checksum(&icmp)); icmp.ip.src = tcp->ip.dst; icmp.ip.dst = tcp->ip.src; - icmp.ip.proto = FT_IPPROTO_ICMP; + icmp.ip.proto = WI_IPPROTO_ICMP; icmp.ip.id = ee16(S->ipcounter++); icmp.ip.csum = 0; iphdr_set_checksum(&icmp.ip); @@ -1179,7 +1179,7 @@ static void tcp_rto_cb(void *arg) struct wolfIP_timer tmr = { }; struct wolfIP_timer *ptmr = NULL; int pending = 0; - if ((ts->proto != FT_IPPROTO_TCP) || (ts->sock.tcp.state != TCP_ESTABLISHED)) + if ((ts->proto != WI_IPPROTO_TCP) || (ts->sock.tcp.state != TCP_ESTABLISHED)) return; desc = fifo_peek(&ts->sock.tcp.txbuf); while (desc) { @@ -1383,7 +1383,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len } if ((ts->dst_port==0) || (ts->remote_ip==0)) return -1; - if (len > FT_IP_MTU - IP_HEADER_LEN - UDP_HEADER_LEN) + if (len > WI_IP_MTU - IP_HEADER_LEN - UDP_HEADER_LEN) return -1; /* Fragmentation not supported */ if (fifo_space(&ts->sock.udp.txbuf) < len) return -11; @@ -1858,7 +1858,7 @@ int dhcp_client_init(struct wolfIP *s) wolfIP_sock_close(s, s->dhcp_udp_sd); } - s->dhcp_udp_sd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, FT_IPPROTO_UDP); + s->dhcp_udp_sd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); if (s->dhcp_udp_sd < 0) { s->dhcp_state = DHCP_OFF; return -1; @@ -2090,7 +2090,7 @@ int nslookup(struct wolfIP *s, const char *dname, uint16_t *id, void (*lookup_cb if (s->dns_server == 0) return -101; /* Network unreachable: No DNS server configured */ if (s->dns_id != 0) return -16; /* DNS query already in progress */ if (s->dns_udp_sd <= 0) { - s->dns_udp_sd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, FT_IPPROTO_UDP); + s->dns_udp_sd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP); if (s->dns_udp_sd < 0) return -1; wolfIP_register_callback(s, s->dns_udp_sd, dns_callback, s); @@ -2224,7 +2224,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) ts->sock.tcp.last_ack = ts->sock.tcp.ack; tcp->ack = ee32(ts->sock.tcp.ack); tcp->win = ee16(queue_space(&ts->sock.tcp.rxbuf)); - ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, FT_IPPROTO_TCP, size); + ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, WI_IPPROTO_TCP, size); s->ll_dev.send(&s->ll_dev, tcp, desc->len); desc->flags |= PKT_FLAG_SENT; desc->time_sent = now; @@ -2264,7 +2264,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6); #endif len = desc->len - ETH_HEADER_LEN; - ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, FT_IPPROTO_UDP, len); + ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len); s->ll_dev.send(&s->ll_dev, udp, desc->len); fifo_pop(&t->sock.udp.txbuf); desc = fifo_peek(&t->sock.udp.txbuf); diff --git a/wolfip.h b/wolfip.h index 8a3b0c89..280d97c8 100644 --- a/wolfip.h +++ b/wolfip.h @@ -160,9 +160,8 @@ static inline void iptoa(ip4 ip, char *buf) #endif #include #include -/* Defined in wolfssl_io.c */ -int wolfSSL_SetIO_FT(WOLFSSL* ssl, int fd); -int wolfSSL_SetIO_FT_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); +int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd); +int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); #endif #endif From 4173749de1a01d8cb0535ad35b070ab6fc66ea37 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 08:15:39 +0100 Subject: [PATCH 03/25] Added multiple interfaces --- config.h | 4 + docs/API.md | 20 ++ src/test/unit/unit.c | 157 ++++++++++++--- src/wolfip.c | 445 ++++++++++++++++++++++++++++++++----------- wolfip.h | 4 + 5 files changed, 495 insertions(+), 135 deletions(-) diff --git a/config.h b/config.h index a0bdafad..aeac6eca 100644 --- a/config.h +++ b/config.h @@ -11,6 +11,10 @@ #define MAX_NEIGHBORS 16 +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 1 +#endif + /* Linux test configuration */ #define WOLFIP_IP "10.10.10.2" #define LINUX_IP "10.10.10.1" diff --git a/docs/API.md b/docs/API.md index cf1d7b5f..d66d178f 100644 --- a/docs/API.md +++ b/docs/API.md @@ -30,6 +30,7 @@ struct ll { int (*send)(struct ll *ll, void *buf, uint32_t len); // Transmit function }; ``` +wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper still returns slot `0`. ### IP Configuration ```c @@ -40,6 +41,7 @@ struct ipconf { ip4 gw; // Default gateway }; ``` +Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on index `0` for backwards compatibility. ### Socket Address Structures ```c @@ -160,6 +162,12 @@ Processes pending network events. - now: Current timestamp - Returns: Number of events processed +```c +void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len); +void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); +``` +Pass inbound frames to the stack. `_ex` allows the caller to specify which interface slot produced the frame. + ```c void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw); void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw); @@ -171,6 +179,18 @@ Set/get IP configuration. - mask: Subnet mask - gw: Default gateway +```c +void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw); +void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); +``` +Per-interface versions of the IP configuration helpers. The legacy functions target interface `0`. + +```c +struct ll *wolfIP_getdev(struct wolfIP *s); +struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); +``` +Access the link-layer descriptor(s) that should be wired to hardware drivers. `_ex` returns `NULL` if `if_idx` exceeds `WOLFIP_MAX_INTERFACES`. + ## DHCP Client Functions ```c diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 2307a050..2bbdb958 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #include "check.h" +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 2 +#endif +#include #include "../../wolfip.c" #include /* for random() */ @@ -33,7 +37,6 @@ uint32_t wolfIP_getrandom(void) static uint8_t mem[8 * 1024]; static uint32_t memsz = 8 * 1024; -static const char ifname[] = "mock0"; static const uint8_t ifmac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; static uint8_t last_frame_sent[LINK_MTU]; static uint32_t last_frame_sent_size = 0; @@ -54,17 +57,27 @@ static int mock_poll(struct ll *dev, void *frame, uint32_t len) return 0; } - -void mock_link_init(struct wolfIP *s) +static void mock_link_init_idx(struct wolfIP *s, unsigned int idx, const uint8_t *mac_override) { - struct ll *ll = &s->ll_dev; - strncpy((char *)ll->ifname, ifname, sizeof(ll->ifname) - 1); - memcpy(ll->mac, ifmac, 6); - ll->mac[5] ^= 1; + struct ll *ll = wolfIP_getdev_ex(s, idx); + ck_assert_ptr_nonnull(ll); + memset(ll, 0, sizeof(*ll)); + snprintf((char *)ll->ifname, sizeof(ll->ifname), "mock%u", idx); + if (mac_override) { + memcpy(ll->mac, mac_override, 6); + } else { + memcpy(ll->mac, ifmac, 6); + ll->mac[5] ^= (uint8_t)(idx + 1); + } ll->poll = mock_poll; ll->send = mock_send; } +void mock_link_init(struct wolfIP *s) +{ + mock_link_init_idx(s, 0, NULL); +} + static struct timers_binheap heap; static void reset_heap(void) { heap.size = 0; @@ -452,19 +465,19 @@ START_TEST(test_arp_request_basic) uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */ mock_link_init(&s); s.last_tick = 1000; - arp_request(&s, target_ip); + arp_request(&s, 0, target_ip); ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet)); arp = (struct arp_packet *)last_frame_sent; ck_assert_mem_eq(arp->eth.dst, "\xff\xff\xff\xff\xff\xff", 6); - ck_assert_mem_eq(arp->eth.src, s.ll_dev.mac, 6); + ck_assert_mem_eq(arp->eth.src, s.ll_dev[0].mac, 6); ck_assert_int_eq(arp->eth.type, ee16(0x0806)); ck_assert_int_eq(arp->htype, ee16(1)); ck_assert_int_eq(arp->ptype, ee16(0x0800)); ck_assert_int_eq(arp->hlen, 6); ck_assert_int_eq(arp->plen, 4); ck_assert_int_eq(arp->opcode, ee16(ARP_REQUEST)); - ck_assert_mem_eq(arp->sma, s.ll_dev.mac, 6); - ck_assert_int_eq(arp->sip, ee32(s.ipconf.ip)); + ck_assert_mem_eq(arp->sma, s.ll_dev[0].mac, 6); + ck_assert_int_eq(arp->sip, ee32(s.ipconf[0].ip)); ck_assert_mem_eq(arp->tma, "\x00\x00\x00\x00\x00\x00", 6); ck_assert_int_eq(arp->tip, ee32(target_ip)); } @@ -477,9 +490,9 @@ START_TEST(test_arp_request_throttle) uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/ mock_link_init(&s); s.last_tick = 1000; - s.arp.last_arp = 880; + s.arp.last_arp[0] = 880; last_frame_sent_size = 0; - arp_request(&s, target_ip); + arp_request(&s, 0, target_ip); ck_assert_int_eq(last_frame_sent_size, 0); } END_TEST @@ -490,7 +503,7 @@ START_TEST(test_arp_request_target_ip) { wolfIP_init(&s); mock_link_init(&s); s.last_tick = 1000; - arp_request(&s, target_ip); + arp_request(&s, 0, target_ip); ck_assert_int_eq(((struct arp_packet *)(last_frame_sent))->tip, ee32(target_ip)); } END_TEST @@ -506,7 +519,7 @@ START_TEST(test_arp_request_handling) { struct wolfIP s; wolfIP_init(&s); mock_link_init(&s); - s.ipconf.ip = device_ip; + s.ipconf[0].ip = device_ip; /* Prepare ARP request */ arp_req.opcode = ee16(ARP_REQUEST); @@ -515,7 +528,7 @@ START_TEST(test_arp_request_handling) { arp_req.tip = ee32(device_ip); /* Call arp_recv with the ARP request */ - arp_recv(&s, &arp_req, sizeof(arp_req)); + arp_recv(&s, 0, &arp_req, sizeof(arp_req)); wolfIP_poll(&s, 1000); wolfIP_poll(&s, 1001); wolfIP_poll(&s, 1002); @@ -529,7 +542,7 @@ START_TEST(test_arp_request_handling) { arp_reply = (struct arp_packet *)last_frame_sent; ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet)); ck_assert_int_eq(arp_reply->opcode, ee16(ARP_REPLY)); - ck_assert_mem_eq(arp_reply->sma, s.ll_dev.mac, 6); // source MAC + ck_assert_mem_eq(arp_reply->sma, s.ll_dev[0].mac, 6); // source MAC ck_assert_int_eq(arp_reply->sip, ee32(device_ip)); // source IP ck_assert_mem_eq(arp_reply->tma, req_mac, 6); // target MAC ck_assert_int_eq(arp_reply->tip, ee32(req_ip)); // target IP @@ -551,7 +564,7 @@ START_TEST(test_arp_reply_handling) { memcpy(arp_reply.sma, reply_mac, 6); /* Call arp_recv with the ARP reply */ - arp_recv(&s, &arp_reply, sizeof(arp_reply)); + arp_recv(&s, 0, &arp_reply, sizeof(arp_reply)); /* Check if ARP table updated with reply IP and MAC */ ck_assert_int_eq(s.arp.neighbors[0].ip, reply_ip); @@ -560,7 +573,7 @@ START_TEST(test_arp_reply_handling) { /* Update same IP with a different MAC address */ uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; memcpy(arp_reply.sma, new_mac, 6); - arp_recv(&s, &arp_reply, sizeof(arp_reply)); + arp_recv(&s, 0, &arp_reply, sizeof(arp_reply)); /* Check if ARP table updates with new MAC */ ck_assert_mem_eq(s.arp.neighbors[0].mac, new_mac, 6); @@ -580,7 +593,7 @@ START_TEST(test_arp_lookup_success) { memcpy(s.arp.neighbors[0].mac, mock_mac, 6); /* Test arp_lookup */ - int result = arp_lookup(&s, ip, found_mac); + int result = arp_lookup(&s, 0, ip, found_mac); ck_assert_int_eq(result, 0); ck_assert_mem_eq(found_mac, mock_mac, 6); } @@ -594,13 +607,102 @@ START_TEST(test_arp_lookup_failure) { mock_link_init(&s); /* Ensure arp_lookup fails for unknown IP */ - int result = arp_lookup(&s, ip, found_mac); + int result = arp_lookup(&s, 0, ip, found_mac); ck_assert_int_eq(result, -1); uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0}; ck_assert_mem_eq(found_mac, zero_mac, 6); } END_TEST +START_TEST(test_wolfip_getdev_ex_api) +{ + struct wolfIP s; + wolfIP_init(&s); + struct ll *ll_def = wolfIP_getdev(&s); + ck_assert_ptr_nonnull(ll_def); + ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, 0)); + ck_assert_ptr_null(wolfIP_getdev_ex(&s, WOLFIP_MAX_INTERFACES)); +} +END_TEST + +START_TEST(test_wolfip_ipconfig_ex_per_interface) +{ + struct wolfIP s; + ip4 base_ip = 0x0A000001; + ip4 base_mask = 0xFFFFFF00; + ip4 base_gw = 0x0A0000FE; + ip4 iface_ip = 0x0A000201; + ip4 iface_mask = 0xFFFF0000; + ip4 iface_gw = 0x0A0002FE; + ip4 out_ip = 0, out_mask = 0, out_gw = 0; + ip4 def_ip = 0, def_mask = 0, def_gw = 0; + + wolfIP_init(&s); + wolfIP_ipconfig_set(&s, base_ip, base_mask, base_gw); + + wolfIP_ipconfig_set_ex(&s, 1, iface_ip, iface_mask, iface_gw); + wolfIP_ipconfig_get_ex(&s, 1, &out_ip, &out_mask, &out_gw); + + ck_assert_uint_eq(out_ip, iface_ip); + ck_assert_uint_eq(out_mask, iface_mask); + ck_assert_uint_eq(out_gw, iface_gw); + + wolfIP_ipconfig_get(&s, &def_ip, &def_mask, &def_gw); + ck_assert_uint_eq(def_ip, base_ip); + ck_assert_uint_eq(def_mask, base_mask); + ck_assert_uint_eq(def_gw, base_gw); + + wolfIP_ipconfig_set_ex(&s, WOLFIP_MAX_INTERFACES, 0xDEADBEEF, 0xFFFFFFFF, 0x01010101); + ck_assert_uint_eq(s.ipconf[1].ip, iface_ip); + ck_assert_uint_eq(s.ipconf[1].mask, iface_mask); + ck_assert_uint_eq(s.ipconf[1].gw, iface_gw); + + wolfIP_ipconfig_get_ex(&s, 1, NULL, NULL, NULL); +} +END_TEST + +START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply) +{ + struct wolfIP s; + struct arp_packet arp_req; + struct arp_packet *arp_reply; + uint8_t requester_mac[6] = {0x10, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t iface1_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01}; + + wolfIP_init(&s); + mock_link_init(&s); + mock_link_init_idx(&s, 1, iface1_mac); + wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + + memset(&arp_req, 0, sizeof(arp_req)); + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + last_frame_sent_size = 0; + + memset(arp_req.eth.dst, 0xFF, sizeof(arp_req.eth.dst)); + memcpy(arp_req.eth.src, requester_mac, 6); + arp_req.eth.type = ee16(ETH_TYPE_ARP); + arp_req.htype = ee16(1); + arp_req.ptype = ee16(ETH_TYPE_IP); + arp_req.hlen = 6; + arp_req.plen = 4; + arp_req.opcode = ee16(ARP_REQUEST); + memcpy(arp_req.sma, requester_mac, 6); + arp_req.sip = ee32(0xC0A80164); + memset(arp_req.tma, 0, sizeof(arp_req.tma)); + arp_req.tip = ee32(0xC0A80101); + + wolfIP_recv_ex(&s, 1, &arp_req, sizeof(arp_req)); + + ck_assert_uint_eq(last_frame_sent_size, sizeof(struct arp_packet)); + arp_reply = (struct arp_packet *)last_frame_sent; + ck_assert_uint_eq(arp_reply->opcode, ee16(ARP_REPLY)); + ck_assert_mem_eq(arp_reply->eth.src, iface1_mac, 6); + ck_assert_mem_eq(arp_reply->sma, iface1_mac, 6); + ck_assert_uint_eq(arp_reply->sip, ee32(s.ipconf[1].ip)); +} +END_TEST + // Test for `transport_checksum` calculation START_TEST(test_transport_checksum) { @@ -653,13 +755,14 @@ END_TEST START_TEST(test_eth_output_add_header) { struct wolfIP_eth_frame eth_frame; struct wolfIP S; - memset(&S, 0, sizeof(S)); + wolfIP_init(&S); memset(ð_frame, 0, sizeof(eth_frame)); uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; - memcpy(S.ll_dev.mac, test_mac, 6); + struct ll *ll = wolfIP_getdev(&S); + memcpy(ll->mac, test_mac, 6); - eth_output_add_header(&S, NULL, ð_frame, ETH_TYPE_IP); + eth_output_add_header(&S, 0, NULL, ð_frame, ETH_TYPE_IP); ck_assert_mem_eq(eth_frame.dst, "\xff\xff\xff\xff\xff\xff", 6); // Broadcast ck_assert_mem_eq(eth_frame.src, test_mac, 6); @@ -765,6 +868,10 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_utils); tcase_add_test(tc_utils, test_cancel_timer); suite_add_tcase(s, tc_utils); + tcase_add_test(tc_utils, test_wolfip_getdev_ex_api); + suite_add_tcase(s, tc_utils); + tcase_add_test(tc_utils, test_wolfip_ipconfig_ex_per_interface); + suite_add_tcase(s, tc_utils); tcase_add_test(tc_proto, test_arp_request_basic); suite_add_tcase(s, tc_proto); @@ -780,6 +887,8 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_arp_lookup_failure); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_wolfip_recv_ex_multi_interface_arp_reply); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_utils, test_transport_checksum); suite_add_tcase(s, tc_proto); diff --git a/src/wolfip.c b/src/wolfip.c index 7ffbfa8f..8399aedf 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -67,12 +67,6 @@ /* Macros */ #define IS_IP_BCAST(ip) (ip == 0xFFFFFFFF) -#define IS_IP_LOCAL(s,ipa) \ - ((ipa & s->ipconf.mask) == (s->ipconf.ip & s->ipconf.mask)) - -#define NEXTHOP(s,ip) \ - (IS_IP_BCAST(ip)?ip: \ - ((IS_IP_LOCAL(s,ip) ? ip : s->ipconf.gw))) #define PKT_FLAG_SENT 0x01 #define PKT_FLAG_ACKED 0x02 @@ -493,6 +487,7 @@ struct tsocket { #ifdef ETHERNET uint8_t nexthop_mac[6]; #endif + uint8_t if_idx; uint8_t rxmem[RXBUF_SIZE]; uint8_t txmem[TXBUF_SIZE]; void (*callback)(int sock_fd, uint16_t events, void *arg); @@ -514,6 +509,7 @@ struct PACKED arp_packet { struct arp_neighbor { ip4 ip; uint8_t mac[6]; + uint8_t if_idx; }; #endif @@ -535,8 +531,9 @@ struct timers_binheap { struct wolfIP { - struct ll ll_dev; - struct ipconf ipconf; + struct ll ll_dev[WOLFIP_MAX_INTERFACES]; + struct ipconf ipconf[WOLFIP_MAX_INTERFACES]; + unsigned int if_count; enum dhcp_state dhcp_state; /* State machine for DHCP */ uint32_t dhcp_xid; /* DHCP transaction ID while DORA */ int dhcp_udp_sd; /* DHCP socket descriptor. DHCP uses an UDP socket */ @@ -555,7 +552,7 @@ struct wolfIP uint64_t last_tick; #ifdef ETHERNET struct wolfIP_arp { - uint64_t last_arp; + uint64_t last_arp[WOLFIP_MAX_INTERFACES]; struct arp_neighbor neighbors[MAX_NEIGHBORS]; } arp; #endif @@ -564,6 +561,92 @@ struct wolfIP /* ***************************** */ /* Implementation */ +static inline struct ll *wolfIP_ll_at(struct wolfIP *s, unsigned int if_idx) +{ + if (!s || if_idx >= s->if_count) + return NULL; + return &s->ll_dev[if_idx]; +} + +static inline struct ipconf *wolfIP_ipconf_at(struct wolfIP *s, unsigned int if_idx) +{ + if (!s || if_idx >= s->if_count) + return NULL; + return &s->ipconf[if_idx]; +} + +static inline int ip_is_local_conf(const struct ipconf *conf, ip4 addr) +{ + if (!conf) + return 0; + if (conf->mask == 0) + return conf->ip == addr; + return ((addr & conf->mask) == (conf->ip & conf->mask)); +} + +static inline ip4 wolfIP_select_nexthop(const struct ipconf *conf, ip4 dest) +{ + if (IS_IP_BCAST(dest)) + return dest; + if (!conf) + return dest; + if (ip_is_local_conf(conf, dest)) + return dest; + if (conf->gw != IPADDR_ANY) + return conf->gw; + return dest; +} + +static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) +{ + unsigned int fallback = 0; + int has_fallback = 0; + + if (!s || s->if_count == 0) + return 0; + + if (dest == IPADDR_ANY || IS_IP_BCAST(dest)) + return 0; + + for (unsigned int i = 0; i < s->if_count; i++) { + struct ipconf *conf = &s->ipconf[i]; + if (conf->ip == IPADDR_ANY && conf->gw == IPADDR_ANY) + continue; + if (ip_is_local_conf(conf, dest) || conf->ip == dest) { + return i; + } + if (!has_fallback && conf->gw != IPADDR_ANY) { + fallback = i; + has_fallback = 1; + } + } + return has_fallback ? fallback : 0; +} + +static inline unsigned int wolfIP_socket_if_idx(const struct tsocket *t) +{ + if (!t || !t->S || t->if_idx >= t->S->if_count) + return 0; + return t->if_idx; +} + +static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int *found) +{ + if (found) + *found = 0; + if (!s || s->if_count == 0 || local_ip == IPADDR_ANY) + return 0; + for (unsigned int i = 0; i < s->if_count; i++) { + struct ipconf *conf = &s->ipconf[i]; + if (conf->ip == local_ip) { + if (found) + *found = 1; + return i; + } + } + return 0; +} + /* User Callbacks */ void wolfIP_register_callback(struct wolfIP *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg) { @@ -665,6 +748,7 @@ static struct tsocket *udp_new_socket(struct wolfIP *s) if (t->proto == 0) { t->proto = WI_IPPROTO_UDP; t->S = s; + t->if_idx = 0; fifo_init(&t->sock.udp.rxbuf, t->rxmem, RXBUF_SIZE); fifo_init(&t->sock.udp.txbuf, t->txmem, TXBUF_SIZE); t->events |= CB_EVENT_WRITABLE; @@ -674,13 +758,19 @@ static struct tsocket *udp_new_socket(struct wolfIP *s) return NULL; } -static void udp_try_recv(struct wolfIP *s, struct wolfIP_udp_datagram *udp, uint32_t frame_len) +static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_udp_datagram *udp, uint32_t frame_len) { + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ip4 local_ip = conf ? conf->ip : IPADDR_ANY; + ip4 dst_ip = ee32(udp->ip.dst); for (int i = 0; i < MAX_UDPSOCKETS; i++) { struct tsocket *t = &s->udpsockets[i]; if (t->src_port == ee16(udp->dst_port) && t->dst_port == ee16(udp->src_port) && (((t->local_ip == 0) && DHCP_IS_RUNNING(s)) || - (t->local_ip == ee32(udp->ip.dst) && t->remote_ip != s->ipconf.ip)) ) { + (t->local_ip == dst_ip && t->remote_ip != local_ip)) ) { + + if (t->local_ip == 0) + t->if_idx = (uint8_t)if_idx; /* UDP datagram sanity checks */ if ((int)frame_len != ee16(udp->len) + IP_HEADER_LEN + ETH_HEADER_LEN) @@ -701,6 +791,7 @@ static struct tsocket *tcp_new_socket(struct wolfIP *s) if (t->proto == 0) { t->proto = WI_IPPROTO_TCP; t->S = s; + t->if_idx = 0; t->sock.tcp.state = TCP_CLOSED; t->sock.tcp.rto = 1000; t->sock.tcp.cwnd = 2 * TCP_MSS; @@ -869,9 +960,12 @@ static void iphdr_set_checksum(struct wolfIP_ip_packet *ip) } #ifdef ETHERNET -static int eth_output_add_header(struct wolfIP *S, const uint8_t *dst, struct wolfIP_eth_frame *eth, +static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, uint16_t type) { + struct ll *ll = wolfIP_ll_at(S, if_idx); + if (!ll) + return -1; if (!dst) { /* Arp request, broadcast */ memset(eth->dst, 0xff, 6); @@ -879,7 +973,7 @@ static int eth_output_add_header(struct wolfIP *S, const uint8_t *dst, struct wo /* Send to nexthop */ memcpy(eth->dst, dst, 6); } - memcpy(eth->src, S->ll_dev.mac, 6); + memcpy(eth->src, ll->mac, 6); eth->type = ee16(type); return 0; } @@ -917,7 +1011,8 @@ static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, udp->csum = ee16(transport_checksum(&ph, &udp->src_port)); } #ifdef ETHERNET - eth_output_add_header(t->S, t->nexthop_mac, (struct wolfIP_eth_frame *)ip, ETH_TYPE_IP); + unsigned int if_idx = wolfIP_socket_if_idx(t); + eth_output_add_header(t->S, if_idx, t->nexthop_mac, (struct wolfIP_eth_frame *)ip, ETH_TYPE_IP); #endif return 0; } @@ -1050,14 +1145,18 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp) } /* Preselect socket, parse options, manage handshakes, pass to application */ -static void tcp_input(struct wolfIP *S, struct wolfIP_tcp_seg *tcp, uint32_t frame_len) +static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_seg *tcp, uint32_t frame_len) { + struct ipconf *conf = wolfIP_ipconf_at(S, if_idx); + struct ll *ll = wolfIP_ll_at(S, if_idx); + ip4 local_ip = conf ? conf->ip : IPADDR_ANY; for (int i = 0; i < MAX_TCPSOCKETS; i++) { uint32_t tcplen; uint32_t iplen; struct tsocket *t = &S->tcpsockets[i]; if (t->src_port == ee16(tcp->dst_port) && - t->local_ip == ee32(tcp->ip.dst) && t->remote_ip != S->ipconf.ip) { + t->local_ip == ee32(tcp->ip.dst) && t->remote_ip != local_ip) { + t->if_idx = (uint8_t)if_idx; /* TCP segment sanity checks */ iplen = ee16(tcp->ip.len); if (iplen > frame_len - sizeof(struct wolfIP_eth_frame)) { @@ -1083,8 +1182,9 @@ static void tcp_input(struct wolfIP *S, struct wolfIP_tcp_seg *tcp, uint32_t fra icmp.ip.id = ee16(S->ipcounter++); icmp.ip.csum = 0; iphdr_set_checksum(&icmp.ip); - eth_output_add_header(S, icmp.ip.eth.src, &icmp.ip.eth, ETH_TYPE_IP); - S->ll_dev.send(&S->ll_dev, &icmp, sizeof(struct wolfIP_icmp_packet)); + eth_output_add_header(S, if_idx, icmp.ip.eth.src, &icmp.ip.eth, ETH_TYPE_IP); + if (ll && ll->send) + ll->send(ll, &icmp, sizeof(struct wolfIP_icmp_packet)); return; } tcplen = iplen - (IP_HEADER_LEN + (tcp->hlen >> 2)); @@ -1245,6 +1345,13 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; ts->dst_port = ee16(sin->sin_port); ts->remote_ip = ee32(sin->sin_addr.s_addr); + unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ts->if_idx = (uint8_t)if_idx; + if (ts->local_ip == 0 && conf && conf->ip != IPADDR_ANY) + ts->local_ip = conf->ip; + else if (ts->local_ip == 0 && s->ipconf[0].ip != IPADDR_ANY) + ts->local_ip = s->ipconf[0].ip; return 0; } if ((sockfd & MARK_TCP_SOCKET) == 0) @@ -1258,8 +1365,16 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad return -2; if (ts->sock.tcp.state == TCP_CLOSED) { ts->sock.tcp.state = TCP_SYN_SENT; - ts->local_ip = s->ipconf.ip; ts->remote_ip = ee32(sin->sin_addr.s_addr); + unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ts->if_idx = (uint8_t)if_idx; + if (conf && conf->ip != IPADDR_ANY) + ts->local_ip = conf->ip; + else if (s->ipconf[0].ip != IPADDR_ANY) + ts->local_ip = s->ipconf[0].ip; + else + ts->local_ip = 0; if (!ts->src_port) ts->src_port = (uint16_t)(wolfIP_getrandom() & 0xFFFF); if (ts->src_port < 1024) @@ -1298,6 +1413,7 @@ int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *add newts->callback = ts->callback; newts->callback_arg = ts->callback_arg; newts->local_ip = ts->local_ip; + newts->if_idx = ts->if_idx; newts->remote_ip = ts->remote_ip; newts->src_port = ts->src_port; newts->dst_port = ts->dst_port; @@ -1392,8 +1508,15 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (ts->src_port < 1024) ts->src_port += 1024; } - if(ts->local_ip == 0) - ts->local_ip = s->ipconf.ip; + unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ts->if_idx = (uint8_t)if_idx; + if (ts->local_ip == 0) { + if (conf && conf->ip != IPADDR_ANY) + ts->local_ip = conf->ip; + else if (s->ipconf[0].ip != IPADDR_ANY) + ts->local_ip = s->ipconf[0].ip; + } udp->src_port = ee16(ts->src_port); udp->dst_port = ee16(ts->dst_port); @@ -1526,6 +1649,12 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr const struct wolfIP_sockaddr_in *sin = (const struct wolfIP_sockaddr_in *)addr; if (!sin || addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; + ip4 bind_ip = ee32(sin->sin_addr.s_addr); + int match = 0; + unsigned int if_idx = wolfIP_if_for_local_ip(s, bind_ip, &match); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if ((bind_ip != IPADDR_ANY) && !match) + return -1; if (sockfd & MARK_TCP_SOCKET) { ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; @@ -1533,7 +1662,13 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr return -1; if ((sin->sin_family != AF_INET) || (addrlen < sizeof(struct wolfIP_sockaddr_in))) return -1; - ts->local_ip = s->ipconf.ip; + ts->if_idx = (uint8_t)if_idx; + if (bind_ip != IPADDR_ANY) + ts->local_ip = bind_ip; + else if (conf && conf->ip != IPADDR_ANY) + ts->local_ip = conf->ip; + else if (s->ipconf[0].ip != IPADDR_ANY) + ts->local_ip = s->ipconf[0].ip; ts->src_port = ee16(sin->sin_port); return 0; } else if (sockfd & MARK_UDP_SOCKET) { @@ -1542,6 +1677,11 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr return -1; if ((sin->sin_family != AF_INET) || (addrlen < sizeof(struct wolfIP_sockaddr_in))) return -1; + ts->if_idx = (uint8_t)if_idx; + if (bind_ip != IPADDR_ANY) + ts->local_ip = bind_ip; + else if (conf && conf->ip != IPADDR_ANY) + ts->local_ip = conf->ip; ts->src_port = ee16(sin->sin_port); return 0; } else return -1; @@ -1575,10 +1715,11 @@ int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr /* Reply to ICecho requests */ -static void icmp_input(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t len) +static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { struct wolfIP_icmp_packet *icmp = (struct wolfIP_icmp_packet *)ip; uint32_t tmp; + struct ll *ll = wolfIP_ll_at(s, if_idx); if (!DHCP_IS_RUNNING(s) && (icmp->type == ICMP_ECHO_REQUEST)) { icmp->type = ICMP_ECHO_REPLY; icmp->csum += 8; @@ -1588,8 +1729,9 @@ static void icmp_input(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t l ip->id = ee16(s->ipcounter++); ip->csum = 0; iphdr_set_checksum(ip); - eth_output_add_header(s, ip->eth.src, &ip->eth, ETH_TYPE_IP); - s->ll_dev.send(&s->ll_dev, ip, len); + eth_output_add_header(s, if_idx, ip->eth.src, &ip->eth, ETH_TYPE_IP); + if (ll && ll->send) + ll->send(ll, ip, len); } } @@ -1651,8 +1793,8 @@ static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); } ip = ee32(msg->yiaddr); - s->ipconf.ip = ip; - s->ipconf.mask = ee32(netmask); + s->ipconf[0].ip = ip; + s->ipconf[0].mask = ee32(netmask); s->dhcp_ip = ip; dhcp_cancel_timer(s); s->dhcp_state = DHCP_REQUEST_SENT; @@ -1682,16 +1824,16 @@ static int dhcp_parse_ack(struct wolfIP *s, struct dhcp_msg *msg) if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); if (opt->code == DHCP_OPTION_OFFER_IP) - s->ipconf.ip = ee32(data); + s->ipconf[0].ip = ee32(data); if (opt->code == DHCP_OPTION_SUBNET_MASK) - s->ipconf.mask = ee32(data); + s->ipconf[0].mask = ee32(data); if (opt->code == DHCP_OPTION_ROUTER) - s->ipconf.gw = ee32(data); + s->ipconf[0].gw = ee32(data); if ((opt->code == DHCP_OPTION_DNS) && (s->dns_server == 0)) s->dns_server = ee32(data); opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); } - if ((s->ipconf.ip != 0) && (s->ipconf.mask != 0)) { + if ((s->ipconf[0].ip != 0) && (s->ipconf[0].mask != 0)) { dhcp_cancel_timer(s); s->dhcp_state = DHCP_BOUND; return 0; @@ -1716,9 +1858,9 @@ static int dhcp_poll(struct wolfIP *s) dhcp_send_request(s); else if ((s->dhcp_state == DHCP_REQUEST_SENT) && (dhcp_parse_ack(s, &msg) == 0)) { LOG("DHCP configuration received.\n"); - LOG("IP Address: %u.%u.%u.%u\n", (s->ipconf.ip >> 24) & 0xFF, (s->ipconf.ip >> 16) & 0xFF, (s->ipconf.ip >> 8) & 0xFF, (s->ipconf.ip >> 0) & 0xFF); - LOG("Subnet Mask: %u.%u.%u.%u\n", (s->ipconf.mask >> 24) & 0xFF, (s->ipconf.mask >> 16) & 0xFF, (s->ipconf.mask >> 8) & 0xFF, (s->ipconf.mask >> 0) & 0xFF); - LOG("Gateway: %u.%u.%u.%u\n", (s->ipconf.gw >> 24) & 0xFF, (s->ipconf.gw >> 16) & 0xFF, (s->ipconf.gw >> 8) & 0xFF, (s->ipconf.gw >> 0) & 0xFF); + LOG("IP Address: %u.%u.%u.%u\n", (s->ipconf[0].ip >> 24) & 0xFF, (s->ipconf[0].ip >> 16) & 0xFF, (s->ipconf[0].ip >> 8) & 0xFF, (s->ipconf[0].ip >> 0) & 0xFF); + LOG("Subnet Mask: %u.%u.%u.%u\n", (s->ipconf[0].mask >> 24) & 0xFF, (s->ipconf[0].mask >> 16) & 0xFF, (s->ipconf[0].mask >> 8) & 0xFF, (s->ipconf[0].mask >> 0) & 0xFF); + LOG("Gateway: %u.%u.%u.%u\n", (s->ipconf[0].gw >> 24) & 0xFF, (s->ipconf[0].gw >> 16) & 0xFF, (s->ipconf[0].gw >> 8) & 0xFF, (s->ipconf[0].gw >> 0) & 0xFF); if (s->dns_server) LOG("DNS Server: %u.%u.%u.%u\n", (s->dns_server >> 24) & 0xFF, (s->dns_server >> 16) & 0xFF, (s->dns_server >> 8) & 0xFF, (s->dns_server >> 0) & 0xFF); } @@ -1740,7 +1882,13 @@ static int dhcp_send_request(struct wolfIP *s) req.hlen = 6; /* MAC */ req.xid = ee32(s->dhcp_xid); req.magic = ee32(DHCP_MAGIC); - memcpy(req.chaddr, s->ll_dev.mac, 6); + { + struct ll *ll = wolfIP_ll_at(s, 0); + if (ll) + memcpy(req.chaddr, ll->mac, 6); + else + memset(req.chaddr, 0, 6); + } /* Set options */ memset(req.options, 0xFF, sizeof(req.options)); @@ -1810,7 +1958,13 @@ static int dhcp_send_discover(struct wolfIP *s) disc.hlen = 6; /* MAC */ disc.xid = ee32(s->dhcp_xid); disc.magic = ee32(DHCP_MAGIC); - memcpy(disc.chaddr, s->ll_dev.mac, 6); + { + struct ll *ll = wolfIP_ll_at(s, 0); + if (ll) + memcpy(disc.chaddr, ll->mac, 6); + else + memset(disc.chaddr, 0, 6); + } /* Set options */ memset(disc.options, 0xFF, sizeof(disc.options)); @@ -1877,73 +2031,84 @@ int dhcp_client_init(struct wolfIP *s) /* ARP */ #ifdef ETHERNET -static void arp_request(struct wolfIP *s, ip4 tip) +static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, const uint8_t *mac) +{ + if (!s) + return; + for (int i = 0; i < MAX_NEIGHBORS; i++) { + if (s->arp.neighbors[i].ip == ip && s->arp.neighbors[i].if_idx == if_idx) { + memcpy(s->arp.neighbors[i].mac, mac, 6); + return; + } + } + for (int i = 0; i < MAX_NEIGHBORS; i++) { + if (s->arp.neighbors[i].ip == IPADDR_ANY) { + s->arp.neighbors[i].ip = ip; + s->arp.neighbors[i].if_idx = (uint8_t)if_idx; + memcpy(s->arp.neighbors[i].mac, mac, 6); + return; + } + } +} + +static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip) { struct arp_packet arp; - if (s->arp.last_arp + 1000 > s->last_tick) { + struct ll *ll = wolfIP_ll_at(s, if_idx); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + + if (!ll || !conf) + return; + + if (s->arp.last_arp[if_idx] + 1000 > s->last_tick) { return; } - s->arp.last_arp = s->last_tick; + s->arp.last_arp[if_idx] = s->last_tick; memset(&arp, 0, sizeof(struct arp_packet)); - memcpy(arp.eth.dst, "\xff\xff\xff\xff\xff\xff", 6); - memcpy(arp.eth.src, s->ll_dev.mac, 6); - arp.eth.type = ee16(0x0806); + eth_output_add_header(s, if_idx, NULL, &arp.eth, ETH_TYPE_ARP); arp.htype = ee16(1); /* Ethernet */ arp.ptype = ee16(0x0800); arp.hlen = 6; arp.plen = 4; arp.opcode = ee16(ARP_REQUEST); - memcpy(arp.sma, s->ll_dev.mac, 6); - arp.sip = ee32(s->ipconf.ip); + memcpy(arp.sma, ll->mac, 6); + arp.sip = ee32(conf->ip); memset(arp.tma, 0, 6); arp.tip = ee32(tip); - eth_output_add_header(s, NULL, &arp.eth, ETH_TYPE_ARP); - s->ll_dev.send(&s->ll_dev, &arp, sizeof(struct arp_packet)); + if (ll->send) + ll->send(ll, &arp, sizeof(struct arp_packet)); } -static void arp_recv(struct wolfIP *s, void *buf, int len) +static void arp_recv(struct wolfIP *s, unsigned int if_idx, void *buf, int len) { struct arp_packet *arp = (struct arp_packet *)buf; - if (arp->opcode == ee16(ARP_REQUEST) && arp->tip == ee32(s->ipconf.ip)) { + struct ll *ll = wolfIP_ll_at(s, if_idx); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + + if (!ll || !conf) + return; + + if (arp->opcode == ee16(ARP_REQUEST) && arp->tip == ee32(conf->ip)) { arp->opcode = ee16(ARP_REPLY); memcpy(arp->tma, arp->sma, 6); - memcpy(arp->sma, s->ll_dev.mac, 6); + memcpy(arp->sma, ll->mac, 6); arp->tip = arp->sip; - arp->sip = ee32(s->ipconf.ip); - /* Add neighbor to ARP table */ - for (int i = 0; i < MAX_NEIGHBORS; i++) { - if ((s->arp.neighbors[i].ip == IPADDR_ANY) || (s->arp.neighbors[i].ip == ee32(arp->sip))) { - memcpy(s->arp.neighbors[i].mac, arp->sma, 6); - s->arp.neighbors[i].ip = ee32(arp->sip); - break; - } - } - eth_output_add_header(s, arp->tma, &arp->eth, ETH_TYPE_ARP); - s->ll_dev.send(&s->ll_dev, buf, len); + arp->sip = ee32(conf->ip); + arp_store_neighbor(s, if_idx, ee32(arp->sip), arp->sma); + eth_output_add_header(s, if_idx, arp->tma, &arp->eth, ETH_TYPE_ARP); + if (ll->send) + ll->send(ll, buf, len); } if (arp->opcode == ee16(ARP_REPLY)) { - int i; - for (i = 0; i < MAX_NEIGHBORS; i++) { - if (s->arp.neighbors[i].ip == ee32(arp->sip)) { - memcpy(s->arp.neighbors[i].mac, arp->sma, 6); - break; - } - } - for (i = 0; i < MAX_NEIGHBORS; i++) { - if ((s->arp.neighbors[i].ip == IPADDR_ANY) || (s->arp.neighbors[i].ip == ee32(arp->sip))) { - memcpy(s->arp.neighbors[i].mac, arp->sma, 6); - s->arp.neighbors[i].ip = ee32(arp->sip); - break; - } - } + arp_store_neighbor(s, if_idx, ee32(arp->sip), arp->sma); } } -static int arp_lookup(struct wolfIP *s, ip4 ip, uint8_t *mac) +static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac) { memset(mac, 0, 6); for (int i = 0; i < MAX_NEIGHBORS; i++) { - if (s->arp.neighbors[i].ip == ip) { + if (s->arp.neighbors[i].ip == ip && s->arp.neighbors[i].if_idx == if_idx) { memcpy(mac, s->arp.neighbors[i].mac, 6); return 0; } @@ -1956,12 +2121,23 @@ static int arp_lookup(struct wolfIP *s, ip4 ip, uint8_t *mac) /* Initialize the IP stack */ void wolfIP_init(struct wolfIP *s) { + if (!s) + return; memset(s, 0, sizeof(struct wolfIP)); + s->if_count = WOLFIP_MAX_INTERFACES; + for (unsigned int i = 0; i < s->if_count; i++) { + s->ipconf[i].ll = wolfIP_ll_at(s, i); + } } struct ll *wolfIP_getdev(struct wolfIP *s) { - return &s->ll_dev; + return wolfIP_getdev_ex(s, 0); +} + +struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) +{ + return wolfIP_ll_at(s, if_idx); } static struct wolfIP wolfIP_static; @@ -1973,45 +2149,59 @@ void wolfIP_init_static(struct wolfIP **s) *s = &wolfIP_static; } -static inline void ip_recv(struct wolfIP *s, struct wolfIP_ip_packet *ip, +static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { if (ip->ver_ihl == 0x45 && ip->proto == 0x06) { struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)ip; - tcp_input(s, tcp, len); + tcp_input(s, if_idx, tcp, len); } else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) { struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)ip; - udp_try_recv(s, udp, len); + udp_try_recv(s, if_idx, udp, len); } else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) { - icmp_input(s, ip, len); + icmp_input(s, if_idx, ip, len); } } -/* Try to receive a packet from the network interface. - * - * This function is called either after polling the device driver - * in the loop, or in the device driver dsr callback. - */ -void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len) +static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) { + if (!s) + return; #ifdef ETHERNET + struct ll *ll = wolfIP_ll_at(s, if_idx); + if (!ll) + return; struct wolfIP_eth_frame *eth = (struct wolfIP_eth_frame *)buf; - if (eth->type == ee16(0x0800)) { + if (eth->type == ee16(ETH_TYPE_IP)) { struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)eth; - if ((memcmp(eth->dst, s->ll_dev.mac, 6) != 0) && (memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) { + if ((memcmp(eth->dst, ll->mac, 6) != 0) && (memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) { return; /* Not for us */ } - ip_recv(s, ip, len); - } else if (eth->type == ee16(0x0806)) { - arp_recv(s, buf, len); + ip_recv(s, if_idx, ip, len); + } else if (eth->type == ee16(ETH_TYPE_ARP)) { + arp_recv(s, if_idx, buf, len); } #else /* No ethernet, assume IP */ struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)buf; - ip_recv(s, ip, len); + ip_recv(s, if_idx, ip, len); #endif - /* No default action required: the buffer is in stack and will be discarded on return */ +} + +/* Try to receive a packet from the network interface. + * + * This function is called either after polling the device driver + * in the loop, or in the device driver dsr callback. + */ +void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len) +{ + wolfIP_recv_on(s, 0, buf, len); +} + +void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) +{ + wolfIP_recv_on(s, if_idx, buf, len); } /* DNS Client */ @@ -2155,12 +2345,15 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) s->last_tick = now; /* Step 1: Poll the device */ - if (s->ll_dev.poll) { + for (unsigned int if_idx = 0; if_idx < s->if_count; if_idx++) { + struct ll *ll = wolfIP_ll_at(s, if_idx); + if (!ll || !ll->poll) + continue; do { - len = s->ll_dev.poll(&s->ll_dev, buf, LINK_MTU); + len = ll->poll(ll, buf, LINK_MTU); if (len > 0) { /* Process packet */ - wolfIP_recv(s, buf, len); + wolfIP_recv_on(s, if_idx, buf, len); } } while (len > 0); } @@ -2201,10 +2394,12 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) continue; } else { #ifdef ETHERNET - ip4 nexthop = NEXTHOP(s, ts->remote_ip); - if (arp_lookup(s, nexthop, ts->nexthop_mac) < 0) { + unsigned int if_idx = wolfIP_socket_if_idx(ts); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ip4 nexthop = wolfIP_select_nexthop(conf, ts->remote_ip); + if (arp_lookup(s, if_idx, nexthop, ts->nexthop_mac) < 0) { /* Send ARP request */ - arp_request(s, nexthop); + arp_request(s, if_idx, nexthop); break; }else #endif @@ -2225,7 +2420,11 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) tcp->ack = ee32(ts->sock.tcp.ack); tcp->win = ee16(queue_space(&ts->sock.tcp.rxbuf)); ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, WI_IPPROTO_TCP, size); - s->ll_dev.send(&s->ll_dev, tcp, desc->len); + { + struct ll *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(ts)); + if (ll && ll->send) + ll->send(ll, tcp, desc->len); + } desc->flags |= PKT_FLAG_SENT; desc->time_sent = now; if (size == IP_HEADER_LEN + (uint32_t)(tcp->hlen >> 2)) { @@ -2255,17 +2454,23 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) while (desc) { struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)(t->txmem + desc->pos + sizeof(*desc)); #ifdef ETHERNET - ip4 nexthop = NEXTHOP(s, t->remote_ip); - if ((!IS_IP_BCAST(nexthop) && (arp_lookup(s, nexthop, t->nexthop_mac) < 0))) { + unsigned int if_idx = wolfIP_socket_if_idx(t); + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + ip4 nexthop = wolfIP_select_nexthop(conf, t->remote_ip); + if ((!IS_IP_BCAST(nexthop) && (arp_lookup(s, if_idx, nexthop, t->nexthop_mac) < 0))) { /* Send ARP request */ - arp_request(s, nexthop); + arp_request(s, if_idx, nexthop); break; } if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6); #endif len = desc->len - ETH_HEADER_LEN; ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len); - s->ll_dev.send(&s->ll_dev, udp, desc->len); + { + struct ll *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(t)); + if (ll && ll->send) + ll->send(ll, udp, desc->len); + } fifo_pop(&t->sock.udp.txbuf); desc = fifo_peek(&t->sock.udp.txbuf); } @@ -2275,15 +2480,33 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw) { - s->ipconf.ip = ip; - s->ipconf.mask = mask; - s->ipconf.gw = gw; + wolfIP_ipconfig_set_ex(s, 0, ip, mask, gw); } void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw) { - *ip = s->ipconf.ip; - *mask = s->ipconf.mask; - *gw = s->ipconf.gw; + wolfIP_ipconfig_get_ex(s, 0, ip, mask, gw); } +void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw) +{ + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if (!conf) + return; + conf->ip = ip; + conf->mask = mask; + conf->gw = gw; +} + +void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw) +{ + struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if (!conf) + return; + if (ip) + *ip = conf->ip; + if (mask) + *mask = conf->mask; + if (gw) + *gw = conf->gw; +} diff --git a/wolfip.h b/wolfip.h index 280d97c8..03709e35 100644 --- a/wolfip.h +++ b/wolfip.h @@ -98,10 +98,14 @@ void wolfIP_init(struct wolfIP *s); void wolfIP_init_static(struct wolfIP **s); int wolfIP_poll(struct wolfIP *s, uint64_t now); void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len); +void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw); void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw); struct ll *wolfIP_getdev(struct wolfIP *s); +struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); +void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw); +void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); /* Callback flags */ #define CB_EVENT_READABLE 0x01 /* Accepted connection or data available */ From eb29076d486bdd1db2ab70148417a00d5f285065 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 17:16:27 +0100 Subject: [PATCH 04/25] Added simple packet forwarding between interfaces --- .github/workflows/linux.yml | 16 +- Makefile | 20 +- config.h | 4 + docs/API.md | 7 + src/port/wolfssl_io.c | 94 ++++- src/test/test_ttl_expired.c | 353 ++++++++++++++++ src/test/test_wolfssl_forwarding.c | 626 +++++++++++++++++++++++++++++ src/test/unit/unit.c | 102 +++++ src/wolfip.c | 170 +++++++- wolfip.h | 1 + 10 files changed, 1350 insertions(+), 43 deletions(-) create mode 100644 src/test/test_ttl_expired.c create mode 100644 src/test/test_wolfssl_forwarding.c diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9ec07eb0..5577bf17 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -19,6 +19,7 @@ jobs: - name: Update repo run: | sudo apt-get update + sudo apt-get install -y libwolfssl-dev sudo modprobe tun - name: Build linux tests @@ -26,8 +27,13 @@ jobs: mkdir -p build/port make -# - name: Run interop tests -# run: | -# sudo build/test -# -# + - name: Run unit tests + run: make unit + + - name: Run standalone tests + run: | + sudo ./build/test-evloop + sudo ./build/test-wolfssl + ./build/test-wolfssl-forwarding + ./build/test-ttl-expired + diff --git a/Makefile b/Makefile index 5077b101..6ac36a7c 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ OBJ=build/wolfip.o \ build/port/posix/linux_tap.o EXE=build/tcpecho build/tcp_netcat_poll build/tcp_netcat_select \ - build/test-evloop build/test-dns + build/test-evloop build/test-dns build/test-wolfssl-forwarding \ + build/test-ttl-expired build/test-wolfssl LIB=libwolfip.so PREFIX=/usr/local @@ -80,12 +81,29 @@ build/tcp_netcat_select: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_net build/test-wolfssl:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP build/test-httpd:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -Isrc/http +build/test-wolfssl-forwarding:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -DWOLFIP_MAX_INTERFACES=2 -DWOLFIP_ENABLE_FORWARDING=1 build/test-wolfssl: $(OBJ) build/test/test_native_wolfssl.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -lwolfssl -Wl,--end-group +build/test-wolfssl-forwarding: build/test/test_wolfssl_forwarding.o build/test/wolfip_forwarding.o build/port/posix/linux_tap.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o + @echo "[LD] $@" + @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -lwolfssl -Wl,--end-group + +build/test/test_wolfssl_forwarding.o: CFLAGS+=-DWOLFIP_MAX_INTERFACES=2 -DWOLFIP_ENABLE_FORWARDING=1 + +build/test/wolfip_forwarding.o: src/wolfip.c + @mkdir -p `dirname $@` || true + @echo "[CC] $< (forwarding)" + @$(CC) $(CFLAGS) -DWOLFIP_MAX_INTERFACES=2 -DWOLFIP_ENABLE_FORWARDING=1 -c $< -o $@ + +build/test/test_ttl_expired.o: CFLAGS+=-DWOLFIP_MAX_INTERFACES=2 -DWOLFIP_ENABLE_FORWARDING=1 +build/test-ttl-expired: build/test/test_ttl_expired.o build/test/wolfip_forwarding.o + @echo "[LD] $@" + @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group + build/test-httpd: $(OBJ) build/test/test_httpd.o build/port/wolfssl_io.o build/certs/server_key.o build/certs/server_cert.o build/http/httpd.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -lwolfssl -Wl,--end-group diff --git a/config.h b/config.h index aeac6eca..b2df6fd3 100644 --- a/config.h +++ b/config.h @@ -15,6 +15,10 @@ #define WOLFIP_MAX_INTERFACES 1 #endif +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 0 +#endif + /* Linux test configuration */ #define WOLFIP_IP "10.10.10.2" #define LINUX_IP "10.10.10.1" diff --git a/docs/API.md b/docs/API.md index d66d178f..5cdc5569 100644 --- a/docs/API.md +++ b/docs/API.md @@ -43,6 +43,8 @@ struct ipconf { ``` Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on index `0` for backwards compatibility. +If `WOLFIP_ENABLE_FORWARDING` is set to `1` at compile time, the stack performs simple IPv4 forwarding between interfaces. Packets received on one interface whose destinations match another configured interface are re-sent with the IP TTL decreased by one (or an ICMP TTL-exceeded response if the TTL would drop to zero). + ### Socket Address Structures ```c struct wolfIP_sockaddr_in { @@ -153,6 +155,11 @@ Initializes a static wolfIP instance. - Parameters: - s: Pointer to wolfIP instance pointer +```c +size_t wolfIP_instance_size(void); +``` +Returns the size (in bytes) required to store a `struct wolfIP`. Use this when allocating stacks from custom memory managers. + ```c int wolfIP_poll(struct wolfIP *s, uint64_t now); ``` diff --git a/src/port/wolfssl_io.c b/src/port/wolfssl_io.c index 83625c78..e03e8e0d 100644 --- a/src/port/wolfssl_io.c +++ b/src/port/wolfssl_io.c @@ -1,6 +1,5 @@ /* wolfssl_io.c - * - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2025 wolfSSL Inc. * * This file is part of wolfIP TCP/IP stack. * @@ -17,39 +16,77 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * wolfIP <-> wolfSSL glue for custom IO callbacks. */ #include "wolfip.h" #include #include +#include + +#define MAX_WOLFIP_CTX 8 + +struct ctx_entry { + WOLFSSL_CTX *ctx; + struct wolfIP *stack; +}; + +struct wolfip_io_desc { + int fd; + struct wolfIP *stack; +}; -static struct wolfIP *ref_ipstack = NULL; +static struct ctx_entry ctx_map[MAX_WOLFIP_CTX]; +static struct wolfip_io_desc io_descs[MAX_WOLFIP_CTX]; + +static struct wolfIP *wolfIP_lookup_stack(WOLFSSL_CTX *ctx) +{ + for (int i = 0; i < MAX_WOLFIP_CTX; i++) { + if (ctx_map[i].ctx == ctx) + return ctx_map[i].stack; + } + return NULL; +} + +static void wolfIP_register_stack(WOLFSSL_CTX *ctx, struct wolfIP *stack) +{ + for (int i = 0; i < MAX_WOLFIP_CTX; i++) { + if (ctx_map[i].ctx == ctx || ctx_map[i].ctx == NULL) { + ctx_map[i].ctx = ctx; + ctx_map[i].stack = stack; + return; + } + } +} static int wolfIP_io_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx) { - int ret = 0; - int fd = (intptr_t)ctx; + struct wolfip_io_desc *desc = (struct wolfip_io_desc *)ctx; (void)ssl; - if (!ref_ipstack) - return -1; - ret = wolfIP_sock_recv(ref_ipstack, fd, buf, sz, 0); - if (ret == -11) + + if (!desc || !desc->stack) + return WOLFSSL_CBIO_ERR_GENERAL; + + int ret = wolfIP_sock_recv(desc->stack, desc->fd, buf, sz, 0); + if (ret == -11 || ret == -1) return WOLFSSL_CBIO_ERR_WANT_READ; - else if (ret <= 0) + if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; return ret; } static int wolfIP_io_send(WOLFSSL* ssl, char* buf, int sz, void* ctx) { - int ret = 0; - int fd = (intptr_t)ctx; + struct wolfip_io_desc *desc = (struct wolfip_io_desc *)ctx; (void)ssl; - if (!ref_ipstack) - return -1; - ret = wolfIP_sock_send(ref_ipstack, fd, buf, sz, 0); - if (ret == -11) + + if (!desc || !desc->stack) + return WOLFSSL_CBIO_ERR_GENERAL; + + int ret = wolfIP_sock_send(desc->stack, desc->fd, buf, sz, 0); + if (ret == -11 || ret == -1) return WOLFSSL_CBIO_ERR_WANT_WRITE; - else if (ret <= 0) + if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; return ret; } @@ -58,14 +95,27 @@ int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX* ctx, struct wolfIP *s) { wolfSSL_SetIORecv(ctx, wolfIP_io_recv); wolfSSL_SetIOSend(ctx, wolfIP_io_send); - ref_ipstack = s; + wolfIP_register_stack(ctx, s); return 0; } int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd) { - wolfSSL_SetIOReadCtx(ssl, (void*)(intptr_t)fd); - wolfSSL_SetIOWriteCtx(ssl, (void*)(intptr_t)fd); - return 0; -} + WOLFSSL_CTX *ctx = wolfSSL_get_SSL_CTX(ssl); + struct wolfIP *stack = wolfIP_lookup_stack(ctx); + + if (!stack) + return WOLFSSL_CBIO_ERR_GENERAL; + for (int i = 0; i < MAX_WOLFIP_CTX; i++) { + if (io_descs[i].stack == NULL) { + io_descs[i].fd = fd; + io_descs[i].stack = stack; + wolfSSL_SetIOReadCtx(ssl, &io_descs[i]); + wolfSSL_SetIOWriteCtx(ssl, &io_descs[i]); + return 0; + } + } + + return -1; +} diff --git a/src/test/test_ttl_expired.c b/src/test/test_ttl_expired.c new file mode 100644 index 00000000..2e048e37 --- /dev/null +++ b/src/test/test_ttl_expired.c @@ -0,0 +1,353 @@ +/* test_ttl_expired.c + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * Validate that wolfIP emits an ICMP TTL Expired message when forwarding + * a packet whose TTL reaches zero. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "wolfip.h" + +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 2 +#endif + +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 1 +#endif + +#ifndef IP4 +#define IP4(a,b,c,d) (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | \ + ((uint32_t)(c) << 8) | (uint32_t)(d)) +#endif + +#define HOST_IP IP4(10,0,1,10) +#define ROUTER_IF0 IP4(10,0,1,1) +#define ROUTER_GW IP4(10,0,1,254) +#define ROUTER_IF1 IP4(10,0,2,1) +#define DEST_IP IP4(10,0,2,200) + +#define PACKED __attribute__((packed)) + +struct eth_hdr { + uint8_t dst[6]; + uint8_t src[6]; + uint16_t type; +} PACKED; + +struct ipv4_hdr { + uint8_t ver_ihl; + uint8_t tos; + uint16_t len; + uint16_t id; + uint16_t flags_frag; + uint8_t ttl; + uint8_t proto; + uint16_t csum; + uint32_t src; + uint32_t dst; +} PACKED; + +struct icmp_echo { + uint8_t type; + uint8_t code; + uint16_t csum; + uint16_t id; + uint16_t seq; +} PACKED; + +static uint16_t ones_csum(const void *buf, size_t len) +{ + const uint16_t *p = buf; + uint32_t acc = 0; + while (len > 1) { + acc += *p++; + len -= 2; + } + if (len) + acc += *((const uint8_t *)p); + while (acc >> 16) + acc = (acc & 0xFFFF) + (acc >> 16); + return (uint16_t)~acc; +} + +uint32_t wolfIP_getrandom(void) +{ + return (uint32_t)rand(); +} + +struct mem_link { + pthread_mutex_t lock; + pthread_cond_t cond[2]; + int ready[2]; + size_t len[2]; + uint8_t buf[2][LINK_MTU]; +}; + +struct mem_ep { + struct ll *ll; + struct mem_link *link; + int idx; +}; + +static struct mem_ep mem_eps[2]; + +static void mem_link_init(struct mem_link *link) +{ + pthread_mutex_init(&link->lock, NULL); + pthread_cond_init(&link->cond[0], NULL); + pthread_cond_init(&link->cond[1], NULL); + link->ready[0] = link->ready[1] = 0; + link->len[0] = link->len[1] = 0; +} + +static struct mem_ep *mem_ep_lookup(struct ll *ll) +{ + for (size_t i = 0; i < 2; i++) + if (mem_eps[i].ll == ll) + return &mem_eps[i]; + return NULL; +} + +static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) +{ + struct mem_ep *ep = mem_ep_lookup(ll); + if (!ep) + return -1; + struct mem_link *link = ep->link; + int idx = ep->idx; + int ret = 0; + + pthread_mutex_lock(&link->lock); + if (link->ready[idx]) { + size_t copy = link->len[idx]; + if (copy > len) + copy = len; + memcpy(buf, link->buf[idx], copy); + link->ready[idx] = 0; + pthread_cond_signal(&link->cond[idx]); + ret = (int)copy; + } + pthread_mutex_unlock(&link->lock); + return ret; +} + +static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) +{ + struct mem_ep *ep = mem_ep_lookup(ll); + if (!ep) + return -1; + struct mem_link *link = ep->link; + int dst = 1 - ep->idx; + + pthread_mutex_lock(&link->lock); + while (link->ready[dst]) + pthread_cond_wait(&link->cond[dst], &link->lock); + if (len > LINK_MTU) + len = LINK_MTU; + memcpy(link->buf[dst], buf, len); + link->len[dst] = len; + link->ready[dst] = 1; + pthread_cond_signal(&link->cond[dst]); + pthread_mutex_unlock(&link->lock); + return (int)len; +} + +static void mem_attach(struct ll *ll, struct mem_link *link, int idx, const uint8_t *mac) +{ + ll->poll = mem_ll_poll; + ll->send = mem_ll_send; + memcpy(ll->mac, mac, 6); + snprintf(ll->ifname, sizeof(ll->ifname), "mem%d", idx); + mem_eps[idx].ll = ll; + mem_eps[idx].link = link; + mem_eps[idx].idx = idx; +} + +static void mem_host_send(struct mem_link *link, const uint8_t *frame, size_t len) +{ + pthread_mutex_lock(&link->lock); + while (link->ready[1]) + pthread_cond_wait(&link->cond[1], &link->lock); + if (len > LINK_MTU) + len = LINK_MTU; + memcpy(link->buf[1], frame, len); + link->len[1] = len; + link->ready[1] = 1; + pthread_cond_signal(&link->cond[1]); + pthread_mutex_unlock(&link->lock); +} + +static int mem_host_recv(struct mem_link *link, uint8_t *frame, size_t cap, int timeout_ms) +{ + int ret = -1; + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += timeout_ms / 1000; + ts.tv_nsec += (timeout_ms % 1000) * 1000000L; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000L; + } + + pthread_mutex_lock(&link->lock); + while (!link->ready[0]) { + int rc = pthread_cond_timedwait(&link->cond[0], &link->lock, &ts); + if (rc == ETIMEDOUT) + goto out; + } + if (link->len[0] > cap) + cap = link->len[0]; + memcpy(frame, link->buf[0], link->len[0]); + ret = (int)link->len[0]; + link->ready[0] = 0; + pthread_cond_signal(&link->cond[0]); +out: + pthread_mutex_unlock(&link->lock); + return ret; +} + +static void build_ttl_frame(uint8_t *frame, const uint8_t *src_mac, const uint8_t *dst_mac, + uint32_t src_ip, uint32_t dst_ip) +{ + struct eth_hdr *eth = (struct eth_hdr *)frame; + struct ipv4_hdr *ip = (struct ipv4_hdr *)(frame + sizeof(*eth)); + struct icmp_echo *icmp = (struct icmp_echo *)(frame + sizeof(*eth) + sizeof(*ip)); + + memcpy(eth->dst, dst_mac, 6); + memcpy(eth->src, src_mac, 6); + eth->type = htons(ETH_P_IP); + + memset(ip, 0, sizeof(*ip)); + ip->ver_ihl = 0x45; + ip->ttl = 1; + ip->proto = 1; + ip->len = htons(sizeof(*ip) + sizeof(*icmp)); + ip->id = htons(0x1234); + ip->src = htonl(src_ip); + ip->dst = htonl(dst_ip); + ip->csum = ones_csum(ip, sizeof(*ip)); + + memset(icmp, 0, sizeof(*icmp)); + icmp->type = 8; + icmp->id = htons(0x0101); + icmp->seq = htons(1); + icmp->csum = ones_csum(icmp, sizeof(*icmp)); +} + +static int dummy_send(struct ll *ll, void *buf, uint32_t len) +{ + (void)ll; + (void)buf; + return (int)len; +} + +static int dummy_poll(struct ll *ll, void *buf, uint32_t len) +{ + (void)ll; + (void)buf; + (void)len; + return 0; +} + +static volatile int running = 1; + +static void *poll_thread(void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + while (running) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + uint64_t now = (uint64_t)ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; + wolfIP_poll(s, now); + usleep(1000); + } + return NULL; +} + +int main(void) +{ + setvbuf(stdout, NULL, _IONBF, 0); + struct wolfIP *router; + struct ll *iface0; + struct ll *iface1; + struct mem_link link; + pthread_t th; + uint8_t host_mac[6] = {0x02,0x00,0x00,0x00,0xAA,0x01}; + uint8_t router0_mac[6] = {0x02,0x00,0x00,0x00,0xBB,0x01}; + uint8_t router1_mac[6] = {0x02,0x00,0x00,0x00,0xCC,0x01}; + uint8_t frame[LINK_MTU]; + int rc = EXIT_FAILURE; + + mem_link_init(&link); + wolfIP_init_static(&router); + + iface0 = wolfIP_getdev(router); + iface1 = wolfIP_getdev_ex(router, 1); + if (!iface0 || !iface1) { + fprintf(stderr, "missing interfaces\n"); + return EXIT_FAILURE; + } + + mem_attach(iface0, &link, 1, router0_mac); + + iface1->send = dummy_send; + iface1->poll = dummy_poll; + memcpy(iface1->mac, router1_mac, 6); + + wolfIP_ipconfig_set(router, ROUTER_IF0, IP4(255,255,255,0), ROUTER_GW); + wolfIP_ipconfig_set_ex(router, 1, ROUTER_IF1, IP4(255,255,255,0), IP4(0,0,0,0)); + + running = 1; + if (pthread_create(&th, NULL, poll_thread, router) != 0) { + perror("pthread_create"); + return EXIT_FAILURE; + } + + build_ttl_frame(frame, host_mac, router0_mac, HOST_IP, DEST_IP); + mem_host_send(&link, frame, sizeof(struct eth_hdr) + sizeof(struct ipv4_hdr) + sizeof(struct icmp_echo)); + + int n = mem_host_recv(&link, frame, sizeof(frame), 1000); + if (n > 0) { + struct eth_hdr *eth = (struct eth_hdr *)frame; + struct ipv4_hdr *ip = (struct ipv4_hdr *)(frame + sizeof(*eth)); + struct icmp_echo *icmp = (struct icmp_echo *)(frame + sizeof(*eth) + sizeof(*ip)); + if (ntohs(eth->type) == ETH_P_IP && ip->proto == 1 && icmp->type == 11 && + ntohl(ip->src) == DEST_IP && ntohl(ip->dst) == HOST_IP) { + printf("TTL expired response received\n"); + rc = EXIT_SUCCESS; + } + } else { + fprintf(stderr, "No TTL expired response\n"); + } + + running = 0; + pthread_join(th, NULL); + return rc; +} diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c new file mode 100644 index 00000000..4bdbf805 --- /dev/null +++ b/src/test/test_wolfssl_forwarding.c @@ -0,0 +1,626 @@ +/* test_wolfssl_forwarding.c + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * Integration test that exercises wolfIP's TLS echo server across a simple + * IP router running with forwarding enabled. The topology is: + * + * client (wolfIP) <--mem link--> router (2 interfaces, forwarding on) + * <--mem link--> server (wolfIP TLS echo) + * + * The router itself opens no sockets; it only polls the stack so incoming + * frames are forwarded between the two networks. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 2 +#endif + +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 1 +#endif + +#include "wolfip.h" +#include +#include +#include +#include + +extern const unsigned char ca_der[]; +extern const unsigned long ca_der_len; +extern const unsigned char server_der[]; +extern const unsigned long server_der_len; +extern const unsigned char server_key_der[]; +extern const unsigned long server_key_der_len; +static pthread_t th_server, th_client, th_router; + +/* Helper macros */ +#define IP4(a,b,c,d) (((ip4)(a) << 24) | ((ip4)(b) << 16) | ((ip4)(c) << 8) | (ip4)(d)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Millisecond clock */ +static uint64_t monotonic_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; +} + +static void wolfip_reset_io(WOLFSSL *ssl) +{ + void *ctx; + if (!ssl) + return; + ctx = wolfSSL_GetIOReadCtx(ssl); + if (ctx) { + wolfSSL_SetIOReadCtx(ssl, NULL); + wolfSSL_SetIOWriteCtx(ssl, NULL); + } +} + +/* ------------------------------------------------------------------------- */ +/* In-memory link layer */ +/* ------------------------------------------------------------------------- */ + +struct mem_link { + pthread_mutex_t lock; + pthread_cond_t cond[2]; + uint8_t buf[2][LINK_MTU]; + uint32_t len[2]; + int ready[2]; + const char *name[2]; +}; + +struct mem_ep { + struct ll *ll; + struct mem_link *link; + int idx; +}; + +static struct mem_ep mem_eps[8]; +static size_t mem_ep_count; + +static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, + const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip); + +static void mem_link_init(struct mem_link *link) +{ + pthread_mutex_init(&link->lock, NULL); + pthread_cond_init(&link->cond[0], NULL); + pthread_cond_init(&link->cond[1], NULL); + link->ready[0] = link->ready[1] = 0; + link->len[0] = link->len[1] = 0; + link->name[0] = link->name[1] = ""; +} + +static struct mem_ep *mem_ep_lookup(struct ll *ll) +{ + for (size_t i = 0; i < mem_ep_count; i++) { + if (mem_eps[i].ll == ll) + return &mem_eps[i]; + } + return NULL; +} + +static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) +{ + struct mem_ep *ep = mem_ep_lookup(ll); + if (!ep) + return -1; + struct mem_link *link = ep->link; + int idx = ep->idx; + int ret = 0; + + pthread_mutex_lock(&link->lock); + if (link->ready[idx]) { + uint32_t copy = link->len[idx]; + if (copy > len) + copy = len; + memcpy(buf, link->buf[idx], copy); + link->ready[idx] = 0; + pthread_cond_signal(&link->cond[idx]); + ret = (int)copy; + } + pthread_mutex_unlock(&link->lock); + return ret; +} + +static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) +{ + struct mem_ep *ep = mem_ep_lookup(ll); + if (!ep) + return -1; + struct mem_link *link = ep->link; + int dst = 1 - ep->idx; + + pthread_mutex_lock(&link->lock); + while (link->ready[dst]) + pthread_cond_wait(&link->cond[dst], &link->lock); + if (len > LINK_MTU) + len = LINK_MTU; + memcpy(link->buf[dst], buf, len); + link->len[dst] = len; + link->ready[dst] = 1; + pthread_cond_signal(&link->cond[dst]); + pthread_mutex_unlock(&link->lock); + return (int)len; +} + +static void mem_link_attach(struct ll *ll, struct mem_link *link, int idx, + const char *ifname, const uint8_t mac[6]) +{ + ll->poll = mem_ll_poll; + ll->send = mem_ll_send; + snprintf(ll->ifname, sizeof(ll->ifname), "%s", ifname); + memcpy(ll->mac, mac, 6); + link->name[idx] = ifname; + mem_eps[mem_ep_count++] = (struct mem_ep){ .ll = ll, .link = link, .idx = idx }; +} + +/* ------------------------------------------------------------------------- */ +/* TLS echo server (wolfIP stack) */ +/* ------------------------------------------------------------------------- */ + +#define TEST_PAYLOAD (1024) + +static struct wolfIP *server_stack; +static int server_listen_fd = -1; +static int server_client_fd = -1; +static WOLFSSL_CTX *server_ctx = NULL; +static WOLFSSL *server_ssl = NULL; +static uint8_t server_buf[TEST_PAYLOAD]; +static int server_bytes_recv = 0; +static int server_bytes_sent = 0; +static volatile int server_done = 0; +static int server_handshake_done = 0; + +static void server_cb(int fd, uint16_t events, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + + + if (fd == server_listen_fd && (events & CB_EVENT_READABLE) && server_client_fd == -1) { + server_client_fd = wolfIP_sock_accept(s, server_listen_fd, NULL, NULL); + if (server_client_fd > 0) { + server_ssl = wolfSSL_new(server_ctx); + wolfSSL_SetIO_wolfIP(server_ssl, server_client_fd); + server_handshake_done = 0; + } + return; + } + + if (fd != server_client_fd || server_ssl == NULL) + return; + + if (!server_handshake_done) { + int ret = wolfSSL_accept(server_ssl); + if (ret == SSL_SUCCESS) { + server_handshake_done = 1; + } else { + int err = wolfSSL_get_error(server_ssl, ret); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + return; + } + wolfIP_sock_close(s, server_client_fd); + server_client_fd = -1; + wolfip_reset_io(server_ssl); + wolfSSL_free(server_ssl); + server_ssl = NULL; + server_done = 1; + return; + } + } + + if (events & (CB_EVENT_READABLE | CB_EVENT_WRITABLE)) { + if (server_bytes_recv < TEST_PAYLOAD) { + int ret = wolfSSL_read(server_ssl, server_buf + server_bytes_recv, + TEST_PAYLOAD - server_bytes_recv); + if (ret > 0) + server_bytes_recv += ret; + } + if (server_bytes_recv == TEST_PAYLOAD && server_bytes_sent < TEST_PAYLOAD) { + int ret = wolfSSL_write(server_ssl, server_buf + server_bytes_sent, + TEST_PAYLOAD - server_bytes_sent); + if (ret > 0) + server_bytes_sent += ret; + } + if (server_bytes_sent == TEST_PAYLOAD) { + wolfIP_sock_close(s, server_client_fd); + server_client_fd = -1; + wolfip_reset_io(server_ssl); + wolfSSL_free(server_ssl); + server_ssl = NULL; + server_handshake_done = 0; + server_done = 1; + } + } + + if (events & CB_EVENT_CLOSED) { + if (server_ssl) { + wolfip_reset_io(server_ssl); + wolfSSL_free(server_ssl); + server_ssl = NULL; + } + server_client_fd = -1; + server_handshake_done = 0; + server_done = 1; + } +} + +static int server_setup(struct wolfIP *s) +{ + struct wolfIP_sockaddr_in local = { + .sin_family = AF_INET, + .sin_port = ee16(4433), + .sin_addr.s_addr = 0, + }; + + server_ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method()); + if (!server_ctx) + return -1; + wolfSSL_SetIO_wolfIP_CTX(server_ctx, s); + + if (wolfSSL_CTX_use_certificate_buffer(server_ctx, server_der, + server_der_len, SSL_FILETYPE_ASN1) != SSL_SUCCESS) + return -1; + if (wolfSSL_CTX_use_PrivateKey_buffer(server_ctx, server_key_der, + server_key_der_len, SSL_FILETYPE_ASN1) != SSL_SUCCESS) + return -1; + + server_listen_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (server_listen_fd < 0) + return -1; + wolfIP_register_callback(s, server_listen_fd, server_cb, s); + if (wolfIP_sock_bind(s, server_listen_fd, (struct wolfIP_sockaddr *)&local, + sizeof(local)) < 0) + return -1; + if (wolfIP_sock_listen(s, server_listen_fd, 1) < 0) + return -1; + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* TLS client (wolfIP stack) */ +/* ------------------------------------------------------------------------- */ + +static struct wolfIP *client_stack; +static WOLFSSL_CTX *client_ctx = NULL; +static WOLFSSL *client_ssl = NULL; +static int client_fd = -1; +static uint8_t client_tx[TEST_PAYLOAD]; +static uint8_t client_rx[TEST_PAYLOAD]; +static int client_sent = 0; +static int client_recv = 0; + +enum client_state { + CLIENT_STATE_IDLE = 0, + CLIENT_STATE_HANDSHAKE, + CLIENT_STATE_WRITE, + CLIENT_STATE_READ, + CLIENT_STATE_DONE, + CLIENT_STATE_ERROR +}; + +static volatile enum client_state client_state = CLIENT_STATE_IDLE; + +static void client_cb(int fd, uint16_t events, void *arg) +{ + struct wolfIP *cli = (struct wolfIP *)arg; + (void)cli; + + if (fd != client_fd || client_ssl == NULL) + return; + + int progress = 1; + + while (progress) { + progress = 0; + if (client_state == CLIENT_STATE_HANDSHAKE) { + int ret = wolfSSL_connect(client_ssl); + if (ret == SSL_SUCCESS) { + client_state = CLIENT_STATE_WRITE; + progress = 1; + continue; + } else { + int err = wolfSSL_get_error(client_ssl, ret); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) + break; + client_state = CLIENT_STATE_ERROR; + break; + } + } + if (client_state == CLIENT_STATE_WRITE && + (events & (CB_EVENT_WRITABLE | CB_EVENT_READABLE))) { + int ret = wolfSSL_write(client_ssl, client_tx + client_sent, + TEST_PAYLOAD - client_sent); + if (ret > 0) { + client_sent += ret; + progress = 1; + if (client_sent == TEST_PAYLOAD) + client_state = CLIENT_STATE_READ; + } else { + int err = wolfSSL_get_error(client_ssl, ret); + if (err != WOLFSSL_ERROR_WANT_WRITE) { + client_state = CLIENT_STATE_ERROR; + } + break; + } + } + if (client_state == CLIENT_STATE_READ && (events & CB_EVENT_READABLE)) { + int ret = wolfSSL_read(client_ssl, client_rx + client_recv, + TEST_PAYLOAD - client_recv); + if (ret > 0) { + client_recv += ret; + progress = 1; + if (client_recv == TEST_PAYLOAD) { + if (memcmp(client_rx, client_tx, TEST_PAYLOAD) == 0) { + client_state = CLIENT_STATE_DONE; + wolfIP_sock_close(cli, client_fd); + wolfip_reset_io(client_ssl); + } else { + client_state = CLIENT_STATE_ERROR; + } + } + } else if (ret == 0) { + client_state = CLIENT_STATE_ERROR; + } else { + int err = wolfSSL_get_error(client_ssl, ret); + if (err != WOLFSSL_ERROR_WANT_READ) + client_state = CLIENT_STATE_ERROR; + break; + } + } else if (client_state == CLIENT_STATE_READ && !(events & CB_EVENT_READABLE)) { + break; + } + } + + if ((events & CB_EVENT_CLOSED) && client_state != CLIENT_STATE_DONE) + client_state = CLIENT_STATE_ERROR; +} + +static int client_start(struct wolfIP *cli, ip4 server_ip) +{ + struct wolfIP_sockaddr_in remote = { + .sin_family = AF_INET, + .sin_port = ee16(4433), + .sin_addr.s_addr = ee32(server_ip), + }; + + client_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + if (!client_ctx) + return -1; + wolfSSL_SetIO_wolfIP_CTX(client_ctx, cli); + wolfSSL_CTX_load_verify_buffer(client_ctx, ca_der, ca_der_len, SSL_FILETYPE_ASN1); + + client_ssl = wolfSSL_new(client_ctx); + if (!client_ssl) + return -1; + + for (size_t i = 0; i < sizeof(client_tx); i += 16) + memcpy(client_tx + i, "Test pattern - -", 16); + + client_fd = wolfIP_sock_socket(cli, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (client_fd < 0) + return -1; + wolfIP_register_callback(cli, client_fd, client_cb, cli); + wolfSSL_SetIO_wolfIP(client_ssl, client_fd); + + client_state = CLIENT_STATE_HANDSHAKE; + { + int conn = wolfIP_sock_connect(cli, client_fd, + (struct wolfIP_sockaddr *)&remote, sizeof(remote)); + if (conn < 0 && conn != -11) { + client_state = CLIENT_STATE_ERROR; + return -1; + } + } + /* Kick-start handshake */ + { + int first = wolfSSL_connect(client_ssl); + if (first != SSL_SUCCESS) { + int err = wolfSSL_get_error(client_ssl, first); + if (!(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE)) + return -1; + } + } + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* Router */ +/* ------------------------------------------------------------------------- */ + +static struct wolfIP *router_stack; +static volatile int router_running = 1; + +/* ------------------------------------------------------------------------- */ +/* Stack polling threads */ +/* ------------------------------------------------------------------------- */ + +static void *poll_thread(void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + while (1) { + uint64_t now = monotonic_ms(); + wolfIP_poll(s, now); + usleep(1000); + if (s == client_stack) { + static int last_state = -1; + if ((int)client_state != last_state) { + last_state = client_state; + } + } + if (s == router_stack) { + if (!router_running) + break; + } else if (s == server_stack) { + if (server_done) + break; + } else if (s == client_stack) { + if (client_state == CLIENT_STATE_DONE || client_state == CLIENT_STATE_ERROR) { + server_done = 1; + break; + } + } + } + return NULL; +} + +/* ------------------------------------------------------------------------- */ +/* Main */ +/* ------------------------------------------------------------------------- */ + +int main(void) +{ + setvbuf(stdout, NULL, _IONBF, 0); + /* MAC addresses */ + static const uint8_t mac_client[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0x10}; + static const uint8_t mac_router0[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0xFE}; + static const uint8_t mac_router1[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0xFE}; + static const uint8_t mac_server[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0x10}; + + struct mem_link link_client_router; + struct mem_link link_router_server; + int ret = 0; + + mem_link_init(&link_client_router); + mem_link_init(&link_router_server); + + wolfSSL_Init(); + wolfSSL_Debugging_OFF(); + + /* Initialise stacks */ + size_t stack_sz = wolfIP_instance_size(); + client_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + router_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + server_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (!client_stack || !router_stack || !server_stack) { + fprintf(stderr, "failed to allocate stacks\n"); + ret = 1; + goto cleanup; + } + XMEMSET(client_stack, 0, stack_sz); + XMEMSET(router_stack, 0, stack_sz); + XMEMSET(server_stack, 0, stack_sz); + wolfIP_init(client_stack); + wolfIP_init(router_stack); + wolfIP_init(server_stack); + + /* Attach memory links */ + mem_link_attach(wolfIP_getdev(client_stack), &link_client_router, 0, "cli0", mac_client); + mem_link_attach(wolfIP_getdev_ex(router_stack, 0), &link_client_router, 1, "rt0", mac_router0); + mem_link_attach(wolfIP_getdev_ex(router_stack, 1), &link_router_server, 0, "rt1", mac_router1); + mem_link_attach(wolfIP_getdev(server_stack), &link_router_server, 1, "srv0", mac_server); + + /* Configure IP addresses */ + wolfIP_ipconfig_set(client_stack, IP4(10,0,1,2), IP4(255,255,255,0), IP4(10,0,1,254)); + wolfIP_ipconfig_set_ex(router_stack, 0, IP4(10,0,1,254), IP4(255,255,255,0), IP4(0,0,0,0)); + wolfIP_ipconfig_set_ex(router_stack, 1, IP4(10,0,2,1), IP4(255,255,255,0), IP4(0,0,0,0)); + wolfIP_ipconfig_set(server_stack, IP4(10,0,2,2), IP4(255,255,255,0), IP4(10,0,2,1)); + + /* Pre-populate ARP entries so forwarding can proceed immediately */ + inject_arp_reply(client_stack, 0, mac_router0, IP4(10,0,1,254), mac_client, IP4(10,0,1,2)); + inject_arp_reply(router_stack, 0, mac_client, IP4(10,0,1,2), mac_router0, IP4(10,0,1,254)); + inject_arp_reply(router_stack, 1, mac_server, IP4(10,0,2,2), mac_router1, IP4(10,0,2,1)); + inject_arp_reply(server_stack, 0, mac_router1, IP4(10,0,2,1), mac_server, IP4(10,0,2,2)); + + if (server_setup(server_stack) < 0) { + fprintf(stderr, "failed to set up server\n"); + ret = 1; + goto cleanup; + } + + if (client_start(client_stack, IP4(10,0,2,2)) < 0) { + fprintf(stderr, "failed to start client\n"); + ret = 1; + goto cleanup; + } + + router_running = 1; + if (pthread_create(&th_router, NULL, poll_thread, router_stack) != 0) { + fprintf(stderr, "failed to start router thread\n"); + ret = 1; + goto cleanup; + } + if (pthread_create(&th_server, NULL, poll_thread, server_stack) != 0) { + fprintf(stderr, "failed to start server thread\n"); + ret = 1; + goto cleanup; + } + if (pthread_create(&th_client, NULL, poll_thread, client_stack) != 0) { + fprintf(stderr, "failed to start client thread\n"); + ret = 1; + goto cleanup; + } + + +cleanup: + pthread_join(th_server, NULL); + + printf("Test result: %s\n", ret == 0 ? "SUCCESS" : "FAIL"); + return ret; +} +#include +#define TEST_PACKED __attribute__((packed)) + +struct TEST_PACKED test_arp_packet { + uint8_t dst[6]; + uint8_t src[6]; + uint16_t type; + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; + uint8_t sma[6]; + uint32_t sip; + uint8_t tma[6]; + uint32_t tip; +}; + +static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, + const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip) +{ + struct test_arp_packet pkt; + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.dst, dst_mac, 6); + memcpy(pkt.src, src_mac, 6); + pkt.type = htons(0x0806); + pkt.htype = htons(1); + pkt.ptype = htons(0x0800); + pkt.hlen = 6; + pkt.plen = 4; + pkt.opcode = htons(2); /* reply */ + memcpy(pkt.sma, src_mac, 6); + pkt.sip = htonl(src_ip); + memcpy(pkt.tma, dst_mac, 6); + pkt.tip = htonl(dst_ip); + wolfIP_recv_ex(stack, if_idx, &pkt, sizeof(pkt)); +} diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 2bbdb958..58429411 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -22,6 +22,9 @@ #ifndef WOLFIP_MAX_INTERFACES #define WOLFIP_MAX_INTERFACES 2 #endif +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 1 +#endif #include #include "../../wolfip.c" #include /* for random() */ @@ -703,6 +706,101 @@ START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply) } END_TEST +START_TEST(test_wolfip_forwarding_basic) +{ + struct wolfIP s; + struct wolfIP_ip_packet frame; + struct wolfIP_ip_packet *fwd; + uint8_t src_mac[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56}; + uint8_t iface1_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x02}; + uint8_t next_hop_mac[6] = {0x02, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}; + uint32_t dest_ip = 0xC0A80164; /* 192.168.1.100 */ + uint8_t initial_ttl = 2; + uint16_t orig_csum; + uint16_t expected_csum; + + wolfIP_init(&s); + mock_link_init(&s); + mock_link_init_idx(&s, 1, iface1_mac); + wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + s.arp.neighbors[0].ip = dest_ip; + s.arp.neighbors[0].if_idx = 1; + memcpy(s.arp.neighbors[0].mac, next_hop_mac, 6); + + memset(&frame, 0, sizeof(frame)); + memcpy(frame.eth.dst, s.ll_dev[0].mac, 6); + memcpy(frame.eth.src, src_mac, 6); + frame.eth.type = ee16(ETH_TYPE_IP); + frame.ver_ihl = 0x45; + frame.ttl = initial_ttl; + frame.proto = WI_IPPROTO_UDP; + frame.len = ee16(IP_HEADER_LEN); + frame.src = ee32(0xC0A800AA); + frame.dst = ee32(dest_ip); + frame.csum = 0; + iphdr_set_checksum(&frame); + orig_csum = ee16(frame.csum); + + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + last_frame_sent_size = 0; + + wolfIP_recv_ex(&s, 0, &frame, sizeof(frame)); + + ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_ip_packet)); + fwd = (struct wolfIP_ip_packet *)last_frame_sent; + ck_assert_mem_eq(fwd->eth.dst, next_hop_mac, 6); + ck_assert_mem_eq(fwd->eth.src, s.ll_dev[1].mac, 6); + ck_assert_uint_eq(fwd->ttl, (uint8_t)(initial_ttl - 1)); + expected_csum = (uint16_t)(orig_csum + 1); + if (expected_csum == 0) + expected_csum = 0xFFFF; + ck_assert_uint_eq(ee16(fwd->csum), expected_csum); +} +END_TEST + +START_TEST(test_wolfip_forwarding_ttl_expired) +{ + struct wolfIP s; + struct wolfIP_ip_packet frame; + struct wolfIP_icmp_packet *icmp; + uint8_t src_mac[6] = {0x52, 0x54, 0x00, 0xAA, 0xBB, 0xCC}; + uint8_t iface1_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x03}; + uint32_t dest_ip = 0xC0A80110; + + wolfIP_init(&s); + mock_link_init(&s); + mock_link_init_idx(&s, 1, iface1_mac); + wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + + memset(&frame, 0, sizeof(frame)); + memcpy(frame.eth.dst, s.ll_dev[0].mac, 6); + memcpy(frame.eth.src, src_mac, 6); + frame.eth.type = ee16(ETH_TYPE_IP); + frame.ver_ihl = 0x45; + frame.ttl = 1; + frame.proto = WI_IPPROTO_UDP; + frame.len = ee16(IP_HEADER_LEN); + frame.src = ee32(0xC0A800AA); + frame.dst = ee32(dest_ip); + frame.csum = 0; + iphdr_set_checksum(&frame); + + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + last_frame_sent_size = 0; + + wolfIP_recv_ex(&s, 0, &frame, sizeof(frame)); + + ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_icmp_packet)); + icmp = (struct wolfIP_icmp_packet *)last_frame_sent; + ck_assert_uint_eq(icmp->type, ICMP_TTL_EXCEEDED); + ck_assert_mem_eq(icmp->ip.eth.dst, src_mac, 6); + ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[0].mac, 6); + ck_assert_uint_eq(frame.ttl, 1); /* original packet should remain unchanged */ +} +END_TEST + // Test for `transport_checksum` calculation START_TEST(test_transport_checksum) { @@ -889,6 +987,10 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_wolfip_recv_ex_multi_interface_arp_reply); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_wolfip_forwarding_basic); + suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_wolfip_forwarding_ttl_expired); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_utils, test_transport_checksum); suite_add_tcase(s, tc_proto); diff --git a/src/wolfip.c b/src/wolfip.c index 8399aedf..56bed323 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -584,6 +584,26 @@ static inline int ip_is_local_conf(const struct ipconf *conf, ip4 addr) return ((addr & conf->mask) == (conf->ip & conf->mask)); } +#if WOLFIP_ENABLE_FORWARDING +static unsigned int wolfIP_forward_interface(struct wolfIP *s, unsigned int in_if, ip4 dest) +{ + if (!s || s->if_count < 2) + return s ? s->if_count : 0; + for (unsigned int i = 0; i < s->if_count; i++) { + struct ipconf *conf = &s->ipconf[i]; + if (i == in_if) + continue; + if (!conf || conf->ip == IPADDR_ANY) + continue; + if (dest == conf->ip) + return s->if_count; + if (ip_is_local_conf(conf, dest)) + return i; + } + return s->if_count; +} +#endif + static inline ip4 wolfIP_select_nexthop(const struct ipconf *conf, ip4 dest) { if (IS_IP_BCAST(dest)) @@ -647,6 +667,48 @@ static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int * return 0; } +#ifdef ETHERNET +static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp); +static void iphdr_set_checksum(struct wolfIP_ip_packet *ip); +static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, + uint16_t type); +#endif +#if WOLFIP_ENABLE_FORWARDING && defined(ETHERNET) +static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip); +static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); +#endif + +#ifdef ETHERNET +static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) +{ + struct ll *ll = wolfIP_ll_at(s, if_idx); + if (!ll || !ll->send) + return; + struct wolfIP_icmp_packet icmp; + memset(&icmp, 0, sizeof(icmp)); + icmp.type = ICMP_TTL_EXCEEDED; + icmp.csum = ee16(icmp_checksum(&icmp)); + icmp.ip.ver_ihl = 0x45; + icmp.ip.ttl = 64; + icmp.ip.proto = WI_IPPROTO_ICMP; + icmp.ip.id = ee16(s->ipcounter++); + icmp.ip.len = ee16(IP_HEADER_LEN + ICMP_HEADER_LEN); + icmp.ip.src = orig->dst; + icmp.ip.dst = orig->src; + icmp.ip.csum = 0; + iphdr_set_checksum(&icmp.ip); + eth_output_add_header(s, if_idx, orig->eth.src, &icmp.ip.eth, ETH_TYPE_IP); + ll->send(ll, &icmp, sizeof(struct wolfIP_icmp_packet)); +} +#else +static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) +{ + (void)s; + (void)if_idx; + (void)orig; +} +#endif + /* User Callbacks */ void wolfIP_register_callback(struct wolfIP *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg) { @@ -979,6 +1041,53 @@ static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const ui } #endif +#if WOLFIP_ENABLE_FORWARDING +static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 dest, uint8_t *mac, int *broadcast) +{ +#ifdef ETHERNET + if (!broadcast || !mac) + return 0; + if (IS_IP_BCAST(dest)) { + *broadcast = 1; + return 1; + } + *broadcast = 0; + if (arp_lookup(s, out_if, dest, mac) == 0) + return 1; + arp_request(s, out_if, dest); + return 0; +#else + (void)s; + (void)out_if; + (void)dest; + (void)mac; + (void)broadcast; + return 0; +#endif +} + +static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct wolfIP_ip_packet *ip, uint32_t len, const uint8_t *mac, int broadcast) +{ +#ifdef ETHERNET + struct ll *ll = wolfIP_ll_at(s, out_if); + if (!ll || !ll->send) + return; + if (broadcast) + eth_output_add_header(s, out_if, NULL, &ip->eth, ETH_TYPE_IP); + else + eth_output_add_header(s, out_if, mac, &ip->eth, ETH_TYPE_IP); + ll->send(ll, ip, len); +#else + (void)s; + (void)out_if; + (void)ip; + (void)len; + (void)mac; + (void)broadcast; +#endif +} +#endif + static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, uint8_t proto, uint16_t len) { union transport_pseudo_header ph; @@ -1148,7 +1257,6 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp) static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_seg *tcp, uint32_t frame_len) { struct ipconf *conf = wolfIP_ipconf_at(S, if_idx); - struct ll *ll = wolfIP_ll_at(S, if_idx); ip4 local_ip = conf ? conf->ip : IPADDR_ANY; for (int i = 0; i < MAX_TCPSOCKETS; i++) { uint32_t tcplen; @@ -1171,20 +1279,7 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_s } /* Check IP ttl */ if (tcp->ip.ttl == 0) { - /* Send ICMP TTL exceeded */ - struct wolfIP_icmp_packet icmp; - memset(&icmp, 0, sizeof(icmp)); - icmp.type = ICMP_TTL_EXCEEDED; - icmp.csum = ee16(icmp_checksum(&icmp)); - icmp.ip.src = tcp->ip.dst; - icmp.ip.dst = tcp->ip.src; - icmp.ip.proto = WI_IPPROTO_ICMP; - icmp.ip.id = ee16(S->ipcounter++); - icmp.ip.csum = 0; - iphdr_set_checksum(&icmp.ip); - eth_output_add_header(S, if_idx, icmp.ip.eth.src, &icmp.ip.eth, ETH_TYPE_IP); - if (ll && ll->send) - ll->send(ll, &icmp, sizeof(struct wolfIP_icmp_packet)); + wolfIP_send_ttl_exceeded(S, if_idx, &tcp->ip); return; } tcplen = iplen - (IP_HEADER_LEN + (tcp->hlen >> 2)); @@ -2149,9 +2244,54 @@ void wolfIP_init_static(struct wolfIP **s) *s = &wolfIP_static; } +size_t wolfIP_instance_size(void) +{ + return sizeof(struct wolfIP); +} + static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { +#if WOLFIP_ENABLE_FORWARDING + if (ip->ver_ihl == 0x45) { + ip4 dest = ee32(ip->dst); + int is_local = 0; + if (dest == IPADDR_ANY || IS_IP_BCAST(dest)) { + is_local = 1; + } else { + for (unsigned int i = 0; i < s->if_count; i++) { + struct ipconf *conf = &s->ipconf[i]; + if (!conf || conf->ip == IPADDR_ANY) + continue; + if (conf->ip == dest) { + is_local = 1; + break; + } + } + } + if (!is_local) { + unsigned int out_if = wolfIP_forward_interface(s, if_idx, dest); + if (out_if < s->if_count) { + if (ip->ttl <= 1) { + wolfIP_send_ttl_exceeded(s, if_idx, ip); + return; + } + uint8_t mac[6]; + int broadcast = 0; + if (!wolfIP_forward_prepare(s, out_if, dest, mac, &broadcast)) + return; + ip->ttl--; + uint16_t csum = ee16(ip->csum); + csum = (uint16_t)(csum + 1); + if (csum == 0) + csum = 0xFFFF; + ip->csum = ee16(csum); + wolfIP_forward_packet(s, out_if, ip, len, broadcast ? NULL : mac, broadcast); + return; + } + } + } +#endif if (ip->ver_ihl == 0x45 && ip->proto == 0x06) { struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)ip; tcp_input(s, if_idx, tcp, len); diff --git a/wolfip.h b/wolfip.h index 03709e35..71284f04 100644 --- a/wolfip.h +++ b/wolfip.h @@ -96,6 +96,7 @@ int nslookup(struct wolfIP *s, const char *name, uint16_t *id, void (*lookup_cb) /* IP stack interface */ void wolfIP_init(struct wolfIP *s); void wolfIP_init_static(struct wolfIP **s); +size_t wolfIP_instance_size(void); int wolfIP_poll(struct wolfIP *s, uint64_t now); void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len); void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); From 403f130ada38dd51042e15ed5b3827b89fcf7f47 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 18:31:26 +0100 Subject: [PATCH 05/25] Added loopback interface --- config.h | 8 ++ docs/API.md | 9 +- src/test/unit/unit.c | 133 +++++++++++++++++-------- src/wolfip.c | 231 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 295 insertions(+), 86 deletions(-) diff --git a/config.h b/config.h index b2df6fd3..b44e3827 100644 --- a/config.h +++ b/config.h @@ -19,6 +19,14 @@ #define WOLFIP_ENABLE_FORWARDING 0 #endif +#ifndef WOLFIP_ENABLE_LOOPBACK +#define WOLFIP_ENABLE_LOOPBACK 0 +#endif + +#if WOLFIP_ENABLE_LOOPBACK && WOLFIP_MAX_INTERFACES < 2 +#error "WOLFIP_ENABLE_LOOPBACK requires WOLFIP_MAX_INTERFACES > 1" +#endif + /* Linux test configuration */ #define WOLFIP_IP "10.10.10.2" #define LINUX_IP "10.10.10.1" diff --git a/docs/API.md b/docs/API.md index 5cdc5569..094a8ff9 100644 --- a/docs/API.md +++ b/docs/API.md @@ -30,7 +30,7 @@ struct ll { int (*send)(struct ll *ll, void *buf, uint32_t len); // Transmit function }; ``` -wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper still returns slot `0`. +wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper targets the first hardware slot (index `0` normally, or `1` when the optional loopback interface is enabled). ### IP Configuration ```c @@ -41,10 +41,15 @@ struct ipconf { ip4 gw; // Default gateway }; ``` -Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on index `0` for backwards compatibility. +Each `struct wolfIP` instance owns `WOLFIP_MAX_INTERFACES` `ipconf` entries—one per link-layer slot. Use the `_ex` helpers to read or update a specific interface; the legacy accessors operate on the first hardware interface (index `0` unless loopback support is compiled in). If `WOLFIP_ENABLE_FORWARDING` is set to `1` at compile time, the stack performs simple IPv4 forwarding between interfaces. Packets received on one interface whose destinations match another configured interface are re-sent with the IP TTL decreased by one (or an ICMP TTL-exceeded response if the TTL would drop to zero). +Enabling `WOLFIP_ENABLE_LOOPBACK` (requires `WOLFIP_MAX_INTERFACES > 1`) creates an internal loopback +device at index `0` with the fixed address `127.0.0.1/8`. Traffic sent to that address is reflected back +through the stack so local sockets, pings, and other services behave as they would on a standard +loopback interface; the first hardware interface then shifts to index `1` for legacy helpers. + ### Socket Address Structures ```c struct wolfIP_sockaddr_in { diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 58429411..c5ffb00e 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -19,12 +19,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #include "check.h" -#ifndef WOLFIP_MAX_INTERFACES -#define WOLFIP_MAX_INTERFACES 2 -#endif +#include "../../../config.h" +#undef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 3 +#undef WOLFIP_ENABLE_FORWARDING #ifndef WOLFIP_ENABLE_FORWARDING #define WOLFIP_ENABLE_FORWARDING 1 #endif +#if WOLFIP_ENABLE_LOOPBACK +#define TEST_LOOPBACK_IF 0U +#define TEST_PRIMARY_IF 1U +#define TEST_SECOND_IF 2U +#else +#define TEST_LOOPBACK_IF 0U +#define TEST_PRIMARY_IF 0U +#define TEST_SECOND_IF 1U +#endif #include #include "../../wolfip.c" #include /* for random() */ @@ -78,7 +88,11 @@ static void mock_link_init_idx(struct wolfIP *s, unsigned int idx, const uint8_t void mock_link_init(struct wolfIP *s) { - mock_link_init_idx(s, 0, NULL); + unsigned int idx = 0; +#if WOLFIP_ENABLE_LOOPBACK + idx = 1; +#endif + mock_link_init_idx(s, idx, NULL); } static struct timers_binheap heap; @@ -468,19 +482,19 @@ START_TEST(test_arp_request_basic) uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */ mock_link_init(&s); s.last_tick = 1000; - arp_request(&s, 0, target_ip); + arp_request(&s, TEST_PRIMARY_IF, target_ip); ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet)); arp = (struct arp_packet *)last_frame_sent; ck_assert_mem_eq(arp->eth.dst, "\xff\xff\xff\xff\xff\xff", 6); - ck_assert_mem_eq(arp->eth.src, s.ll_dev[0].mac, 6); + ck_assert_mem_eq(arp->eth.src, s.ll_dev[TEST_PRIMARY_IF].mac, 6); ck_assert_int_eq(arp->eth.type, ee16(0x0806)); ck_assert_int_eq(arp->htype, ee16(1)); ck_assert_int_eq(arp->ptype, ee16(0x0800)); ck_assert_int_eq(arp->hlen, 6); ck_assert_int_eq(arp->plen, 4); ck_assert_int_eq(arp->opcode, ee16(ARP_REQUEST)); - ck_assert_mem_eq(arp->sma, s.ll_dev[0].mac, 6); - ck_assert_int_eq(arp->sip, ee32(s.ipconf[0].ip)); + ck_assert_mem_eq(arp->sma, s.ll_dev[TEST_PRIMARY_IF].mac, 6); + ck_assert_int_eq(arp->sip, ee32(s.ipconf[TEST_PRIMARY_IF].ip)); ck_assert_mem_eq(arp->tma, "\x00\x00\x00\x00\x00\x00", 6); ck_assert_int_eq(arp->tip, ee32(target_ip)); } @@ -493,9 +507,9 @@ START_TEST(test_arp_request_throttle) uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/ mock_link_init(&s); s.last_tick = 1000; - s.arp.last_arp[0] = 880; + s.arp.last_arp[TEST_PRIMARY_IF] = 880; last_frame_sent_size = 0; - arp_request(&s, 0, target_ip); + arp_request(&s, TEST_PRIMARY_IF, target_ip); ck_assert_int_eq(last_frame_sent_size, 0); } END_TEST @@ -506,7 +520,7 @@ START_TEST(test_arp_request_target_ip) { wolfIP_init(&s); mock_link_init(&s); s.last_tick = 1000; - arp_request(&s, 0, target_ip); + arp_request(&s, TEST_PRIMARY_IF, target_ip); ck_assert_int_eq(((struct arp_packet *)(last_frame_sent))->tip, ee32(target_ip)); } END_TEST @@ -522,7 +536,7 @@ START_TEST(test_arp_request_handling) { struct wolfIP s; wolfIP_init(&s); mock_link_init(&s); - s.ipconf[0].ip = device_ip; + s.ipconf[TEST_PRIMARY_IF].ip = device_ip; /* Prepare ARP request */ arp_req.opcode = ee16(ARP_REQUEST); @@ -531,7 +545,7 @@ START_TEST(test_arp_request_handling) { arp_req.tip = ee32(device_ip); /* Call arp_recv with the ARP request */ - arp_recv(&s, 0, &arp_req, sizeof(arp_req)); + arp_recv(&s, TEST_PRIMARY_IF, &arp_req, sizeof(arp_req)); wolfIP_poll(&s, 1000); wolfIP_poll(&s, 1001); wolfIP_poll(&s, 1002); @@ -545,7 +559,7 @@ START_TEST(test_arp_request_handling) { arp_reply = (struct arp_packet *)last_frame_sent; ck_assert_int_eq(last_frame_sent_size, sizeof(struct arp_packet)); ck_assert_int_eq(arp_reply->opcode, ee16(ARP_REPLY)); - ck_assert_mem_eq(arp_reply->sma, s.ll_dev[0].mac, 6); // source MAC + ck_assert_mem_eq(arp_reply->sma, s.ll_dev[TEST_PRIMARY_IF].mac, 6); // source MAC ck_assert_int_eq(arp_reply->sip, ee32(device_ip)); // source IP ck_assert_mem_eq(arp_reply->tma, req_mac, 6); // target MAC ck_assert_int_eq(arp_reply->tip, ee32(req_ip)); // target IP @@ -567,7 +581,7 @@ START_TEST(test_arp_reply_handling) { memcpy(arp_reply.sma, reply_mac, 6); /* Call arp_recv with the ARP reply */ - arp_recv(&s, 0, &arp_reply, sizeof(arp_reply)); + arp_recv(&s, TEST_PRIMARY_IF, &arp_reply, sizeof(arp_reply)); /* Check if ARP table updated with reply IP and MAC */ ck_assert_int_eq(s.arp.neighbors[0].ip, reply_ip); @@ -576,7 +590,7 @@ START_TEST(test_arp_reply_handling) { /* Update same IP with a different MAC address */ uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; memcpy(arp_reply.sma, new_mac, 6); - arp_recv(&s, 0, &arp_reply, sizeof(arp_reply)); + arp_recv(&s, TEST_PRIMARY_IF, &arp_reply, sizeof(arp_reply)); /* Check if ARP table updates with new MAC */ ck_assert_mem_eq(s.arp.neighbors[0].mac, new_mac, 6); @@ -596,7 +610,7 @@ START_TEST(test_arp_lookup_success) { memcpy(s.arp.neighbors[0].mac, mock_mac, 6); /* Test arp_lookup */ - int result = arp_lookup(&s, 0, ip, found_mac); + int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); ck_assert_int_eq(result, 0); ck_assert_mem_eq(found_mac, mock_mac, 6); } @@ -610,7 +624,7 @@ START_TEST(test_arp_lookup_failure) { mock_link_init(&s); /* Ensure arp_lookup fails for unknown IP */ - int result = arp_lookup(&s, 0, ip, found_mac); + int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); ck_assert_int_eq(result, -1); uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0}; ck_assert_mem_eq(found_mac, zero_mac, 6); @@ -623,11 +637,46 @@ START_TEST(test_wolfip_getdev_ex_api) wolfIP_init(&s); struct ll *ll_def = wolfIP_getdev(&s); ck_assert_ptr_nonnull(ll_def); - ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, 0)); + ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF)); +#if WOLFIP_ENABLE_LOOPBACK + ck_assert_ptr_ne(ll_def, wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF)); +#endif ck_assert_ptr_null(wolfIP_getdev_ex(&s, WOLFIP_MAX_INTERFACES)); } END_TEST +#if WOLFIP_ENABLE_LOOPBACK +START_TEST(test_wolfip_loopback_defaults) +{ + struct wolfIP s; + struct ll *loop; + struct ll *hw; + ip4 ip = 0, mask = 0, gw = 0; + + wolfIP_init(&s); + + loop = wolfIP_getdev_ex(&s, TEST_LOOPBACK_IF); + ck_assert_ptr_nonnull(loop); + ck_assert_ptr_nonnull(loop->send); + ck_assert_uint_eq(loop->mac[0], 0x02); + + wolfIP_ipconfig_get_ex(&s, TEST_LOOPBACK_IF, &ip, &mask, &gw); + ck_assert_uint_eq(ip, 0x7F000001U); + ck_assert_uint_eq(mask, 0xFF000000U); + ck_assert_uint_eq(gw, 0U); + + wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0x0A0000FEU); + wolfIP_ipconfig_get_ex(&s, TEST_PRIMARY_IF, &ip, &mask, &gw); + ck_assert_uint_eq(ip, 0x0A000001U); + ck_assert_uint_eq(mask, 0xFFFFFF00U); + ck_assert_uint_eq(gw, 0x0A0000FEU); + + hw = wolfIP_getdev(&s); + ck_assert_ptr_eq(hw, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF)); +} +END_TEST +#endif + START_TEST(test_wolfip_ipconfig_ex_per_interface) { struct wolfIP s; @@ -643,8 +692,8 @@ START_TEST(test_wolfip_ipconfig_ex_per_interface) wolfIP_init(&s); wolfIP_ipconfig_set(&s, base_ip, base_mask, base_gw); - wolfIP_ipconfig_set_ex(&s, 1, iface_ip, iface_mask, iface_gw); - wolfIP_ipconfig_get_ex(&s, 1, &out_ip, &out_mask, &out_gw); + wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, iface_ip, iface_mask, iface_gw); + wolfIP_ipconfig_get_ex(&s, TEST_SECOND_IF, &out_ip, &out_mask, &out_gw); ck_assert_uint_eq(out_ip, iface_ip); ck_assert_uint_eq(out_mask, iface_mask); @@ -656,11 +705,11 @@ START_TEST(test_wolfip_ipconfig_ex_per_interface) ck_assert_uint_eq(def_gw, base_gw); wolfIP_ipconfig_set_ex(&s, WOLFIP_MAX_INTERFACES, 0xDEADBEEF, 0xFFFFFFFF, 0x01010101); - ck_assert_uint_eq(s.ipconf[1].ip, iface_ip); - ck_assert_uint_eq(s.ipconf[1].mask, iface_mask); - ck_assert_uint_eq(s.ipconf[1].gw, iface_gw); + ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].ip, iface_ip); + ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].mask, iface_mask); + ck_assert_uint_eq(s.ipconf[TEST_SECOND_IF].gw, iface_gw); - wolfIP_ipconfig_get_ex(&s, 1, NULL, NULL, NULL); + wolfIP_ipconfig_get_ex(&s, TEST_SECOND_IF, NULL, NULL, NULL); } END_TEST @@ -674,9 +723,9 @@ START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply) wolfIP_init(&s); mock_link_init(&s); - mock_link_init_idx(&s, 1, iface1_mac); + mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac); wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); - wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0); memset(&arp_req, 0, sizeof(arp_req)); memset(last_frame_sent, 0, sizeof(last_frame_sent)); @@ -695,14 +744,14 @@ START_TEST(test_wolfip_recv_ex_multi_interface_arp_reply) memset(arp_req.tma, 0, sizeof(arp_req.tma)); arp_req.tip = ee32(0xC0A80101); - wolfIP_recv_ex(&s, 1, &arp_req, sizeof(arp_req)); + wolfIP_recv_ex(&s, TEST_SECOND_IF, &arp_req, sizeof(arp_req)); ck_assert_uint_eq(last_frame_sent_size, sizeof(struct arp_packet)); arp_reply = (struct arp_packet *)last_frame_sent; ck_assert_uint_eq(arp_reply->opcode, ee16(ARP_REPLY)); ck_assert_mem_eq(arp_reply->eth.src, iface1_mac, 6); ck_assert_mem_eq(arp_reply->sma, iface1_mac, 6); - ck_assert_uint_eq(arp_reply->sip, ee32(s.ipconf[1].ip)); + ck_assert_uint_eq(arp_reply->sip, ee32(s.ipconf[TEST_SECOND_IF].ip)); } END_TEST @@ -721,15 +770,15 @@ START_TEST(test_wolfip_forwarding_basic) wolfIP_init(&s); mock_link_init(&s); - mock_link_init_idx(&s, 1, iface1_mac); + mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac); wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); - wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0); s.arp.neighbors[0].ip = dest_ip; - s.arp.neighbors[0].if_idx = 1; + s.arp.neighbors[0].if_idx = TEST_SECOND_IF; memcpy(s.arp.neighbors[0].mac, next_hop_mac, 6); memset(&frame, 0, sizeof(frame)); - memcpy(frame.eth.dst, s.ll_dev[0].mac, 6); + memcpy(frame.eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6); memcpy(frame.eth.src, src_mac, 6); frame.eth.type = ee16(ETH_TYPE_IP); frame.ver_ihl = 0x45; @@ -745,12 +794,12 @@ START_TEST(test_wolfip_forwarding_basic) memset(last_frame_sent, 0, sizeof(last_frame_sent)); last_frame_sent_size = 0; - wolfIP_recv_ex(&s, 0, &frame, sizeof(frame)); + wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame)); ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_ip_packet)); fwd = (struct wolfIP_ip_packet *)last_frame_sent; ck_assert_mem_eq(fwd->eth.dst, next_hop_mac, 6); - ck_assert_mem_eq(fwd->eth.src, s.ll_dev[1].mac, 6); + ck_assert_mem_eq(fwd->eth.src, s.ll_dev[TEST_SECOND_IF].mac, 6); ck_assert_uint_eq(fwd->ttl, (uint8_t)(initial_ttl - 1)); expected_csum = (uint16_t)(orig_csum + 1); if (expected_csum == 0) @@ -770,12 +819,12 @@ START_TEST(test_wolfip_forwarding_ttl_expired) wolfIP_init(&s); mock_link_init(&s); - mock_link_init_idx(&s, 1, iface1_mac); + mock_link_init_idx(&s, TEST_SECOND_IF, iface1_mac); wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); - wolfIP_ipconfig_set_ex(&s, 1, 0xC0A80101, 0xFFFFFF00, 0); + wolfIP_ipconfig_set_ex(&s, TEST_SECOND_IF, 0xC0A80101, 0xFFFFFF00, 0); memset(&frame, 0, sizeof(frame)); - memcpy(frame.eth.dst, s.ll_dev[0].mac, 6); + memcpy(frame.eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6); memcpy(frame.eth.src, src_mac, 6); frame.eth.type = ee16(ETH_TYPE_IP); frame.ver_ihl = 0x45; @@ -790,13 +839,13 @@ START_TEST(test_wolfip_forwarding_ttl_expired) memset(last_frame_sent, 0, sizeof(last_frame_sent)); last_frame_sent_size = 0; - wolfIP_recv_ex(&s, 0, &frame, sizeof(frame)); + wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame)); ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_icmp_packet)); icmp = (struct wolfIP_icmp_packet *)last_frame_sent; ck_assert_uint_eq(icmp->type, ICMP_TTL_EXCEEDED); ck_assert_mem_eq(icmp->ip.eth.dst, src_mac, 6); - ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[0].mac, 6); + ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[TEST_PRIMARY_IF].mac, 6); ck_assert_uint_eq(frame.ttl, 1); /* original packet should remain unchanged */ } END_TEST @@ -968,6 +1017,10 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_utils); tcase_add_test(tc_utils, test_wolfip_getdev_ex_api); suite_add_tcase(s, tc_utils); +#if WOLFIP_ENABLE_LOOPBACK + tcase_add_test(tc_utils, test_wolfip_loopback_defaults); + suite_add_tcase(s, tc_utils); +#endif tcase_add_test(tc_utils, test_wolfip_ipconfig_ex_per_interface); suite_add_tcase(s, tc_utils); diff --git a/src/wolfip.c b/src/wolfip.c index 56bed323..0ac68e89 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -21,9 +21,38 @@ #include #include +#include #include "wolfip.h" #include "config.h" +#if WOLFIP_ENABLE_LOOPBACK +#define WOLFIP_LOOPBACK_IF_IDX 0U +#define WOLFIP_PRIMARY_IF_IDX 1U +#define WOLFIP_LOOPBACK_IP 0x7F000001U +#define WOLFIP_LOOPBACK_MASK 0xFF000000U +static inline int wolfIP_is_loopback_if(unsigned int if_idx) +{ + return if_idx == WOLFIP_LOOPBACK_IF_IDX; +} +#else +#define WOLFIP_LOOPBACK_IF_IDX 0U +#define WOLFIP_PRIMARY_IF_IDX 0U +static inline int wolfIP_is_loopback_if(unsigned int if_idx) +{ + (void)if_idx; + return 0; +} +#endif + +#define WOLFIP_CONTAINER_OF(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) + +#if WOLFIP_ENABLE_LOOPBACK +static int wolfIP_loopback_send(struct ll *ll, void *buf, uint32_t len); +static int wolfIP_loopback_poll(struct ll *ll, void *buf, uint32_t len); +#endif +static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); + /* Fixed size binary heap: each element is a timer. */ #define MAX_TIMERS MAX_TCPSOCKETS * 3 @@ -558,6 +587,33 @@ struct wolfIP #endif }; +#if WOLFIP_ENABLE_LOOPBACK +static int wolfIP_loopback_poll(struct ll *ll, void *buf, uint32_t len) +{ + (void)ll; + (void)buf; + (void)len; + return 0; +} + +static int wolfIP_loopback_send(struct ll *ll, void *buf, uint32_t len) +{ + struct wolfIP *s; + uint32_t copy = len; + uint8_t frame[LINK_MTU]; + if (!ll || !buf) + return -1; + s = WOLFIP_CONTAINER_OF(ll, struct wolfIP, ll_dev); + if (!s) + return -1; + if (copy > LINK_MTU) + copy = LINK_MTU; + memcpy(frame, buf, copy); + wolfIP_recv_on(s, WOLFIP_LOOPBACK_IF_IDX, frame, copy); + return (int)copy; +} +#endif + /* ***************************** */ /* Implementation */ @@ -575,6 +631,11 @@ static inline struct ipconf *wolfIP_ipconf_at(struct wolfIP *s, unsigned int if_ return &s->ipconf[if_idx]; } +static inline struct ipconf *wolfIP_primary_ipconf(struct wolfIP *s) +{ + return wolfIP_ipconf_at(s, WOLFIP_PRIMARY_IF_IDX); +} + static inline int ip_is_local_conf(const struct ipconf *conf, ip4 addr) { if (!conf) @@ -619,14 +680,20 @@ static inline ip4 wolfIP_select_nexthop(const struct ipconf *conf, ip4 dest) static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) { - unsigned int fallback = 0; - int has_fallback = 0; + unsigned int default_if = 0; + unsigned int gw_fallback = 0; + unsigned int first_non_loop = 0; + int has_gw_fallback = 0; + int has_non_loop = 0; if (!s || s->if_count == 0) return 0; + if (WOLFIP_PRIMARY_IF_IDX < s->if_count) + default_if = WOLFIP_PRIMARY_IF_IDX; + if (dest == IPADDR_ANY || IS_IP_BCAST(dest)) - return 0; + return default_if; for (unsigned int i = 0; i < s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; @@ -635,12 +702,20 @@ static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) if (ip_is_local_conf(conf, dest) || conf->ip == dest) { return i; } - if (!has_fallback && conf->gw != IPADDR_ANY) { - fallback = i; - has_fallback = 1; + if (!wolfIP_is_loopback_if(i) && !has_non_loop) { + first_non_loop = i; + has_non_loop = 1; + } + if (!wolfIP_is_loopback_if(i) && !has_gw_fallback && conf->gw != IPADDR_ANY) { + gw_fallback = i; + has_gw_fallback = 1; } } - return has_fallback ? fallback : 0; + if (has_gw_fallback) + return gw_fallback; + if (has_non_loop) + return first_non_loop; + return default_if; } static inline unsigned int wolfIP_socket_if_idx(const struct tsocket *t) @@ -652,10 +727,15 @@ static inline unsigned int wolfIP_socket_if_idx(const struct tsocket *t) static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int *found) { + unsigned int primary = 0; if (found) *found = 0; - if (!s || s->if_count == 0 || local_ip == IPADDR_ANY) + if (!s || s->if_count == 0) return 0; + if (WOLFIP_PRIMARY_IF_IDX < s->if_count) + primary = WOLFIP_PRIMARY_IF_IDX; + if (local_ip == IPADDR_ANY) + return primary; for (unsigned int i = 0; i < s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; if (conf->ip == local_ip) { @@ -664,7 +744,7 @@ static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int * return i; } } - return 0; + return primary; } #ifdef ETHERNET @@ -1047,6 +1127,13 @@ static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 des #ifdef ETHERNET if (!broadcast || !mac) return 0; + if (wolfIP_is_loopback_if(out_if)) { + struct ll *loop = wolfIP_ll_at(s, out_if); + if (loop) + memcpy(mac, loop->mac, 6); + *broadcast = 0; + return 1; + } if (IS_IP_BCAST(dest)) { *broadcast = 1; return 1; @@ -1445,8 +1532,11 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad ts->if_idx = (uint8_t)if_idx; if (ts->local_ip == 0 && conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; - else if (ts->local_ip == 0 && s->ipconf[0].ip != IPADDR_ANY) - ts->local_ip = s->ipconf[0].ip; + else if (ts->local_ip == 0) { + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary && primary->ip != IPADDR_ANY) + ts->local_ip = primary->ip; + } return 0; } if ((sockfd & MARK_TCP_SOCKET) == 0) @@ -1466,10 +1556,13 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad ts->if_idx = (uint8_t)if_idx; if (conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; - else if (s->ipconf[0].ip != IPADDR_ANY) - ts->local_ip = s->ipconf[0].ip; - else - ts->local_ip = 0; + else { + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary && primary->ip != IPADDR_ANY) + ts->local_ip = primary->ip; + else + ts->local_ip = 0; + } if (!ts->src_port) ts->src_port = (uint16_t)(wolfIP_getrandom() & 0xFFFF); if (ts->src_port < 1024) @@ -1609,8 +1702,11 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (ts->local_ip == 0) { if (conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; - else if (s->ipconf[0].ip != IPADDR_ANY) - ts->local_ip = s->ipconf[0].ip; + else { + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary && primary->ip != IPADDR_ANY) + ts->local_ip = primary->ip; + } } udp->src_port = ee16(ts->src_port); @@ -1762,8 +1858,11 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr ts->local_ip = bind_ip; else if (conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; - else if (s->ipconf[0].ip != IPADDR_ANY) - ts->local_ip = s->ipconf[0].ip; + else { + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary && primary->ip != IPADDR_ANY) + ts->local_ip = primary->ip; + } ts->src_port = ee16(sin->sin_port); return 0; } else if (sockfd & MARK_UDP_SOCKET) { @@ -1777,6 +1876,11 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr ts->local_ip = bind_ip; else if (conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; + else { + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary && primary->ip != IPADDR_ANY) + ts->local_ip = primary->ip; + } ts->src_port = ee16(sin->sin_port); return 0; } else return -1; @@ -1872,6 +1976,7 @@ static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) struct dhcp_option *opt = (struct dhcp_option *)(msg->options); uint32_t ip; uint32_t netmask = 0xFFFFFF00; + struct ipconf *primary = wolfIP_primary_ipconf(s); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_MSG_TYPE) { if (opt->data[0] == DHCP_OFFER) { @@ -1888,8 +1993,10 @@ static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); } ip = ee32(msg->yiaddr); - s->ipconf[0].ip = ip; - s->ipconf[0].mask = ee32(netmask); + if (primary) { + primary->ip = ip; + primary->mask = ee32(netmask); + } s->dhcp_ip = ip; dhcp_cancel_timer(s); s->dhcp_state = DHCP_REQUEST_SENT; @@ -1909,6 +2016,7 @@ static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) static int dhcp_parse_ack(struct wolfIP *s, struct dhcp_msg *msg) { struct dhcp_option *opt = (struct dhcp_option *)(msg->options); + struct ipconf *primary = wolfIP_primary_ipconf(s); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_MSG_TYPE) { if (opt->data[0] == DHCP_ACK) { @@ -1918,17 +2026,19 @@ static int dhcp_parse_ack(struct wolfIP *s, struct dhcp_msg *msg) while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); - if (opt->code == DHCP_OPTION_OFFER_IP) - s->ipconf[0].ip = ee32(data); - if (opt->code == DHCP_OPTION_SUBNET_MASK) - s->ipconf[0].mask = ee32(data); - if (opt->code == DHCP_OPTION_ROUTER) - s->ipconf[0].gw = ee32(data); + if (primary) { + if (opt->code == DHCP_OPTION_OFFER_IP) + primary->ip = ee32(data); + if (opt->code == DHCP_OPTION_SUBNET_MASK) + primary->mask = ee32(data); + if (opt->code == DHCP_OPTION_ROUTER) + primary->gw = ee32(data); + } if ((opt->code == DHCP_OPTION_DNS) && (s->dns_server == 0)) s->dns_server = ee32(data); opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); } - if ((s->ipconf[0].ip != 0) && (s->ipconf[0].mask != 0)) { + if (primary && (primary->ip != 0) && (primary->mask != 0)) { dhcp_cancel_timer(s); s->dhcp_state = DHCP_BOUND; return 0; @@ -1953,9 +2063,12 @@ static int dhcp_poll(struct wolfIP *s) dhcp_send_request(s); else if ((s->dhcp_state == DHCP_REQUEST_SENT) && (dhcp_parse_ack(s, &msg) == 0)) { LOG("DHCP configuration received.\n"); - LOG("IP Address: %u.%u.%u.%u\n", (s->ipconf[0].ip >> 24) & 0xFF, (s->ipconf[0].ip >> 16) & 0xFF, (s->ipconf[0].ip >> 8) & 0xFF, (s->ipconf[0].ip >> 0) & 0xFF); - LOG("Subnet Mask: %u.%u.%u.%u\n", (s->ipconf[0].mask >> 24) & 0xFF, (s->ipconf[0].mask >> 16) & 0xFF, (s->ipconf[0].mask >> 8) & 0xFF, (s->ipconf[0].mask >> 0) & 0xFF); - LOG("Gateway: %u.%u.%u.%u\n", (s->ipconf[0].gw >> 24) & 0xFF, (s->ipconf[0].gw >> 16) & 0xFF, (s->ipconf[0].gw >> 8) & 0xFF, (s->ipconf[0].gw >> 0) & 0xFF); + struct ipconf *primary = wolfIP_primary_ipconf(s); + if (primary) { + LOG("IP Address: %u.%u.%u.%u\n", (primary->ip >> 24) & 0xFF, (primary->ip >> 16) & 0xFF, (primary->ip >> 8) & 0xFF, (primary->ip >> 0) & 0xFF); + LOG("Subnet Mask: %u.%u.%u.%u\n", (primary->mask >> 24) & 0xFF, (primary->mask >> 16) & 0xFF, (primary->mask >> 8) & 0xFF, (primary->mask >> 0) & 0xFF); + LOG("Gateway: %u.%u.%u.%u\n", (primary->gw >> 24) & 0xFF, (primary->gw >> 16) & 0xFF, (primary->gw >> 8) & 0xFF, (primary->gw >> 0) & 0xFF); + } if (s->dns_server) LOG("DNS Server: %u.%u.%u.%u\n", (s->dns_server >> 24) & 0xFF, (s->dns_server >> 16) & 0xFF, (s->dns_server >> 8) & 0xFF, (s->dns_server >> 0) & 0xFF); } @@ -1978,7 +2091,7 @@ static int dhcp_send_request(struct wolfIP *s) req.xid = ee32(s->dhcp_xid); req.magic = ee32(DHCP_MAGIC); { - struct ll *ll = wolfIP_ll_at(s, 0); + struct ll *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); if (ll) memcpy(req.chaddr, ll->mac, 6); else @@ -2054,7 +2167,7 @@ static int dhcp_send_discover(struct wolfIP *s) disc.xid = ee32(s->dhcp_xid); disc.magic = ee32(DHCP_MAGIC); { - struct ll *ll = wolfIP_ll_at(s, 0); + struct ll *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); if (ll) memcpy(disc.chaddr, ll->mac, 6); else @@ -2223,11 +2336,31 @@ void wolfIP_init(struct wolfIP *s) for (unsigned int i = 0; i < s->if_count; i++) { s->ipconf[i].ll = wolfIP_ll_at(s, i); } +#if WOLFIP_ENABLE_LOOPBACK + if (s->if_count > WOLFIP_LOOPBACK_IF_IDX) { + struct ll *loop = wolfIP_ll_at(s, WOLFIP_LOOPBACK_IF_IDX); + struct ipconf *loop_conf = wolfIP_ipconf_at(s, WOLFIP_LOOPBACK_IF_IDX); + static const uint8_t loop_mac[6] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }; + if (loop) { + memcpy(loop->mac, loop_mac, sizeof(loop_mac)); + strncpy(loop->ifname, "lo", sizeof(loop->ifname) - 1); + loop->ifname[sizeof(loop->ifname) - 1] = '\0'; + loop->poll = wolfIP_loopback_poll; + loop->send = wolfIP_loopback_send; + } + if (loop_conf) { + loop_conf->ll = loop; + loop_conf->ip = WOLFIP_LOOPBACK_IP; + loop_conf->mask = WOLFIP_LOOPBACK_MASK; + loop_conf->gw = IPADDR_ANY; + } + } +#endif } struct ll *wolfIP_getdev(struct wolfIP *s) { - return wolfIP_getdev_ex(s, 0); + return wolfIP_getdev_ex(s, WOLFIP_PRIMARY_IF_IDX); } struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) @@ -2336,7 +2469,7 @@ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uin */ void wolfIP_recv(struct wolfIP *s, void *buf, uint32_t len) { - wolfIP_recv_on(s, 0, buf, len); + wolfIP_recv_on(s, WOLFIP_PRIMARY_IF_IDX, buf, len); } void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) @@ -2537,11 +2670,15 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) unsigned int if_idx = wolfIP_socket_if_idx(ts); struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); ip4 nexthop = wolfIP_select_nexthop(conf, ts->remote_ip); - if (arp_lookup(s, if_idx, nexthop, ts->nexthop_mac) < 0) { + if (wolfIP_is_loopback_if(if_idx)) { + struct ll *loop = wolfIP_ll_at(s, if_idx); + if (loop) + memcpy(ts->nexthop_mac, loop->mac, 6); + } else if (arp_lookup(s, if_idx, nexthop, ts->nexthop_mac) < 0) { /* Send ARP request */ arp_request(s, if_idx, nexthop); break; - }else + } #endif if (in_flight <= ts->sock.tcp.cwnd) { struct wolfIP_timer new_tmr = {}; @@ -2597,12 +2734,18 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) unsigned int if_idx = wolfIP_socket_if_idx(t); struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); ip4 nexthop = wolfIP_select_nexthop(conf, t->remote_ip); - if ((!IS_IP_BCAST(nexthop) && (arp_lookup(s, if_idx, nexthop, t->nexthop_mac) < 0))) { - /* Send ARP request */ - arp_request(s, if_idx, nexthop); - break; + if (wolfIP_is_loopback_if(if_idx)) { + struct ll *loop = wolfIP_ll_at(s, if_idx); + if (loop) + memcpy(t->nexthop_mac, loop->mac, 6); + } else { + if ((!IS_IP_BCAST(nexthop) && (arp_lookup(s, if_idx, nexthop, t->nexthop_mac) < 0))) { + /* Send ARP request */ + arp_request(s, if_idx, nexthop); + break; + } + if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6); } - if (IS_IP_BCAST(nexthop)) memset(t->nexthop_mac, 0xFF, 6); #endif len = desc->len - ETH_HEADER_LEN; ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len); @@ -2620,12 +2763,12 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw) { - wolfIP_ipconfig_set_ex(s, 0, ip, mask, gw); + wolfIP_ipconfig_set_ex(s, WOLFIP_PRIMARY_IF_IDX, ip, mask, gw); } void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw) { - wolfIP_ipconfig_get_ex(s, 0, ip, mask, gw); + wolfIP_ipconfig_get_ex(s, WOLFIP_PRIMARY_IF_IDX, ip, mask, gw); } void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw) From 81ca520c84b332ca8b1f79fd2aa851ce1488c427 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 18:39:39 +0100 Subject: [PATCH 06/25] Discard routed traffic with destination 127.x.x.x --- src/test/unit/unit.c | 42 ++++++++++++++++++++++++++++++++++++++++-- src/wolfip.c | 8 ++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index c5ffb00e..101f3c0b 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -22,6 +22,8 @@ #include "../../../config.h" #undef WOLFIP_MAX_INTERFACES #define WOLFIP_MAX_INTERFACES 3 +#undef WOLFIP_ENABLE_LOOPBACK +#define WOLFIP_ENABLE_LOOPBACK 1 #undef WOLFIP_ENABLE_FORWARDING #ifndef WOLFIP_ENABLE_FORWARDING #define WOLFIP_ENABLE_FORWARDING 1 @@ -607,6 +609,7 @@ START_TEST(test_arp_lookup_success) { /* Add a known IP-MAC pair */ s.arp.neighbors[0].ip = ip; + s.arp.neighbors[0].if_idx = TEST_PRIMARY_IF; memcpy(s.arp.neighbors[0].mac, mock_mac, 6); /* Test arp_lookup */ @@ -850,6 +853,39 @@ START_TEST(test_wolfip_forwarding_ttl_expired) } END_TEST +START_TEST(test_loopback_dest_not_forwarded) +{ + struct wolfIP s; + struct wolfIP_ip_packet frame; + uint8_t src_mac[6] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60}; + + wolfIP_init(&s); + mock_link_init(&s); + mock_link_init_idx(&s, TEST_SECOND_IF, NULL); + wolfIP_ipconfig_set(&s, 0xC0A80001, 0xFFFFFF00, 0); + + memset(&frame, 0, sizeof(frame)); + memcpy(frame.eth.dst, s.ll_dev[TEST_PRIMARY_IF].mac, 6); + memcpy(frame.eth.src, src_mac, 6); + frame.eth.type = ee16(ETH_TYPE_IP); + frame.ver_ihl = 0x45; + frame.ttl = 64; + frame.proto = WI_IPPROTO_UDP; + frame.len = ee16(IP_HEADER_LEN); + frame.src = ee32(0x0A000002U); + frame.dst = ee32(0x7F000001U); + frame.csum = 0; + iphdr_set_checksum(&frame); + + memset(last_frame_sent, 0, sizeof(last_frame_sent)); + last_frame_sent_size = 0; + + wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame)); + + ck_assert_uint_eq(last_frame_sent_size, 0); +} +END_TEST + // Test for `transport_checksum` calculation START_TEST(test_transport_checksum) { @@ -906,10 +942,10 @@ START_TEST(test_eth_output_add_header) { memset(ð_frame, 0, sizeof(eth_frame)); uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; - struct ll *ll = wolfIP_getdev(&S); + struct ll *ll = wolfIP_getdev_ex(&S, TEST_PRIMARY_IF); memcpy(ll->mac, test_mac, 6); - eth_output_add_header(&S, 0, NULL, ð_frame, ETH_TYPE_IP); + eth_output_add_header(&S, TEST_PRIMARY_IF, NULL, ð_frame, ETH_TYPE_IP); ck_assert_mem_eq(eth_frame.dst, "\xff\xff\xff\xff\xff\xff", 6); // Broadcast ck_assert_mem_eq(eth_frame.src, test_mac, 6); @@ -1044,6 +1080,8 @@ Suite *wolf_suite(void) suite_add_tcase(s, tc_proto); tcase_add_test(tc_proto, test_wolfip_forwarding_ttl_expired); suite_add_tcase(s, tc_proto); + tcase_add_test(tc_proto, test_loopback_dest_not_forwarded); + suite_add_tcase(s, tc_proto); tcase_add_test(tc_utils, test_transport_checksum); suite_add_tcase(s, tc_proto); diff --git a/src/wolfip.c b/src/wolfip.c index 0ac68e89..eff702eb 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2385,6 +2385,14 @@ size_t wolfIP_instance_size(void) static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { +#if WOLFIP_ENABLE_LOOPBACK + if (!wolfIP_is_loopback_if(if_idx)) { + ip4 dest = ee32(ip->dst); + if ((dest & WOLFIP_LOOPBACK_MASK) == (WOLFIP_LOOPBACK_IP & WOLFIP_LOOPBACK_MASK)) { + return; + } + } +#endif #if WOLFIP_ENABLE_FORWARDING if (ip->ver_ihl == 0x45) { ip4 dest = ee32(ip->dst); From 20d9501f55ef11fe692a9a97c8fa15210078c8af Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 29 Oct 2025 18:55:38 +0100 Subject: [PATCH 07/25] Fixed github actions --- .github/workflows/cppcheck.yml | 8 ++++---- .github/workflows/linux.yml | 25 ++++++++++++++++--------- .github/workflows/units.yml | 7 +++---- Makefile | 6 +++++- config.h | 2 +- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index c4cf27a6..a254cc38 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -1,5 +1,4 @@ -Name: CppCheck code linter - +name: CppCheck code linter on: push: @@ -9,16 +8,17 @@ on: jobs: linter: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Update repo run: | sudo apt-get update + sudo apt install -y cppcheck - name: Run cppcheck run: | diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5577bf17..0939203d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,5 +1,4 @@ -Name: Linux interop tests - +name: Linux interop tests on: push: @@ -8,11 +7,11 @@ on: branches: [ '*' ] jobs: - unit_test: - runs-on: ubuntu-22.04 + linux_test: + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true @@ -27,13 +26,21 @@ jobs: mkdir -p build/port make - - name: Run unit tests - run: make unit - - - name: Run standalone tests + - name: Run standalone "event loop" test run: | sudo ./build/test-evloop + sudo killall tcpdump || true + + - name: Run standalone wolfssl test + run: | sudo ./build/test-wolfssl + sudo killall tcpdump || true + + - name: Run standalone forwarding test + run: | ./build/test-wolfssl-forwarding + + - name: Run standalone TTL expired test + run: | ./build/test-ttl-expired diff --git a/.github/workflows/units.yml b/.github/workflows/units.yml index a92a93ee..bebafe9a 100644 --- a/.github/workflows/units.yml +++ b/.github/workflows/units.yml @@ -1,5 +1,4 @@ -Name: Unit Tests - +name: Unit Tests on: push: @@ -9,10 +8,10 @@ on: jobs: unit_test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true diff --git a/Makefile b/Makefile index 6ac36a7c..9b0d6e5a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,9 @@ CFLAGS+=-g -ggdb LDFLAGS+=-pthread CPPCHECK=cppcheck -CPPCHECK_FLAGS=--enable=all --suppress=missingIncludeSystem \ +CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \ + --suppress=missingIncludeSystem \ + -i src/test \ --suppress=unusedFunction --suppress=unusedVariable \ --suppress=missingInclude --suppress=variableScope \ --suppress=constVariable --suppress=constVariablePointer \ @@ -12,8 +14,10 @@ CPPCHECK_FLAGS=--enable=all --suppress=missingIncludeSystem \ --suppress=constParameterCallback \ --suppress=toomanyconfigs \ --suppress=unmatchedSuppression --inconclusive \ + --disable=style \ --std=c99 --language=c \ --platform=unix64 \ + --check-level=exhaustive \ --error-exitcode=1 --xml --xml-version=2 OBJ=build/wolfip.o \ diff --git a/config.h b/config.h index b44e3827..2915717a 100644 --- a/config.h +++ b/config.h @@ -12,7 +12,7 @@ #define MAX_NEIGHBORS 16 #ifndef WOLFIP_MAX_INTERFACES -#define WOLFIP_MAX_INTERFACES 1 +#define WOLFIP_MAX_INTERFACES 2 #endif #ifndef WOLFIP_ENABLE_FORWARDING From 4d083e434d0979cb1e5e776f1f73f00c5938e493 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 3 Nov 2025 16:22:00 +0100 Subject: [PATCH 08/25] Renamed 'struct ll' into 'struct wolfIP_ll_dev' --- docs/API.md | 12 ++--- src/port/posix/bsd_socket.c | 4 +- src/port/posix/linux_tap.c | 6 +-- src/port/raspberry-pico-usb-server/src/main.c | 6 +-- src/test/test_httpd.c | 4 +- src/test/test_linux_dhcp_dns.c | 4 +- src/test/test_linux_eventloop.c | 4 +- src/test/test_native_wolfssl.c | 4 +- src/test/test_ttl_expired.c | 18 +++---- src/test/test_wolfssl_forwarding.c | 10 ++-- src/test/unit/unit.c | 14 +++--- src/wolfip.c | 48 +++++++++---------- wolfip.h | 12 ++--- 13 files changed, 73 insertions(+), 73 deletions(-) diff --git a/docs/API.md b/docs/API.md index 094a8ff9..70a45871 100644 --- a/docs/API.md +++ b/docs/API.md @@ -23,11 +23,11 @@ wolfIP is a minimal TCP/IP stack designed for resource-constrained embedded syst ### Device Driver Interface ```c -struct ll { +struct wolfIP_ll_dev { uint8_t mac[6]; // Device MAC address char ifname[16]; // Interface name - int (*poll)(struct ll *ll, void *buf, uint32_t len); // Receive function - int (*send)(struct ll *ll, void *buf, uint32_t len); // Transmit function + int (*poll)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); // Receive function + int (*send)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); // Transmit function }; ``` wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` (default `1`). Call `wolfIP_getdev_ex()` to access a specific slot; the legacy `wolfIP_getdev()` helper targets the first hardware slot (index `0` normally, or `1` when the optional loopback interface is enabled). @@ -35,7 +35,7 @@ wolfIP maintains an array of these descriptors sized by `WOLFIP_MAX_INTERFACES` ### IP Configuration ```c struct ipconf { - struct ll *ll; // Link layer device + struct wolfIP_ll_dev *ll; // Link layer device ip4 ip; // IPv4 address ip4 mask; // Subnet mask ip4 gw; // Default gateway @@ -198,8 +198,8 @@ void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 Per-interface versions of the IP configuration helpers. The legacy functions target interface `0`. ```c -struct ll *wolfIP_getdev(struct wolfIP *s); -struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); +struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s); +struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); ``` Access the link-layer descriptor(s) that should be wired to hardware drivers. `_ex` returns `NULL` if `if_idx` exceeds `WOLFIP_MAX_INTERFACES`. diff --git a/src/port/posix/bsd_socket.c b/src/port/posix/bsd_socket.c index b2c8f949..944407da 100644 --- a/src/port/posix/bsd_socket.c +++ b/src/port/posix/bsd_socket.c @@ -534,7 +534,7 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) { /* Catch-all function to initialize a new tap device as the network interface. * This is defined in port/linux.c * */ -extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); void *wolfIP_sock_posix_ip_loop(void *arg) { struct wolfIP *ipstack = (struct wolfIP *)arg; @@ -553,7 +553,7 @@ void *wolfIP_sock_posix_ip_loop(void *arg) { void __attribute__((constructor)) init_wolfip_posix() { struct in_addr linux_ip; - struct ll *tapdev; + struct wolfIP_ll_dev *tapdev; pthread_t wolfIP_thread; if (IPSTACK) return; diff --git a/src/port/posix/linux_tap.c b/src/port/posix/linux_tap.c index ca2207ab..47fef861 100644 --- a/src/port/posix/linux_tap.c +++ b/src/port/posix/linux_tap.c @@ -45,7 +45,7 @@ void print_buffer(uint8_t *buf, int len) printf("\n"); } -static int tap_poll(struct ll *ll, void *buf, uint32_t len) +static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct pollfd pfd; (void)ll; @@ -63,14 +63,14 @@ static int tap_poll(struct ll *ll, void *buf, uint32_t len) return read(tap_fd, buf, len); } -static int tap_send(struct ll *ll, void *buf, uint32_t len) +static int tap_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { (void)ll; //print_buffer(buf, len); return write(tap_fd, buf, len); } -int tap_init(struct ll *ll, const char *ifname, uint32_t host_ip) +int tap_init(struct wolfIP_ll_dev *ll, const char *ifname, uint32_t host_ip) { struct ifreq ifr; struct sockaddr_in *addr; diff --git a/src/port/raspberry-pico-usb-server/src/main.c b/src/port/raspberry-pico-usb-server/src/main.c index c4c6b9af..d4ee612b 100644 --- a/src/port/raspberry-pico-usb-server/src/main.c +++ b/src/port/raspberry-pico-usb-server/src/main.c @@ -77,7 +77,7 @@ uint32_t wolfIP_getrandom(void) * It is called by the wolfIP stack when a frame is ready to be sent. * It will return the number of bytes sent, or 0 if the USB host is not ready. */ -static int ll_usb_send(struct ll *dev, void *frame, uint32_t sz) { +static int ll_usb_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t sz) { uint16_t sz16 = (uint16_t)sz; uint32_t i; (void) dev; @@ -152,7 +152,7 @@ bool tud_network_recv_cb(const uint8_t *src, uint16_t size) { * * Frames copied in tusb_net_push_rx are processed here and sent to the stack. */ -int ll_usb_poll(struct ll *dev, void *frame, uint32_t sz) { +int ll_usb_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t sz) { int i; (void) dev; if (sz < 64) @@ -213,7 +213,7 @@ static void telnetd_init(void) int main(void) { - struct ll *tusb_netdev; + struct wolfIP_ll_dev *tusb_netdev; /* initialize TinyUSB */ board_init(); diff --git a/src/test/test_httpd.c b/src/test/test_httpd.c index 109ff86e..ca5332f3 100644 --- a/src/test/test_httpd.c +++ b/src/test/test_httpd.c @@ -71,7 +71,7 @@ static int test_loop(struct wolfIP *s, int active_close) /* Catch-all function to initialize a new tap device as the network interface. * This is defined in port/linux.c * */ -extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); /* Test cases */ @@ -126,7 +126,7 @@ static void test_httpd(struct wolfIP *s) int main(int argc, char **argv) { struct wolfIP *s; - struct ll *tapdev; + struct wolfIP_ll_dev *tapdev; struct timeval tv = {0, 0}; struct in_addr linux_ip; uint32_t srv_ip; diff --git a/src/test/test_linux_dhcp_dns.c b/src/test/test_linux_dhcp_dns.c index 2d859ad8..df0694a3 100644 --- a/src/test/test_linux_dhcp_dns.c +++ b/src/test/test_linux_dhcp_dns.c @@ -192,7 +192,7 @@ static void *pt_echoserver(void *arg) /* Catch-all function to initialize a new tap device as the network interface. * This is defined in port/linux.c * */ -extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); void test_wolfip_echoclient(struct wolfIP *s) { @@ -237,7 +237,7 @@ void ns_cb(uint32_t ip) int main(int argc, char **argv) { struct wolfIP *s; - struct ll *tapdev; + struct wolfIP_ll_dev *tapdev; struct timeval tv; struct in_addr linux_ip; uint32_t srv_ip; diff --git a/src/test/test_linux_eventloop.c b/src/test/test_linux_eventloop.c index 9e8840b9..0ddcf99b 100644 --- a/src/test/test_linux_eventloop.c +++ b/src/test/test_linux_eventloop.c @@ -324,7 +324,7 @@ static void *pt_echoserver(void *arg) /* Catch-all function to initialize a new tap device as the network interface. * This is defined in port/linux.c * */ -extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); /* Test cases */ @@ -420,7 +420,7 @@ void test_wolfip_echoclient(struct wolfIP *s) int main(int argc, char **argv) { struct wolfIP *s; - struct ll *tapdev; + struct wolfIP_ll_dev *tapdev; struct timeval tv = {0, 0}; struct in_addr linux_ip; uint32_t srv_ip; diff --git a/src/test/test_native_wolfssl.c b/src/test/test_native_wolfssl.c index cda8efb0..03bc1648 100644 --- a/src/test/test_native_wolfssl.c +++ b/src/test/test_native_wolfssl.c @@ -257,7 +257,7 @@ void *pt_echoclient(void *arg) /* Catch-all function to initialize a new tap device as the network interface. * This is defined in port/linux.c * */ -extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); /* Test cases */ @@ -333,7 +333,7 @@ void test_wolfip_echoserver(struct wolfIP *s, uint32_t srv_ip) int main(int argc, char **argv) { struct wolfIP *s; - struct ll *tapdev; + struct wolfIP_ll_dev *tapdev; struct timeval tv = {0, 0}; struct in_addr linux_ip; uint32_t srv_ip; diff --git a/src/test/test_ttl_expired.c b/src/test/test_ttl_expired.c index 2e048e37..700e0148 100644 --- a/src/test/test_ttl_expired.c +++ b/src/test/test_ttl_expired.c @@ -111,7 +111,7 @@ struct mem_link { }; struct mem_ep { - struct ll *ll; + struct wolfIP_ll_dev *ll; struct mem_link *link; int idx; }; @@ -127,7 +127,7 @@ static void mem_link_init(struct mem_link *link) link->len[0] = link->len[1] = 0; } -static struct mem_ep *mem_ep_lookup(struct ll *ll) +static struct mem_ep *mem_ep_lookup(struct wolfIP_ll_dev *ll) { for (size_t i = 0; i < 2; i++) if (mem_eps[i].ll == ll) @@ -135,7 +135,7 @@ static struct mem_ep *mem_ep_lookup(struct ll *ll) return NULL; } -static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) +static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); if (!ep) @@ -158,7 +158,7 @@ static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) return ret; } -static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) +static int mem_ll_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); if (!ep) @@ -179,7 +179,7 @@ static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) return (int)len; } -static void mem_attach(struct ll *ll, struct mem_link *link, int idx, const uint8_t *mac) +static void mem_attach(struct wolfIP_ll_dev *ll, struct mem_link *link, int idx, const uint8_t *mac) { ll->poll = mem_ll_poll; ll->send = mem_ll_send; @@ -261,14 +261,14 @@ static void build_ttl_frame(uint8_t *frame, const uint8_t *src_mac, const uint8_ icmp->csum = ones_csum(icmp, sizeof(*icmp)); } -static int dummy_send(struct ll *ll, void *buf, uint32_t len) +static int dummy_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { (void)ll; (void)buf; return (int)len; } -static int dummy_poll(struct ll *ll, void *buf, uint32_t len) +static int dummy_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { (void)ll; (void)buf; @@ -295,8 +295,8 @@ int main(void) { setvbuf(stdout, NULL, _IONBF, 0); struct wolfIP *router; - struct ll *iface0; - struct ll *iface1; + struct wolfIP_ll_dev *iface0; + struct wolfIP_ll_dev *iface1; struct mem_link link; pthread_t th; uint8_t host_mac[6] = {0x02,0x00,0x00,0x00,0xAA,0x01}; diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index 4bdbf805..c124b3a8 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -99,7 +99,7 @@ struct mem_link { }; struct mem_ep { - struct ll *ll; + struct wolfIP_ll_dev *ll; struct mem_link *link; int idx; }; @@ -120,7 +120,7 @@ static void mem_link_init(struct mem_link *link) link->name[0] = link->name[1] = ""; } -static struct mem_ep *mem_ep_lookup(struct ll *ll) +static struct mem_ep *mem_ep_lookup(struct wolfIP_ll_dev *ll) { for (size_t i = 0; i < mem_ep_count; i++) { if (mem_eps[i].ll == ll) @@ -129,7 +129,7 @@ static struct mem_ep *mem_ep_lookup(struct ll *ll) return NULL; } -static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) +static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); if (!ep) @@ -152,7 +152,7 @@ static int mem_ll_poll(struct ll *ll, void *buf, uint32_t len) return ret; } -static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) +static int mem_ll_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); if (!ep) @@ -173,7 +173,7 @@ static int mem_ll_send(struct ll *ll, void *buf, uint32_t len) return (int)len; } -static void mem_link_attach(struct ll *ll, struct mem_link *link, int idx, +static void mem_link_attach(struct wolfIP_ll_dev *ll, struct mem_link *link, int idx, const char *ifname, const uint8_t mac[6]) { ll->poll = mem_ll_poll; diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 101f3c0b..2f54ce3a 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -56,7 +56,7 @@ static const uint8_t ifmac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; static uint8_t last_frame_sent[LINK_MTU]; static uint32_t last_frame_sent_size = 0; -static int mock_send(struct ll *dev, void *frame, uint32_t len) +static int mock_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) { (void)dev; memcpy(last_frame_sent, frame, len); @@ -64,7 +64,7 @@ static int mock_send(struct ll *dev, void *frame, uint32_t len) return 0; } -static int mock_poll(struct ll *dev, void *frame, uint32_t len) +static int mock_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) { (void)dev; (void)frame; @@ -74,7 +74,7 @@ static int mock_poll(struct ll *dev, void *frame, uint32_t len) static void mock_link_init_idx(struct wolfIP *s, unsigned int idx, const uint8_t *mac_override) { - struct ll *ll = wolfIP_getdev_ex(s, idx); + struct wolfIP_ll_dev *ll = wolfIP_getdev_ex(s, idx); ck_assert_ptr_nonnull(ll); memset(ll, 0, sizeof(*ll)); snprintf((char *)ll->ifname, sizeof(ll->ifname), "mock%u", idx); @@ -638,7 +638,7 @@ START_TEST(test_wolfip_getdev_ex_api) { struct wolfIP s; wolfIP_init(&s); - struct ll *ll_def = wolfIP_getdev(&s); + struct wolfIP_ll_dev *ll_def = wolfIP_getdev(&s); ck_assert_ptr_nonnull(ll_def); ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF)); #if WOLFIP_ENABLE_LOOPBACK @@ -652,8 +652,8 @@ END_TEST START_TEST(test_wolfip_loopback_defaults) { struct wolfIP s; - struct ll *loop; - struct ll *hw; + struct wolfIP_ll_dev *loop; + struct wolfIP_ll_dev *hw; ip4 ip = 0, mask = 0, gw = 0; wolfIP_init(&s); @@ -942,7 +942,7 @@ START_TEST(test_eth_output_add_header) { memset(ð_frame, 0, sizeof(eth_frame)); uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; - struct ll *ll = wolfIP_getdev_ex(&S, TEST_PRIMARY_IF); + struct wolfIP_ll_dev *ll = wolfIP_getdev_ex(&S, TEST_PRIMARY_IF); memcpy(ll->mac, test_mac, 6); eth_output_add_header(&S, TEST_PRIMARY_IF, NULL, ð_frame, ETH_TYPE_IP); diff --git a/src/wolfip.c b/src/wolfip.c index eff702eb..0bdd5b92 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -48,8 +48,8 @@ static inline int wolfIP_is_loopback_if(unsigned int if_idx) ((type *)((char *)(ptr) - offsetof(type, member))) #if WOLFIP_ENABLE_LOOPBACK -static int wolfIP_loopback_send(struct ll *ll, void *buf, uint32_t len); -static int wolfIP_loopback_poll(struct ll *ll, void *buf, uint32_t len); +static int wolfIP_loopback_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); +static int wolfIP_loopback_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); #endif static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); @@ -560,7 +560,7 @@ struct timers_binheap { struct wolfIP { - struct ll ll_dev[WOLFIP_MAX_INTERFACES]; + struct wolfIP_ll_dev ll_dev[WOLFIP_MAX_INTERFACES]; struct ipconf ipconf[WOLFIP_MAX_INTERFACES]; unsigned int if_count; enum dhcp_state dhcp_state; /* State machine for DHCP */ @@ -588,7 +588,7 @@ struct wolfIP }; #if WOLFIP_ENABLE_LOOPBACK -static int wolfIP_loopback_poll(struct ll *ll, void *buf, uint32_t len) +static int wolfIP_loopback_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { (void)ll; (void)buf; @@ -596,7 +596,7 @@ static int wolfIP_loopback_poll(struct ll *ll, void *buf, uint32_t len) return 0; } -static int wolfIP_loopback_send(struct ll *ll, void *buf, uint32_t len) +static int wolfIP_loopback_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct wolfIP *s; uint32_t copy = len; @@ -617,7 +617,7 @@ static int wolfIP_loopback_send(struct ll *ll, void *buf, uint32_t len) /* ***************************** */ /* Implementation */ -static inline struct ll *wolfIP_ll_at(struct wolfIP *s, unsigned int if_idx) +static inline struct wolfIP_ll_dev *wolfIP_ll_at(struct wolfIP *s, unsigned int if_idx) { if (!s || if_idx >= s->if_count) return NULL; @@ -761,7 +761,7 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma #ifdef ETHERNET static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) { - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); if (!ll || !ll->send) return; struct wolfIP_icmp_packet icmp; @@ -1105,7 +1105,7 @@ static void iphdr_set_checksum(struct wolfIP_ip_packet *ip) static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, uint16_t type) { - struct ll *ll = wolfIP_ll_at(S, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(S, if_idx); if (!ll) return -1; if (!dst) { @@ -1128,7 +1128,7 @@ static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 des if (!broadcast || !mac) return 0; if (wolfIP_is_loopback_if(out_if)) { - struct ll *loop = wolfIP_ll_at(s, out_if); + struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, out_if); if (loop) memcpy(mac, loop->mac, 6); *broadcast = 0; @@ -1156,7 +1156,7 @@ static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 des static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct wolfIP_ip_packet *ip, uint32_t len, const uint8_t *mac, int broadcast) { #ifdef ETHERNET - struct ll *ll = wolfIP_ll_at(s, out_if); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, out_if); if (!ll || !ll->send) return; if (broadcast) @@ -1918,7 +1918,7 @@ static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_p { struct wolfIP_icmp_packet *icmp = (struct wolfIP_icmp_packet *)ip; uint32_t tmp; - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); if (!DHCP_IS_RUNNING(s) && (icmp->type == ICMP_ECHO_REQUEST)) { icmp->type = ICMP_ECHO_REPLY; icmp->csum += 8; @@ -2091,7 +2091,7 @@ static int dhcp_send_request(struct wolfIP *s) req.xid = ee32(s->dhcp_xid); req.magic = ee32(DHCP_MAGIC); { - struct ll *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); if (ll) memcpy(req.chaddr, ll->mac, 6); else @@ -2167,7 +2167,7 @@ static int dhcp_send_discover(struct wolfIP *s) disc.xid = ee32(s->dhcp_xid); disc.magic = ee32(DHCP_MAGIC); { - struct ll *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, WOLFIP_PRIMARY_IF_IDX); if (ll) memcpy(disc.chaddr, ll->mac, 6); else @@ -2262,7 +2262,7 @@ static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, co static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip) { struct arp_packet arp; - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); if (!ll || !conf) @@ -2290,7 +2290,7 @@ static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip) static void arp_recv(struct wolfIP *s, unsigned int if_idx, void *buf, int len) { struct arp_packet *arp = (struct arp_packet *)buf; - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); if (!ll || !conf) @@ -2338,7 +2338,7 @@ void wolfIP_init(struct wolfIP *s) } #if WOLFIP_ENABLE_LOOPBACK if (s->if_count > WOLFIP_LOOPBACK_IF_IDX) { - struct ll *loop = wolfIP_ll_at(s, WOLFIP_LOOPBACK_IF_IDX); + struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, WOLFIP_LOOPBACK_IF_IDX); struct ipconf *loop_conf = wolfIP_ipconf_at(s, WOLFIP_LOOPBACK_IF_IDX); static const uint8_t loop_mac[6] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }; if (loop) { @@ -2358,12 +2358,12 @@ void wolfIP_init(struct wolfIP *s) #endif } -struct ll *wolfIP_getdev(struct wolfIP *s) +struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s) { return wolfIP_getdev_ex(s, WOLFIP_PRIMARY_IF_IDX); } -struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) +struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) { return wolfIP_ll_at(s, if_idx); } @@ -2450,7 +2450,7 @@ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uin if (!s) return; #ifdef ETHERNET - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); if (!ll) return; struct wolfIP_eth_frame *eth = (struct wolfIP_eth_frame *)buf; @@ -2627,7 +2627,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) /* Step 1: Poll the device */ for (unsigned int if_idx = 0; if_idx < s->if_count; if_idx++) { - struct ll *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); if (!ll || !ll->poll) continue; do { @@ -2679,7 +2679,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); ip4 nexthop = wolfIP_select_nexthop(conf, ts->remote_ip); if (wolfIP_is_loopback_if(if_idx)) { - struct ll *loop = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, if_idx); if (loop) memcpy(ts->nexthop_mac, loop->mac, 6); } else if (arp_lookup(s, if_idx, nexthop, ts->nexthop_mac) < 0) { @@ -2706,7 +2706,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) tcp->win = ee16(queue_space(&ts->sock.tcp.rxbuf)); ip_output_add_header(ts, (struct wolfIP_ip_packet *)tcp, WI_IPPROTO_TCP, size); { - struct ll *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(ts)); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(ts)); if (ll && ll->send) ll->send(ll, tcp, desc->len); } @@ -2743,7 +2743,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); ip4 nexthop = wolfIP_select_nexthop(conf, t->remote_ip); if (wolfIP_is_loopback_if(if_idx)) { - struct ll *loop = wolfIP_ll_at(s, if_idx); + struct wolfIP_ll_dev *loop = wolfIP_ll_at(s, if_idx); if (loop) memcpy(t->nexthop_mac, loop->mac, 6); } else { @@ -2758,7 +2758,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) len = desc->len - ETH_HEADER_LEN; ip_output_add_header(t, (struct wolfIP_ip_packet *)udp, WI_IPPROTO_UDP, len); { - struct ll *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(t)); + struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, wolfIP_socket_if_idx(t)); if (ll && ll->send) ll->send(ll, udp, desc->len); } diff --git a/wolfip.h b/wolfip.h index 71284f04..3d9b0dec 100644 --- a/wolfip.h +++ b/wolfip.h @@ -22,18 +22,18 @@ typedef uint32_t ip4; /* Device driver interface */ /* Struct to contain a hw device description */ -struct ll { +struct wolfIP_ll_dev { uint8_t mac[6]; char ifname[16]; /* poll function */ - int (*poll)(struct ll *ll, void *buf, uint32_t len); + int (*poll)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); /* send function */ - int (*send)(struct ll *ll, void *buf, uint32_t len); + int (*send)(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); }; /* Struct to contain an IP device configuration */ struct ipconf { - struct ll *ll; + struct wolfIP_ll_dev *ll; ip4 ip; ip4 mask; ip4 gw; @@ -103,8 +103,8 @@ void wolfIP_recv_ex(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t l void wolfIP_ipconfig_set(struct wolfIP *s, ip4 ip, ip4 mask, ip4 gw); void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw); -struct ll *wolfIP_getdev(struct wolfIP *s); -struct ll *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); +struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s); +struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx); void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw); void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw); From 077eed35cb39937d4cdf81445cda7fe8ef1abc0a Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 3 Nov 2025 16:37:45 +0100 Subject: [PATCH 09/25] Rewritten error handling according to review --- src/http/httpd.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/http/httpd.c b/src/http/httpd.c index 1a2e433c..aec1ede0 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -92,6 +92,7 @@ static struct http_url *http_find_url(struct httpd *httpd, const char *path) { void http_send_response_headers(struct http_client *hc, int status_code, const char *status_text, const char *content_type, size_t content_length) { char txt_response[HTTP_TX_BUF_LEN]; + int rc; memset(txt_response, 0, sizeof(txt_response)); if (!hc) return; /* If content_lenght is 0, assume chunked encoding */ @@ -109,20 +110,16 @@ void http_send_response_headers(struct http_client *hc, int status_code, const c status_code, status_text, content_type, content_length); } if (hc->ssl) { - int rc = wolfSSL_write(hc->ssl, txt_response, strlen(txt_response)); - if (rc <= 0) { - /* Error – close connection */ - wolfSSL_free(hc->ssl); - hc->ssl = NULL; - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } + rc = wolfSSL_write(hc->ssl, txt_response, strlen(txt_response)); } else { - int rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, txt_response, strlen(txt_response), 0); - if (rc <= 0) { - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } + rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, txt_response, strlen(txt_response), 0); + } + if (rc <= 0) { + /* Error – close connection */ + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; } } From 3f1cec6fe81666632f834a9cc4974b4ba5f51cba Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 3 Nov 2025 17:34:03 +0100 Subject: [PATCH 10/25] Addressed review comments --- Makefile | 2 +- src/http/httpd.c | 71 ++++++++++----- src/http/httpd.h | 5 ++ src/port/posix/bsd_socket.c | 2 +- src/port/posix/linux_tap.c | 2 +- src/port/wolfssl_io.c | 36 ++++++-- src/test/tcp_echo.c | 2 +- src/test/test_ttl_expired.c | 26 ++++-- src/test/test_wolfssl_forwarding.c | 28 +++--- src/test/unit/unit.c | 139 ++++++++++++++++++----------- src/wolfip.c | 128 +++++++++++++++++--------- 11 files changed, 296 insertions(+), 145 deletions(-) diff --git a/Makefile b/Makefile index 9b0d6e5a..218b2a2b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC?=gcc CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE -CFLAGS+=-g -ggdb +CFLAGS+=-g -ggdb -Wdeclaration-after-statement LDFLAGS+=-pthread CPPCHECK=cppcheck diff --git a/src/http/httpd.c b/src/http/httpd.c index aec1ede0..b54d95fc 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -21,6 +21,7 @@ #include "wolfip.h" #include "httpd.h" #include +#include static const char *http_status_text(int status_code) { switch (status_code) { @@ -187,7 +188,6 @@ void http_send_response_chunk_end(struct http_client *hc) { hc->ssl = NULL; wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); hc->client_sd = 0; - return; } } else { if (wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0) <= 0) { @@ -217,27 +217,47 @@ void http_send_418_teapot(struct http_client *hc) { http_status_text(HTTP_STATUS_TEAPOT), "text/plain", 0); } -int http_url_decode(char *buf, size_t len) { +static int http_hex_value(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + c = (char)tolower((unsigned char)c); + if (c >= 'a' && c <= 'f') + return 10 + (c - 'a'); + return -1; +} + +int http_url_decode(char *buf, size_t len) +{ char *p = buf; - char *q; - while (p < buf + len) { - q = strchr(p, '%'); - if (!q) { - break; - } - /* Ensure we have two more hex digits */ - if (q + 2 >= buf + len) { - break; /* Malformed escape */ - } - /* Validate hex characters before conversion */ - if (!isxdigit((unsigned char)q[1]) || !isxdigit((unsigned char)q[2])) { + char *end = buf + len; + int hi; + int lo; + size_t tail; + + while (p < end) { + char *percent = memchr(p, '%', (size_t)(end - p)); + if (!percent) break; - } - *q = (char) strtol(q + 1, NULL, 16); - memmove(q + 1, q + 3, len - (q + 3 - buf)); + + if (percent + 2 >= end) + return HTTP_URL_DECODE_ERR_TRUNCATED; + + hi = http_hex_value(percent[1]); + lo = http_hex_value(percent[2]); + if (hi < 0 || lo < 0) + return HTTP_URL_DECODE_ERR_BAD_ESCAPE; + + *percent = (char)((hi << 4) | lo); + + tail = (size_t)(end - (percent + 3)); + memmove(percent + 1, percent + 3, tail); + end -= 2; len -= 2; + p = percent + 1; } - return len; + + return (int)len; } int http_url_encode(char *buf, size_t len, size_t max_len) { @@ -258,8 +278,11 @@ int http_url_encode(char *buf, size_t len, size_t max_len) { *(q + 2) = '0'; len += 2; } - if (q && (len < max_len)) + if (q) { + if (len >= max_len) + return -1; /* No space for the null terminator */ q[len] = '\0'; + } return len; } @@ -269,10 +292,18 @@ static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len) char *q; size_t n; int ret; + int decoded_len; struct http_request req; struct http_url *url = NULL; memset(&req, 0, sizeof(struct http_request)); - http_url_decode(p, len); /* Decode can be done in place */ + decoded_len = http_url_decode(p, len); /* Decode can be done in place */ + if (decoded_len < 0) { + http_send_response_headers(hc, HTTP_STATUS_BAD_REQUEST, + http_status_text(HTTP_STATUS_BAD_REQUEST), "text/plain", 0); + return decoded_len; + } + len = (size_t)decoded_len; + end = p + len; if (len < 4) goto bad_request; /* Parse the request line */ diff --git a/src/http/httpd.h b/src/http/httpd.h index 0265e39e..a94a2452 100644 --- a/src/http/httpd.h +++ b/src/http/httpd.h @@ -78,6 +78,11 @@ void http_send_500_server_error(struct http_client *hc); void http_send_503_service_unavailable(struct http_client *hc); void http_send_418_teapot(struct http_client *hc); +/* URL decoding return codes */ +#define HTTP_URL_DECODE_ERR_TRUNCATED (-1) +#define HTTP_URL_DECODE_ERR_BAD_ESCAPE (-2) + +/* Returns the decoded length on success, or negative error code on failure. */ int http_url_decode(char *buf, size_t len); int http_url_encode(char *buf, size_t len, size_t max_len); diff --git a/src/port/posix/bsd_socket.c b/src/port/posix/bsd_socket.c index 944407da..6137d347 100644 --- a/src/port/posix/bsd_socket.c +++ b/src/port/posix/bsd_socket.c @@ -153,10 +153,10 @@ int wolfIP_sock_fcntl(struct wolfIP *ipstack, int fd, int cmd, int arg) { int fcntl(int fd, int cmd, ...) { va_list ap; int arg; + int ret; va_start(ap, cmd); arg = va_arg(ap, int); va_end(ap); - int ret; if (in_the_stack) { return host_fcntl(fd, cmd, arg); } else { diff --git a/src/port/posix/linux_tap.c b/src/port/posix/linux_tap.c index 47fef861..a7764fbf 100644 --- a/src/port/posix/linux_tap.c +++ b/src/port/posix/linux_tap.c @@ -48,8 +48,8 @@ void print_buffer(uint8_t *buf, int len) static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct pollfd pfd; - (void)ll; int ret; + (void)ll; pfd.fd = tap_fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 2); diff --git a/src/port/wolfssl_io.c b/src/port/wolfssl_io.c index e03e8e0d..172e5f32 100644 --- a/src/port/wolfssl_io.c +++ b/src/port/wolfssl_io.c @@ -24,7 +24,14 @@ #include #include -#define MAX_WOLFIP_CTX 8 +#ifndef EAGAIN +#define EAGAIN (11) +#endif + + +#ifndef MAX_WOLFIP_CTX + #define MAX_WOLFIP_CTX 8 /* Default value */ +#endif struct ctx_entry { WOLFSSL_CTX *ctx; @@ -62,13 +69,14 @@ static void wolfIP_register_stack(WOLFSSL_CTX *ctx, struct wolfIP *stack) static int wolfIP_io_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx) { struct wolfip_io_desc *desc = (struct wolfip_io_desc *)ctx; + int ret; (void)ssl; if (!desc || !desc->stack) return WOLFSSL_CBIO_ERR_GENERAL; - int ret = wolfIP_sock_recv(desc->stack, desc->fd, buf, sz, 0); - if (ret == -11 || ret == -1) + ret = wolfIP_sock_recv(desc->stack, desc->fd, buf, sz, 0); + if (ret == -EAGAIN || ret == -1) return WOLFSSL_CBIO_ERR_WANT_READ; if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; @@ -78,13 +86,14 @@ static int wolfIP_io_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx) static int wolfIP_io_send(WOLFSSL* ssl, char* buf, int sz, void* ctx) { struct wolfip_io_desc *desc = (struct wolfip_io_desc *)ctx; + int ret; (void)ssl; if (!desc || !desc->stack) return WOLFSSL_CBIO_ERR_GENERAL; - int ret = wolfIP_sock_send(desc->stack, desc->fd, buf, sz, 0); - if (ret == -11 || ret == -1) + ret = wolfIP_sock_send(desc->stack, desc->fd, buf, sz, 0); + if (ret == -EAGAIN || ret == -1) return WOLFSSL_CBIO_ERR_WANT_WRITE; if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; @@ -101,8 +110,20 @@ int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX* ctx, struct wolfIP *s) int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd) { - WOLFSSL_CTX *ctx = wolfSSL_get_SSL_CTX(ssl); - struct wolfIP *stack = wolfIP_lookup_stack(ctx); + WOLFSSL_CTX *ctx; + struct wolfIP *stack; + + if (!ssl) + return -1; + + ctx = wolfSSL_get_SSL_CTX(ssl); + + if (!ctx) + return -1; + + stack = wolfIP_lookup_stack(ctx); + if (fd < 0) + return -1; if (!stack) return WOLFSSL_CBIO_ERR_GENERAL; @@ -116,6 +137,5 @@ int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd) return 0; } } - return -1; } diff --git a/src/test/tcp_echo.c b/src/test/tcp_echo.c index fd63a3e9..ae5f0d1c 100644 --- a/src/test/tcp_echo.c +++ b/src/test/tcp_echo.c @@ -63,6 +63,7 @@ int main() { printf("Echo server listening on port %d\n", PORT); while (1) { + ssize_t bytes_read; // Accept a client connection if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { perror("Accept failed"); @@ -71,7 +72,6 @@ int main() { printf("Client connected, fd: %d\n", client_fd); - ssize_t bytes_read; while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) { write(client_fd, buffer, bytes_read); // Echo data back to the client } diff --git a/src/test/test_ttl_expired.c b/src/test/test_ttl_expired.c index 700e0148..e1fbb115 100644 --- a/src/test/test_ttl_expired.c +++ b/src/test/test_ttl_expired.c @@ -138,11 +138,14 @@ static struct mem_ep *mem_ep_lookup(struct wolfIP_ll_dev *ll) static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); + struct mem_link *link; + int idx; + int ret = 0; + if (!ep) return -1; - struct mem_link *link = ep->link; - int idx = ep->idx; - int ret = 0; + link = ep->link; + idx = ep->idx; pthread_mutex_lock(&link->lock); if (link->ready[idx]) { @@ -161,10 +164,13 @@ static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) static int mem_ll_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); + struct mem_link *link; + int dst; + if (!ep) return -1; - struct mem_link *link = ep->link; - int dst = 1 - ep->idx; + link = ep->link; + dst = 1 - ep->idx; pthread_mutex_lock(&link->lock); while (link->ready[dst]) @@ -283,8 +289,10 @@ static void *poll_thread(void *arg) struct wolfIP *s = (struct wolfIP *)arg; while (running) { struct timespec ts; + uint64_t now; + clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t now = (uint64_t)ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; + now = (uint64_t)ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000ULL; wolfIP_poll(s, now); usleep(1000); } @@ -293,7 +301,6 @@ static void *poll_thread(void *arg) int main(void) { - setvbuf(stdout, NULL, _IONBF, 0); struct wolfIP *router; struct wolfIP_ll_dev *iface0; struct wolfIP_ll_dev *iface1; @@ -304,6 +311,9 @@ int main(void) uint8_t router1_mac[6] = {0x02,0x00,0x00,0x00,0xCC,0x01}; uint8_t frame[LINK_MTU]; int rc = EXIT_FAILURE; + int n; + + setvbuf(stdout, NULL, _IONBF, 0); mem_link_init(&link); wolfIP_init_static(&router); @@ -333,7 +343,7 @@ int main(void) build_ttl_frame(frame, host_mac, router0_mac, HOST_IP, DEST_IP); mem_host_send(&link, frame, sizeof(struct eth_hdr) + sizeof(struct ipv4_hdr) + sizeof(struct icmp_echo)); - int n = mem_host_recv(&link, frame, sizeof(frame), 1000); + n = mem_host_recv(&link, frame, sizeof(frame), 1000); if (n > 0) { struct eth_hdr *eth = (struct eth_hdr *)frame; struct ipv4_hdr *ip = (struct ipv4_hdr *)(frame + sizeof(*eth)); diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index c124b3a8..6238679a 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -132,11 +132,14 @@ static struct mem_ep *mem_ep_lookup(struct wolfIP_ll_dev *ll) static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); + struct mem_link *link; + int idx; + int ret = 0; + if (!ep) return -1; - struct mem_link *link = ep->link; - int idx = ep->idx; - int ret = 0; + link = ep->link; + idx = ep->idx; pthread_mutex_lock(&link->lock); if (link->ready[idx]) { @@ -155,10 +158,13 @@ static int mem_ll_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) static int mem_ll_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { struct mem_ep *ep = mem_ep_lookup(ll); + struct mem_link *link; + int dst; + if (!ep) return -1; - struct mem_link *link = ep->link; - int dst = 1 - ep->idx; + link = ep->link; + dst = 1 - ep->idx; pthread_mutex_lock(&link->lock); while (link->ready[dst]) @@ -333,13 +339,11 @@ static volatile enum client_state client_state = CLIENT_STATE_IDLE; static void client_cb(int fd, uint16_t events, void *arg) { struct wolfIP *cli = (struct wolfIP *)arg; - (void)cli; + int progress = 1; if (fd != client_fd || client_ssl == NULL) return; - int progress = 1; - while (progress) { progress = 0; if (client_state == CLIENT_STATE_HANDSHAKE) { @@ -499,16 +503,16 @@ static void *poll_thread(void *arg) int main(void) { - setvbuf(stdout, NULL, _IONBF, 0); - /* MAC addresses */ static const uint8_t mac_client[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0x10}; static const uint8_t mac_router0[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0xFE}; static const uint8_t mac_router1[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0xFE}; static const uint8_t mac_server[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0x10}; - struct mem_link link_client_router; struct mem_link link_router_server; int ret = 0; + size_t stack_sz; + + setvbuf(stdout, NULL, _IONBF, 0); mem_link_init(&link_client_router); mem_link_init(&link_router_server); @@ -517,7 +521,7 @@ int main(void) wolfSSL_Debugging_OFF(); /* Initialise stacks */ - size_t stack_sz = wolfIP_instance_size(); + stack_sz = wolfIP_instance_size(); client_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); router_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); server_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 2f54ce3a..1535131b 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -149,6 +149,7 @@ START_TEST(test_fifo_push_and_pop_multiple) { struct fifo f; uint8_t data[] = {1, 2, 3, 4, 5}; uint8_t data2[] = {6, 7, 8, 9, 10}; + struct pkt_desc *desc; fifo_init(&f, mem, memsz); ck_assert_int_eq(fifo_space(&f), memsz); @@ -160,7 +161,7 @@ START_TEST(test_fifo_push_and_pop_multiple) { ck_assert_int_eq(fifo_push(&f, data2, sizeof(data2)), 0); // Test pop - struct pkt_desc *desc = fifo_pop(&f); + desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); ck_assert_int_eq(desc->len, sizeof(data)); ck_assert_mem_eq((const uint8_t *)f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); @@ -175,10 +176,11 @@ END_TEST START_TEST(test_fifo_pop_success) { struct fifo f; uint8_t data[] = {1, 2, 3, 4}; + struct pkt_desc *desc; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); // Add data to FIFO - struct pkt_desc *desc = fifo_pop(&f); + desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Ensure we got a valid descriptor ck_assert_int_eq(desc->len, sizeof(data)); // Check length ck_assert_mem_eq((const uint8_t *)f.data + desc->pos + sizeof(struct pkt_desc), data, sizeof(data)); // Check data @@ -186,9 +188,10 @@ START_TEST(test_fifo_pop_success) { START_TEST(test_fifo_pop_empty) { struct fifo f; + struct pkt_desc *desc; fifo_init(&f, mem, memsz); - struct pkt_desc *desc = fifo_pop(&f); + desc = fifo_pop(&f); ck_assert_ptr_eq(desc, NULL); // Ensure pop returns NULL on empty FIFO } @@ -209,11 +212,12 @@ START_TEST(test_fifo_push_wrap) { uint8_t buffer[100]; uint8_t data[] = {1, 2, 3, 4}; int ret; + struct pkt_desc *desc; fifo_init(&f, buffer, sizeof(buffer)); fifo_push(&f, data, sizeof(data)); // Add data to FIFO // Pop the data to make space - struct pkt_desc *desc = fifo_pop(&f); + desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Push data to wrap around the buffer @@ -229,11 +233,12 @@ START_TEST(test_fifo_push_wrap_multiple) { uint8_t data[] = {1, 2, 3, 4}; uint8_t data2[] = {5, 6, 7, 8, 9}; int ret; + struct pkt_desc *desc; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); // Add data to FIFO // Pop the data to make space - struct pkt_desc *desc = fifo_pop(&f); + desc = fifo_pop(&f); ck_assert_ptr_nonnull(desc); // Push data to wrap around the buffer @@ -253,6 +258,8 @@ START_TEST(test_fifo_next_success) { struct fifo f; uint8_t data1[] = {1, 2, 3, 4}; uint8_t data2[] = {5, 6, 7, 8, 9}; + struct pkt_desc *desc; + struct pkt_desc *next_desc; fifo_init(&f, mem, memsz); @@ -262,35 +269,39 @@ START_TEST(test_fifo_next_success) { ck_assert_int_eq(fifo_len(&f), sizeof(data1) + sizeof(data2) + 2 * sizeof(struct pkt_desc)); // Get the first packet descriptor - struct pkt_desc *desc = fifo_peek(&f); + desc = fifo_peek(&f); ck_assert_ptr_nonnull(desc); // Get the next packet descriptor using fifo_next - struct pkt_desc *next_desc = fifo_next(&f, desc); + next_desc = fifo_next(&f, desc); ck_assert_ptr_nonnull(next_desc); // Ensure next descriptor is valid ck_assert_int_eq(next_desc->len, sizeof(data2)); // Check length of next packet } START_TEST(test_fifo_next_empty_fifo) { struct fifo f; + struct pkt_desc *desc; + struct pkt_desc *next_desc; fifo_init(&f, mem, memsz); // Start with an empty FIFO - struct pkt_desc *desc = NULL; - struct pkt_desc *next_desc = fifo_next(&f, desc); + desc = NULL; + next_desc = fifo_next(&f, desc); ck_assert_ptr_eq(next_desc, NULL); // Ensure next returns NULL on empty FIFO } START_TEST(test_fifo_next_end_of_fifo) { struct fifo f; uint8_t data[] = {1, 2, 3, 4}; + struct pkt_desc *desc; + struct pkt_desc *next_desc; fifo_init(&f, mem, memsz); fifo_push(&f, data, sizeof(data)); - struct pkt_desc *desc = fifo_peek(&f); // Get first packet + desc = fifo_peek(&f); // Get first packet fifo_pop(&f); // Simulate removing the packet - struct pkt_desc *next_desc = fifo_next(&f, desc); + next_desc = fifo_next(&f, desc); ck_assert_ptr_eq(next_desc, NULL); // Should return NULL as there are no more packets } END_TEST @@ -346,10 +357,11 @@ END_TEST START_TEST(test_queue_insert_empty) { struct queue q; - queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {1, 2, 3, 4}; + int res; + queue_init(&q, mem, memsz, 0x12345678); - int res = queue_insert(&q, data, 0, sizeof(data)); + res = queue_insert(&q, data, 0, sizeof(data)); ck_assert_int_eq(res, 0); ck_assert_int_eq(queue_len(&q), sizeof(data)); ck_assert_int_eq(q.head, sizeof(data)); @@ -359,12 +371,14 @@ END_TEST START_TEST(test_queue_insert_sequential) { struct queue q; - queue_init(&q, mem, memsz, 0x12345678); uint8_t data1[] = {1, 2}; uint8_t data2[] = {3, 4}; + int res1; + int res2; + queue_init(&q, mem, memsz, 0x12345678); - int res1 = queue_insert(&q, data1, 0, sizeof(data1)); - int res2 = queue_insert(&q, data2, 2, sizeof(data2)); + res1 = queue_insert(&q, data1, 0, sizeof(data1)); + res2 = queue_insert(&q, data2, 2, sizeof(data2)); ck_assert_int_eq(res1, 0); ck_assert_int_eq(res2, 0); ck_assert_int_eq(queue_len(&q), sizeof(data1) + sizeof(data2)); @@ -375,12 +389,13 @@ END_TEST START_TEST(test_queue_pop) { struct queue q; - queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {5, 6, 7, 8}; uint8_t out[4]; + int len; + queue_init(&q, mem, memsz, 0x12345678); queue_insert(&q, data, 0, sizeof(data)); - int len = queue_pop(&q, out, sizeof(out)); + len = queue_pop(&q, out, sizeof(out)); ck_assert_int_eq(len, sizeof(out)); ck_assert_mem_eq(out, data, sizeof(data)); ck_assert_int_eq(queue_len(&q), 0); @@ -390,14 +405,15 @@ END_TEST START_TEST(test_queue_pop_wraparound) { struct queue q; - queue_init(&q, mem, memsz, 0x12345678); uint8_t data[] = {9, 10, 11, 12}; uint8_t out[4]; + int len; + queue_init(&q, mem, memsz, 0x12345678); q.head = memsz - 1; q.tail = memsz - 1; queue_insert(&q, data, 0, sizeof(data)); - int len = queue_pop(&q, out, sizeof(out)); + len = queue_pop(&q, out, sizeof(out)); ck_assert_int_eq(len, sizeof(out)); ck_assert_mem_eq(out, data, sizeof(data)); ck_assert_int_eq(queue_len(&q), 0); @@ -407,15 +423,18 @@ END_TEST /* Utils */ START_TEST(test_insert_timer) { - reset_heap(); - struct wolfIP_timer tmr1 = { .expires = 100 }; struct wolfIP_timer tmr2 = { .expires = 50 }; struct wolfIP_timer tmr3 = { .expires = 200 }; + int id1; + int id2; + int id3; + + reset_heap(); - int id1 = timers_binheap_insert(&heap, tmr1); - int id2 = timers_binheap_insert(&heap, tmr2); - int id3 = timers_binheap_insert(&heap, tmr3); + id1 = timers_binheap_insert(&heap, tmr1); + id2 = timers_binheap_insert(&heap, tmr2); + id3 = timers_binheap_insert(&heap, tmr3); ck_assert_int_eq(heap.size, 3); ck_assert_int_lt(heap.timers[0].expires, heap.timers[1].expires); @@ -426,17 +445,18 @@ START_TEST(test_insert_timer) { END_TEST START_TEST(test_pop_timer) { - reset_heap(); - struct wolfIP_timer tmr1 = { .expires = 300 }; struct wolfIP_timer tmr2 = { .expires = 100 }; struct wolfIP_timer tmr3 = { .expires = 200 }; + struct wolfIP_timer popped; + + reset_heap(); timers_binheap_insert(&heap, tmr1); timers_binheap_insert(&heap, tmr2); timers_binheap_insert(&heap, tmr3); - struct wolfIP_timer popped = timers_binheap_pop(&heap); + popped = timers_binheap_pop(&heap); ck_assert_int_eq(popped.expires, 100); ck_assert_int_eq(heap.size, 2); ck_assert_int_lt(heap.timers[0].expires, heap.timers[1].expires); @@ -444,9 +464,9 @@ START_TEST(test_pop_timer) { END_TEST START_TEST(test_is_timer_expired) { - reset_heap(); - struct wolfIP_timer tmr = { .expires = 150 }; + + reset_heap(); timers_binheap_insert(&heap, tmr); ck_assert_int_eq(is_timer_expired(&heap, 100), 0); @@ -456,19 +476,22 @@ START_TEST(test_is_timer_expired) { END_TEST START_TEST(test_cancel_timer) { - reset_heap(); - struct wolfIP_timer tmr1 = { .expires = 100 }; struct wolfIP_timer tmr2 = { .expires = 200 }; + int id1; + int id2; + struct wolfIP_timer popped; - int id1 = timers_binheap_insert(&heap, tmr1); - int id2 = timers_binheap_insert(&heap, tmr2); + reset_heap(); + + id1 = timers_binheap_insert(&heap, tmr1); + id2 = timers_binheap_insert(&heap, tmr2); (void)id2; timer_binheap_cancel(&heap, id1); ck_assert_int_eq(heap.timers[0].expires, 0); // tmr1 canceled - struct wolfIP_timer popped = timers_binheap_pop(&heap); + popped = timers_binheap_pop(&heap); ck_assert_int_eq(popped.expires, 200); // Only tmr2 should remain ck_assert_int_eq(heap.size, 0); } @@ -480,8 +503,9 @@ START_TEST(test_arp_request_basic) { struct wolfIP s; struct arp_packet *arp; - wolfIP_init(&s); uint32_t target_ip = 0xC0A80002; /* 192.168.0.2 */ + + wolfIP_init(&s); mock_link_init(&s); s.last_tick = 1000; arp_request(&s, TEST_PRIMARY_IF, target_ip); @@ -505,8 +529,9 @@ END_TEST START_TEST(test_arp_request_throttle) { struct wolfIP s; - wolfIP_init(&s); uint32_t target_ip = 0xC0A80002; /*192.168.0.2*/ + + wolfIP_init(&s); mock_link_init(&s); s.last_tick = 1000; s.arp.last_arp[TEST_PRIMARY_IF] = 880; @@ -517,8 +542,9 @@ START_TEST(test_arp_request_throttle) END_TEST START_TEST(test_arp_request_target_ip) { - uint32_t target_ip = 0xC0A80002; struct wolfIP s; + uint32_t target_ip = 0xC0A80002; + wolfIP_init(&s); mock_link_init(&s); s.last_tick = 1000; @@ -530,12 +556,13 @@ END_TEST START_TEST(test_arp_request_handling) { struct arp_packet arp_req; struct arp_packet *arp_reply; - memset(&arp_req, 0, sizeof(arp_req)); uint32_t req_ip = 0xC0A80002; // 192.168.0.2 uint32_t device_ip = 0xC0A80001; // 192.168.0.1 uint8_t req_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; //uint8_t mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; struct wolfIP s; + + memset(&arp_req, 0, sizeof(arp_req)); wolfIP_init(&s); mock_link_init(&s); s.ipconf[TEST_PRIMARY_IF].ip = device_ip; @@ -570,10 +597,12 @@ END_TEST START_TEST(test_arp_reply_handling) { struct arp_packet arp_reply; - memset(&arp_reply, 0, sizeof(arp_reply)); uint32_t reply_ip = 0xC0A80003; // 192.168.0.3 uint8_t reply_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01}; + uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; struct wolfIP s; + + memset(&arp_reply, 0, sizeof(arp_reply)); wolfIP_init(&s); mock_link_init(&s); @@ -590,7 +619,6 @@ START_TEST(test_arp_reply_handling) { ck_assert_mem_eq(s.arp.neighbors[0].mac, reply_mac, 6); /* Update same IP with a different MAC address */ - uint8_t new_mac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; memcpy(arp_reply.sma, new_mac, 6); arp_recv(&s, TEST_PRIMARY_IF, &arp_reply, sizeof(arp_reply)); @@ -604,6 +632,8 @@ START_TEST(test_arp_lookup_success) { uint32_t ip = 0xC0A80002; const uint8_t mock_mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01}; struct wolfIP s; + int result; + wolfIP_init(&s); mock_link_init(&s); @@ -613,7 +643,7 @@ START_TEST(test_arp_lookup_success) { memcpy(s.arp.neighbors[0].mac, mock_mac, 6); /* Test arp_lookup */ - int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); + result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); ck_assert_int_eq(result, 0); ck_assert_mem_eq(found_mac, mock_mac, 6); } @@ -623,13 +653,15 @@ START_TEST(test_arp_lookup_failure) { uint8_t found_mac[6]; uint32_t ip = 0xC0A80004; struct wolfIP s; + int result; + uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0}; + wolfIP_init(&s); mock_link_init(&s); /* Ensure arp_lookup fails for unknown IP */ - int result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); + result = arp_lookup(&s, TEST_PRIMARY_IF, ip, found_mac); ck_assert_int_eq(result, -1); - uint8_t zero_mac[6] = {0, 0, 0, 0, 0, 0}; ck_assert_mem_eq(found_mac, zero_mac, 6); } END_TEST @@ -637,8 +669,9 @@ END_TEST START_TEST(test_wolfip_getdev_ex_api) { struct wolfIP s; + struct wolfIP_ll_dev *ll_def; wolfIP_init(&s); - struct wolfIP_ll_dev *ll_def = wolfIP_getdev(&s); + ll_def = wolfIP_getdev(&s); ck_assert_ptr_nonnull(ll_def); ck_assert_ptr_eq(ll_def, wolfIP_getdev_ex(&s, TEST_PRIMARY_IF)); #if WOLFIP_ENABLE_LOOPBACK @@ -891,6 +924,7 @@ END_TEST START_TEST(test_transport_checksum) { union transport_pseudo_header ph; struct wolfIP_tcp_seg tcp_data; + uint16_t checksum; memset(&ph, 0, sizeof(ph)); memset(&tcp_data, 0, sizeof(tcp_data)); @@ -909,7 +943,7 @@ START_TEST(test_transport_checksum) { tcp_data.flags = 0x02; // SYN tcp_data.win = ee16(65535); - uint16_t checksum = transport_checksum(&ph, &tcp_data.src_port); + checksum = transport_checksum(&ph, &tcp_data.src_port); ck_assert_msg(checksum != 0, "Transport checksum should not be zero"); } END_TEST @@ -938,11 +972,13 @@ END_TEST START_TEST(test_eth_output_add_header) { struct wolfIP_eth_frame eth_frame; struct wolfIP S; + uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + struct wolfIP_ll_dev *ll; + wolfIP_init(&S); memset(ð_frame, 0, sizeof(eth_frame)); - uint8_t test_mac[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; - struct wolfIP_ll_dev *ll = wolfIP_getdev_ex(&S, TEST_PRIMARY_IF); + ll = wolfIP_getdev_ex(&S, TEST_PRIMARY_IF); memcpy(ll->mac, test_mac, 6); eth_output_add_header(&S, TEST_PRIMARY_IF, NULL, ð_frame, ETH_TYPE_IP); @@ -958,6 +994,9 @@ START_TEST(test_ip_output_add_header) { struct tsocket t; struct wolfIP_ip_packet ip; struct wolfIP S; + int result; + struct wolfIP_tcp_seg *tcp; + memset(&t, 0, sizeof(t)); memset(&ip, 0, sizeof(ip)); memset(&S, 0, sizeof(S)); @@ -968,7 +1007,7 @@ START_TEST(test_ip_output_add_header) { t.S = &S; // Run the function for a TCP packet - int result = ip_output_add_header(&t, &ip, WI_IPPROTO_TCP, 40); + result = ip_output_add_header(&t, &ip, WI_IPPROTO_TCP, 40); ck_assert_int_eq(result, 0); // Validate IP header fields @@ -980,7 +1019,7 @@ START_TEST(test_ip_output_add_header) { ck_assert_msg(ip.csum != 0, "IP header checksum should not be zero"); // Check the pseudo-header checksum calculation for TCP segment - struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)&ip; + tcp = (struct wolfIP_tcp_seg *)&ip; ck_assert_msg(tcp->csum != 0, "TCP checksum should not be zero"); } END_TEST diff --git a/src/wolfip.c b/src/wolfip.c index 0bdd5b92..0cae610e 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -646,22 +646,23 @@ static inline int ip_is_local_conf(const struct ipconf *conf, ip4 addr) } #if WOLFIP_ENABLE_FORWARDING -static unsigned int wolfIP_forward_interface(struct wolfIP *s, unsigned int in_if, ip4 dest) +static int wolfIP_forward_interface(struct wolfIP *s, unsigned int in_if, ip4 dest) { + int i; if (!s || s->if_count < 2) return s ? s->if_count : 0; - for (unsigned int i = 0; i < s->if_count; i++) { + for (i = 0; i < (int)s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; - if (i == in_if) + if (i == (int)in_if) continue; if (!conf || conf->ip == IPADDR_ANY) continue; if (dest == conf->ip) - return s->if_count; + return -1; if (ip_is_local_conf(conf, dest)) return i; } - return s->if_count; + return -1; } #endif @@ -685,6 +686,7 @@ static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) unsigned int first_non_loop = 0; int has_gw_fallback = 0; int has_non_loop = 0; + unsigned int i; if (!s || s->if_count == 0) return 0; @@ -695,7 +697,7 @@ static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) if (dest == IPADDR_ANY || IS_IP_BCAST(dest)) return default_if; - for (unsigned int i = 0; i < s->if_count; i++) { + for (i = 0; i < s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; if (conf->ip == IPADDR_ANY && conf->gw == IPADDR_ANY) continue; @@ -728,6 +730,7 @@ static inline unsigned int wolfIP_socket_if_idx(const struct tsocket *t) static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int *found) { unsigned int primary = 0; + unsigned int i; if (found) *found = 0; if (!s || s->if_count == 0) @@ -736,7 +739,7 @@ static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int * primary = WOLFIP_PRIMARY_IF_IDX; if (local_ip == IPADDR_ANY) return primary; - for (unsigned int i = 0; i < s->if_count; i++) { + for (i = 0; i < s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; if (conf->ip == local_ip) { if (found) @@ -762,9 +765,9 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); + struct wolfIP_icmp_packet icmp; if (!ll || !ll->send) return; - struct wolfIP_icmp_packet icmp; memset(&icmp, 0, sizeof(icmp)); icmp.type = ICMP_TTL_EXCEEDED; icmp.csum = ee16(icmp_checksum(&icmp)); @@ -840,6 +843,7 @@ static struct wolfIP_timer timers_binheap_pop(struct timers_binheap *heap) static int timers_binheap_insert(struct timers_binheap *heap, struct wolfIP_timer tmr) { static uint32_t timer_id = 1; + int i; if (timer_id == 0) timer_id = 1; while (heap->size > 0 && heap->timers[0].expires == 0) @@ -848,7 +852,7 @@ static int timers_binheap_insert(struct timers_binheap *heap, struct wolfIP_time /* Insert at the end */ heap->timers[heap->size] = tmr; heap->size++; - int i = heap->size - 1; + i = heap->size - 1; while (i > 0 && heap->timers[i].expires < heap->timers[(i-1)/2].expires) { struct wolfIP_timer tmp = heap->timers[i]; heap->timers[i] = heap->timers[(i-1)/2]; @@ -884,8 +888,9 @@ static void timer_binheap_cancel(struct timers_binheap *heap, uint32_t id) static struct tsocket *udp_new_socket(struct wolfIP *s) { struct tsocket *t; + int i; - for (int i = 0; i < MAX_UDPSOCKETS; i++) { + for (i = 0; i < MAX_UDPSOCKETS; i++) { t = &s->udpsockets[i]; if (t->proto == 0) { t->proto = WI_IPPROTO_UDP; @@ -903,9 +908,10 @@ static struct tsocket *udp_new_socket(struct wolfIP *s) static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_udp_datagram *udp, uint32_t frame_len) { struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + int i; ip4 local_ip = conf ? conf->ip : IPADDR_ANY; ip4 dst_ip = ee32(udp->ip.dst); - for (int i = 0; i < MAX_UDPSOCKETS; i++) { + for (i = 0; i < MAX_UDPSOCKETS; i++) { struct tsocket *t = &s->udpsockets[i]; if (t->src_port == ee16(udp->dst_port) && t->dst_port == ee16(udp->src_port) && (((t->local_ip == 0) && DHCP_IS_RUNNING(s)) || @@ -928,7 +934,8 @@ static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ud static struct tsocket *tcp_new_socket(struct wolfIP *s) { struct tsocket *t; - for (int i = 0; i < MAX_TCPSOCKETS; i++) { + int i; + for (i = 0; i < MAX_TCPSOCKETS; i++) { t = &s->tcpsockets[i]; if (t->proto == 0) { t->proto = WI_IPPROTO_TCP; @@ -1178,6 +1185,7 @@ static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, uint8_t proto, uint16_t len) { union transport_pseudo_header ph; + unsigned int if_idx; memset(&ph, 0, sizeof(ph)); memset(ip, 0, sizeof(struct wolfIP_ip_packet)); ip->src = ee32(t->local_ip); @@ -1207,8 +1215,10 @@ static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, udp->csum = ee16(transport_checksum(&ph, &udp->src_port)); } #ifdef ETHERNET - unsigned int if_idx = wolfIP_socket_if_idx(t); + if_idx = wolfIP_socket_if_idx(t); eth_output_add_header(t->S, if_idx, t->nexthop_mac, (struct wolfIP_eth_frame *)ip, ETH_TYPE_IP); +#else + (void)if_idx; #endif return 0; } @@ -1345,7 +1355,8 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_s { struct ipconf *conf = wolfIP_ipconf_at(S, if_idx); ip4 local_ip = conf ? conf->ip : IPADDR_ANY; - for (int i = 0; i < MAX_TCPSOCKETS; i++) { + int i; + for (i = 0; i < MAX_TCPSOCKETS; i++) { uint32_t tcplen; uint32_t iplen; struct tsocket *t = &S->tcpsockets[i]; @@ -1520,15 +1531,18 @@ int wolfIP_sock_socket(struct wolfIP *s, int domain, int type, int protocol) int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen) { struct tsocket *ts; - const struct wolfIP_sockaddr_in *sin = (const struct wolfIP_sockaddr_in *)addr; + const struct wolfIP_sockaddr_in *sin; + unsigned int if_idx; if (!addr) return -2; + sin = (const struct wolfIP_sockaddr_in *)addr; if (sockfd & MARK_UDP_SOCKET) { + struct ipconf *conf; ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; ts->dst_port = ee16(sin->sin_port); ts->remote_ip = ee32(sin->sin_addr.s_addr); - unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); - struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + conf = wolfIP_ipconf_at(s, if_idx); ts->if_idx = (uint8_t)if_idx; if (ts->local_ip == 0 && conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; @@ -1549,10 +1563,11 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad if ((sin->sin_family != AF_INET) || (addrlen < sizeof(struct wolfIP_sockaddr_in))) return -2; if (ts->sock.tcp.state == TCP_CLOSED) { + struct ipconf *conf; ts->sock.tcp.state = TCP_SYN_SENT; ts->remote_ip = ee32(sin->sin_addr.s_addr); - unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); - struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + conf = wolfIP_ipconf_at(s, if_idx); ts->if_idx = (uint8_t)if_idx; if (conf && conf->ip != IPADDR_ANY) ts->local_ip = conf->ip; @@ -1628,13 +1643,18 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len { uint8_t frame[LINK_MTU]; struct tsocket *ts; - struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)frame; - struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)frame; - + struct wolfIP_tcp_seg *tcp; + struct wolfIP_udp_datagram *udp; + tcp = (struct wolfIP_tcp_seg *)frame; + udp = (struct wolfIP_udp_datagram *)frame; (void)flags; if (sockfd < 0) return -1; + + if ((!buf) || (len == 0)) + return -1; + if (sockfd & MARK_TCP_SOCKET) { size_t sent = 0; struct tcp_opt_ts *tsopt = (struct tcp_opt_ts *)tcp->data; @@ -1675,6 +1695,8 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len return sent; } else if (sockfd & MARK_UDP_SOCKET) { const struct wolfIP_sockaddr_in *sin = (const struct wolfIP_sockaddr_in *)dest_addr; + unsigned int if_idx; + struct ipconf *conf; ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; if ((ts->dst_port == 0) && (dest_addr == NULL)) return -1; @@ -1696,8 +1718,8 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (ts->src_port < 1024) ts->src_port += 1024; } - unsigned int if_idx = wolfIP_route_for_ip(s, ts->remote_ip); - struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + if_idx = wolfIP_route_for_ip(s, ts->remote_ip); + conf = wolfIP_ipconf_at(s, if_idx); ts->if_idx = (uint8_t)if_idx; if (ts->local_ip == 0) { if (conf && conf->ip != IPADDR_ANY) @@ -1837,13 +1859,17 @@ int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen) { struct tsocket *ts; + ip4 bind_ip; + struct ipconf *conf; const struct wolfIP_sockaddr_in *sin = (const struct wolfIP_sockaddr_in *)addr; + int match = 0; + unsigned int if_idx; + if (!sin || addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; - ip4 bind_ip = ee32(sin->sin_addr.s_addr); - int match = 0; - unsigned int if_idx = wolfIP_if_for_local_ip(s, bind_ip, &match); - struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); + bind_ip = ee32(sin->sin_addr.s_addr); + if_idx = wolfIP_if_for_local_ip(s, bind_ip, &match); + conf = wolfIP_ipconf_at(s, if_idx); if ((bind_ip != IPADDR_ANY) && !match) return -1; @@ -2062,8 +2088,8 @@ static int dhcp_poll(struct wolfIP *s) if ((s->dhcp_state == DHCP_DISCOVER_SENT) && (dhcp_parse_offer(s, &msg) == 0)) dhcp_send_request(s); else if ((s->dhcp_state == DHCP_REQUEST_SENT) && (dhcp_parse_ack(s, &msg) == 0)) { - LOG("DHCP configuration received.\n"); struct ipconf *primary = wolfIP_primary_ipconf(s); + LOG("DHCP configuration received.\n"); if (primary) { LOG("IP Address: %u.%u.%u.%u\n", (primary->ip >> 24) & 0xFF, (primary->ip >> 16) & 0xFF, (primary->ip >> 8) & 0xFF, (primary->ip >> 0) & 0xFF); LOG("Subnet Mask: %u.%u.%u.%u\n", (primary->mask >> 24) & 0xFF, (primary->mask >> 16) & 0xFF, (primary->mask >> 8) & 0xFF, (primary->mask >> 0) & 0xFF); @@ -2241,15 +2267,16 @@ int dhcp_client_init(struct wolfIP *s) static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, const uint8_t *mac) { + int i; if (!s) return; - for (int i = 0; i < MAX_NEIGHBORS; i++) { + for (i = 0; i < MAX_NEIGHBORS; i++) { if (s->arp.neighbors[i].ip == ip && s->arp.neighbors[i].if_idx == if_idx) { memcpy(s->arp.neighbors[i].mac, mac, 6); return; } } - for (int i = 0; i < MAX_NEIGHBORS; i++) { + for (i = 0; i < MAX_NEIGHBORS; i++) { if (s->arp.neighbors[i].ip == IPADDR_ANY) { s->arp.neighbors[i].ip = ip; s->arp.neighbors[i].if_idx = (uint8_t)if_idx; @@ -2314,8 +2341,9 @@ static void arp_recv(struct wolfIP *s, unsigned int if_idx, void *buf, int len) static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac) { + int i; memset(mac, 0, 6); - for (int i = 0; i < MAX_NEIGHBORS; i++) { + for (i = 0; i < MAX_NEIGHBORS; i++) { if (s->arp.neighbors[i].ip == ip && s->arp.neighbors[i].if_idx == if_idx) { memcpy(mac, s->arp.neighbors[i].mac, 6); return 0; @@ -2329,11 +2357,12 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma /* Initialize the IP stack */ void wolfIP_init(struct wolfIP *s) { + unsigned int i; if (!s) return; memset(s, 0, sizeof(struct wolfIP)); s->if_count = WOLFIP_MAX_INTERFACES; - for (unsigned int i = 0; i < s->if_count; i++) { + for (i = 0; i < s->if_count; i++) { s->ipconf[i].ll = wolfIP_ll_at(s, i); } #if WOLFIP_ENABLE_LOOPBACK @@ -2385,6 +2414,9 @@ size_t wolfIP_instance_size(void) static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { +#if WOLFIP_ENABLE_FORWARDING + unsigned int i; +#endif #if WOLFIP_ENABLE_LOOPBACK if (!wolfIP_is_loopback_if(if_idx)) { ip4 dest = ee32(ip->dst); @@ -2400,7 +2432,7 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ if (dest == IPADDR_ANY || IS_IP_BCAST(dest)) { is_local = 1; } else { - for (unsigned int i = 0; i < s->if_count; i++) { + for (i = 0; i < s->if_count; i++) { struct ipconf *conf = &s->ipconf[i]; if (!conf || conf->ip == IPADDR_ANY) continue; @@ -2411,18 +2443,20 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ } } if (!is_local) { - unsigned int out_if = wolfIP_forward_interface(s, if_idx, dest); - if (out_if < s->if_count) { + int out_if = wolfIP_forward_interface(s, if_idx, dest); + if (out_if > 0) { + uint8_t mac[6]; + int broadcast = 0; + uint16_t csum; + if (ip->ttl <= 1) { wolfIP_send_ttl_exceeded(s, if_idx, ip); return; } - uint8_t mac[6]; - int broadcast = 0; if (!wolfIP_forward_prepare(s, out_if, dest, mac, &broadcast)) return; ip->ttl--; - uint16_t csum = ee16(ip->csum); + csum = ee16(ip->csum); csum = (uint16_t)(csum + 1); if (csum == 0) csum = 0xFFFF; @@ -2447,13 +2481,20 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) { +#ifdef ETHERNET + struct wolfIP_ll_dev *ll; + struct wolfIP_eth_frame *eth; +#else + struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)buf; +#endif if (!s) return; + #ifdef ETHERNET - struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); + ll = wolfIP_ll_at(s, if_idx); if (!ll) return; - struct wolfIP_eth_frame *eth = (struct wolfIP_eth_frame *)buf; + eth = (struct wolfIP_eth_frame *)buf; if (eth->type == ee16(ETH_TYPE_IP)) { struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)eth; if ((memcmp(eth->dst, ll->mac, 6) != 0) && (memcmp(eth->dst, "\xff\xff\xff\xff\xff\xff", 6) != 0)) { @@ -2465,7 +2506,7 @@ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uin } #else /* No ethernet, assume IP */ - struct wolfIP_ip_packet *ip = (struct wolfIP_ip_packet *)buf; + ip = (struct wolfIP_ip_packet *)buf; ip_recv(s, if_idx, ip, len); #endif } @@ -2620,13 +2661,14 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) int len = 0; int i = 0; uint8_t buf[LINK_MTU]; + unsigned int if_idx; struct wolfIP_timer tmr; memset(buf, 0, LINK_MTU); s->last_tick = now; /* Step 1: Poll the device */ - for (unsigned int if_idx = 0; if_idx < s->if_count; if_idx++) { + for (if_idx = 0; if_idx < s->if_count; if_idx++) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); if (!ll || !ll->poll) continue; From ef81ba1345a9915197110d307465e24fcff62a49 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 06:17:24 +0100 Subject: [PATCH 11/25] Addressed more reviewers comments --- src/http/httpd.c | 135 ++++++++++++++++++++++++----------------------- src/wolfip.c | 10 +--- wolfip.h | 3 +- 3 files changed, 71 insertions(+), 77 deletions(-) diff --git a/src/http/httpd.c b/src/http/httpd.c index b54d95fc..42d2061e 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -17,6 +17,29 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + * + * This is a simple HTTP server module for wolfIP. + * + * This file contains a basic implementation of a HTTP server + * that can be used with wolfIP. + * + * The HTTP server supports: + * - GET requests + * - POST requests + * - Basic file serving + * - Basic error handling + * + * Usage: + * - Initialize via httpd_init() + * - Add static pages via httpd_register_static_page() + * - Add request handlers via httpd_register_handler() + * + * Note: + * - Responses are sent immediately after generation. No buffering is done. + * If the output socket is flooded, extra responses will be discarded. + * + * */ #include "wolfip.h" #include "httpd.h" @@ -43,16 +66,6 @@ static const char *http_status_text(int status_code) { return "Unknown"; } } -/* -static struct http_client *http_client_find(struct httpd *httpd, int sd) { - for (int i = 0; i < HTTPD_MAX_CLIENTS; i++) { - if (httpd->clients[i].client_sd == sd) { - return &httpd->clients[i]; - } - } - return NULL; -} -*/ int httpd_register_handler(struct httpd *httpd, const char *path, int (*handler)(struct httpd *httpd, struct http_client *hc, struct http_request *req)) { for (int i = 0; i < HTTPD_MAX_URLS; i++) { @@ -125,75 +138,63 @@ void http_send_response_headers(struct http_client *hc, int status_code, const c } void http_send_response_body(struct http_client *hc, const void *body, size_t len) { - if (!hc) return; - if (hc->ssl) { - int rc = wolfSSL_write(hc->ssl, body, len); - if (rc <= 0) { - wolfSSL_free(hc->ssl); - hc->ssl = NULL; - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } - } else { - int rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, body, len, 0); - if (rc <= 0) { - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } + int rc; + if (!hc) + return; + if (hc->ssl) + rc = wolfSSL_write(hc->ssl, body, len); + else + rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, body, len, 0); + + if (rc <= 0) { + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; } } +static int http_write_response(struct http_client *hc, const void *buf, size_t len) +{ + struct wolfIP *s; + if (!hc) + return -1; + s = hc->httpd->ipstack; + if (hc->ssl) + return wolfSSL_write(hc->ssl, buf, len); + else + return wolfIP_sock_send(s, hc->client_sd, buf, len, 0); +} + void http_send_response_chunk(struct http_client *hc, const void *chunk, size_t len) { char txt_chunk[8]; memset(txt_chunk, 0, sizeof(txt_chunk)); - if (!hc) return; + if (!hc) + return; snprintf(txt_chunk, sizeof(txt_chunk), "%zx\r\n", len); - if (hc->ssl) { - int rc = wolfSSL_write(hc->ssl, txt_chunk, strlen(txt_chunk)); - if (rc <= 0) - goto close_conn; - rc = wolfSSL_write(hc->ssl, chunk, len); - if (rc <= 0) - goto close_conn; - rc = wolfSSL_write(hc->ssl, "\r\n", 2); - if (rc <= 0) - goto close_conn; - } else { - struct wolfIP *s = hc->httpd->ipstack; - int rc = wolfIP_sock_send(s, hc->client_sd, txt_chunk, strlen(txt_chunk), 0); - if (rc <= 0) - goto close_conn; - rc = wolfIP_sock_send(s, hc->client_sd, chunk, len, 0); - if (rc <= 0) - goto close_conn; - rc = wolfIP_sock_send(s, hc->client_sd, "\r\n", 2, 0); - if (rc <= 0) - goto close_conn; - } - return; -close_conn: - if (hc->ssl) { + if ((http_write_response(hc, txt_chunk, strlen(txt_chunk)) <= 0) || + (http_write_response(hc, chunk, len) <= 0) || + (http_write_response(hc, "\r\n", 2) <= 0)) { wolfSSL_free(hc->ssl); hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; } - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; } void http_send_response_chunk_end(struct http_client *hc) { - if (!hc) return; - if (hc->ssl) { - if (wolfSSL_write(hc->ssl, "0\r\n\r\n", 5) <= 0) { - wolfSSL_free(hc->ssl); - hc->ssl = NULL; - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } - } else { - if (wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0) <= 0) { - wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); - hc->client_sd = 0; - } + int rc; + if (!hc) + return; + if (hc->ssl) + rc = wolfSSL_write(hc->ssl, "0\r\n\r\n", 5); + else + rc = wolfIP_sock_send(hc->httpd->ipstack, hc->client_sd, "0\r\n\r\n", 5, 0); + if (rc <= 0) { + wolfSSL_free(hc->ssl); + hc->ssl = NULL; + wolfIP_sock_close(hc->httpd->ipstack, hc->client_sd); + hc->client_sd = 0; } } @@ -369,7 +370,7 @@ static int parse_http_request(struct http_client *hc, uint8_t *buf, size_t len) url = http_find_url(hc->httpd, req.path); if (!url) goto not_found; - + if ((url->handler == NULL) && (url->static_content == NULL)) goto service_unavailable; if (url->handler == NULL) { diff --git a/src/wolfip.c b/src/wolfip.c index 0cae610e..3e2d3c4a 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -49,7 +49,6 @@ static inline int wolfIP_is_loopback_if(unsigned int if_idx) #if WOLFIP_ENABLE_LOOPBACK static int wolfIP_loopback_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); -static int wolfIP_loopback_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len); #endif static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len); @@ -588,13 +587,6 @@ struct wolfIP }; #if WOLFIP_ENABLE_LOOPBACK -static int wolfIP_loopback_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) -{ - (void)ll; - (void)buf; - (void)len; - return 0; -} static int wolfIP_loopback_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { @@ -2374,7 +2366,7 @@ void wolfIP_init(struct wolfIP *s) memcpy(loop->mac, loop_mac, sizeof(loop_mac)); strncpy(loop->ifname, "lo", sizeof(loop->ifname) - 1); loop->ifname[sizeof(loop->ifname) - 1] = '\0'; - loop->poll = wolfIP_loopback_poll; + loop->poll = NULL; loop->send = wolfIP_loopback_send; } if (loop_conf) { diff --git a/wolfip.h b/wolfip.h index 3d9b0dec..c9c02422 100644 --- a/wolfip.h +++ b/wolfip.h @@ -21,7 +21,8 @@ typedef uint32_t ip4; #endif /* Device driver interface */ -/* Struct to contain a hw device description */ +/* Struct to contain link-layer (ll) device description + */ struct wolfIP_ll_dev { uint8_t mac[6]; char ifname[16]; From b68b0fd5609cb94dbc020bea2dc16cf45d270005 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 07:14:31 +0100 Subject: [PATCH 12/25] Refactored forwarding test. Added support for configurable ARP cache. Fixed forward packets checksum. --- src/test/test_wolfssl_forwarding.c | 614 ++++++++++++++++------------- src/wolfip.c | 134 ++++++- 2 files changed, 451 insertions(+), 297 deletions(-) diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index 6238679a..ad539d55 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -1,40 +1,21 @@ /* test_wolfssl_forwarding.c * - * Copyright (C) 2025 wolfSSL Inc. - * - * This file is part of wolfIP TCP/IP stack. - * - * wolfIP is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfIP is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - * - * Integration test that exercises wolfIP's TLS echo server across a simple - * IP router running with forwarding enabled. The topology is: - * - * client (wolfIP) <--mem link--> router (2 interfaces, forwarding on) - * <--mem link--> server (wolfIP TLS echo) - * - * The router itself opens no sockets; it only polls the stack so incoming - * frames are forwarded between the two networks. + * Simplified forwarding test that exercises a wolfIP TLS echo server + * reachable through a wolfIP router while the client runs on the host + * using the Linux TCP/IP stack. */ +#include +#include +#include #include #include #include #include #include +#include +#include #include -#include #include #include "config.h" @@ -59,13 +40,47 @@ extern const unsigned char server_der[]; extern const unsigned long server_der_len; extern const unsigned char server_key_der[]; extern const unsigned long server_key_der_len; -static pthread_t th_server, th_client, th_router; -/* Helper macros */ +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, uint32_t host_ip); + #define IP4(a,b,c,d) (((ip4)(a) << 24) | ((ip4)(b) << 16) | ((ip4)(c) << 8) | (ip4)(d)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -/* Millisecond clock */ +#define TEST_PAYLOAD 1024 +#define TAP_IFNAME "wtls0" +#define HOST_ROUTE "10.20.2.0/24" + +static const ip4 host_ip4 = IP4(10,20,1,2); +static const ip4 router_lan_ip4 = IP4(10,20,1,254); +static const ip4 router_wan_ip4 = IP4(10,20,2,1); +static const ip4 server_ip4 = IP4(10,20,2,2); + +static pthread_t th_server; +static pthread_t th_router; + +static struct wolfIP *router_stack; +static struct wolfIP *server_stack; + +static int server_listen_fd = -1; +static int server_client_fd = -1; +static WOLFSSL_CTX *server_ctx = NULL; +static WOLFSSL *server_ssl = NULL; +static uint8_t server_buf[TEST_PAYLOAD]; +static int server_bytes_recv = 0; +static int server_bytes_sent = 0; +static volatile int server_done = 0; +static int server_handshake_done = 0; + +static volatile int router_running = 1; + +static void ip4_to_str(ip4 addr, char *buf, size_t len) +{ + snprintf(buf, len, "%u.%u.%u.%u", + (unsigned)((addr >> 24) & 0xFF), + (unsigned)((addr >> 16) & 0xFF), + (unsigned)((addr >> 8) & 0xFF), + (unsigned)(addr & 0xFF)); +} + static uint64_t monotonic_ms(void) { struct timespec ts; @@ -107,9 +122,6 @@ struct mem_ep { static struct mem_ep mem_eps[8]; static size_t mem_ep_count; -static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, - const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip); - static void mem_link_init(struct mem_link *link) { pthread_mutex_init(&link->lock, NULL); @@ -194,30 +206,20 @@ static void mem_link_attach(struct wolfIP_ll_dev *ll, struct mem_link *link, int /* TLS echo server (wolfIP stack) */ /* ------------------------------------------------------------------------- */ -#define TEST_PAYLOAD (1024) - -static struct wolfIP *server_stack; -static int server_listen_fd = -1; -static int server_client_fd = -1; -static WOLFSSL_CTX *server_ctx = NULL; -static WOLFSSL *server_ssl = NULL; -static uint8_t server_buf[TEST_PAYLOAD]; -static int server_bytes_recv = 0; -static int server_bytes_sent = 0; -static volatile int server_done = 0; -static int server_handshake_done = 0; - static void server_cb(int fd, uint16_t events, void *arg) { struct wolfIP *s = (struct wolfIP *)arg; - - + (void)events; if (fd == server_listen_fd && (events & CB_EVENT_READABLE) && server_client_fd == -1) { server_client_fd = wolfIP_sock_accept(s, server_listen_fd, NULL, NULL); if (server_client_fd > 0) { + wolfIP_register_callback(s, server_client_fd, server_cb, s); server_ssl = wolfSSL_new(server_ctx); wolfSSL_SetIO_wolfIP(server_ssl, server_client_fd); server_handshake_done = 0; + server_bytes_recv = 0; + server_bytes_sent = 0; + printf("TLS server: accepted client (fd 0x%04x)\n", server_client_fd); } return; } @@ -229,11 +231,12 @@ static void server_cb(int fd, uint16_t events, void *arg) int ret = wolfSSL_accept(server_ssl); if (ret == SSL_SUCCESS) { server_handshake_done = 1; + printf("TLS server: handshake complete\n"); } else { int err = wolfSSL_get_error(server_ssl, ret); - if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) return; - } + fprintf(stderr, "TLS server: handshake failed (%d)\n", err); wolfIP_sock_close(s, server_client_fd); server_client_fd = -1; wolfip_reset_io(server_ssl); @@ -248,14 +251,16 @@ static void server_cb(int fd, uint16_t events, void *arg) if (server_bytes_recv < TEST_PAYLOAD) { int ret = wolfSSL_read(server_ssl, server_buf + server_bytes_recv, TEST_PAYLOAD - server_bytes_recv); - if (ret > 0) + if (ret > 0) { server_bytes_recv += ret; + } } if (server_bytes_recv == TEST_PAYLOAD && server_bytes_sent < TEST_PAYLOAD) { int ret = wolfSSL_write(server_ssl, server_buf + server_bytes_sent, TEST_PAYLOAD - server_bytes_sent); - if (ret > 0) + if (ret > 0) { server_bytes_sent += ret; + } } if (server_bytes_sent == TEST_PAYLOAD) { wolfIP_sock_close(s, server_client_fd); @@ -265,6 +270,7 @@ static void server_cb(int fd, uint16_t events, void *arg) server_ssl = NULL; server_handshake_done = 0; server_done = 1; + printf("TLS server: echoed %d bytes\n", TEST_PAYLOAD); } } @@ -313,247 +319,298 @@ static int server_setup(struct wolfIP *s) } /* ------------------------------------------------------------------------- */ -/* TLS client (wolfIP stack) */ +/* Stack polling */ /* ------------------------------------------------------------------------- */ -static struct wolfIP *client_stack; -static WOLFSSL_CTX *client_ctx = NULL; -static WOLFSSL *client_ssl = NULL; -static int client_fd = -1; -static uint8_t client_tx[TEST_PAYLOAD]; -static uint8_t client_rx[TEST_PAYLOAD]; -static int client_sent = 0; -static int client_recv = 0; - -enum client_state { - CLIENT_STATE_IDLE = 0, - CLIENT_STATE_HANDSHAKE, - CLIENT_STATE_WRITE, - CLIENT_STATE_READ, - CLIENT_STATE_DONE, - CLIENT_STATE_ERROR -}; +static void *poll_thread(void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + while (1) { + uint64_t now = monotonic_ms(); + wolfIP_poll(s, now); + usleep(1000); + if (s == router_stack) { + if (!router_running) + break; + } else if (s == server_stack) { + if (server_done) + break; + } + } + return NULL; +} -static volatile enum client_state client_state = CLIENT_STATE_IDLE; +/* ------------------------------------------------------------------------- */ +/* Linux TLS client */ +/* ------------------------------------------------------------------------- */ -static void client_cb(int fd, uint16_t events, void *arg) +static int run_linux_tls_client(ip4 server_ip) { - struct wolfIP *cli = (struct wolfIP *)arg; - int progress = 1; + struct sockaddr_in remote = { + .sin_family = AF_INET, + .sin_port = htons(4433), + .sin_addr.s_addr = htonl(server_ip), + }; + uint8_t tx[TEST_PAYLOAD]; + uint8_t rx[TEST_PAYLOAD]; + WOLFSSL_CTX *ctx = NULL; + WOLFSSL *ssl = NULL; + int fd = -1; + int ret = -1; + int err = 0; + size_t sent = 0; + size_t received = 0; + int connected = 0; + char remote_str[16]; + + ip4_to_str(server_ip, remote_str, sizeof(remote_str)); + printf("TLS client: connecting to %s:%u\n", remote_str, 4433); + + ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + if (!ctx) { + fprintf(stderr, "linux client: failed to init context\n"); + goto out; + } + wolfSSL_CTX_load_verify_buffer(ctx, ca_der, ca_der_len, SSL_FILETYPE_ASN1); - if (fd != client_fd || client_ssl == NULL) - return; + ssl = wolfSSL_new(ctx); + if (!ssl) { + fprintf(stderr, "linux client: failed to allocate ssl object\n"); + goto out; + } - while (progress) { - progress = 0; - if (client_state == CLIENT_STATE_HANDSHAKE) { - int ret = wolfSSL_connect(client_ssl); - if (ret == SSL_SUCCESS) { - client_state = CLIENT_STATE_WRITE; - progress = 1; - continue; - } else { - int err = wolfSSL_get_error(client_ssl, ret); - if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) - break; - client_state = CLIENT_STATE_ERROR; - break; - } + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + goto out; + } + wolfSSL_set_fd(ssl, fd); + + for (int attempt = 0; attempt < 50; attempt++) { + int cret; + cret = connect(fd, (struct sockaddr *)&remote, sizeof(remote)); + if (cret == 0) { + connected = 1; + printf("TLS client: TCP connected\n"); + break; } - if (client_state == CLIENT_STATE_WRITE && - (events & (CB_EVENT_WRITABLE | CB_EVENT_READABLE))) { - int ret = wolfSSL_write(client_ssl, client_tx + client_sent, - TEST_PAYLOAD - client_sent); - if (ret > 0) { - client_sent += ret; - progress = 1; - if (client_sent == TEST_PAYLOAD) - client_state = CLIENT_STATE_READ; - } else { - int err = wolfSSL_get_error(client_ssl, ret); - if (err != WOLFSSL_ERROR_WANT_WRITE) { - client_state = CLIENT_STATE_ERROR; + if (errno == EINPROGRESS) { + if (wolfSSL_get_using_nonblock(ssl) == 0) + wolfSSL_set_using_nonblock(ssl, 1); + if (poll(&(struct pollfd){ .fd = fd, .events = POLLOUT }, 1, 100) > 0) { + socklen_t errlen = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == 0 && err == 0) { + connected = 1; + printf("TLS client: TCP connect completed after wait\n"); + break; } - break; } + continue; } - if (client_state == CLIENT_STATE_READ && (events & CB_EVENT_READABLE)) { - int ret = wolfSSL_read(client_ssl, client_rx + client_recv, - TEST_PAYLOAD - client_recv); - if (ret > 0) { - client_recv += ret; - progress = 1; - if (client_recv == TEST_PAYLOAD) { - if (memcmp(client_rx, client_tx, TEST_PAYLOAD) == 0) { - client_state = CLIENT_STATE_DONE; - wolfIP_sock_close(cli, client_fd); - wolfip_reset_io(client_ssl); - } else { - client_state = CLIENT_STATE_ERROR; - } - } - } else if (ret == 0) { - client_state = CLIENT_STATE_ERROR; - } else { - int err = wolfSSL_get_error(client_ssl, ret); - if (err != WOLFSSL_ERROR_WANT_READ) - client_state = CLIENT_STATE_ERROR; - break; - } - } else if (client_state == CLIENT_STATE_READ && !(events & CB_EVENT_READABLE)) { - break; + if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == ETIMEDOUT) { + usleep(100000); + continue; } + perror("connect"); + goto out; } - if ((events & CB_EVENT_CLOSED) && client_state != CLIENT_STATE_DONE) - client_state = CLIENT_STATE_ERROR; -} - -static int client_start(struct wolfIP *cli, ip4 server_ip) -{ - struct wolfIP_sockaddr_in remote = { - .sin_family = AF_INET, - .sin_port = ee16(4433), - .sin_addr.s_addr = ee32(server_ip), - }; + if (!connected) { + fprintf(stderr, "linux client: unable to connect after retries\n"); + goto out; + } - client_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); - if (!client_ctx) - return -1; - wolfSSL_SetIO_wolfIP_CTX(client_ctx, cli); - wolfSSL_CTX_load_verify_buffer(client_ctx, ca_der, ca_der_len, SSL_FILETYPE_ASN1); + while (1) { + int hret = wolfSSL_connect(ssl); + if (hret == SSL_SUCCESS) { + printf("TLS client: TLS handshake complete\n"); + break; + } + err = wolfSSL_get_error(ssl, hret); + if (err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE) { + usleep(1000); + continue; + } + fprintf(stderr, "linux client: handshake failed (%d)\n", err); + goto out; + } - client_ssl = wolfSSL_new(client_ctx); - if (!client_ssl) - return -1; + for (size_t i = 0; i < sizeof(tx); i += 16) + memcpy(tx + i, "Test pattern - -", 16); - for (size_t i = 0; i < sizeof(client_tx); i += 16) - memcpy(client_tx + i, "Test pattern - -", 16); + while (sent < sizeof(tx)) { + int wrote = wolfSSL_write(ssl, tx + sent, (int)(sizeof(tx) - sent)); + if (wrote > 0) { + sent += (size_t)wrote; + continue; + } + err = wolfSSL_get_error(ssl, wrote); + if (err == WOLFSSL_ERROR_WANT_WRITE || err == WOLFSSL_ERROR_WANT_READ) { + usleep(1000); + continue; + } + fprintf(stderr, "linux client: write failed (%d)\n", err); + goto out; + } + printf("TLS client: wrote %d bytes\n", TEST_PAYLOAD); - client_fd = wolfIP_sock_socket(cli, AF_INET, IPSTACK_SOCK_STREAM, 0); - if (client_fd < 0) - return -1; - wolfIP_register_callback(cli, client_fd, client_cb, cli); - wolfSSL_SetIO_wolfIP(client_ssl, client_fd); - - client_state = CLIENT_STATE_HANDSHAKE; - { - int conn = wolfIP_sock_connect(cli, client_fd, - (struct wolfIP_sockaddr *)&remote, sizeof(remote)); - if (conn < 0 && conn != -11) { - client_state = CLIENT_STATE_ERROR; - return -1; + while (received < sizeof(rx)) { + int got = wolfSSL_read(ssl, rx + received, (int)(sizeof(rx) - received)); + if (got > 0) { + received += (size_t)got; + continue; } + if (got == 0) { + fprintf(stderr, "linux client: unexpected eof\n"); + goto out; + } + err = wolfSSL_get_error(ssl, got); + if (err == WOLFSSL_ERROR_WANT_READ) { + usleep(1000); + continue; + } + fprintf(stderr, "linux client: read failed (%d)\n", err); + goto out; } - /* Kick-start handshake */ - { - int first = wolfSSL_connect(client_ssl); - if (first != SSL_SUCCESS) { - int err = wolfSSL_get_error(client_ssl, first); - if (!(err == WOLFSSL_ERROR_WANT_READ || err == WOLFSSL_ERROR_WANT_WRITE)) - return -1; + printf("TLS client: read %d bytes\n", TEST_PAYLOAD); + + if (memcmp(tx, rx, sizeof(tx)) != 0) { + fprintf(stderr, "linux client: payload mismatch\n"); + goto out; } + + printf("TLS client: verified %d-byte echo\n", TEST_PAYLOAD); + ret = 0; + +out: + if (ssl) { + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); } - return 0; + if (ctx) + wolfSSL_CTX_free(ctx); + if (fd >= 0) + close(fd); + return ret; } /* ------------------------------------------------------------------------- */ -/* Router */ +/* ARP helper */ /* ------------------------------------------------------------------------- */ -static struct wolfIP *router_stack; -static volatile int router_running = 1; +#define TEST_PACKED __attribute__((packed)) -/* ------------------------------------------------------------------------- */ -/* Stack polling threads */ -/* ------------------------------------------------------------------------- */ +struct TEST_PACKED test_arp_packet { + uint8_t dst[6]; + uint8_t src[6]; + uint16_t type; + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; + uint8_t sma[6]; + uint32_t sip; + uint8_t tma[6]; + uint32_t tip; +}; -static void *poll_thread(void *arg) +static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, + const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip) { - struct wolfIP *s = (struct wolfIP *)arg; - while (1) { - uint64_t now = monotonic_ms(); - wolfIP_poll(s, now); - usleep(1000); - if (s == client_stack) { - static int last_state = -1; - if ((int)client_state != last_state) { - last_state = client_state; - } - } - if (s == router_stack) { - if (!router_running) - break; - } else if (s == server_stack) { - if (server_done) - break; - } else if (s == client_stack) { - if (client_state == CLIENT_STATE_DONE || client_state == CLIENT_STATE_ERROR) { - server_done = 1; - break; - } - } - } - return NULL; + struct test_arp_packet pkt; + memset(&pkt, 0, sizeof(pkt)); + memcpy(pkt.dst, dst_mac, 6); + memcpy(pkt.src, src_mac, 6); + pkt.type = htons(0x0806); + pkt.htype = htons(1); + pkt.ptype = htons(0x0800); + pkt.hlen = 6; + pkt.plen = 4; + pkt.opcode = htons(2); + memcpy(pkt.sma, src_mac, 6); + pkt.sip = htonl(src_ip); + memcpy(pkt.tma, dst_mac, 6); + pkt.tip = htonl(dst_ip); + wolfIP_recv_ex(stack, if_idx, &pkt, sizeof(pkt)); } /* ------------------------------------------------------------------------- */ -/* Main */ +/* Main */ /* ------------------------------------------------------------------------- */ int main(void) { - static const uint8_t mac_client[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0x10}; - static const uint8_t mac_router0[6] = {0x02, 0x00, 0x00, 0x00, 0x01, 0xFE}; static const uint8_t mac_router1[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0xFE}; static const uint8_t mac_server[6] = {0x02, 0x00, 0x00, 0x00, 0x02, 0x10}; - struct mem_link link_client_router; struct mem_link link_router_server; - int ret = 0; + struct wolfIP_ll_dev *tap_dev = NULL; size_t stack_sz; + int ret = 0; + int router_started = 0; + int server_started = 0; + char route_cmd[128] = {0}; + char route_del_cmd[128] = {0}; + struct in_addr host_addr = { .s_addr = htonl(host_ip4) }; + uint8_t host_mac[6]; + char host_str[16]; + char lan_str[16]; + char wan_str[16]; + char srv_str[16]; setvbuf(stdout, NULL, _IONBF, 0); - mem_link_init(&link_client_router); mem_link_init(&link_router_server); wolfSSL_Init(); wolfSSL_Debugging_OFF(); - /* Initialise stacks */ + ip4_to_str(host_ip4, host_str, sizeof(host_str)); + ip4_to_str(router_lan_ip4, lan_str, sizeof(lan_str)); + ip4_to_str(router_wan_ip4, wan_str, sizeof(wan_str)); + ip4_to_str(server_ip4, srv_str, sizeof(srv_str)); + printf("Configuration: host=%s router_lan=%s router_wan=%s server=%s\n", + host_str, lan_str, wan_str, srv_str); + stack_sz = wolfIP_instance_size(); - client_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); router_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); server_stack = (struct wolfIP *)XMALLOC(stack_sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (!client_stack || !router_stack || !server_stack) { + if (!router_stack || !server_stack) { fprintf(stderr, "failed to allocate stacks\n"); ret = 1; goto cleanup; } - XMEMSET(client_stack, 0, stack_sz); XMEMSET(router_stack, 0, stack_sz); XMEMSET(server_stack, 0, stack_sz); - wolfIP_init(client_stack); wolfIP_init(router_stack); wolfIP_init(server_stack); - /* Attach memory links */ - mem_link_attach(wolfIP_getdev(client_stack), &link_client_router, 0, "cli0", mac_client); - mem_link_attach(wolfIP_getdev_ex(router_stack, 0), &link_client_router, 1, "rt0", mac_router0); - mem_link_attach(wolfIP_getdev_ex(router_stack, 1), &link_router_server, 0, "rt1", mac_router1); - mem_link_attach(wolfIP_getdev(server_stack), &link_router_server, 1, "srv0", mac_server); + tap_dev = wolfIP_getdev(router_stack); + if (!tap_dev) { + fprintf(stderr, "failed to obtain router interface 0\n"); + ret = 1; + goto cleanup; + } + if (tap_init(tap_dev, TAP_IFNAME, host_addr.s_addr) < 0) { + perror("tap_init"); + ret = 1; + goto cleanup; + } + memcpy(host_mac, tap_dev->mac, sizeof(host_mac)); + host_mac[5] ^= 1; + + mem_link_attach(wolfIP_getdev_ex(router_stack, 1), &link_router_server, 0, + "rt1", mac_router1); + mem_link_attach(wolfIP_getdev(server_stack), &link_router_server, 1, + "srv0", mac_server); - /* Configure IP addresses */ - wolfIP_ipconfig_set(client_stack, IP4(10,0,1,2), IP4(255,255,255,0), IP4(10,0,1,254)); - wolfIP_ipconfig_set_ex(router_stack, 0, IP4(10,0,1,254), IP4(255,255,255,0), IP4(0,0,0,0)); - wolfIP_ipconfig_set_ex(router_stack, 1, IP4(10,0,2,1), IP4(255,255,255,0), IP4(0,0,0,0)); - wolfIP_ipconfig_set(server_stack, IP4(10,0,2,2), IP4(255,255,255,0), IP4(10,0,2,1)); + wolfIP_ipconfig_set_ex(router_stack, 0, router_lan_ip4, IP4(255,255,255,0), IP4(0,0,0,0)); + wolfIP_ipconfig_set_ex(router_stack, 1, router_wan_ip4, IP4(255,255,255,0), IP4(0,0,0,0)); + wolfIP_ipconfig_set(server_stack, server_ip4, IP4(255,255,255,0), router_wan_ip4); - /* Pre-populate ARP entries so forwarding can proceed immediately */ - inject_arp_reply(client_stack, 0, mac_router0, IP4(10,0,1,254), mac_client, IP4(10,0,1,2)); - inject_arp_reply(router_stack, 0, mac_client, IP4(10,0,1,2), mac_router0, IP4(10,0,1,254)); - inject_arp_reply(router_stack, 1, mac_server, IP4(10,0,2,2), mac_router1, IP4(10,0,2,1)); - inject_arp_reply(server_stack, 0, mac_router1, IP4(10,0,2,1), mac_server, IP4(10,0,2,2)); + inject_arp_reply(router_stack, 1, mac_server, server_ip4, mac_router1, router_wan_ip4); + inject_arp_reply(server_stack, 0, mac_router1, router_wan_ip4, mac_server, server_ip4); + inject_arp_reply(router_stack, 0, host_mac, host_ip4, tap_dev->mac, router_lan_ip4); if (server_setup(server_stack) < 0) { fprintf(stderr, "failed to set up server\n"); @@ -561,70 +618,69 @@ int main(void) goto cleanup; } - if (client_start(client_stack, IP4(10,0,2,2)) < 0) { - fprintf(stderr, "failed to start client\n"); - ret = 1; - goto cleanup; - } - router_running = 1; + server_done = 0; + if (pthread_create(&th_router, NULL, poll_thread, router_stack) != 0) { fprintf(stderr, "failed to start router thread\n"); ret = 1; goto cleanup; } + router_started = 1; + if (pthread_create(&th_server, NULL, poll_thread, server_stack) != 0) { fprintf(stderr, "failed to start server thread\n"); ret = 1; goto cleanup; } - if (pthread_create(&th_client, NULL, poll_thread, client_stack) != 0) { - fprintf(stderr, "failed to start client thread\n"); + server_started = 1; + + snprintf(route_cmd, sizeof(route_cmd), + "ip route add %s dev %s via %u.%u.%u.%u 2>/dev/null", + HOST_ROUTE, TAP_IFNAME, + (router_lan_ip4 >> 24) & 0xFF, + (router_lan_ip4 >> 16) & 0xFF, + (router_lan_ip4 >> 8) & 0xFF, + router_lan_ip4 & 0xFF); + snprintf(route_del_cmd, sizeof(route_del_cmd), + "ip route del %s dev %s 2>/dev/null", + HOST_ROUTE, TAP_IFNAME); + if (route_cmd[0]) + system(route_cmd); + + if (run_linux_tls_client(server_ip4) < 0) { + fprintf(stderr, "linux client: test failed\n"); ret = 1; - goto cleanup; } - cleanup: - pthread_join(th_server, NULL); + router_running = 0; + server_done = 1; - printf("Test result: %s\n", ret == 0 ? "SUCCESS" : "FAIL"); - return ret; -} -#include -#define TEST_PACKED __attribute__((packed)) + if (server_started) + pthread_join(th_server, NULL); + if (router_started) + pthread_join(th_router, NULL); -struct TEST_PACKED test_arp_packet { - uint8_t dst[6]; - uint8_t src[6]; - uint16_t type; - uint16_t htype; - uint16_t ptype; - uint8_t hlen; - uint8_t plen; - uint16_t opcode; - uint8_t sma[6]; - uint32_t sip; - uint8_t tma[6]; - uint32_t tip; -}; + if (route_del_cmd[0]) + system(route_del_cmd); -static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, - const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip) -{ - struct test_arp_packet pkt; - memset(&pkt, 0, sizeof(pkt)); - memcpy(pkt.dst, dst_mac, 6); - memcpy(pkt.src, src_mac, 6); - pkt.type = htons(0x0806); - pkt.htype = htons(1); - pkt.ptype = htons(0x0800); - pkt.hlen = 6; - pkt.plen = 4; - pkt.opcode = htons(2); /* reply */ - memcpy(pkt.sma, src_mac, 6); - pkt.sip = htonl(src_ip); - memcpy(pkt.tma, dst_mac, 6); - pkt.tip = htonl(dst_ip); - wolfIP_recv_ex(stack, if_idx, &pkt, sizeof(pkt)); + if (server_ssl) { + wolfip_reset_io(server_ssl); + wolfSSL_free(server_ssl); + server_ssl = NULL; + } + if (server_ctx) { + wolfSSL_CTX_free(server_ctx); + server_ctx = NULL; + } + if (server_listen_fd >= 0 && server_stack) + wolfIP_sock_close(server_stack, server_listen_fd); + if (router_stack) + XFREE(router_stack, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (server_stack) + XFREE(server_stack, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + printf("Test result: %s\n", ret == 0 ? "SUCCESS" : "FAIL"); + return ret; } diff --git a/src/wolfip.c b/src/wolfip.c index 3e2d3c4a..d94442c7 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -540,6 +540,23 @@ struct arp_neighbor { uint8_t if_idx; }; +#ifndef WOLFIP_ARP_PENDING_MAX +#define WOLFIP_ARP_PENDING_MAX 4 +#endif + +struct arp_pending_entry { + ip4 dest; + uint32_t len; + uint8_t if_idx; + uint8_t frame[LINK_MTU]; +}; + +static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); +#if WOLFIP_ENABLE_FORWARDING +static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct wolfIP_ip_packet *ip, + uint32_t len, const uint8_t *mac, int broadcast); +#endif + #endif struct wolfIP; @@ -583,6 +600,7 @@ struct wolfIP uint64_t last_arp[WOLFIP_MAX_INTERFACES]; struct arp_neighbor neighbors[MAX_NEIGHBORS]; } arp; + struct arp_pending_entry arp_pending[WOLFIP_ARP_PENDING_MAX]; #endif }; @@ -651,8 +669,9 @@ static int wolfIP_forward_interface(struct wolfIP *s, unsigned int in_if, ip4 de continue; if (dest == conf->ip) return -1; - if (ip_is_local_conf(conf, dest)) + if (ip_is_local_conf(conf, dest)) { return i; + } } return -1; } @@ -705,10 +724,12 @@ static unsigned int wolfIP_route_for_ip(struct wolfIP *s, ip4 dest) has_gw_fallback = 1; } } - if (has_gw_fallback) + if (has_gw_fallback) { return gw_fallback; - if (has_non_loop) + } + if (has_non_loop) { return first_non_loop; + } return default_if; } @@ -2257,25 +2278,104 @@ int dhcp_client_init(struct wolfIP *s) /* ARP */ #ifdef ETHERNET +#if WOLFIP_ENABLE_FORWARDING +static void arp_queue_packet(struct wolfIP *s, unsigned int if_idx, ip4 dest, + const struct wolfIP_ip_packet *ip, uint32_t len) +{ + int slot = -1; + int i; + + if (!s || len == 0) + return; + if (len > LINK_MTU) + len = LINK_MTU; + + for (i = 0; i < WOLFIP_ARP_PENDING_MAX; i++) { + if (s->arp_pending[i].dest == dest && s->arp_pending[i].if_idx == if_idx) { + slot = i; + break; + } + if (slot < 0 && s->arp_pending[i].dest == IPADDR_ANY) + slot = i; + } + if (slot < 0) + slot = 0; + + memcpy(s->arp_pending[slot].frame, ip, len); + s->arp_pending[slot].len = len; + s->arp_pending[slot].dest = dest; + s->arp_pending[slot].if_idx = (uint8_t)if_idx; +} + +static void arp_flush_pending(struct wolfIP *s, unsigned int if_idx, ip4 ip) +{ + uint8_t mac[6]; + int i; + + if (!s) + return; + if (arp_lookup(s, if_idx, ip, mac) != 0) + return; + + for (i = 0; i < WOLFIP_ARP_PENDING_MAX; i++) { + struct arp_pending_entry *pending = &s->arp_pending[i]; + if (pending->dest != ip || pending->if_idx != if_idx) + continue; + if (pending->len == 0) { + pending->dest = IPADDR_ANY; + continue; + } + if (pending->len > LINK_MTU) + pending->len = LINK_MTU; + { + struct wolfIP_ip_packet *pkt = + (struct wolfIP_ip_packet *)pending->frame; + + if (pkt->ttl <= 1) { + pending->dest = IPADDR_ANY; + pending->len = 0; + continue; + } + pkt->ttl--; + pkt->csum = 0; + iphdr_set_checksum(pkt); + wolfIP_forward_packet(s, if_idx, pkt, pending->len, mac, 0); + } + pending->dest = IPADDR_ANY; + pending->len = 0; + } +} +#endif /* WOLFIP_ENABLE_FORWARDING */ + static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, const uint8_t *mac) { int i; + int stored = 0; if (!s) return; for (i = 0; i < MAX_NEIGHBORS; i++) { if (s->arp.neighbors[i].ip == ip && s->arp.neighbors[i].if_idx == if_idx) { memcpy(s->arp.neighbors[i].mac, mac, 6); - return; + stored = 1; + break; } } - for (i = 0; i < MAX_NEIGHBORS; i++) { - if (s->arp.neighbors[i].ip == IPADDR_ANY) { - s->arp.neighbors[i].ip = ip; - s->arp.neighbors[i].if_idx = (uint8_t)if_idx; - memcpy(s->arp.neighbors[i].mac, mac, 6); - return; + if (!stored) { + for (i = 0; i < MAX_NEIGHBORS; i++) { + if (s->arp.neighbors[i].ip == IPADDR_ANY) { + s->arp.neighbors[i].ip = ip; + s->arp.neighbors[i].if_idx = (uint8_t)if_idx; + memcpy(s->arp.neighbors[i].mac, mac, 6); + stored = 1; + break; + } } } + if (stored) { +#if WOLFIP_ENABLE_FORWARDING + arp_flush_pending(s, if_idx, ip); +#endif + } } static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip) @@ -2436,23 +2536,21 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ } if (!is_local) { int out_if = wolfIP_forward_interface(s, if_idx, dest); - if (out_if > 0) { + if (out_if >= 0) { uint8_t mac[6]; int broadcast = 0; - uint16_t csum; if (ip->ttl <= 1) { wolfIP_send_ttl_exceeded(s, if_idx, ip); return; } - if (!wolfIP_forward_prepare(s, out_if, dest, mac, &broadcast)) + if (!wolfIP_forward_prepare(s, out_if, dest, mac, &broadcast)) { + arp_queue_packet(s, out_if, dest, ip, len); return; + } ip->ttl--; - csum = ee16(ip->csum); - csum = (uint16_t)(csum + 1); - if (csum == 0) - csum = 0xFFFF; - ip->csum = ee16(csum); + ip->csum = 0; + iphdr_set_checksum(ip); wolfIP_forward_packet(s, out_if, ip, len, broadcast ? NULL : mac, broadcast); return; } From f5f325a70224a65a4f4e78835578a8481aff3d44 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 07:27:14 +0100 Subject: [PATCH 13/25] Fixed unit test --- .github/workflows/linux.yml | 2 +- src/test/unit/unit.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 0939203d..7acef615 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -38,7 +38,7 @@ jobs: - name: Run standalone forwarding test run: | - ./build/test-wolfssl-forwarding + sudo ./build/test-wolfssl-forwarding - name: Run standalone TTL expired test run: | diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 1535131b..152cb9d0 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -837,9 +837,13 @@ START_TEST(test_wolfip_forwarding_basic) ck_assert_mem_eq(fwd->eth.dst, next_hop_mac, 6); ck_assert_mem_eq(fwd->eth.src, s.ll_dev[TEST_SECOND_IF].mac, 6); ck_assert_uint_eq(fwd->ttl, (uint8_t)(initial_ttl - 1)); - expected_csum = (uint16_t)(orig_csum + 1); - if (expected_csum == 0) - expected_csum = 0xFFFF; + { + uint32_t sum = orig_csum + 0x0100; + sum = (sum & 0xFFFF) + (sum >> 16); + expected_csum = (uint16_t)sum; + if (expected_csum == 0) + expected_csum = 0xFFFF; + } ck_assert_uint_eq(ee16(fwd->csum), expected_csum); } END_TEST From fe0c281abe3171b3a0db86a602df63ba54d13b55 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 07:32:00 +0100 Subject: [PATCH 14/25] Add delay in forwarding test client connect --- src/test/test_wolfssl_forwarding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index ad539d55..c218558c 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -363,6 +363,7 @@ static int run_linux_tls_client(ip4 server_ip) int connected = 0; char remote_str[16]; + sleep(1); ip4_to_str(server_ip, remote_str, sizeof(remote_str)); printf("TLS client: connecting to %s:%u\n", remote_str, 4433); From 75e457e15f203633bb83b7984e25f4642289f17d Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 07:40:05 +0100 Subject: [PATCH 15/25] Try expanding arp queue for forwarding --- src/wolfip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wolfip.c b/src/wolfip.c index d94442c7..14229fe8 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -541,7 +541,7 @@ struct arp_neighbor { }; #ifndef WOLFIP_ARP_PENDING_MAX -#define WOLFIP_ARP_PENDING_MAX 4 +#define WOLFIP_ARP_PENDING_MAX 8 #endif struct arp_pending_entry { From f82f0b080b8e17babda8b9866ec898e90a606f32 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 11:26:49 +0100 Subject: [PATCH 16/25] Forward test: removed artificial arp injections --- src/test/test_wolfssl_forwarding.c | 26 +++----------------------- src/wolfip.c | 2 +- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index c218558c..d84d025b 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -516,26 +516,6 @@ struct TEST_PACKED test_arp_packet { uint32_t tip; }; -static void inject_arp_reply(struct wolfIP *stack, unsigned int if_idx, - const uint8_t *src_mac, ip4 src_ip, const uint8_t *dst_mac, ip4 dst_ip) -{ - struct test_arp_packet pkt; - memset(&pkt, 0, sizeof(pkt)); - memcpy(pkt.dst, dst_mac, 6); - memcpy(pkt.src, src_mac, 6); - pkt.type = htons(0x0806); - pkt.htype = htons(1); - pkt.ptype = htons(0x0800); - pkt.hlen = 6; - pkt.plen = 4; - pkt.opcode = htons(2); - memcpy(pkt.sma, src_mac, 6); - pkt.sip = htonl(src_ip); - memcpy(pkt.tma, dst_mac, 6); - pkt.tip = htonl(dst_ip); - wolfIP_recv_ex(stack, if_idx, &pkt, sizeof(pkt)); -} - /* ------------------------------------------------------------------------- */ /* Main */ /* ------------------------------------------------------------------------- */ @@ -609,9 +589,9 @@ int main(void) wolfIP_ipconfig_set_ex(router_stack, 1, router_wan_ip4, IP4(255,255,255,0), IP4(0,0,0,0)); wolfIP_ipconfig_set(server_stack, server_ip4, IP4(255,255,255,0), router_wan_ip4); - inject_arp_reply(router_stack, 1, mac_server, server_ip4, mac_router1, router_wan_ip4); - inject_arp_reply(server_stack, 0, mac_router1, router_wan_ip4, mac_server, server_ip4); - inject_arp_reply(router_stack, 0, host_mac, host_ip4, tap_dev->mac, router_lan_ip4); + //inject_arp_reply(router_stack, 1, mac_server, server_ip4, mac_router1, router_wan_ip4); + //inject_arp_reply(server_stack, 0, mac_router1, router_wan_ip4, mac_server, server_ip4); + //inject_arp_reply(router_stack, 0, host_mac, host_ip4, tap_dev->mac, router_lan_ip4); if (server_setup(server_stack) < 0) { fprintf(stderr, "failed to set up server\n"); diff --git a/src/wolfip.c b/src/wolfip.c index 14229fe8..d94442c7 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -541,7 +541,7 @@ struct arp_neighbor { }; #ifndef WOLFIP_ARP_PENDING_MAX -#define WOLFIP_ARP_PENDING_MAX 8 +#define WOLFIP_ARP_PENDING_MAX 4 #endif struct arp_pending_entry { From 5d71f94ace77da5b25319b1a9c1e7ea02c8362ea Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 11:39:30 +0100 Subject: [PATCH 17/25] Mapped error numbers to defines --- src/port/wolfssl_io.c | 8 ++------ src/wolfip.c | 30 +++++++++++++++--------------- wolfip.h | 7 +++++++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/port/wolfssl_io.c b/src/port/wolfssl_io.c index 172e5f32..dbd1f4be 100644 --- a/src/port/wolfssl_io.c +++ b/src/port/wolfssl_io.c @@ -24,10 +24,6 @@ #include #include -#ifndef EAGAIN -#define EAGAIN (11) -#endif - #ifndef MAX_WOLFIP_CTX #define MAX_WOLFIP_CTX 8 /* Default value */ @@ -76,7 +72,7 @@ static int wolfIP_io_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx) return WOLFSSL_CBIO_ERR_GENERAL; ret = wolfIP_sock_recv(desc->stack, desc->fd, buf, sz, 0); - if (ret == -EAGAIN || ret == -1) + if (ret == -WOLFIP_EAGAIN || ret == -1) return WOLFSSL_CBIO_ERR_WANT_READ; if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; @@ -93,7 +89,7 @@ static int wolfIP_io_send(WOLFSSL* ssl, char* buf, int sz, void* ctx) return WOLFSSL_CBIO_ERR_GENERAL; ret = wolfIP_sock_send(desc->stack, desc->fd, buf, sz, 0); - if (ret == -EAGAIN || ret == -1) + if (ret == -WOLFIP_EAGAIN || ret == -1) return WOLFSSL_CBIO_ERR_WANT_WRITE; if (ret <= 0) return WOLFSSL_CBIO_ERR_CONN_CLOSE; diff --git a/src/wolfip.c b/src/wolfip.c index d94442c7..cf579f49 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -335,7 +335,7 @@ static int queue_pop(struct queue *q, void *data, uint32_t len) { uint32_t q_len = queue_len(q); if (q_len == 0) - return -11; + return -WOLFIP_EAGAIN; if (len > q_len) len = q_len; memcpy(data, (const uint8_t *)q->data + q->tail, len); @@ -1547,7 +1547,7 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad const struct wolfIP_sockaddr_in *sin; unsigned int if_idx; if (!addr) - return -2; + return -WOLFIP_EINVAL; sin = (const struct wolfIP_sockaddr_in *)addr; if (sockfd & MARK_UDP_SOCKET) { struct ipconf *conf; @@ -1572,9 +1572,9 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad if (ts->sock.tcp.state == TCP_ESTABLISHED) return 0; if (ts->sock.tcp.state == TCP_SYN_SENT) - return -11; /* Call again */ + return -WOLFIP_EAGAIN; /* Call again */ if ((sin->sin_family != AF_INET) || (addrlen < sizeof(struct wolfIP_sockaddr_in))) - return -2; + return -WOLFIP_EINVAL; if (ts->sock.tcp.state == TCP_CLOSED) { struct ipconf *conf; ts->sock.tcp.state = TCP_SYN_SENT; @@ -1597,9 +1597,9 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad ts->src_port += 1024; ts->dst_port = ee16(sin->sin_port); tcp_send_syn(ts, 0x02); - return -11; + return -WOLFIP_EAGAIN; } - return -2; + return -WOLFIP_EINVAL; } int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, socklen_t *addrlen) @@ -1645,7 +1645,7 @@ int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *add ts->sock.tcp.seq = wolfIP_getrandom(); return (newts - s->tcpsockets) | MARK_TCP_SOCKET; } else if (ts->sock.tcp.state == TCP_LISTEN) { - return -11; + return -WOLFIP_EAGAIN; } } return -1;; @@ -1703,7 +1703,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len ts->sock.tcp.seq += payload_len; } if (sent == 0) - return -11; + return -WOLFIP_EAGAIN; else return sent; } else if (sockfd & MARK_UDP_SOCKET) { @@ -1725,7 +1725,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (len > WI_IP_MTU - IP_HEADER_LEN - UDP_HEADER_LEN) return -1; /* Fragmentation not supported */ if (fifo_space(&ts->sock.udp.txbuf) < len) - return -11; + return -WOLFIP_EAGAIN; if (ts->src_port == 0) { ts->src_port = (uint16_t)(wolfIP_getrandom() & 0xFFFF); if (ts->src_port < 1024) @@ -1796,7 +1796,7 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in return -1; if (addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); if (fifo_len(&ts->sock.udp.rxbuf) == 0) - return -11; + return -WOLFIP_EAGAIN; desc = fifo_peek(&ts->sock.udp.rxbuf); udp = (struct wolfIP_udp_datagram *)(ts->rxmem + desc->pos + sizeof(*desc)); if (sin) { @@ -1830,20 +1830,20 @@ int wolfIP_sock_close(struct wolfIP *s, int sockfd) if (ts->sock.tcp.state == TCP_ESTABLISHED) { ts->sock.tcp.state = TCP_FIN_WAIT_1; tcp_send_finack(ts); - return -11; + return -WOLFIP_EAGAIN; } else if (ts->sock.tcp.state == TCP_CLOSE_WAIT) { ts->sock.tcp.state = TCP_LAST_ACK; tcp_send_finack(ts); - return -11; + return -WOLFIP_EAGAIN; } else if (ts->sock.tcp.state == TCP_CLOSING) { ts->sock.tcp.state = TCP_TIME_WAIT; - return -11; + return -WOLFIP_EAGAIN; } else if (ts->sock.tcp.state == TCP_FIN_WAIT_1) { ts->sock.tcp.state = TCP_CLOSING; - return -11; + return -WOLFIP_EAGAIN; } else if (ts->sock.tcp.state == TCP_FIN_WAIT_2) { ts->sock.tcp.state = TCP_TIME_WAIT; - return -11; + return -WOLFIP_EAGAIN; } else if (ts->sock.tcp.state != TCP_CLOSED) { ts->sock.tcp.state = TCP_CLOSED; close_socket(ts); diff --git a/wolfip.h b/wolfip.h index c9c02422..f89e5d29 100644 --- a/wolfip.h +++ b/wolfip.h @@ -12,6 +12,13 @@ typedef uint32_t ip4; #define ee32(x) __builtin_bswap32(x) #define DEBUG +#ifndef WOLFIP_EINVAL +#define WOLFIP_EINVAL (22) +#endif +#ifndef WOLFIP_EAGAIN +#define WOLFIP_EAGAIN (11) +#endif + #ifdef DEBUG #include From 84ac04374d73d32bdcfb727ead3a23e45f67b6fc Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 11:51:57 +0100 Subject: [PATCH 18/25] more stray "-11" instead of EINVAL --- src/http/httpd.c | 2 +- src/port/posix/bsd_socket.c | 4 ++-- src/test/test_linux_dhcp_dns.c | 2 +- src/test/test_linux_eventloop.c | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/http/httpd.c b/src/http/httpd.c index 42d2061e..2ca7ca15 100644 --- a/src/http/httpd.c +++ b/src/http/httpd.c @@ -410,7 +410,7 @@ static void http_recv_cb(int sd, uint16_t event, void *arg) { } } else { ret = wolfIP_sock_recv(hc->httpd->ipstack, sd, buf, sizeof(buf), 0); - if (ret == -11) + if (ret == -WOLFIP_EAGAIN) return; } if (ret <= 0) diff --git a/src/port/posix/bsd_socket.c b/src/port/posix/bsd_socket.c index 6137d347..ec825178 100644 --- a/src/port/posix/bsd_socket.c +++ b/src/port/posix/bsd_socket.c @@ -101,10 +101,10 @@ static int (*host_fcntl) (int fd, int cmd, ...); int __wolfip_retval; \ do { \ __wolfip_retval = wolfIP_sock_##call(IPSTACK, fd, ## __VA_ARGS__); \ - if (__wolfip_retval == -11) { \ + if (__wolfip_retval == -EAGAIN) { \ usleep(1000); \ } \ - } while (__wolfip_retval == -11); \ + } while (__wolfip_retval == -EAGAIN); \ if (__wolfip_retval < 0) { \ errno = __wolfip_retval; \ pthread_mutex_unlock(&wolfIP_mutex); \ diff --git a/src/test/test_linux_dhcp_dns.c b/src/test/test_linux_dhcp_dns.c index df0694a3..3133f367 100644 --- a/src/test/test_linux_dhcp_dns.c +++ b/src/test/test_linux_dhcp_dns.c @@ -75,7 +75,7 @@ static void client_cb(int fd, uint16_t event, void *arg) while ((total_r < total_w) && (event & CB_EVENT_READABLE)) { ret = wolfIP_sock_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, 0, NULL, NULL); if (ret < 0){ - if (ret != -11) { + if (ret != -EAGAIN) { printf("Client read: %d\n", ret); } return; diff --git a/src/test/test_linux_eventloop.c b/src/test/test_linux_eventloop.c index 0ddcf99b..1587b59b 100644 --- a/src/test/test_linux_eventloop.c +++ b/src/test/test_linux_eventloop.c @@ -58,7 +58,7 @@ static void server_cb(int fd, uint16_t event, void *arg) } } else if ((fd == client_fd) && (event & CB_EVENT_READABLE )) { ret = wolfIP_sock_recvfrom((struct wolfIP *)arg, client_fd, buf, sizeof(buf), 0, NULL, NULL); - if (ret != -11) { + if (ret != -EAGAIN) { if (ret < 0) { printf("Recv error: %d\n", ret); wolfIP_sock_close((struct wolfIP *)arg, client_fd); @@ -83,7 +83,7 @@ static void server_cb(int fd, uint16_t event, void *arg) } if ((!closed) && (tot_sent < tot_recv)) { snd_ret = wolfIP_sock_sendto((struct wolfIP *)arg, client_fd, buf + tot_sent, tot_recv - tot_sent, 0, NULL, 0); - if (snd_ret != -11) { + if (snd_ret != -EAGAIN) { if (snd_ret < 0) { printf("Send error: %d\n", snd_ret); wolfIP_sock_close((struct wolfIP *)arg, client_fd); @@ -141,7 +141,7 @@ static void client_cb(int fd, uint16_t event, void *arg) while ((total_r < total_w) && (event & CB_EVENT_READABLE)) { ret = wolfIP_sock_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, 0, NULL, NULL); if (ret < 0){ - if (ret != -11) { + if (ret != -EAGAIN) { printf("Client read: %d\n", ret); } return; From 67b8c3be91316eda8c3b8b5a1db907a84802dbeb Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 12:04:04 +0100 Subject: [PATCH 19/25] Reviewer's comment: Check fd boundary in connect/sendto --- src/wolfip.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index cf579f49..5e177b0b 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -1546,11 +1546,14 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad struct tsocket *ts; const struct wolfIP_sockaddr_in *sin; unsigned int if_idx; - if (!addr) + if ((!addr)|| (sockfd < 0)) return -WOLFIP_EINVAL; sin = (const struct wolfIP_sockaddr_in *)addr; if (sockfd & MARK_UDP_SOCKET) { struct ipconf *conf; + if ((sockfd & ~MARK_UDP_SOCKET) >= MAX_UDPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; ts->dst_port = ee16(sin->sin_port); ts->remote_ip = ee32(sin->sin_addr.s_addr); @@ -1566,8 +1569,12 @@ int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockad } return 0; } + if ((sockfd & MARK_TCP_SOCKET) == 0) - return -1; + return -WOLFIP_EINVAL; + if ((sockfd & ~MARK_TCP_SOCKET)>= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state == TCP_ESTABLISHED) return 0; @@ -1671,9 +1678,13 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len if (sockfd & MARK_TCP_SOCKET) { size_t sent = 0; struct tcp_opt_ts *tsopt = (struct tcp_opt_ts *)tcp->data; + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state != TCP_ESTABLISHED) return -1; + while (sent < len) { uint32_t payload_len = len - sent; if (payload_len > (TCP_MSS - TCP_OPTIONS_LEN)) @@ -1710,6 +1721,9 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len const struct wolfIP_sockaddr_in *sin = (const struct wolfIP_sockaddr_in *)dest_addr; unsigned int if_idx; struct ipconf *conf; + if ((sockfd & ~MARK_UDP_SOCKET) >= MAX_UDPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; if ((ts->dst_port == 0) && (dest_addr == NULL)) return -1; From b0287f346506edf68eae3f9e1c68f1df04a8455f Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 12:45:13 +0100 Subject: [PATCH 20/25] More boundary checks --- src/wolfip.c | 79 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 5e177b0b..67487dc8 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -1616,12 +1616,17 @@ int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *add struct tsocket *newts; if ((addr) && (!(addrlen) || (*addrlen < sizeof(struct wolfIP_sockaddr_in)))) - return -1; + return -WOLFIP_EINVAL; + + if (sockfd < 0) + return -WOLFIP_EINVAL; if (addr && addrlen) *addrlen = sizeof(struct wolfIP_sockaddr_in); if (sockfd & MARK_TCP_SOCKET) { + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if ((ts->sock.tcp.state != TCP_SYN_RCVD) && (ts->sock.tcp.state != TCP_LISTEN)) return -1; @@ -1655,7 +1660,7 @@ int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *add return -WOLFIP_EAGAIN; } } - return -1;; + return -WOLFIP_EINVAL; } int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags, @@ -1670,7 +1675,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len (void)flags; if (sockfd < 0) - return -1; + return -WOLFIP_EINVAL; if ((!buf) || (len == 0)) return -1; @@ -1771,7 +1776,7 @@ int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len int wolfIP_sock_send(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags) { return wolfIP_sock_sendto(s, sockfd, buf, len, flags, NULL, 0); -} +} int wolfIP_sock_write(struct wolfIP *s, int sockfd, const void *buf, size_t len) { @@ -1787,7 +1792,12 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in struct tsocket *ts; (void)flags; + if (sockfd < 0) + return -WOLFIP_EINVAL; + if (sockfd & MARK_TCP_SOCKET) { + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state == TCP_CLOSE_WAIT) { @@ -1805,6 +1815,8 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in } } else if (sockfd & MARK_UDP_SOCKET) { struct wolfIP_sockaddr_in *sin = (struct wolfIP_sockaddr_in *)src_addr; + if ((sockfd & ~MARK_UDP_SOCKET) >= MAX_UDPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; if (sin && *addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; @@ -1824,7 +1836,8 @@ int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, in memcpy(buf, udp->data, seg_len); fifo_pop(&ts->sock.udp.rxbuf); return seg_len; - } else return -1; + } else + return -WOLFIP_EINVAL; } int wolfIP_sock_recv(struct wolfIP *s, int sockfd, void *buf, size_t len, int flags) @@ -1839,8 +1852,13 @@ int wolfIP_sock_read(struct wolfIP *s, int sockfd, void *buf, size_t len) int wolfIP_sock_close(struct wolfIP *s, int sockfd) { + if (sockfd < 0) + return -WOLFIP_EINVAL; if (sockfd & MARK_TCP_SOCKET) { - struct tsocket *ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; + struct tsocket *ts; + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state == TCP_ESTABLISHED) { ts->sock.tcp.state = TCP_FIN_WAIT_1; tcp_send_finack(ts); @@ -1864,7 +1882,10 @@ int wolfIP_sock_close(struct wolfIP *s, int sockfd) return 0; } else return -1; } else if (sockfd & MARK_UDP_SOCKET) { - struct tsocket *ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; + struct tsocket *ts; + if ((sockfd & ~MARK_UDP_SOCKET) >= MAX_UDPSOCKETS) + return -WOLFIP_EINVAL; + ts = &s->tcpsockets[sockfd & ~MARK_UDP_SOCKET]; close_socket(ts); return 0; } else return -1; @@ -1873,8 +1894,19 @@ int wolfIP_sock_close(struct wolfIP *s, int sockfd) int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen) { - struct tsocket *ts = &s->tcpsockets[sockfd]; - struct wolfIP_sockaddr_in *sin = (struct wolfIP_sockaddr_in *)addr; + struct tsocket *ts; + struct wolfIP_sockaddr_in *sin; + + if ((!addr) || (sockfd < 0)) + return -WOLFIP_EINVAL; + + if ((sockfd & MARK_TCP_SOCKET) == 0) + return -1; + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; + + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; + sin = (struct wolfIP_sockaddr_in *)addr; if (!sin || *addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; sin->sin_family = AF_INET; @@ -1893,7 +1925,11 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr unsigned int if_idx; if (!sin || addrlen < sizeof(struct wolfIP_sockaddr_in)) - return -1; + return -WOLFIP_EINVAL; + + if (sockfd < 0) + return -WOLFIP_EINVAL; + bind_ip = ee32(sin->sin_addr.s_addr); if_idx = wolfIP_if_for_local_ip(s, bind_ip, &match); conf = wolfIP_ipconf_at(s, if_idx); @@ -1901,6 +1937,8 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr return -1; if (sockfd & MARK_TCP_SOCKET) { + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state != TCP_CLOSED) return -1; @@ -1919,6 +1957,8 @@ int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr ts->src_port = ee16(sin->sin_port); return 0; } else if (sockfd & MARK_UDP_SOCKET) { + if ((sockfd & ~MARK_UDP_SOCKET) >= MAX_UDPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; if (ts->src_port != 0) return -1; @@ -1944,9 +1984,15 @@ int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog) { struct tsocket *ts; (void)backlog; + if (sockfd < 0) + return -WOLFIP_EINVAL; if (sockfd & MARK_TCP_SOCKET) { + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; - } else return -1; + } else + return -1; + if (ts->sock.tcp.state != TCP_CLOSED) return -1; ts->sock.tcp.state = TCP_LISTEN; @@ -1955,8 +2001,17 @@ int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog) int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen) { - struct tsocket *ts = &s->tcpsockets[sockfd]; + struct tsocket *ts; struct wolfIP_sockaddr_in *sin = (struct wolfIP_sockaddr_in *)addr; + if (sockfd < 0) + return -WOLFIP_EINVAL; + if ((sockfd & MARK_TCP_SOCKET) == 0) { + return -1; + } + if ((sockfd & ~MARK_TCP_SOCKET) >= MAX_TCPSOCKETS) + return -WOLFIP_EINVAL; + + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (!sin || *addrlen < sizeof(struct wolfIP_sockaddr_in)) return -1; sin->sin_family = AF_INET; From daeb5c1a4b49f4e51b9661f2d54a77bb358177db Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 12:48:02 +0100 Subject: [PATCH 21/25] Added compile time sanity check on limits --- wolfip.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/wolfip.h b/wolfip.h index f89e5d29..3109da9c 100644 --- a/wolfip.h +++ b/wolfip.h @@ -50,10 +50,23 @@ struct ipconf { /* Socket interface */ #define MARK_TCP_SOCKET 0x100 /* Mark a socket as TCP */ #define MARK_UDP_SOCKET 0x200 /* Mark a socket as UDP */ + + +/* Compile-time sanity check for socket marks & number of sockets */ #if (MARK_TCP_SOCKET >= MARK_UDP_SOCKET) #error "MARK_TCP_SOCKET must be less than MARK_UDP_SOCKET" #endif +#if MAX_TCPSOCKETS > 255 +#error "MAX_TCPSOCKETS must be less than 256" +#endif + +#if MAX_UDPSOCKETS > 255 +#error "MAX_UDPSOCKETS must be less than 256" +#endif + + + #ifndef WOLF_POSIX #define IPSTACK_SOCK_STREAM 1 From 729abe8b5b54848ddaca7a6d1b84a1486cc0b2f3 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 20:04:03 +0100 Subject: [PATCH 22/25] Fixed TTL expired. Traceroute now works --- src/wolfip.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 67487dc8..3a1277c9 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -414,11 +414,23 @@ union transport_pseudo_header { }; /* ICMP */ + +#define TTL_EXCEEDED_ORIG_PACKET_SIZE (28) +#define ICMP_TTL_EXCEEDED_SIZE (36) + struct PACKED wolfIP_icmp_packet { struct wolfIP_ip_packet ip; uint8_t type, code; uint16_t csum; - uint8_t data[0]; + uint8_t unused[4]; +}; + +struct PACKED wolfIP_icmp_ttl_exceeded_packet { + struct wolfIP_ip_packet ip; + uint8_t type, code; + uint16_t csum; + uint8_t unused[4]; + uint8_t orig_packet[TTL_EXCEEDED_ORIG_PACKET_SIZE]; }; /* DHCP */ @@ -764,7 +776,7 @@ static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int * } #ifdef ETHERNET -static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp); +static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp, uint16_t len); static void iphdr_set_checksum(struct wolfIP_ip_packet *ip); static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, uint16_t type); @@ -778,23 +790,26 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); - struct wolfIP_icmp_packet icmp; + struct wolfIP_icmp_ttl_exceeded_packet icmp; if (!ll || !ll->send) return; memset(&icmp, 0, sizeof(icmp)); icmp.type = ICMP_TTL_EXCEEDED; - icmp.csum = ee16(icmp_checksum(&icmp)); + memcpy(icmp.orig_packet, ((uint8_t *)orig) + ETH_HEADER_LEN, + TTL_EXCEEDED_ORIG_PACKET_SIZE); + icmp.csum = ee16(icmp_checksum((struct wolfIP_icmp_packet *)&icmp, + ICMP_TTL_EXCEEDED_SIZE)); icmp.ip.ver_ihl = 0x45; icmp.ip.ttl = 64; icmp.ip.proto = WI_IPPROTO_ICMP; icmp.ip.id = ee16(s->ipcounter++); - icmp.ip.len = ee16(IP_HEADER_LEN + ICMP_HEADER_LEN); - icmp.ip.src = orig->dst; + icmp.ip.len = ee16(IP_HEADER_LEN + ICMP_TTL_EXCEEDED_SIZE); + icmp.ip.src = ee32(wolfIP_ipconf_at(s, if_idx)->ip); icmp.ip.dst = orig->src; icmp.ip.csum = 0; iphdr_set_checksum(&icmp.ip); eth_output_add_header(s, if_idx, orig->eth.src, &icmp.ip.eth, ETH_TYPE_IP); - ll->send(ll, &icmp, sizeof(struct wolfIP_icmp_packet)); + ll->send(ll, &icmp, sizeof(icmp)); } #else static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) @@ -1093,12 +1108,12 @@ static uint16_t transport_checksum(union transport_pseudo_header *ph, void *_dat return ~sum; } -static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp) +static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp, uint16_t len) { uint32_t sum = 0; uint32_t i = 0; uint16_t *ptr = (uint16_t *)(&icmp->type); - for (i = 0; i < ICMP_HEADER_LEN / 2; i++) { + for (i = 0; i < len / 2; i++) { sum += ee16(ptr[i]); } while (sum >> 16) { From ae321041cf858d780b39b436a382431ecb5b6ab7 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 20:12:09 +0100 Subject: [PATCH 23/25] Improved/fixed test for TTL exceeded --- src/test/test_ttl_expired.c | 69 ++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/src/test/test_ttl_expired.c b/src/test/test_ttl_expired.c index e1fbb115..a29ce07e 100644 --- a/src/test/test_ttl_expired.c +++ b/src/test/test_ttl_expired.c @@ -52,6 +52,7 @@ #define ROUTER_GW IP4(10,0,1,254) #define ROUTER_IF1 IP4(10,0,2,1) #define DEST_IP IP4(10,0,2,200) +#define TTL_EXCEEDED_DATA_LEN 28 #define PACKED __attribute__((packed)) @@ -82,6 +83,14 @@ struct icmp_echo { uint16_t seq; } PACKED; +struct icmp_ttl_exceeded { + uint8_t type; + uint8_t code; + uint16_t csum; + uint8_t unused[4]; + uint8_t data[TTL_EXCEEDED_DATA_LEN]; +} PACKED; + static uint16_t ones_csum(const void *buf, size_t len) { const uint16_t *p = buf; @@ -344,19 +353,63 @@ int main(void) mem_host_send(&link, frame, sizeof(struct eth_hdr) + sizeof(struct ipv4_hdr) + sizeof(struct icmp_echo)); n = mem_host_recv(&link, frame, sizeof(frame), 1000); - if (n > 0) { + if (n <= 0) { + fprintf(stderr, "No TTL expired response\n"); + goto cleanup; + } + + { struct eth_hdr *eth = (struct eth_hdr *)frame; struct ipv4_hdr *ip = (struct ipv4_hdr *)(frame + sizeof(*eth)); - struct icmp_echo *icmp = (struct icmp_echo *)(frame + sizeof(*eth) + sizeof(*ip)); - if (ntohs(eth->type) == ETH_P_IP && ip->proto == 1 && icmp->type == 11 && - ntohl(ip->src) == DEST_IP && ntohl(ip->dst) == HOST_IP) { - printf("TTL expired response received\n"); - rc = EXIT_SUCCESS; + struct icmp_ttl_exceeded *icmp = (struct icmp_ttl_exceeded *)(frame + sizeof(*eth) + sizeof(*ip)); + struct ipv4_hdr *orig_ip = (struct ipv4_hdr *)icmp->data; + struct icmp_echo *orig_icmp = (struct icmp_echo *)(icmp->data + sizeof(*orig_ip)); + size_t expected_len = sizeof(*eth) + sizeof(*ip) + sizeof(*icmp); + uint16_t ip_len = ntohs(ip->len); + uint16_t expected_ip_len = (uint16_t)(sizeof(*ip) + sizeof(*icmp)); + + if ((size_t)n != expected_len) { + fprintf(stderr, "Unexpected frame length: got %d expected %zu\n", n, expected_len); + goto mismatch; } - } else { - fprintf(stderr, "No TTL expired response\n"); + if (ntohs(eth->type) != ETH_P_IP || + memcmp(eth->dst, host_mac, sizeof(host_mac)) != 0 || + memcmp(eth->src, router0_mac, sizeof(router0_mac)) != 0) { + fprintf(stderr, "Ethernet header mismatch\n"); + goto mismatch; + } + if (ip->ver_ihl != 0x45 || ip->proto != 1 || ip->ttl != 64 || + ip_len != expected_ip_len || + ntohl(ip->src) != ROUTER_IF0 || ntohl(ip->dst) != HOST_IP) { + fprintf(stderr, "IPv4 header mismatch\n"); + goto mismatch; + } + if (icmp->type != 11 || icmp->code != 0 || + memcmp(icmp->unused, "\x00\x00\x00\x00", sizeof(icmp->unused)) != 0) { + fprintf(stderr, "ICMP header mismatch\n"); + goto mismatch; + } + if (orig_ip->ver_ihl != 0x45 || orig_ip->proto != 1 || + ntohl(orig_ip->src) != HOST_IP || ntohl(orig_ip->dst) != DEST_IP || + ntohs(orig_ip->len) != sizeof(*orig_ip) + sizeof(struct icmp_echo) || + ntohs(orig_ip->id) != 0x1234 || orig_ip->ttl != 1) { + fprintf(stderr, "Embedded IPv4 header mismatch\n"); + goto mismatch; + } + if (orig_icmp->type != 8 || orig_icmp->code != 0 || + ntohs(orig_icmp->id) != 0x0101 || ntohs(orig_icmp->seq) != 1) { + fprintf(stderr, "Embedded ICMP header mismatch\n"); + goto mismatch; + } + printf("TTL expired response received\n"); + rc = EXIT_SUCCESS; + goto cleanup; } +mismatch: + fprintf(stderr, "TTL expired response mismatch\n"); + +cleanup: running = 0; pthread_join(th, NULL); return rc; From 9a884e6ae7ef1f80523d191e555f0849c07b5372 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 20:17:51 +0100 Subject: [PATCH 24/25] Update/fix expected fields in unit test --- src/test/unit/unit.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/test/unit/unit.c b/src/test/unit/unit.c index 152cb9d0..5efbb7da 100644 --- a/src/test/unit/unit.c +++ b/src/test/unit/unit.c @@ -852,7 +852,7 @@ START_TEST(test_wolfip_forwarding_ttl_expired) { struct wolfIP s; struct wolfIP_ip_packet frame; - struct wolfIP_icmp_packet *icmp; + struct wolfIP_icmp_ttl_exceeded_packet *icmp; uint8_t src_mac[6] = {0x52, 0x54, 0x00, 0xAA, 0xBB, 0xCC}; uint8_t iface1_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x03}; uint32_t dest_ip = 0xC0A80110; @@ -881,11 +881,22 @@ START_TEST(test_wolfip_forwarding_ttl_expired) wolfIP_recv_ex(&s, TEST_PRIMARY_IF, &frame, sizeof(frame)); - ck_assert_uint_eq(last_frame_sent_size, sizeof(struct wolfIP_icmp_packet)); - icmp = (struct wolfIP_icmp_packet *)last_frame_sent; + ck_assert_uint_eq(last_frame_sent_size, + sizeof(struct wolfIP_icmp_ttl_exceeded_packet)); + icmp = (struct wolfIP_icmp_ttl_exceeded_packet *)last_frame_sent; ck_assert_uint_eq(icmp->type, ICMP_TTL_EXCEEDED); + ck_assert_uint_eq(icmp->code, 0); + ck_assert_mem_eq(icmp->unused, "\x00\x00\x00\x00", sizeof(icmp->unused)); ck_assert_mem_eq(icmp->ip.eth.dst, src_mac, 6); ck_assert_mem_eq(icmp->ip.eth.src, s.ll_dev[TEST_PRIMARY_IF].mac, 6); + ck_assert_uint_eq(icmp->ip.ttl, 64); + ck_assert_uint_eq(ee16(icmp->ip.len), + (uint16_t)(IP_HEADER_LEN + ICMP_TTL_EXCEEDED_SIZE)); + ck_assert_uint_eq(ee32(icmp->ip.src), s.ipconf[TEST_PRIMARY_IF].ip); + ck_assert_uint_eq(ee32(icmp->ip.dst), ee32(frame.src)); + ck_assert_mem_eq(icmp->orig_packet, + ((uint8_t *)&frame) + ETH_HEADER_LEN, + TTL_EXCEEDED_ORIG_PACKET_SIZE); ck_assert_uint_eq(frame.ttl, 1); /* original packet should remain unchanged */ } END_TEST From bdb734b2f7b250fe35fe5a16c1d0c0e00157bfaf Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 5 Nov 2025 21:37:23 +0100 Subject: [PATCH 25/25] Cleanup dead code --- src/test/test_wolfssl_forwarding.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/test_wolfssl_forwarding.c b/src/test/test_wolfssl_forwarding.c index d84d025b..e1ef5fe1 100644 --- a/src/test/test_wolfssl_forwarding.c +++ b/src/test/test_wolfssl_forwarding.c @@ -589,10 +589,6 @@ int main(void) wolfIP_ipconfig_set_ex(router_stack, 1, router_wan_ip4, IP4(255,255,255,0), IP4(0,0,0,0)); wolfIP_ipconfig_set(server_stack, server_ip4, IP4(255,255,255,0), router_wan_ip4); - //inject_arp_reply(router_stack, 1, mac_server, server_ip4, mac_router1, router_wan_ip4); - //inject_arp_reply(server_stack, 0, mac_router1, router_wan_ip4, mac_server, server_ip4); - //inject_arp_reply(router_stack, 0, host_mac, host_ip4, tap_dev->mac, router_lan_ip4); - if (server_setup(server_stack) < 0) { fprintf(stderr, "failed to set up server\n"); ret = 1;