From c41ee2f3f64c275420d566e9f883bc3393edaf9f Mon Sep 17 00:00:00 2001 From: Patrick Doane Date: Sat, 23 Jun 2012 16:13:06 -0700 Subject: [PATCH] Async packet sending and resending of single packet during ARP discovery. --- TODO | 1 - kernel/arp.c | 90 ++++++++++++++++++++++++++++++++------------ kernel/arp.h | 2 +- kernel/console_cmd.c | 4 +- kernel/dhcp.c | 8 ++-- kernel/dns.c | 5 +-- kernel/eth.c | 7 +--- kernel/eth_8254x.c | 37 +++++++++++++----- kernel/icmp.c | 10 ++--- kernel/net.c | 26 +++++++++++++ kernel/net.h | 18 ++++++--- kernel/ntp.c | 4 +- 12 files changed, 149 insertions(+), 63 deletions(-) diff --git a/TODO b/TODO index dcd46f6..fb26e4c 100644 --- a/TODO +++ b/TODO @@ -15,4 +15,3 @@ - ARP - Flush out-of-date entries - Prevent ARP flooding - - Save packet during discovery diff --git a/kernel/arp.c b/kernel/arp.c index 1941190..a0b6c95 100644 --- a/kernel/arp.c +++ b/kernel/arp.c @@ -24,6 +24,12 @@ typedef struct ARP_Entry { Eth_Addr ha; IPv4_Addr pa; + + // deferred packet to send + Net_Intf* intf; + u16 ether_type; + u8* pkt; + uint len; } ARP_Entry; static ARP_Entry arp_cache[ARP_CACHE_SIZE]; @@ -76,9 +82,8 @@ static void arp_print(const u8* pkt, uint len) // ------------------------------------------------------------------------------------------------ static void arp_snd(Net_Intf* intf, uint op, const Eth_Addr* tha, const IPv4_Addr* tpa) { - u8 buf[256]; - - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); // HTYPE pkt[0] = (ARP_HTYPE_ETH >> 8) & 0xff; @@ -125,19 +130,23 @@ static void arp_snd(Net_Intf* intf, uint op, const Eth_Addr* tha, const IPv4_Add } // ------------------------------------------------------------------------------------------------ -void arp_request(Net_Intf* intf, const IPv4_Addr* tpa) +static ARP_Entry* arp_lookup(const IPv4_Addr* pa) { - arp_snd(intf, ARP_OP_REQUEST, &broadcast_eth_addr, tpa); -} + ARP_Entry* entry = arp_cache; + ARP_Entry* end = entry + ARP_CACHE_SIZE; + for (; entry != end; ++entry) + { + if (ipv4_addr_eq(&entry->pa, pa)) + { + return entry; + } + } -// ------------------------------------------------------------------------------------------------ -void arp_reply(Net_Intf* intf, const Eth_Addr* tha, const IPv4_Addr* tpa) -{ - arp_snd(intf, ARP_OP_REPLY, tha, tpa); + return 0; } // ------------------------------------------------------------------------------------------------ -static void arp_add(const Eth_Addr* ha, const IPv4_Addr* pa) +static ARP_Entry* arp_add(const Eth_Addr* ha, const IPv4_Addr* pa) { // TODO - handle overflow ARP_Entry* entry = arp_cache; @@ -154,36 +163,56 @@ static void arp_add(const Eth_Addr* ha, const IPv4_Addr* pa) { entry->ha = *ha; entry->pa = *pa; + return entry; } + + console_print("Ran out of ARP entries\n"); + return 0; } // ------------------------------------------------------------------------------------------------ -void arp_init() +void arp_request(Net_Intf* intf, const IPv4_Addr* tpa, u16 ether_type, u8* pkt, uint len) { - // Clear cache of all entries - ARP_Entry* entry = arp_cache; - ARP_Entry* end = entry + ARP_CACHE_SIZE; - for (; entry != end; ++entry) + ARP_Entry* entry = arp_lookup(tpa); + if (!entry) { - memset(&entry->ha, 0, sizeof(Eth_Addr)); - memset(&entry->pa, 0, sizeof(IPv4_Addr)); + entry = arp_add(&null_eth_addr, tpa); + } + + if (entry) + { + // Drop any packet already queued + if (entry->pkt) + { + NetBuf* buf = (NetBuf*)((uintptr_t)entry->pkt & ~0xfff); // buffer starts page aligned + net_free_packet(buf); + } + + entry->intf = intf; + entry->ether_type = ether_type; + entry->pkt = pkt; + entry->len = len; + arp_snd(intf, ARP_OP_REQUEST, &broadcast_eth_addr, tpa); } } // ------------------------------------------------------------------------------------------------ -static ARP_Entry* arp_lookup(const IPv4_Addr* pa) +void arp_reply(Net_Intf* intf, const Eth_Addr* tha, const IPv4_Addr* tpa) +{ + arp_snd(intf, ARP_OP_REPLY, tha, tpa); +} + +// ------------------------------------------------------------------------------------------------ +void arp_init() { + // Clear cache of all entries ARP_Entry* entry = arp_cache; ARP_Entry* end = entry + ARP_CACHE_SIZE; for (; entry != end; ++entry) { - if (ipv4_addr_eq(&entry->pa, pa)) - { - return entry; - } + memset(&entry->ha, 0, sizeof(Eth_Addr)); + memset(&entry->pa, 0, sizeof(IPv4_Addr)); } - - return 0; } // ------------------------------------------------------------------------------------------------ @@ -239,6 +268,17 @@ void arp_rx(Net_Intf* intf, const u8* pkt, uint len) entry->ha = *sha; merge = true; + + // Send deferred packet + if (entry->pkt) + { + eth_tx_intf(entry->intf, spa, entry->ether_type, entry->pkt, entry->len); + + entry->intf = 0; + entry->ether_type = 0; + entry->pkt = 0; + entry->len = 0; + } } // Check if this ARP packet is targeting our IP diff --git a/kernel/arp.h b/kernel/arp.h index 83279fe..36066c1 100644 --- a/kernel/arp.h +++ b/kernel/arp.h @@ -25,7 +25,7 @@ typedef struct ARP_Header void arp_init(); const Eth_Addr* arp_lookup_mac(const IPv4_Addr* pa); -void arp_request(Net_Intf* intf, const IPv4_Addr* tpa); +void arp_request(Net_Intf* intf, const IPv4_Addr* tpa, u16 ether_type, u8* pkt, uint len); void arp_reply(Net_Intf* intf, const Eth_Addr* tha, const IPv4_Addr* tpa); void arp_rx(Net_Intf* intf, const u8* pkt, uint len); diff --git a/kernel/console_cmd.c b/kernel/console_cmd.c index 3854db3..3ec87a9 100644 --- a/kernel/console_cmd.c +++ b/kernel/console_cmd.c @@ -144,9 +144,9 @@ static void cmd_rlog(uint argc, const char** argv) return; } - u8 buf[MAX_PACKET_SIZE]; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); - u8* pkt = buf + MAX_PACKET_HEADER; strcpy((char*)pkt, msg); udp_tx(&dst_addr, PORT_OSHELPER, PORT_OSHELPER, pkt, len); diff --git a/kernel/dhcp.c b/kernel/dhcp.c index cf14bbc..f35a101 100644 --- a/kernel/dhcp.c +++ b/kernel/dhcp.c @@ -200,8 +200,8 @@ static void dhcp_request(Net_Intf* intf, const DHCP_Header* hdr, const DHCP_Opti ipv4_addr_to_str(requested_ip_addr_str, sizeof(requested_ip_addr_str), requested_ip_addr); console_print("DHCP requesting lease for %s\n", requested_ip_addr_str); - u8 buf[MAX_PACKET_SIZE]; - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); // Header u8* p = dhcp_build_header(pkt, xid, &intf->eth_addr, DHCP_REQUEST); @@ -331,8 +331,8 @@ void dhcp_discover(Net_Intf* intf) { console_print("DHCP discovery\n"); - u8 buf[MAX_PACKET_SIZE]; - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); // Header uint xid = 0; diff --git a/kernel/dns.c b/kernel/dns.c index 7a392ac..60da9b4 100644 --- a/kernel/dns.c +++ b/kernel/dns.c @@ -43,9 +43,8 @@ void dns_query_host(const char* host, uint id) return; } - u8 buf[MAX_PACKET_SIZE]; - - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); DNS_Header* hdr = (DNS_Header*)pkt; hdr->id = net_swap16(id); diff --git a/kernel/eth.c b/kernel/eth.c index e06332e..157829d 100644 --- a/kernel/eth.c +++ b/kernel/eth.c @@ -109,11 +109,8 @@ void eth_tx_intf(Net_Intf* intf, const void* dst_addr, u16 ether_type, u8* pkt, dst_eth_addr = arp_lookup_mac(dst_ipv4_addr); if (!dst_eth_addr) { - char dst_addr_str[IPV4_ADDR_STRING_SIZE]; - - ipv4_addr_to_str(dst_addr_str, sizeof(dst_addr_str), dst_ipv4_addr); - console_print(" Unknown IP %s, sending ARP request\n", dst_addr_str); - arp_request(intf, dst_ipv4_addr); + arp_request(intf, dst_ipv4_addr, ether_type, pkt, len); + return; } } } diff --git a/kernel/eth_8254x.c b/kernel/eth_8254x.c index f852071..e4b6c8a 100644 --- a/kernel/eth_8254x.c +++ b/kernel/eth_8254x.c @@ -7,12 +7,13 @@ #include "io.h" #include "ipv4.h" #include "eth.h" +#include "net.h" #include "pci_driver.h" #include "string.h" #include "vm.h" #define RX_DESC_COUNT 32 -#define TX_DESC_COUNT 32 +#define TX_DESC_COUNT 8 #define PACKET_SIZE 2048 @@ -180,7 +181,6 @@ static u16 eeprom_read(u8* mmio_addr, u8 eeprom_addr) return val >> EERD_DATA_SHIFT; } - // ------------------------------------------------------------------------------------------------ static void eth_8254x_poll(Net_Intf* intf) { @@ -214,18 +214,32 @@ static void eth_8254x_tx(u8* pkt, uint len) { TX_Desc* desc = &dev.tx_descs[dev.tx_write]; + // Check for available tx descriptor + if (desc->status & TSTA_DD) + { + // Free packet that was sent with this descriptor. + // TODO - free packets earlier? + + if (desc->addr) + { + NetBuf* buf = (NetBuf*)((uintptr_t)desc->addr & ~0xfff); // buffer starts page aligned + net_free_packet(buf); + } + } + else + { + // TODO - report overflow + console_print("Net overflow\n"); + return; + } + + // Write new tx descriptor desc->addr = (u64)pkt; desc->len = len; desc->cmd = CMD_EOP | CMD_IFCS | CMD_RS; dev.tx_write = (dev.tx_write + 1) & (TX_DESC_COUNT - 1); mmio_write32(dev.mmio_addr + REG_TDT, dev.tx_write); - - while (~desc->status & TSTA_DD) - { - // TODO - wait - //console_print("%x\n", desc->sta); - } } // ------------------------------------------------------------------------------------------------ @@ -352,9 +366,14 @@ void eth_8254x_init(uint id, PCI_DeviceInfo* info) // Transmit Setup TX_Desc* tx_desc = tx_descs; - //TX_Desc* tx_end = tx_desc + TX_DESC_COUNT; + TX_Desc* tx_end = tx_desc + TX_DESC_COUNT; memset(tx_desc, 0, TX_DESC_COUNT * 16); + for (; tx_desc != tx_end; ++tx_desc) + { + tx_desc->status = TSTA_DD; // mark descriptor as 'complete' + } + dev.tx_write = 0; mmio_write32(mmio_addr + REG_TDBAL, (uintptr_t)tx_descs); diff --git a/kernel/icmp.c b/kernel/icmp.c index 1137413..cdf63da 100644 --- a/kernel/icmp.c +++ b/kernel/icmp.c @@ -56,9 +56,8 @@ void icmp_print(const u8* pkt, uint len) static void icmp_echo_reply(const IPv4_Addr* dst_addr, u16 id, u16 sequence, const u8* echo_data, uint echo_data_len) { - u8 buf[MAX_PACKET_SIZE]; - - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); pkt[0] = ICMP_TYPE_ECHO_REPLY; pkt[1] = 0; @@ -84,9 +83,8 @@ static void icmp_echo_reply(const IPv4_Addr* dst_addr, u16 id, u16 sequence, void icmp_echo_request(const IPv4_Addr* dst_addr, u16 id, u16 sequence, const u8* echo_data, uint echo_data_len) { - u8 buf[MAX_PACKET_SIZE]; - - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); pkt[0] = ICMP_TYPE_ECHO_REQUEST; pkt[1] = 0; diff --git a/kernel/net.c b/kernel/net.c index e8986e3..769f028 100644 --- a/kernel/net.c +++ b/kernel/net.c @@ -4,10 +4,15 @@ #include "net.h" #include "arp.h" +#include "console.h" #include "dhcp.h" #include "loopback.h" +#include "vm.h" // ------------------------------------------------------------------------------------------------ + +static Link net_free_packets = { &net_free_packets, &net_free_packets }; + u8 net_trace = 0; // ------------------------------------------------------------------------------------------------ @@ -50,3 +55,24 @@ void net_poll() it = it->next; } } + +// ------------------------------------------------------------------------------------------------ +NetBuf* net_alloc_packet() +{ + Link* p = net_free_packets.next; + if (p != &net_free_packets) + { + link_remove(p); + return link_data(p, NetBuf, link); + } + else + { + return vm_alloc(MAX_PACKET_SIZE); + } +} + +// ------------------------------------------------------------------------------------------------ +void net_free_packet(NetBuf* buf) +{ + link_before(&net_free_packets, &buf->link); +} diff --git a/kernel/net.h b/kernel/net.h index 020e27a..e033816 100644 --- a/kernel/net.h +++ b/kernel/net.h @@ -4,15 +4,20 @@ #pragma once -#include "types.h" +#include "link.h" // ------------------------------------------------------------------------------------------------ -// Packet Header Management +// Net Buffer Management -// Allow for up to 128 bytes to be used in the packet header for various protocols. This allows -// for IPv4 and TCP to both use all but one optional field. +typedef struct NetBuf +{ + Link link; + + // Allow for up to 120 bytes to be used in the packet header for various protocols. This allows + // for IPv4 and TCP to both use all but two optional fields. + u8 proto_headers[120]; +} NetBuf; -#define MAX_PACKET_HEADER 128 #define MAX_PACKET_SIZE 1500 // ------------------------------------------------------------------------------------------------ @@ -53,3 +58,6 @@ extern u8 net_trace; void net_init(); void net_poll(); + +NetBuf* net_alloc_packet(); +void net_free_packet(NetBuf* buf); diff --git a/kernel/ntp.c b/kernel/ntp.c index 13ebc31..9f2343c 100644 --- a/kernel/ntp.c +++ b/kernel/ntp.c @@ -66,8 +66,8 @@ void ntp_rx(Net_Intf* intf, const u8* pkt, uint len) // ------------------------------------------------------------------------------------------------ void ntp_tx(const IPv4_Addr* dst_addr) { - u8 buf[MAX_PACKET_SIZE]; - u8* pkt = buf + MAX_PACKET_HEADER; + NetBuf* buf = net_alloc_packet(); + u8* pkt = (u8*)(buf + 1); NTP_Header* hdr = (NTP_Header*)pkt; hdr->mode = (NTP_VERSION << 3) | MODE_CLIENT;