david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Simplify RX data path.

Kill off the static single net device and move to proper dynamic
registration (which we need with the new device model).

Break the (flawed) assumption that all network-layer protocols can use
ARP; such network-layer protocols (i.e. IPv4) must now register as an ARP
protocol using ARP_NET_PROTOCOL() and provide a single method for checking
the existence of a local network-layer address.
This commit is contained in:
Michael Brown 2006-06-17 22:36:27 +00:00
parent 8aeead7c1c
commit 3c8aafa209
12 changed files with 353 additions and 409 deletions

View File

@ -145,9 +145,6 @@ static int exit_status;
static int initialized; static int initialized;
extern struct net_device static_single_netdev;
/************************************************************************** /**************************************************************************
MAIN - Kick off routine MAIN - Kick off routine
**************************************************************************/ **************************************************************************/
@ -159,13 +156,9 @@ int main ( void ) {
call_init_fns (); call_init_fns ();
probe_devices(); probe_devices();
/* Quick hack until netdevice.c uses proper dynamic registration */ netdev = next_netdev ();
netdev = &static_single_netdev;
if ( ! netdev->poll )
netdev = NULL;
if ( netdev ) { if ( netdev ) {
test_aoeboot ( &static_single_netdev ); test_aoeboot ( netdev );
} else { } else {
printf ( "No network device found\n" ); printf ( "No network device found\n" );
} }

View File

@ -7,9 +7,33 @@
* *
*/ */
#include <gpxe/tables.h>
struct net_device; struct net_device;
struct net_protocol; struct net_protocol;
/** A network-layer protocol that relies upon ARP */
struct arp_net_protocol {
/** Network-layer protocol */
struct net_protocol *net_protocol;
/** Check existence of address
*
* @v netdev Network device
* @v net_addr Network-layer address
* @ret rc Return status code
*/
int ( * check ) ( struct net_device *netdev,
const void *net_addr );
};
/**
* Register an ARP protocol
*
* @v protocol ARP protocol
*/
#define ARP_NET_PROTOCOL( protocol ) \
struct arp_net_protocol protocol __table ( arp_net_protocols, 01 )
extern int arp_resolve ( struct net_device *netdev, extern int arp_resolve ( struct net_device *netdev,
struct net_protocol *net_protocol, struct net_protocol *net_protocol,
const void *dest_net_addr, const void *dest_net_addr,

View File

@ -18,11 +18,14 @@ extern struct ll_protocol ethernet_protocol;
* @v priv_size Size of driver private data * @v priv_size Size of driver private data
* @ret netdev Network device, or NULL * @ret netdev Network device, or NULL
*/ */
#define alloc_etherdev( priv_size ) ( { \ static inline struct net_device * alloc_etherdev ( size_t priv_size ) {
struct net_device *netdev; \ struct net_device *netdev;
netdev = alloc_netdev ( priv_size ); \
if ( netdev ) \ netdev = alloc_netdev ( priv_size );
netdev->ll_protocol = &ethernet_protocol; \ if ( netdev ) {
netdev; } ) netdev->ll_protocol = &ethernet_protocol;
}
return netdev;
}
#endif /* _GPXE_ETHERNET_H */ #endif /* _GPXE_ETHERNET_H */

View File

@ -7,6 +7,8 @@
* *
*/ */
#include <ip.h>
struct net_protocol; struct net_protocol;
extern struct net_protocol ipv4_protocol; extern struct net_protocol ipv4_protocol;
@ -15,6 +17,6 @@ extern int add_ipv4_address ( struct net_device *netdev,
struct in_addr address, struct in_addr netmask, struct in_addr address, struct in_addr netmask,
struct in_addr gateway ); struct in_addr gateway );
extern void del_ipv4_address ( struct net_device *netdev ); extern void del_ipv4_address ( struct net_device *netdev );
extern int ipv4_uip_transmit ( struct pk_buff *pkb ); extern int ipv4_uip_tx ( struct pk_buff *pkb );
#endif /* _GPXE_IP_H */ #endif /* _GPXE_IP_H */

View File

