From 21fbf9cdc5239855da7e27e9c5d6e9c28705c21a Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Wed, 17 Dec 2025 17:38:57 -0300 Subject: [PATCH] add more tests, fix NDP --- mongoose.c | 10 +++-- src/net_builtin.c | 10 +++-- test/mip_test.c | 112 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index 756909a0..256cfb1b 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5525,7 +5525,7 @@ static void tx_ndp_na(struct mg_tcpip_if *ifp, uint8_t *l2_dst, memcpy(data + 4, ip_src, 16); // Target address data[20] = 2; // 4.6.1, target hwaddr data[21] = mg_l2_ip6put(ifp->l2type, l2, data + 22); // option length / 8 - tx_icmp6(ifp, l2_dst, ip_src, ip_dst, 136, 0, data, 20 + 8 * data[21]); + tx_icmp6(ifp, l2_dst, ip_src, ip_dst, 136, 0, data, 20 + (size_t)(8 * data[21])); } static void onstate6change(struct mg_tcpip_if *ifp); @@ -5565,12 +5565,14 @@ static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (pkt->pay.len < sizeof(target)) return; memcpy(target, pkt->pay.buf + 4, sizeof(target)); if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { + uint64_t req[2]; // requester address uint8_t l2[sizeof(struct mg_l2addr)]; uint8_t len, *opts = (uint8_t *) pkt->pay.buf + 20; - if (*opts++ != 2) return; // no target hwaddr + if (*opts++ != 1) return; // no requester hwaddr (source) len = *opts++; // check valid hwaddr and get it if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return; - tx_ndp_na(ifp, l2, target, pkt->ip6->src, true, ifp->mac); + req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit + tx_ndp_na(ifp, l2, target, req, true, ifp->mac); } } @@ -5743,7 +5745,7 @@ static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) { return; // safety net for lousy networks if (plen > room) plen = room; // Copy (truncated) RX payload to TX // Echo Reply, 4.2 - tx_icmp6(ifp, l2addr, pkt->ip6->dst, pkt->ip6->src, 129, 0, + tx_icmp6(ifp, l2addr, target, ips.addr.ip6, 129, 0, pkt->pay.buf, plen); } } break; diff --git a/src/net_builtin.c b/src/net_builtin.c index 537541b0..ba584ee0 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -714,7 +714,7 @@ static void tx_ndp_na(struct mg_tcpip_if *ifp, uint8_t *l2_dst, memcpy(data + 4, ip_src, 16); // Target address data[20] = 2; // 4.6.1, target hwaddr data[21] = mg_l2_ip6put(ifp->l2type, l2, data + 22); // option length / 8 - tx_icmp6(ifp, l2_dst, ip_src, ip_dst, 136, 0, data, 20 + 8 * data[21]); + tx_icmp6(ifp, l2_dst, ip_src, ip_dst, 136, 0, data, 20 + (size_t)(8 * data[21])); } static void onstate6change(struct mg_tcpip_if *ifp); @@ -754,12 +754,14 @@ static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (pkt->pay.len < sizeof(target)) return; memcpy(target, pkt->pay.buf + 4, sizeof(target)); if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) { + uint64_t req[2]; // requester address uint8_t l2[sizeof(struct mg_l2addr)]; uint8_t len, *opts = (uint8_t *) pkt->pay.buf + 20; - if (*opts++ != 2) return; // no target hwaddr + if (*opts++ != 1) return; // no requester hwaddr (source) len = *opts++; // check valid hwaddr and get it if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return; - tx_ndp_na(ifp, l2, target, pkt->ip6->src, true, ifp->mac); + req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit + tx_ndp_na(ifp, l2, target, req, true, ifp->mac); } } @@ -932,7 +934,7 @@ static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) { return; // safety net for lousy networks if (plen > room) plen = room; // Copy (truncated) RX payload to TX // Echo Reply, 4.2 - tx_icmp6(ifp, l2addr, pkt->ip6->dst, pkt->ip6->src, 129, 0, + tx_icmp6(ifp, l2addr, target, ips.addr.ip6, 129, 0, pkt->pay.buf, plen); } } break; diff --git a/test/mip_test.c b/test/mip_test.c index 2a855153..bae036f2 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -1096,6 +1096,10 @@ static void init_icmp_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp, struct mg_tcpip_driver *driver, struct mg_tcpip_if *mif) { init_tests(mgr, e, ipp, driver, mif, 1); // 1 -> ICMP +#if MG_ENABLE_IPV6 + mif->state6 = MG_TCPIP_STATE_READY; // so RS stops + mg_mgr_poll(mgr, 0); +#endif } static void test_icmp_basics(void) { @@ -1112,7 +1116,7 @@ static void test_icmp_basics(void) { ipp.ip6 = NULL; init_icmp_tests(&mgr, &e, &ipp, &driver, &mif); - create_icmp_dat(&e, &ipp, 8, 0, 0); + create_icmp_dat(&e, &ipp, 8, 0, 0); // Echo Request mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); ASSERT(i->src == 1 && i->dst == 2); @@ -1123,7 +1127,7 @@ static void test_icmp_basics(void) { ASSERT(icmp->code == 0); ASSERT(ipcsum(icmp, sizeof(*icmp) + 0) == 0); - create_icmp_dat(&e, &ipp, 8, 0, 69); + create_icmp_dat(&e, &ipp, 8, 0, 69); // Echo Request mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); ASSERT(i->src == 1 && i->dst == 2); @@ -1142,6 +1146,106 @@ static void test_icmp(void) { } +#if MG_ENABLE_IPV6 +static uint16_t icmp6csum(struct ip6 *ip6, size_t len) { + uint32_t cs; + struct icmp6 *icmp6 = (struct icmp6 *) (ip6 + 1); + cs = csumup(0, icmp6, sizeof(*icmp6)); + cs = csumup(cs, icmp6 + 1, len); + cs = csumup(cs, ip6->src, 16); + cs = csumup(cs, ip6->dst, 16); + cs += (uint32_t) (58 + sizeof(*icmp6) + len); + return csumfin(cs); +} + +static void create_icmp6_dat(struct eth *e, struct ipp *ipp, uint8_t type, + uint8_t code, uint8_t *payload, size_t payload_len) { + struct icmp6 icmp6; + struct ip6 *ip6 = ipp->ip6; + memset(&icmp6, 0, sizeof(icmp6)); + icmp6.type = type; + icmp6.code = code; + memcpy(s_driver_data.buf, e, sizeof(*e)); + ip6->plen = mg_htons((uint16_t) (sizeof(icmp6) + payload_len)); + memcpy(s_driver_data.buf + sizeof(*e), ip6, sizeof(*ip6)); + memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip6), &icmp6, sizeof(icmp6)); + if (payload != NULL) + memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip6) + sizeof(icmp6), payload, payload_len); + s_driver_data.len = sizeof(*e) + sizeof(*ip6) + sizeof(icmp6) + payload_len; + icmp6.csum = icmp6csum((struct ip6 *)(s_driver_data.buf + sizeof(*e)), payload_len); + if (s_driver_data.len < 64) s_driver_data.len = 64; // add padding if needed +} + +static void init_icmp6_tests(struct mg_mgr *mgr, struct eth *e, struct ipp *ipp, + struct mg_tcpip_driver *driver, + struct mg_tcpip_if *mif) { + init_tests(mgr, e, ipp, driver, mif, 58); // 58 -> ICMPv6 +} + +static void test_icmp6_basics(void) { + struct mg_mgr mgr; + struct eth e; + struct ip6 ip6; + struct ipp ipp; + struct icmp6 *icmp6 = (struct icmp6 *) (s_driver_data.buf + sizeof(e) + sizeof(ip6)); + struct ip6 *i = (struct ip6 *) (s_driver_data.buf + sizeof(e)); + struct mg_tcpip_driver driver; + struct mg_tcpip_if mif; + uint8_t payload[28], *p = (uint8_t *)(icmp6 + 1); + + + ipp.ip4 = NULL; + ipp.ip6 = &ip6; + init_icmp6_tests(&mgr, &e, &ipp, &driver, &mif); + + create_icmp6_dat(&e, &ipp, 128, 0, NULL, 0); // Echo Request + mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer + while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); + ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0); + ASSERT(i->next == 58); + ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 0)); + ASSERT(icmp6->type == 129); // Echo Reply + ASSERT(icmp6->code == 0); + ASSERT(icmp6csum(i, 0) == 0); + + create_icmp6_dat(&e, &ipp, 128, 0, NULL, 69); // Echo Request + mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer + while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); + ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0); + ASSERT(i->next == 58); + ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 69)); + ASSERT(icmp6->type == 129); // Echo Reply + ASSERT(icmp6->code == 0); + ASSERT(icmp6csum(i, 69) == 0); + + // Neighbor Solicitation + memset(payload, 0, sizeof(payload)); + memcpy(payload + 4, mif.ip6, 16); + payload[20] = 1; // source hwaddr + payload[21] = 1; // hwaddr len + create_icmp6_dat(&e, &ipp, 135, 0, payload, 28); + mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer + while (!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); + ASSERT(i->src[0] == 1 && i->src[1] == 0 && i->dst[0] == 2 && i->dst[1] == 0); + ASSERT(i->next == 58); + ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 28)); + ASSERT(icmp6->type == 136); // Neighbor Advertisement + ASSERT(icmp6->code == 0); + ASSERT(p[0] == 0x60); // solicited + override + ASSERT(memcmp(p + 4, mif.ip6, 16) == 0); // target address + ASSERT(p[20] == 2); // target hwaddr + ASSERT(p[21] == 1); // hwaddr len + ASSERT(memcmp(p + 22, mif.mac, 6) == 0); + + s_driver_data.len = 0; + mg_mgr_free(&mgr); +} + +static void test_icmp6(void) { + test_icmp6_basics(); +} +#endif + #define DASHBOARD(x) \ printf("HEALTH_DASHBOARD\t\"%s\": %s,\n", x, s_error ? "false" : "true"); @@ -1172,6 +1276,10 @@ int main(void) { DASHBOARD("udp"); #if MG_ENABLE_IPV6 + s_error = false; + test_icmp6(); + DASHBOARD("icmp6"); + s_error = false; test_state6change(); DASHBOARD("state6change");