diff --git a/kernel-src/include/kernel/net.h b/kernel-src/include/kernel/net.h index 977b27aa..ade466a6 100644 --- a/kernel-src/include/kernel/net.h +++ b/kernel-src/include/kernel/net.h @@ -28,7 +28,8 @@ typedef struct netdev_t { size_t mtu; uint32_t ip; hashtable_t arpcache; - int (*allocdesc)(size_t requestedsize, netdesc_t *desc); + int (*allocdesc)(struct netdev_t *netdev, size_t requestedsize, netdesc_t *desc); + int (*freedesc)(struct netdev_t *netdev, netdesc_t *desc); int (*sendpacket)(struct netdev_t *_internal, netdesc_t desc, mac_t targetmac, int proto); } netdev_t; @@ -61,20 +62,25 @@ typedef struct { #define MAC_EQUAL(m1,m2) (memcmp(m1, m2, sizeof(mac_t)) == 0) +#define IPV4_PROTO_TCP 0x06 #define IPV4_PROTO_UDP 0x11 #define IPV4_BROADCAST_ADDRESS 0xffffffff void arp_init(); void ipv4_init(); void udp_init(); +void tcp_init(); void netdev_init(); void loopback_init(); netdev_t *loopback_device(); void udp_process(netdev_t *netdev, void *buffer, uint32_t ip); void arp_process(netdev_t *netdev, void *buffer); +void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame); int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac); int udp_sendpacket(void *buffer, size_t packetsize, uint32_t ip, uint16_t srcport, uint16_t dstport, 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); +uint32_t ipv4_getnetdevip(uint32_t ip); void ipv4_process(netdev_t *netdev, void *nextbuff); 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); diff --git a/kernel-src/io/net/arp.c b/kernel-src/io/net/arp.c index 8365e191..b9d15c1d 100644 --- a/kernel-src/io/net/arp.c +++ b/kernel-src/io/net/arp.c @@ -135,14 +135,14 @@ static void send_reply(netdev_t *netdev, uint32_t ip, mac_t mac) { memcpy(&frame.srchw, &netdev->mac, sizeof(mac_t)); memcpy(&frame.dsthw, &mac, sizeof(mac_t)); netdesc_t desc; - int e = netdev->allocdesc(sizeof(arpframe_t), &desc); + int e = netdev->allocdesc(netdev, sizeof(arpframe_t), &desc); if (e) return; memcpy((void *)((uintptr_t)desc.address + desc.curroffset), &frame, sizeof(frame)); e = netdev->sendpacket(netdev, desc, mac, ETH_PROTO_ARP); - // TODO free netdesc + netdev->freedesc(netdev, &desc); } static void handlerthreadfn() { @@ -172,15 +172,26 @@ static void handlerthreadfn() { } } - // executed in dpc context void arp_process(netdev_t *netdev, void *buffer) { arpframe_t *frame = buffer; - __assert(frame->hwtype == cpu_to_be_w(1)); // ethernet - __assert(frame->protocoltype == cpu_to_be_w(0x800)); // ip - __assert(frame->hwlen == 6); - __assert(frame->ptlen == 4); - __assert(MAC_EQUAL(&frame->dsthw, &netdev->mac)); + if (frame->hwtype != cpu_to_be_w(1)) // ethernet + return; + + if (frame->protocoltype != cpu_to_be_w(0x800)) // ip + return; + + if (frame->hwlen != 6) + return; + + if (frame->ptlen != 4) + return; + + if (be_to_cpu_w(frame->opcode) == OPCODE_REPLY && MAC_EQUAL(&frame->dsthw, &netdev->mac) == false) + return; + + if (be_to_cpu_w(frame->opcode) == OPCODE_REQUEST && be_to_cpu_d(frame->dstpt) != netdev->ip) + return; bufferentry_t entry = { .opcode = cpu_to_be_w(frame->opcode), @@ -209,14 +220,14 @@ static int sendrequest(netdev_t *netdev, uint32_t ip) { memcpy(&frame.srchw, &netdev->mac, sizeof(mac_t)); netdesc_t desc; - int e = netdev->allocdesc(sizeof(arpframe_t), &desc); + int e = netdev->allocdesc(netdev, sizeof(arpframe_t), &desc); if (e) return e; memcpy((void *)((uintptr_t)desc.address + desc.curroffset), &frame, sizeof(frame)); e = netdev->sendpacket(netdev, desc, NET_BROADCAST_MAC, ETH_PROTO_ARP); - // TODO free netdesc + netdev->freedesc(netdev, &desc); return e; } @@ -231,7 +242,6 @@ int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac) { if (e) goto cleanup; - // wait // TODO wait on an event instead of looping on a yield (ok for now, but might cause slowdows in the future) diff --git a/kernel-src/io/net/ipv4.c b/kernel-src/io/net/ipv4.c index 412e888e..c748a909 100644 --- a/kernel-src/io/net/ipv4.c +++ b/kernel-src/io/net/ipv4.c @@ -166,7 +166,7 @@ int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, net if (ip != IPV4_BROADCAST_ADDRESS) { routingentry_t entry = getroute(ip); if (entry.netdev == NULL) - return 0; // if a packet can't be routed to anywhere just pretend it was sent somewhere + return ENETUNREACH; int error = arp_lookup(entry.netdev, entry.gateway ? entry.gateway : ip, &mac); if (error) @@ -187,14 +187,14 @@ int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, net for (int i = 0; i < fragmentcount; ++i) { size_t fragmentlen = (i == fragmentcount - 1) ? packetsize - devfragmentsize * (fragmentcount - 1) : devfragmentsize; netdesc_t fragdesc; - int e = netdev->allocdesc(fragmentlen + sizeof(ipv4frame_t), &fragdesc); + int e = netdev->allocdesc(netdev, fragmentlen + sizeof(ipv4frame_t), &fragdesc); if (e) return e; 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 + netdev->freedesc(netdev, &fragdesc); if (e) return e; } diff --git a/kernel-src/io/net/loopback.c b/kernel-src/io/net/loopback.c index 38635322..d7a9f5a7 100644 --- a/kernel-src/io/net/loopback.c +++ b/kernel-src/io/net/loopback.c @@ -13,7 +13,8 @@ static void rx_dpc(context_t *context, dpcarg_t arg) { } // requested size doesn't account for ethernet header or the virtio header -static int loopback_allocdesc(size_t requestedsize, netdesc_t *desc) { +static int loopback_allocdesc(netdev_t *netdev, size_t requestedsize, netdesc_t *desc) { + __assert(requestedsize <= netdev->mtu); desc->address = alloc(requestedsize + sizeof(ethframe_t)); if (desc->address == NULL) return ENOMEM; @@ -23,6 +24,11 @@ static int loopback_allocdesc(size_t requestedsize, netdesc_t *desc) { return 0; } +static int loopback_freedesc(netdev_t *netdev, netdesc_t *desc) { + free(desc->address); + return 0; +} + static int loopback_sendpacket(netdev_t *netdev, netdesc_t desc, mac_t targetmac, int proto) { desc.curroffset = 0; ethframe_t ethframe = { @@ -49,6 +55,7 @@ void loopback_init() { loopbacknetdev.mtu = 30000; loopbacknetdev.sendpacket = loopback_sendpacket; loopbacknetdev.allocdesc = loopback_allocdesc; + loopbacknetdev.freedesc = loopback_freedesc; loopbacknetdev.ip = 0x7f000001; __assert(hashtable_init(&loopbacknetdev.arpcache, 30) == 0); diff --git a/kernel-src/io/net/vionet.c b/kernel-src/io/net/vionet.c index ef4c7e62..4e5aa71e 100644 --- a/kernel-src/io/net/vionet.c +++ b/kernel-src/io/net/vionet.c @@ -67,9 +67,9 @@ static void tx_dpc(context_t *context, dpcarg_t arg) { while (netdev->txqueue.lastusedindex != VIO_QUEUE_DEV_IDX(&netdev->txqueue)) { int idx = netdev->txqueue.lastusedindex++ % netdev->txqueue.size; int buffidx = VIO_QUEUE_DEV_RING(&netdev->txqueue)[idx].index; - __assert(netdev->txwait[buffidx / 2]); - sched_wakeup(netdev->txwait[buffidx / 2], SCHED_WAKEUP_REASON_NORMAL); - netdev->txwait[buffidx / 2] = NULL; + __assert(netdev->txwait[buffidx]); + sched_wakeup(netdev->txwait[buffidx], SCHED_WAKEUP_REASON_NORMAL); + netdev->txwait[buffidx] = NULL; buffers[buffidx].address = 0; semaphore_signal(&netdev->txsem); } @@ -86,7 +86,8 @@ static void tx_irq(isr_t *isr, context_t *context) { #define PREFIX_SIZE (sizeof(ethframe_t) + sizeof(vioframe_t)) // requested size doesn't account for ethernet header or the virtio header -static int vionet_allocdesc(size_t requestedsize, netdesc_t *desc) { +static int vionet_allocdesc(netdev_t *netdev, size_t requestedsize, netdesc_t *desc) { + __assert(requestedsize <= netdev->mtu); size_t truesize = PREFIX_SIZE + requestedsize; void *phys = pmm_allocpage(PMM_SECTION_DEFAULT); if (phys == NULL) @@ -98,6 +99,11 @@ static int vionet_allocdesc(size_t requestedsize, netdesc_t *desc) { return 0; } +static int vionet_freedesc(netdev_t *netdev, netdesc_t *desc) { + pmm_release(FROM_HHDM(desc->address)); + return 0; +} + static int vionet_sendpacket(netdev_t *internal, netdesc_t desc, mac_t targetmac, int proto) { vionetdev_t *netdev = (vionetdev_t *)internal; vioframe_t vioframe = { @@ -175,6 +181,7 @@ int vionet_newdevice(viodevice_t *viodevice) { netdev->netdev.mtu = 1500; netdev->netdev.sendpacket = vionet_sendpacket; netdev->netdev.allocdesc = vionet_allocdesc; + netdev->netdev.freedesc = vionet_freedesc; __assert(hashtable_init(&netdev->netdev.arpcache, 30) == 0); // initialize queues