ipv4: fix receival of different sized headers

This commit is contained in:
Matheus
2026-09-10 23:55:04 -03:00
parent 5aca46e22c
commit d9ea361caf
4 changed files with 25 additions and 15 deletions
+3 -1
View File
@@ -62,6 +62,8 @@ typedef struct {
uint32_t dstaddr; uint32_t dstaddr;
} __attribute__((packed)) ipv4frame_t; } __attribute__((packed)) ipv4frame_t;
#define IPV4_HEADER_LENGTH(version_length) (((version_length) & 0xf) * 4)
typedef struct { typedef struct {
uint16_t srcport; uint16_t srcport;
uint16_t dstport; 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); int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, netdev_t *broadcastdev);
size_t ipv4_getmtu(uint32_t ip); size_t ipv4_getmtu(uint32_t ip);
uint32_t ipv4_getnetdevip(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 ipv4_addroute(netdev_t *netdev, uint32_t addr, uint32_t gateway, uint32_t mask, int weight);
int netdev_register(netdev_t *netdev, char *name); int netdev_register(netdev_t *netdev, char *name);
netdev_t *netdev_getdev(char *name); netdev_t *netdev_getdev(char *name);
+6 -2
View File
@@ -1,5 +1,6 @@
#include <kernel/net.h> #include <kernel/net.h>
#include <kernel/eth.h> #include <kernel/eth.h>
#include <kernel/raw.h>
#include <logging.h> #include <logging.h>
// runs on dpc context, called by the individual driver dpcs on a receive. // 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)); 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: case ETH_PROTO_IP:
ipv4_process(netdev, nextbuff); ipv4_process(netdev, nextbuff, size - sizeof(ethframe_t));
break; break;
case ETH_PROTO_ARP: case ETH_PROTO_ARP:
arp_process(netdev, nextbuff); arp_process(netdev, nextbuff);
break; break;
} }
raw_process(netdev, nextbuff, &src, ethertype, size - sizeof(ethframe_t));
} }
+15 -11
View File
@@ -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) { static int checksum(void *buffer, size_t size) {
uint16_t *p = buffer; uint16_t *p = buffer;
int sum = 0; uint32_t sum = 0;
int i; int i;
for (i = 0; i < (size & ~(1lu)); i += 2) { for (i = 0; i < (size & ~(1lu)); i += 2) {
sum += be_to_cpu_w(p[i >> 1]); sum += be_to_cpu_w(p[i >> 1]);
} }
if (size & 1) { if (size & 1) {
sum += ((uint8_t *)p)[i]; sum += ((uint8_t *)p)[i] << 8;
} }
sum = (sum >> 16) + (sum & 0xffff); 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); 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; ipv4frame_t *frame = buff;
if (checksum(frame, sizeof(ipv4frame_t)) != 0) { if (size < sizeof(ipv4frame_t) || (frame->version_length >> 4) != 4)
printf("ipv4: bad checksum\n");
return; 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; return;
uint16_t flagsfrag = be_to_cpu_w(frame->flags_fragoffset); uint16_t flagsfrag = be_to_cpu_w(frame->flags_fragoffset);
if ((GET_FLAGS(flagsfrag) & FLAG_MF) || (GET_FRAGOFFSET(flagsfrag) > 0)) { if ((GET_FLAGS(flagsfrag) & FLAG_MF) || (GET_FRAGOFFSET(flagsfrag) > 0))
printf("ipv4: reassembly not yet supported!\n");
return; return;
}
uint32_t dstip = be_to_cpu_d(frame->dstaddr); uint32_t dstip = be_to_cpu_d(frame->dstaddr);
uint32_t srcip = be_to_cpu_d(frame->srcaddr); 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) if (dstip != IPV4_BROADCAST_ADDRESS && dstip != netdev->ip)
return; return;
void *nextbuff = (void *)((uintptr_t)buff + sizeof(ipv4frame_t)); void *nextbuff = (void *)((uintptr_t)buff + headerlen);
switch (frame->protocol) { switch (frame->protocol) {
case IPV4_PROTO_UDP: case IPV4_PROTO_UDP:
+1 -1
View File
@@ -413,7 +413,7 @@ void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame) {
.zero = 0, .zero = 0,
.protocol = ipv4frame->protocol, .protocol = ipv4frame->protocol,
// ipv4 len is header + size // 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) { if (checksum(&ipv4pseudoheader, buffer) != 0) {