From d9ea361caf544d4678fe8e07a30cba8792e4448e Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 10 Sep 2026 23:55:04 -0300 Subject: [PATCH] ipv4: fix receival of different sized headers --- kernel-src/include/kernel/net.h | 4 +++- kernel-src/io/net/eth.c | 8 ++++++-- kernel-src/io/net/ipv4.c | 26 +++++++++++++++----------- kernel-src/io/net/tcp.c | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/kernel-src/include/kernel/net.h b/kernel-src/include/kernel/net.h index 957ca342..e4f321db 100644 --- a/kernel-src/include/kernel/net.h +++ b/kernel-src/include/kernel/net.h @@ -62,6 +62,8 @@ typedef struct { uint32_t dstaddr; } __attribute__((packed)) ipv4frame_t; +#define IPV4_HEADER_LENGTH(version_length) (((version_length) & 0xf) * 4) + typedef struct { uint16_t srcport; uint16_t dstport; @@ -92,7 +94,7 @@ int udp_sendpacket(iovec_iterator_t *iovec_iterator, size_t packetsize, uint32_t int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, netdev_t *broadcastdev); size_t ipv4_getmtu(uint32_t ip); uint32_t ipv4_getnetdevip(uint32_t ip); -void ipv4_process(netdev_t *netdev, void *nextbuff); +void ipv4_process(netdev_t *netdev, void *nextbuff, size_t size); int ipv4_addroute(netdev_t *netdev, uint32_t addr, uint32_t gateway, uint32_t mask, int weight); int netdev_register(netdev_t *netdev, char *name); netdev_t *netdev_getdev(char *name); diff --git a/kernel-src/io/net/eth.c b/kernel-src/io/net/eth.c index 0afe5b43..a2aa1069 100644 --- a/kernel-src/io/net/eth.c +++ b/kernel-src/io/net/eth.c @@ -1,5 +1,6 @@ #include #include +#include #include // runs on dpc context, called by the individual driver dpcs on a receive. @@ -20,12 +21,15 @@ void eth_process(netdev_t *netdev, void *buffer, size_t size) { void *nextbuff = (void *)((uintptr_t)buffer + sizeof(ethframe_t)); - switch (be_to_cpu_w(frame->type)) { + uint16_t ethertype = be_to_cpu_w(frame->type); + switch (ethertype) { case ETH_PROTO_IP: - ipv4_process(netdev, nextbuff); + ipv4_process(netdev, nextbuff, size - sizeof(ethframe_t)); break; case ETH_PROTO_ARP: arp_process(netdev, nextbuff); break; } + + raw_process(netdev, nextbuff, &src, ethertype, size - sizeof(ethframe_t)); } diff --git a/kernel-src/io/net/ipv4.c b/kernel-src/io/net/ipv4.c index abbc4bdb..d8a79e12 100644 --- a/kernel-src/io/net/ipv4.c +++ b/kernel-src/io/net/ipv4.c @@ -86,14 +86,14 @@ int ipv4_addroute(netdev_t *netdev, uint32_t addr, uint32_t gateway, uint32_t ma static int checksum(void *buffer, size_t size) { uint16_t *p = buffer; - int sum = 0; + uint32_t sum = 0; int i; for (i = 0; i < (size & ~(1lu)); i += 2) { sum += be_to_cpu_w(p[i >> 1]); } if (size & 1) { - sum += ((uint8_t *)p)[i]; + sum += ((uint8_t *)p)[i] << 8; } sum = (sum >> 16) + (sum & 0xffff); @@ -124,22 +124,26 @@ static int dispatch_fragment(netdev_t *netdev, netdesc_t fragdesc, return netdev->sendpacket(netdev, fragdesc, mac, ETH_PROTO_IP); } -void ipv4_process(netdev_t *netdev, void *buff) { +void ipv4_process(netdev_t *netdev, void *buff, size_t size) { ipv4frame_t *frame = buff; - if (checksum(frame, sizeof(ipv4frame_t)) != 0) { - printf("ipv4: bad checksum\n"); + if (size < sizeof(ipv4frame_t) || (frame->version_length >> 4) != 4) return; - } - if (frame->version_length != VERSION_LENGTH(4, 5)) + size_t headerlen = IPV4_HEADER_LENGTH(frame->version_length); + if (headerlen < sizeof(ipv4frame_t) || headerlen > size) + return; + + size_t packetlen = be_to_cpu_w(frame->packetlen); + if (packetlen < headerlen || packetlen > size) + return; + + if (checksum(frame, headerlen) != 0) return; uint16_t flagsfrag = be_to_cpu_w(frame->flags_fragoffset); - if ((GET_FLAGS(flagsfrag) & FLAG_MF) || (GET_FRAGOFFSET(flagsfrag) > 0)) { - printf("ipv4: reassembly not yet supported!\n"); + if ((GET_FLAGS(flagsfrag) & FLAG_MF) || (GET_FRAGOFFSET(flagsfrag) > 0)) return; - } uint32_t dstip = be_to_cpu_d(frame->dstaddr); uint32_t srcip = be_to_cpu_d(frame->srcaddr); @@ -147,7 +151,7 @@ void ipv4_process(netdev_t *netdev, void *buff) { if (dstip != IPV4_BROADCAST_ADDRESS && dstip != netdev->ip) return; - void *nextbuff = (void *)((uintptr_t)buff + sizeof(ipv4frame_t)); + void *nextbuff = (void *)((uintptr_t)buff + headerlen); switch (frame->protocol) { case IPV4_PROTO_UDP: diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index cfb5d0c8..b45a2688 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -413,7 +413,7 @@ void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame) { .zero = 0, .protocol = ipv4frame->protocol, // ipv4 len is header + size - .length = cpu_to_be_w(be_to_cpu_w(ipv4frame->packetlen) - sizeof(ipv4frame_t)) + .length = cpu_to_be_w(be_to_cpu_w(ipv4frame->packetlen) - IPV4_HEADER_LENGTH(ipv4frame->version_length)) }; if (checksum(&ipv4pseudoheader, buffer) != 0) {