@ -8,6 +8,7 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <gpxe/list.h>
#include <gpxe/tables.h> #include <gpxe/tables.h>
struct pk_buff; struct pk_buff;
@ -24,61 +25,6 @@ struct ll_protocol;
/** Maximum length of a network-layer address */ /** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4 #define MAX_NET_ADDR_LEN 4
/* Network-layer address may be required to hold a link-layer address
* (if NETADDR_FL_RAW is set
*/
#if MAX_NET_ADDR_LEN < MAX_LL_ADDR_LEN
#undef MAX_NET_ADDR_LEN
#define MAX_NET_ADDR_LEN MAX_LL_ADDR_LEN
#endif
/** A generic network-layer header */
struct net_header {
/** Network-layer protocol */
struct net_protocol *net_protocol;
/** Flags
*
* This is the bitwise OR of zero or more PKT_FL_XXX
* values.
*/
int flags;
/** Network-layer destination address */
uint8_t dest_net_addr[MAX_NET_ADDR_LEN];
/** Network-layer source address */
uint8_t source_net_addr[MAX_NET_ADDR_LEN];
};
/** Packet is a broadcast packet */
#define PKT_FL_BROADCAST 0x01
/** Packet is a multicast packet */
#define PKT_FL_MULTICAST 0x02
/** Addresses are raw hardware addresses */
#define PKT_FL_RAW_ADDR 0x04
/** A generic link-layer header */
struct ll_header {
/** Link-layer protocol */
struct ll_protocol *ll_protocol;
/** Flags
*
* This is the bitwise OR of zero or more PKT_FL_XXX
* values.
*/
int flags;
/** Link-layer destination address */
uint8_t dest_ll_addr[MAX_LL_ADDR_LEN];
/** Link-layer source address */
uint8_t source_ll_addr[MAX_LL_ADDR_LEN];
/** Network-layer protocol
*
*
* This is an ETH_P_XXX constant, in network-byte order
*/
uint16_t net_proto;
};
/** /**
* A network-layer protocol * A network-layer protocol
* *
@ -90,11 +36,13 @@ struct net_protocol {
* Process received packet * Process received packet
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @ret rc Return status code * @v netdev Network device
* @v ll_source Link-layer source address
* *
* This method takes ownership of the packet buffer. * This method takes ownership of the packet buffer.
*/ */
int ( * rx_process ) ( struct pk_buff *pkb ); int ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev,
const void *ll_source );
/** /**
* Transcribe network-layer address * Transcribe network-layer address
* *
@ -127,7 +75,6 @@ struct ll_protocol {
/** /**
* Transmit network-layer packet via network device * Transmit network-layer packet via network device
* *
*
* @v pkb Packet buffer * @v pkb Packet buffer
* @v netdev Network device * @v netdev Network device
* @v net_protocol Network-layer protocol * @v net_protocol Network-layer protocol
@ -137,22 +84,20 @@ struct ll_protocol {
* This method should prepend in the link-layer header * This method should prepend in the link-layer header
* (e.g. the Ethernet DIX header) and transmit the packet. * (e.g. the Ethernet DIX header) and transmit the packet.
*/ */
int ( * transmit ) ( struct pk_buff *pkb, struct net_device *netdev, int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev,
struct net_protocol *net_protocol, struct net_protocol *net_protocol,
const void *ll_dest ); const void *ll_dest );
/** /**
* Parse media-specific link-layer header * Handle received packet
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @v llhdr Generic link-layer header * @v netdev Network device
* *
* This method should fill in the generic link-layer header * This method should strip off the link-layer header
* based on information in the link-layer header in the packet * (e.g. the Ethernet DIX header) and pass the packet to
* buffer. * net_rx().
*/ */
void ( * parse_llh ) ( const struct pk_buff *pkb, void ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev );
struct ll_header *llhdr );
/** /**
* Transcribe link-layer address * Transcribe link-layer address
* *
@ -165,7 +110,7 @@ struct ll_protocol {
* The buffer used to hold the transcription is statically * The buffer used to hold the transcription is statically
* allocated. * allocated.
*/ */
const char * ( *ntoa ) ( const void * ll_addr ); const char * ( * ntoa ) ( const void * ll_addr );
/** Link-layer protocol /** Link-layer protocol
* *
* This is an ARPHRD_XXX constant, in network byte order. * This is an ARPHRD_XXX constant, in network byte order.
@ -177,17 +122,6 @@ struct ll_protocol {
const uint8_t *ll_broadcast; const uint8_t *ll_broadcast;
}; };
/**
* A network-layer address assigned to a network device
*
*/
struct net_address {
/** Network-layer protocol */
struct net_protocol *net_protocol;
/** Network-layer address */
uint8_t net_addr[MAX_NET_ADDR_LEN];
};
/** /**
* A network device * A network device
* *
@ -199,6 +133,8 @@ struct net_address {
* not just an Ethernet device. * not just an Ethernet device.
*/ */
struct net_device { struct net_device {
/** List of network devices */
struct list_head list;
/** Transmit packet /** Transmit packet
* *
* @v netdev Network device * @v netdev Network device
@ -231,79 +167,13 @@ struct net_device {
*/ */
uint8_t ll_addr[MAX_LL_ADDR_LEN]; uint8_t ll_addr[MAX_LL_ADDR_LEN];
/** Received packet queue */
struct list_head rx_queue;
/** Driver private data */ /** Driver private data */
void *priv; void *priv;
}; };
extern struct net_device static_single_netdev;
/**
* Allocate network device
*
* @v priv_size Size of private data area (net_device::priv)
* @ret netdev Network device, or NULL
*
* Allocates space for a network device and its private data area.
*
* This macro allows for a very efficient implementation in the case
* of a single static network device; it neatly avoids dynamic
* allocation and can never return failure, meaning that the failure
* path will be optimised away. However, driver writers should not
* rely on this feature; the drivers should be written to allow for
* multiple instances of network devices.
*/
#define alloc_netdev( priv_size ) ( { \
static char priv_data[priv_size]; \
static_single_netdev.priv = priv_data; \
&static_single_netdev; } )
/**
* Free network device
*
* @v netdev Network device
*/
static inline void
free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
/* Nothing to do */
}
/**
* Transmit raw packet via network device
*
* @v netdev Network device
* @v pkb Packet buffer
* @ret rc Return status code
*
* Transmits the packet via the specified network device. The
* link-layer header must already have been filled in. This function
* takes ownership of the packet buffer.
*/
static inline int netdev_transmit ( struct net_device *netdev,
struct pk_buff *pkb ) {
return netdev->transmit ( netdev, pkb );
}
/**
* Transmit network-layer packet
*
* @v pkb Packet buffer
* @v netdev Network device
* @v net_protocol Network-layer protocol
* @v ll_dest Destination link-layer address
* @ret rc Return status code
*
* Prepends link-layer headers to the packet buffer and transmits the
* packet via the specified network device. This function takes
* ownership of the packet buffer.
*/
static inline int net_transmit ( struct pk_buff *pkb,
struct net_device *netdev,
struct net_protocol *net_protocol,
const void *ll_dest ) {
return netdev->ll_protocol->transmit ( pkb, netdev, net_protocol,
ll_dest );
}
/** /**
* Register a link-layer protocol * Register a link-layer protocol
* *
@ -321,23 +191,29 @@ static inline int net_transmit ( struct pk_buff *pkb,
struct net_protocol protocol __table ( net_protocols, 01 ) struct net_protocol protocol __table ( net_protocols, 01 )
/** /**
* Register a network-layer address for the static single network device * Get network device name
* *
* @v net_address Network-layer address * @v netdev Network device
* @ret name Network device name
*
* The name will be the device's link-layer address.
*/ */
#define STATIC_SINGLE_NETDEV_ADDRESS( address ) \ static inline const char * netdev_name ( struct net_device *netdev ) {
struct net_address address __table ( sgl_netdev_addresses, 01 ) return netdev->ll_protocol->ntoa ( netdev->ll_addr );
}
extern int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb );
extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest );
extern void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
uint16_t net_proto, const void *ll_source );
extern int netdev_poll ( struct net_device *netdev );
extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
extern struct net_device * alloc_netdev ( size_t priv_size );
extern int register_netdev ( struct net_device *netdev ); extern int register_netdev ( struct net_device *netdev );
extern void unregister_netdev ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev );
extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ); extern void free_netdev ( struct net_device *netdev );
extern struct net_device * next_netdev ( void );
extern struct net_protocol *find_net_protocol ( uint16_t net_proto );
extern struct net_device *
find_netdev_by_net_addr ( struct net_protocol *net_protocol, void *net_addr );
extern int net_poll ( void );
extern struct pk_buff * net_rx_dequeue ( void );
extern int net_rx_process ( struct pk_buff *pkb );
#endif /* _GPXE_NETDEVICE_H */ #endif /* _GPXE_NETDEVICE_H */

