Skip to content

Commit

Permalink
Async packet sending and resending of single packet during ARP discov…
Browse files Browse the repository at this point in the history
…ery.
  • Loading branch information
pdoane committed Jun 23, 2012
1 parent c778c46 commit c41ee2f
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 63 deletions.
1 change: 0 additions & 1 deletion TODO
Expand Up @@ -15,4 +15,3 @@
- ARP
- Flush out-of-date entries
- Prevent ARP flooding
- Save packet during discovery
90 changes: 65 additions & 25 deletions kernel/arp.c
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion kernel/arp.h
Expand Up @@ -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);
4 changes: 2 additions & 2 deletions kernel/console_cmd.c
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions kernel/dhcp.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 2 additions & 3 deletions kernel/dns.c
Expand Up @@ -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);
Expand Down
7 changes: 2 additions & 5 deletions kernel/eth.c
Expand Up @@ -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;
}
}
}
Expand Down
37 changes: 28 additions & 9 deletions kernel/eth_8254x.c
Expand Up @@ -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

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
}
}

// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 4 additions & 6 deletions kernel/icmp.c
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions kernel/net.c
Expand Up @@ -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;

// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -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);
}
18 changes: 13 additions & 5 deletions kernel/net.h
Expand Up @@ -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

// ------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -53,3 +58,6 @@ extern u8 net_trace;

void net_init();
void net_poll();

NetBuf* net_alloc_packet();
void net_free_packet(NetBuf* buf);

0 comments on commit c41ee2f

Please sign in to comment.