diff --git a/kernel-src/io/net/eth.c b/kernel-src/io/net/eth.c index d0a62a06..7e183595 100644 --- a/kernel-src/io/net/eth.c +++ b/kernel-src/io/net/eth.c @@ -15,12 +15,11 @@ void eth_process(netdev_t *netdev, void *buffer) { if (!(MAC_EQUAL(&dst, &netdev->mac) || MAC_EQUAL(&dst, &broadcast))) return; - printf("our machine!\n"); - void *nextbuff = (void *)((uintptr_t)buffer + sizeof(ethframe_t)); switch (be_to_cpu_w(frame->type)) { case ETH_PROTO_IP: + ipv4_process(netdev, nextbuff); break; case ETH_PROTO_ARP: arp_process(netdev, nextbuff); diff --git a/kernel-src/io/net/ipv4.c b/kernel-src/io/net/ipv4.c index 70d30c82..8118df57 100644 --- a/kernel-src/io/net/ipv4.c +++ b/kernel-src/io/net/ipv4.c @@ -4,6 +4,7 @@ #include #include #include +#include typedef struct { netdev_t *netdev; @@ -79,6 +80,27 @@ int ipv4_addroute(netdev_t *netdev, uint32_t addr, uint32_t gateway, uint32_t ma #define FLAG_MF 1 // offset has to be a multiple of 8 #define FLAGS_FRAGOFFSET(flg, offset) (((flg) << 13) | ((offset) >> 3)) +#define GET_FLAGS(x) (((x) >> 13) & 0x7) +#define GET_FRAGOFFSET(x) ((x) & 0x1fff) + +static int checksum(void *buffer, size_t size) { + uint16_t *p = buffer; + int sum = 0; + int i; + for (int i = 0; i < (size & ~(1lu)); i += 2) { + sum += be_to_cpu_w(p[i >> 1]); + } + + if (size & 1) { + sum += ((uint8_t *)p)[i]; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += sum >> 16; + + uint16_t ret = ~sum; + return ret; +} static int dispatch_fragment(netdev_t *netdev, netdesc_t fragdesc, uintmax_t fragmentoffset, size_t fragmentlen, int id, uint32_t ip, mac_t mac, int proto, bool last) { @@ -90,15 +112,50 @@ static int dispatch_fragment(netdev_t *netdev, netdesc_t fragdesc, .flags_fragoffset = cpu_to_be_w(FLAGS_FRAGOFFSET(!last ? FLAG_MF : 0, fragmentoffset)), .timetolive = 0xff, .protocol = proto, - .framechecksum = 0xfefe, // TODO checksum - .srcaddr = netdev->ip, // TODO src addr + .framechecksum = 0, + .srcaddr = cpu_to_be_d(netdev->ip), .dstaddr = cpu_to_be_d(ip) }; + frame.framechecksum = cpu_to_be_w(checksum(&frame, sizeof(frame))); + memcpy((void *)((uintptr_t)fragdesc.address + fragdesc.curroffset), &frame, sizeof(ipv4frame_t)); return netdev->sendpacket(netdev, fragdesc, mac, ETH_PROTO_IP); } +void ipv4_process(netdev_t *netdev, void *buff) { + ipv4frame_t *frame = buff; + + if (checksum(frame, sizeof(ipv4frame_t)) != 0) { + return; + } + + if (frame->version_length != VERSION_LENGTH(4, 5)) + 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"); + return; + } + + uint32_t dstip = be_to_cpu_d(frame->dstaddr); + uint32_t srcip = be_to_cpu_d(frame->srcaddr); + + if (dstip != IPV4_BROADCAST_ADDRESS && dstip != netdev->ip) + return; + + void *nextbuff = (void *)((uintptr_t)buff + sizeof(ipv4frame_t)); + + switch (frame->protocol) { + case IPV4_PROTO_UDP: + udp_process(netdev, nextbuff, srcip); + break; + } + + return; +} + int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, netdev_t *broadcastdev) { if ((packetsize + sizeof(ipv4frame_t)) > 65535) return EMSGSIZE; @@ -134,7 +191,8 @@ int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, net if (e) return e; - memcpy((void *)((uintptr_t)fragdesc.address + sizeof(ipv4frame_t)), (void *)((uintptr_t)buffer + i * devfragmentsize), fragmentlen); + memcpy((void *)((uintptr_t)fragdesc.address + fragdesc.curroffset + sizeof(ipv4frame_t)), (void *)((uintptr_t)buffer + i * devfragmentsize), fragmentlen); + e = dispatch_fragment(netdev, fragdesc, i * devfragmentsize, fragmentlen, 0x1234, ip, mac, proto, i == fragmentcount - 1); // TODO unallocate desc if (e)