View File

@ -14,9 +14,6 @@
#include <assert.h> #include <assert.h>
#include <gpxe/list.h> #include <gpxe/list.h>
struct net_protocol;
struct ll_protocol;
/** /**
* Packet buffer alignment * Packet buffer alignment
* *
@ -42,6 +39,9 @@ struct ll_protocol;
* This structure is used to represent a network packet within gPXE. * This structure is used to represent a network packet within gPXE.
*/ */
struct pk_buff { struct pk_buff {
/** List of which this buffer is a member */
struct list_head list;
/** Start of the buffer */ /** Start of the buffer */
void *head; void *head;
/** Start of data */ /** Start of data */
@ -50,14 +50,6 @@ struct pk_buff {
void *tail; void *tail;
/** End of the buffer */ /** End of the buffer */
void *end; void *end;
/** List of which this buffer is a member */
struct list_head list;
/** The network-layer protocol */
struct net_protocol *net_protocol;
/** The link-layer protocol */
struct ll_protocol *ll_protocol;
}; };
/** /**

View File

@ -87,7 +87,6 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
data_out_len ); data_out_len );
if ( ! pkb ) if ( ! pkb )
return -ENOMEM; return -ENOMEM;
pkb->net_protocol = &aoe_protocol;
pkb_reserve ( pkb, ETH_HLEN ); pkb_reserve ( pkb, ETH_HLEN );
aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) ); aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) );
aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) ); aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) );
@ -117,7 +116,7 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
/* Send packet */ /* Send packet */
start_timer ( &aoe->timer ); start_timer ( &aoe->timer );
return net_transmit ( pkb, aoe->netdev, &aoe_protocol, aoe->target ); return net_tx ( pkb, aoe->netdev, &aoe_protocol, aoe->target );
} }
/** /**
@ -209,13 +208,15 @@ static int aoe_rx_response ( struct aoe_session *aoe, struct aoehdr *aoehdr,
* Process incoming AoE packets * Process incoming AoE packets
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @v netdev Network device
* @v ll_source Link-layer source address
* @ret rc Return status code * @ret rc Return status code
* *
*/ */
static int aoe_rx ( struct pk_buff *pkb ) { static int aoe_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
const void *ll_source ) {
struct aoehdr *aoehdr = pkb->data; struct aoehdr *aoehdr = pkb->data;
unsigned int len = pkb_len ( pkb ); unsigned int len = pkb_len ( pkb );
struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) );
struct aoe_session *aoe; struct aoe_session *aoe;
int rc = 0; int rc = 0;
@ -241,8 +242,7 @@ static int aoe_rx ( struct pk_buff *pkb ) {
continue; continue;
if ( ntohl ( aoehdr->tag ) != aoe->tag ) if ( ntohl ( aoehdr->tag ) != aoe->tag )
continue; continue;
memcpy ( aoe->target, ethhdr->h_source, memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
sizeof ( aoe->target ) );
rc = aoe_rx_response ( aoe, aoehdr, len ); rc = aoe_rx_response ( aoe, aoehdr, len );
break; break;
} }
@ -256,7 +256,7 @@ static int aoe_rx ( struct pk_buff *pkb ) {
struct net_protocol aoe_protocol = { struct net_protocol aoe_protocol = {
.name = "AoE", .name = "AoE",
.net_proto = htons ( ETH_P_AOE ), .net_proto = htons ( ETH_P_AOE ),
.rx_process = aoe_rx, .rx = aoe_rx,
}; };
NET_PROTOCOL ( aoe_protocol ); NET_PROTOCOL ( aoe_protocol );

View File

@ -36,6 +36,12 @@
* *
*/ */
/** Registered ARP protocols */
static struct arp_net_protocol arp_net_protocols[0]
__table_start ( arp_net_protocols );
static struct arp_net_protocol arp_net_protocols_end[0]
__table_end ( arp_net_protocols );
/** An ARP cache entry */ /** An ARP cache entry */
struct arp_entry { struct arp_entry {
/** Network-layer protocol */ /** Network-layer protocol */
@ -134,7 +140,6 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ); 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
if ( ! pkb ) if ( ! pkb )
return -ENOMEM; return -ENOMEM;
pkb->net_protocol = &arp_protocol;
pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
/* Build up ARP request */ /* Build up ARP request */
@ -154,17 +159,38 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
dest_net_addr, net_protocol->net_addr_len ); dest_net_addr, net_protocol->net_addr_len );
/* Transmit ARP request */ /* Transmit ARP request */
if ( ( rc = net_transmit ( pkb, netdev, &arp_protocol, if ( ( rc = net_tx ( pkb, netdev, &arp_protocol,
ll_protocol->ll_broadcast ) ) != 0 ) ll_protocol->ll_broadcast ) ) != 0 )
return rc; return rc;
return -ENOENT; return -ENOENT;
} }
/**
* Identify ARP protocol
*
* @v net_proto Network-layer protocol, in network-endian order
* @ret arp_net_protocol ARP protocol, or NULL
*
*/
static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
struct arp_net_protocol *arp_net_protocol;
for ( arp_net_protocol = arp_net_protocols ;
arp_net_protocol < arp_net_protocols_end ; arp_net_protocol++ ) {
if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
return arp_net_protocol;
}
}
return NULL;
}
/** /**
* Process incoming ARP packets * Process incoming ARP packets
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @v netdev Network device
* @v ll_source Link-layer source address
* @ret rc Return status code * @ret rc Return status code
* *
* This handles ARP requests and responses as detailed in RFC826. The * This handles ARP requests and responses as detailed in RFC826. The
@ -173,19 +199,21 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
* avoiding the need for extraneous ARP requests; read the RFC for * avoiding the need for extraneous ARP requests; read the RFC for
* details. * details.
*/ */
static int arp_rx ( struct pk_buff *pkb ) { static int arp_rx ( struct pk_buff *pkb, struct net_device *netdev,
const void *ll_source __unused ) {
struct arphdr *arphdr = pkb->data; struct arphdr *arphdr = pkb->data;
struct ll_protocol *ll_protocol; struct arp_net_protocol *arp_net_protocol;
struct net_protocol *net_protocol; struct net_protocol *net_protocol;
struct ll_protocol *ll_protocol;
struct arp_entry *arp; struct arp_entry *arp;
struct net_device *netdev;
int merge = 0; int merge = 0;
/* Identify link-layer and network-layer protocols */ /* Identify network-layer and link-layer protocols */
ll_protocol = pkb->ll_protocol; arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
net_protocol = find_net_protocol ( arphdr->ar_pro ); if ( ! arp_net_protocol )
if ( ! net_protocol )
goto done; goto done;
net_protocol = arp_net_protocol->net_protocol;
ll_protocol = netdev->ll_protocol;
/* Sanity checks */ /* Sanity checks */
if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) || if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
@ -206,9 +234,7 @@ static int arp_rx ( struct pk_buff *pkb ) {
} }
/* See if we own the target protocol address */ /* See if we own the target protocol address */
netdev = find_netdev_by_net_addr ( net_protocol, if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
arp_target_pa ( arphdr ) );
if ( ! netdev )
goto done; goto done;
/* Create new ARP table entry if necessary */ /* Create new ARP table entry if necessary */
@ -239,7 +265,7 @@ static int arp_rx ( struct pk_buff *pkb ) {
memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
/* Send reply */ /* Send reply */
net_transmit ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) ); net_tx ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) );
pkb = NULL; pkb = NULL;
done: done:
@ -264,7 +290,7 @@ arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) {
struct net_protocol arp_protocol = { struct net_protocol arp_protocol = {
.name = "ARP", .name = "ARP",
.net_proto = htons ( ETH_P_ARP ), .net_proto = htons ( ETH_P_ARP ),
.rx_process = arp_rx, .rx = arp_rx,
.ntoa = arp_ntoa, .ntoa = arp_ntoa,
}; };

View File

@ -46,41 +46,43 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
* *
* Prepends the Ethernet link-layer header and transmits the packet. * Prepends the Ethernet link-layer header and transmits the packet.
*/ */
static int eth_transmit ( struct pk_buff *pkb, struct net_device *netdev, static int eth_tx ( struct pk_buff *pkb, struct net_device *netdev,
struct net_protocol *net_protocol, struct net_protocol *net_protocol, const void *ll_dest ) {
const void *ll_dest ) {
struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) ); struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) );
/* Build Ethernet header */
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
ethhdr->h_protocol = net_protocol->net_proto; ethhdr->h_protocol = net_protocol->net_proto;
return netdev_transmit ( netdev, pkb );
/* Hand off to network device */
return netdev_tx ( netdev, pkb );
} }
/** /**
* Parse Ethernet link-layer header * Process received Ethernet packet
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @v llhdr Generic link-layer header * @v netdev Network device
* *
* Fills in the generic link-layer header based on information in the * Strips off the Ethernet link-layer header and passes up to the
* Ethernet link-layer header in the packet buffer. * network-layer protocol.
*/ */
static void eth_parse_llh ( const struct pk_buff *pkb, static void eth_rx ( struct pk_buff *pkb, struct net_device *netdev ) {
struct ll_header *llhdr ) {
struct ethhdr *ethhdr = pkb->data; struct ethhdr *ethhdr = pkb->data;
memcpy ( llhdr->dest_ll_addr, ethhdr->h_dest, ETH_ALEN ); /* Sanity check */
memcpy ( llhdr->source_ll_addr, ethhdr->h_source, ETH_ALEN ); if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) {
llhdr->net_proto = ethhdr->h_protocol; DBG ( "Ethernet packet too short (%d bytes)\n",
pkb_len ( pkb ) );
if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) { return;
llhdr->flags = PKT_FL_BROADCAST;
} else if ( ethhdr->h_dest[0] & 0x01 ) {
llhdr->flags = PKT_FL_MULTICAST;
} else {
llhdr->flags = 0;
} }
/* Strip off Ethernet header */
pkb_pull ( pkb, sizeof ( *ethhdr ) );
/* Hand off to network-layer protocol */
net_rx ( pkb, netdev, ethhdr->h_protocol, ethhdr->h_source );
} }
/** /**
@ -105,8 +107,8 @@ struct ll_protocol ethernet_protocol = {
.ll_proto = htons ( ARPHRD_ETHER ), .ll_proto = htons ( ARPHRD_ETHER ),
.ll_addr_len = ETH_ALEN, .ll_addr_len = ETH_ALEN,
.ll_broadcast = eth_broadcast, .ll_broadcast = eth_broadcast,
.transmit = eth_transmit, .tx = eth_tx,
.parse_llh = eth_parse_llh, .rx = eth_rx,
.ntoa = eth_ntoa, .ntoa = eth_ntoa,
}; };

View File

@ -7,10 +7,6 @@
#include <gpxe/list.h> #include <gpxe/list.h>
#include <gpxe/in.h> #include <gpxe/in.h>
#include <gpxe/arp.h> #include <gpxe/arp.h>
#include <ip.h>
#include <gpxe/if_ether.h> #include <gpxe/if_ether.h>
#include <gpxe/pkbuff.h> #include <gpxe/pkbuff.h>
#include <gpxe/netdevice.h> #include <gpxe/netdevice.h>
@ -104,7 +100,7 @@ void del_ipv4_address ( struct net_device *netdev ) {
* @ret rc Return status code * @ret rc Return status code
* *
*/ */
int ipv4_uip_transmit ( struct pk_buff *pkb ) { int ipv4_uip_tx ( struct pk_buff *pkb ) {
struct iphdr *iphdr = pkb->data; struct iphdr *iphdr = pkb->data;
struct ipv4_miniroute *miniroute; struct ipv4_miniroute *miniroute;
struct net_device *netdev = NULL; struct net_device *netdev = NULL;
@ -162,7 +158,7 @@ int ipv4_uip_transmit ( struct pk_buff *pkb ) {
} }
/* Hand off to link layer */ /* Hand off to link layer */
return net_transmit ( pkb, netdev, &ipv4_protocol, ll_dest ); return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
err: err:
free_pkb ( pkb ); free_pkb ( pkb );
@ -173,12 +169,15 @@ int ipv4_uip_transmit ( struct pk_buff *pkb ) {
* Process incoming IP packets * Process incoming IP packets
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @v netdev Network device
* @v ll_source Link-layer source address
* @ret rc Return status code * @ret rc Return status code
* *
* This handles IP packets by handing them off to the uIP protocol * This handles IP packets by handing them off to the uIP protocol
* stack. * stack.
*/ */
static int ipv4_rx ( struct pk_buff *pkb ) { static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
const void *ll_source __unused ) {
/* Transfer to uIP buffer. Horrendously space-inefficient, /* Transfer to uIP buffer. Horrendously space-inefficient,
* but will do as a proof-of-concept for now. * but will do as a proof-of-concept for now.
@ -195,11 +194,32 @@ static int ipv4_rx ( struct pk_buff *pkb ) {
return -ENOMEM; return -ENOMEM;
pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len ); memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len );
ipv4_uip_transmit ( pkb ); ipv4_uip_tx ( pkb );
} }
return 0; return 0;
} }
/**
* Check existence of IPv4 address for ARP
*
* @v netdev Network device
* @v net_addr Network-layer address
* @ret rc Return status code
*/
static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
const struct in_addr *address = net_addr;
struct ipv4_miniroute *miniroute;
list_for_each_entry ( miniroute, &miniroutes, list ) {
if ( ( miniroute->netdev == netdev ) &&
( miniroute->address.s_addr == address->s_addr ) ) {
/* Found matching address */
return 0;
}
}
return -ENOENT;
}
/** /**
* Convert IPv4 address to dotted-quad notation * Convert IPv4 address to dotted-quad notation
* *
@ -230,18 +250,16 @@ struct net_protocol ipv4_protocol = {
.name = "IP", .name = "IP",
.net_proto = htons ( ETH_P_IP ), .net_proto = htons ( ETH_P_IP ),
.net_addr_len = sizeof ( struct in_addr ), .net_addr_len = sizeof ( struct in_addr ),
.rx_process = ipv4_rx, .rx = ipv4_rx,
.ntoa = ipv4_ntoa, .ntoa = ipv4_ntoa,
}; };
NET_PROTOCOL ( ipv4_protocol ); NET_PROTOCOL ( ipv4_protocol );
/** IPv4 address for the static single net device */ /** IPv4 ARP protocol */
struct net_address static_single_ipv4_address = { struct arp_net_protocol ipv4_arp_protocol = {
.net_protocol = &ipv4_protocol, .net_protocol = &ipv4_protocol,
.check = ipv4_arp_check,
#warning "Remove this static-IP hack"
.net_addr = { 0x0a, 0xfe, 0xfe, 0x01 },
}; };
STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address ); ARP_NET_PROTOCOL ( ipv4_arp_protocol );

View File

@ -20,6 +20,7 @@
#include <byteswap.h> #include <byteswap.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <malloc.h>
#include <gpxe/if_ether.h> #include <gpxe/if_ether.h>
#include <gpxe/pkbuff.h> #include <gpxe/pkbuff.h>
#include <gpxe/tables.h> #include <gpxe/tables.h>
@ -33,39 +34,141 @@
* *
*/ */
/**
* Static single instance of a network device
*
* The gPXE API is designed to accommodate multiple network devices.
* However, in the interests of code size, the implementation behind
* the API supports only a single instance of a network device.
*
* No code outside of netdevice.c should ever refer directly to @c
* static_single_netdev.
*
* Callers should always check the return status of alloc_netdev(),
* register_netdev() etc. In the current implementation this code
* will be optimised out by the compiler, so there is no penalty.
*/
struct net_device static_single_netdev;
/** Registered network-layer protocols */ /** Registered network-layer protocols */
static struct net_protocol net_protocols[0] __table_start ( net_protocols ); static struct net_protocol net_protocols[0] __table_start ( net_protocols );
static struct net_protocol net_protocols_end[0] __table_end ( net_protocols ); static struct net_protocol net_protocols_end[0] __table_end ( net_protocols );
/** Network-layer addresses for @c static_single_netdev */ /** List of network devices */
static struct net_address static_single_netdev_addresses[0] static LIST_HEAD ( net_devices );
__table_start ( sgl_netdev_addresses );
static struct net_address static_single_netdev_addresses_end[0]
__table_end ( sgl_netdev_addresses );
/** Recevied packet queue */
static LIST_HEAD ( rx_queue );
#warning "Remove this static IP address hack" #warning "Remove this static IP address hack"
#include <ip.h> #include <ip.h>
#include <gpxe/ip.h> #include <gpxe/ip.h>
/**
* Transmit raw packet via network device
*
* @v netdev Network device
* @v pkb Packet buffer
* @ret rc Return status code
*
* Transmits the packet via the specified network device. This
* function takes ownership of the packet buffer.
*/
int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb ) {
DBG ( "%s transmitting %p+%zx\n", netdev_name ( netdev ),
pkb->data, pkb_len ( pkb ) );
return netdev->transmit ( netdev, pkb );
}
/**
* Add packet to receive queue
*
* @v netdev Network device
* @v pkb Packet buffer
*
* The packet is added to the network device's RX queue. This
* function takes ownership of the packet buffer.
*/
void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
DBG ( "%s received %p+%zx\n", netdev_name ( netdev ),
pkb->data, pkb_len ( pkb ) );
list_add_tail ( &pkb->list, &netdev->rx_queue );
}
/**
* Transmit network-layer packet
*
* @v pkb Packet buffer
* @v netdev Network device
* @v net_protocol Network-layer protocol
* @v ll_dest Destination link-layer address
* @ret rc Return status code
*
* Prepends link-layer headers to the packet buffer and transmits the
* packet via the specified network device. This function takes
* ownership of the packet buffer.
*/
int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
struct net_protocol *net_protocol, const void *ll_dest ) {
return netdev->ll_protocol->tx ( pkb, netdev, net_protocol, ll_dest );
}
/**
* Process received network-layer packet
*
* @v pkb Packet buffer
* @v netdev Network device
* @v net_proto Network-layer protocol, in network-byte order
* @v ll_source Source link-layer address
*/
void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
uint16_t net_proto, const void *ll_source ) {
struct net_protocol *net_protocol;
/* Hand off to network-layer protocol, if any */
for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
net_protocol++ ) {
if ( net_protocol->net_proto == net_proto ) {
net_protocol->rx ( pkb, netdev, ll_source );
break;
}
}
}
/**
* Poll for packet on network device
*
* @v netdev Network device
* @ret True There are packets present in the receive queue
* @ret False There are no packets present in the receive queue
*
* Polls the network device for received packets. Any received
* packets will be added to the RX packet queue via netdev_rx().
*/
int netdev_poll ( struct net_device *netdev ) {
netdev->poll ( netdev );
return ( ! list_empty ( &netdev->rx_queue ) );
}
/**
* Remove packet from device's receive queue
*
* @v netdev Network device
* @ret pkb Packet buffer, or NULL
*
* Removes the first packet from the device's RX queue and returns it.
* Ownership of the packet is transferred to the caller.
*/
struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev ) {
struct pk_buff *pkb;
list_for_each_entry ( pkb, &netdev->rx_queue, list ) {
list_del ( &pkb->list );
return pkb;
}
return NULL;
}
/**
* Allocate network device
*
* @v priv_size Size of private data area (net_device::priv)
* @ret netdev Network device, or NULL
*
* Allocates space for a network device and its private data area.
*/
struct net_device * alloc_netdev ( size_t priv_size ) {
struct net_device *netdev;
netdev = calloc ( 1, sizeof ( *netdev ) + priv_size );
if ( netdev ) {
INIT_LIST_HEAD ( &netdev->rx_queue );
netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
return netdev;
}
/** /**
* Register network device * Register network device
* *
@ -89,6 +192,10 @@ int register_netdev ( struct net_device *netdev ) {
return rc; return rc;
} }
/* Add to device list */
list_add_tail ( &netdev->list, &net_devices );
DBG ( "%s registered\n", netdev_name ( netdev ) );
return 0; return 0;
} }
@ -100,157 +207,52 @@ int register_netdev ( struct net_device *netdev ) {
* Removes the network device from the list of network devices. * Removes the network device from the list of network devices.
*/ */
void unregister_netdev ( struct net_device *netdev ) { void unregister_netdev ( struct net_device *netdev ) {
struct pk_buff *pkb;
#warning "Remove this static IP address hack" #warning "Remove this static IP address hack"
del_ipv4_address ( netdev ); del_ipv4_address ( netdev );
/* Discard any packets in the RX queue */
while ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) {
DBG ( "%s discarding %p+%zx\n", netdev_name ( netdev ),
pkb->data, pkb_len ( pkb ) );
free_pkb ( pkb );
}
/* Remove from device list */
list_del ( &netdev->list );
DBG ( "%s unregistered\n", netdev_name ( netdev ) );
} }
/** /**
* Add packet to receive queue * Free network device
* *
* @v netdev Network device * @v netdev Network device
* @v pkb Packet buffer
*
* The packet is added to the RX queue. This function takes ownership
* of the packet buffer.
*/ */
void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) { void free_netdev ( struct net_device *netdev ) {
DBG ( "Packet received\n" ); free ( netdev );
pkb->ll_protocol = netdev->ll_protocol;
list_add_tail ( &pkb->list, &rx_queue );
} }
/** /**
* Identify network protocol * Iterate through network devices
* *
* @v net_proto Network-layer protocol, in network-byte order
* @ret net_protocol Network-layer protocol, or NULL
*
* Identify a network-layer protocol from a protocol number, which
* must be an ETH_P_XXX constant in network-byte order.
*/
struct net_protocol * find_net_protocol ( uint16_t net_proto ) {
struct net_protocol *net_protocol;
for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
net_protocol++ ) {
if ( net_protocol->net_proto == net_proto )
return net_protocol;
}
return NULL;
}
/**
* Identify network device by network-layer address
*
* @v net_protocol Network-layer protocol
* @v net_addr Network-layer address
* @ret netdev Network device, or NULL * @ret netdev Network device, or NULL
* *
* Searches through all network devices to find the device with the * This returns the registered network devices in the order of
* specified network-layer address. * registration. If no network devices are registered, it will return
* * NULL.
* Note that even with a static single network device, this function
* can still return NULL.
*/ */
struct net_device * struct net_device * next_netdev ( void ) {
find_netdev_by_net_addr ( struct net_protocol *net_protocol, struct net_device *netdev;
void *net_addr ) {
struct net_address *net_address;
struct net_device *netdev = &static_single_netdev;
for ( net_address = static_single_netdev_addresses ;
net_address < static_single_netdev_addresses_end ;
net_address ++ ) {
if ( ( net_address->net_protocol == net_protocol ) &&
( memcmp ( net_address->net_addr, net_addr,
net_protocol->net_addr_len ) == 0 ) )
return netdev;
}
return NULL; list_for_each_entry ( netdev, &net_devices, list ) {
} list_del ( &netdev->list );
list_add_tail ( &netdev->list, &net_devices );
/** return netdev;
* Poll for packet on all network devices
*
* @ret True There are packets present in the receive queue
* @ret False There are no packets present in the receive queue
*
* Polls all network devices for received packets. Any received
* packets will be added to the RX packet queue via netdev_rx().
*/
int net_poll ( void ) {
struct net_device *netdev = &static_single_netdev;
DBG ( "Polling network\n" );
netdev->poll ( netdev );
return ( ! list_empty ( &rx_queue ) );
}
/**
* Remove packet from receive queue
*
* @ret pkb Packet buffer, or NULL
*
* Removes the first packet from the RX queue and returns it.
* Ownership of the packet is transferred to the caller.
*/
struct pk_buff * net_rx_dequeue ( void ) {
struct pk_buff *pkb;
list_for_each_entry ( pkb, &rx_queue, list ) {
list_del ( &pkb->list );
return pkb;
} }
return NULL; return NULL;
} }
/**
* Process received packet
*
* @v pkb Packet buffer
* @ret rc Return status code
*
* Processes a packet received from the network (and, usually, removed
* from the RX queue by net_rx_dequeue()). This call takes ownership
* of the packet buffer.
*/
int net_rx_process ( struct pk_buff *pkb ) {
struct ll_protocol *ll_protocol;
struct ll_header llhdr;
struct net_protocol *net_protocol;
int rc;
/* Parse link-layer header */
ll_protocol = pkb->ll_protocol;
ll_protocol->parse_llh ( pkb, &llhdr );
/* Identify network-layer protocol */
net_protocol = find_net_protocol ( llhdr.net_proto );
if ( ! net_protocol ) {
DBG ( "Unknown network-layer protocol %x\n",
ntohs ( llhdr.net_proto ) );
free_pkb ( pkb );
return -EPROTONOSUPPORT;
}
pkb->net_protocol = net_protocol;
/* Strip off link-layer header */
#warning "Temporary hack"
pkb_pull ( pkb, ETH_HLEN );
/* Hand off to network layer */
if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) {
DBG ( "Network-layer protocol dropped packet\n" );
return rc;
}
return 0;
}
/** /**
* Single-step the network stack * Single-step the network stack
* *
@ -266,15 +268,21 @@ int net_rx_process ( struct pk_buff *pkb ) {
* multiple packets are processed per poll. * multiple packets are processed per poll.
*/ */
static void net_step ( struct process *process ) { static void net_step ( struct process *process ) {
struct net_device *netdev;
struct pk_buff *pkb; struct pk_buff *pkb;
/* Poll for new packets */ /* Poll and process each network device */
net_poll(); list_for_each_entry ( netdev, &net_devices, list ) {
/* Handle at most one received packet */ /* Poll for new packets */
if ( ( pkb = net_rx_dequeue () ) ) { netdev_poll ( netdev );
net_rx_process ( pkb );
DBG ( "Processed received packet\n" ); /* Handle at most one received packet per poll */
if ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) {
DBG ( "%s processing %p+%zx\n", netdev_name ( netdev ),
pkb->data, pkb_len ( pkb ) );
netdev->ll_protocol->rx ( pkb, netdev );
}
} }
/* Re-schedule ourself */ /* Re-schedule ourself */

View File

@ -177,7 +177,7 @@ static void tcp_periodic ( void ) {
pkb_put ( pkb, uip_len ); pkb_put ( pkb, uip_len );
memcpy ( pkb->data, uip_buf, uip_len ); memcpy ( pkb->data, uip_buf, uip_len );
ipv4_uip_transmit ( pkb ); ipv4_uip_tx ( pkb );
} }
} }
} }