diff --git a/src/core/main.c b/src/core/main.c index 71300a85..e2b6ae82 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -145,9 +145,6 @@ static int exit_status; static int initialized; -extern struct net_device static_single_netdev; - - /************************************************************************** MAIN - Kick off routine **************************************************************************/ @@ -159,13 +156,9 @@ int main ( void ) { call_init_fns (); probe_devices(); - /* Quick hack until netdevice.c uses proper dynamic registration */ - netdev = &static_single_netdev; - if ( ! netdev->poll ) - netdev = NULL; - + netdev = next_netdev (); if ( netdev ) { - test_aoeboot ( &static_single_netdev ); + test_aoeboot ( netdev ); } else { printf ( "No network device found\n" ); } diff --git a/src/include/gpxe/arp.h b/src/include/gpxe/arp.h index a1f9e349..ffaf418a 100644 --- a/src/include/gpxe/arp.h +++ b/src/include/gpxe/arp.h @@ -7,9 +7,33 @@ * */ +#include + struct net_device; 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, struct net_protocol *net_protocol, const void *dest_net_addr, diff --git a/src/include/gpxe/ethernet.h b/src/include/gpxe/ethernet.h index e62eb09b..0188ac81 100644 --- a/src/include/gpxe/ethernet.h +++ b/src/include/gpxe/ethernet.h @@ -18,11 +18,14 @@ extern struct ll_protocol ethernet_protocol; * @v priv_size Size of driver private data * @ret netdev Network device, or NULL */ -#define alloc_etherdev( priv_size ) ( { \ - struct net_device *netdev; \ - netdev = alloc_netdev ( priv_size ); \ - if ( netdev ) \ - netdev->ll_protocol = ðernet_protocol; \ - netdev; } ) +static inline struct net_device * alloc_etherdev ( size_t priv_size ) { + struct net_device *netdev; + + netdev = alloc_netdev ( priv_size ); + if ( netdev ) { + netdev->ll_protocol = ðernet_protocol; + } + return netdev; +} #endif /* _GPXE_ETHERNET_H */ diff --git a/src/include/gpxe/ip.h b/src/include/gpxe/ip.h index 8eac31a6..7cd2fcff 100644 --- a/src/include/gpxe/ip.h +++ b/src/include/gpxe/ip.h @@ -7,6 +7,8 @@ * */ +#include + struct net_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 gateway ); 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 */ diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 68226dc2..b8cf9aee 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -8,6 +8,7 @@ */ #include +#include #include struct pk_buff; @@ -24,61 +25,6 @@ struct ll_protocol; /** Maximum length of a network-layer address */ #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 * @@ -90,11 +36,13 @@ struct net_protocol { * Process received packet * * @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. */ - 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 * @@ -127,7 +75,6 @@ struct ll_protocol { /** * Transmit network-layer packet via network device * - * * @v pkb Packet buffer * @v netdev Network device * @v net_protocol Network-layer protocol @@ -137,22 +84,20 @@ struct ll_protocol { * This method should prepend in the link-layer header * (e.g. the Ethernet DIX header) and transmit the packet. */ - int ( * transmit ) ( struct pk_buff *pkb, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ); + int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev, + struct net_protocol *net_protocol, + const void *ll_dest ); /** - * Parse media-specific link-layer header + * Handle received packet * * @v pkb Packet buffer - * @v llhdr Generic link-layer header + * @v netdev Network device * - * This method should fill in the generic link-layer header - * based on information in the link-layer header in the packet - * buffer. + * This method should strip off the link-layer header + * (e.g. the Ethernet DIX header) and pass the packet to + * net_rx(). */ - void ( * parse_llh ) ( const struct pk_buff *pkb, - struct ll_header *llhdr ); - + void ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev ); /** * Transcribe link-layer address * @@ -165,7 +110,7 @@ struct ll_protocol { * The buffer used to hold the transcription is statically * allocated. */ - const char * ( *ntoa ) ( const void * ll_addr ); + const char * ( * ntoa ) ( const void * ll_addr ); /** Link-layer protocol * * This is an ARPHRD_XXX constant, in network byte order. @@ -177,17 +122,6 @@ struct ll_protocol { 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 * @@ -199,6 +133,8 @@ struct net_address { * not just an Ethernet device. */ struct net_device { + /** List of network devices */ + struct list_head list; /** Transmit packet * * @v netdev Network device @@ -231,79 +167,13 @@ struct net_device { */ uint8_t ll_addr[MAX_LL_ADDR_LEN]; + /** Received packet queue */ + struct list_head rx_queue; + /** Driver private data */ 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 * @@ -321,23 +191,29 @@ static inline int net_transmit ( struct pk_buff *pkb, 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 ) \ - struct net_address address __table ( sgl_netdev_addresses, 01 ) +static inline const char * netdev_name ( struct net_device *netdev ) { + 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 void unregister_netdev ( struct net_device *netdev ); -extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ); - -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 ); +extern void free_netdev ( struct net_device *netdev ); +extern struct net_device * next_netdev ( void ); #endif /* _GPXE_NETDEVICE_H */ diff --git a/src/include/gpxe/pkbuff.h b/src/include/gpxe/pkbuff.h index 6c504029..c363a50d 100644 --- a/src/include/gpxe/pkbuff.h +++ b/src/include/gpxe/pkbuff.h @@ -14,9 +14,6 @@ #include #include -struct net_protocol; -struct ll_protocol; - /** * Packet buffer alignment * @@ -42,6 +39,9 @@ struct ll_protocol; * This structure is used to represent a network packet within gPXE. */ struct pk_buff { + /** List of which this buffer is a member */ + struct list_head list; + /** Start of the buffer */ void *head; /** Start of data */ @@ -50,14 +50,6 @@ struct pk_buff { void *tail; /** End of the buffer */ 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; }; /** diff --git a/src/net/aoe.c b/src/net/aoe.c index 693b3605..e0954fa5 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -87,7 +87,6 @@ static int aoe_send_command ( struct aoe_session *aoe ) { data_out_len ); if ( ! pkb ) return -ENOMEM; - pkb->net_protocol = &aoe_protocol; pkb_reserve ( pkb, ETH_HLEN ); aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) ); aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) ); @@ -117,7 +116,7 @@ static int aoe_send_command ( struct aoe_session *aoe ) { /* Send packet */ 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 * * @v pkb Packet buffer + * @v netdev Network device + * @v ll_source Link-layer source address * @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; unsigned int len = pkb_len ( pkb ); - struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) ); struct aoe_session *aoe; int rc = 0; @@ -241,8 +242,7 @@ static int aoe_rx ( struct pk_buff *pkb ) { continue; if ( ntohl ( aoehdr->tag ) != aoe->tag ) continue; - memcpy ( aoe->target, ethhdr->h_source, - sizeof ( aoe->target ) ); + memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) ); rc = aoe_rx_response ( aoe, aoehdr, len ); break; } @@ -256,7 +256,7 @@ static int aoe_rx ( struct pk_buff *pkb ) { struct net_protocol aoe_protocol = { .name = "AoE", .net_proto = htons ( ETH_P_AOE ), - .rx_process = aoe_rx, + .rx = aoe_rx, }; NET_PROTOCOL ( aoe_protocol ); diff --git a/src/net/arp.c b/src/net/arp.c index 66f9bd4c..6293bf95 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -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 */ struct arp_entry { /** 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 ) ); if ( ! pkb ) return -ENOMEM; - pkb->net_protocol = &arp_protocol; pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); /* 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 ); /* Transmit ARP request */ - if ( ( rc = net_transmit ( pkb, netdev, &arp_protocol, - ll_protocol->ll_broadcast ) ) != 0 ) + if ( ( rc = net_tx ( pkb, netdev, &arp_protocol, + ll_protocol->ll_broadcast ) ) != 0 ) return rc; 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 * * @v pkb Packet buffer + * @v netdev Network device + * @v ll_source Link-layer source address * @ret rc Return status code * * 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 * 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 ll_protocol *ll_protocol; + struct arp_net_protocol *arp_net_protocol; struct net_protocol *net_protocol; + struct ll_protocol *ll_protocol; struct arp_entry *arp; - struct net_device *netdev; int merge = 0; - /* Identify link-layer and network-layer protocols */ - ll_protocol = pkb->ll_protocol; - net_protocol = find_net_protocol ( arphdr->ar_pro ); - if ( ! net_protocol ) + /* Identify network-layer and link-layer protocols */ + arp_net_protocol = arp_find_protocol ( arphdr->ar_pro ); + if ( ! arp_net_protocol ) goto done; + net_protocol = arp_net_protocol->net_protocol; + ll_protocol = netdev->ll_protocol; /* Sanity checks */ 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 */ - netdev = find_netdev_by_net_addr ( net_protocol, - arp_target_pa ( arphdr ) ); - if ( ! netdev ) + if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0) goto done; /* 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 ); /* Send reply */ - net_transmit ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) ); + net_tx ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) ); pkb = NULL; done: @@ -264,7 +290,7 @@ arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) { struct net_protocol arp_protocol = { .name = "ARP", .net_proto = htons ( ETH_P_ARP ), - .rx_process = arp_rx, + .rx = arp_rx, .ntoa = arp_ntoa, }; diff --git a/src/net/ethernet.c b/src/net/ethernet.c index ab7d4277..13b3c2db 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -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. */ -static int eth_transmit ( struct pk_buff *pkb, struct net_device *netdev, - struct net_protocol *net_protocol, - const void *ll_dest ) { +static int eth_tx ( struct pk_buff *pkb, struct net_device *netdev, + struct net_protocol *net_protocol, const void *ll_dest ) { struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) ); + /* Build Ethernet header */ memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); 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 llhdr Generic link-layer header + * @v netdev Network device * - * Fills in the generic link-layer header based on information in the - * Ethernet link-layer header in the packet buffer. + * Strips off the Ethernet link-layer header and passes up to the + * network-layer protocol. */ -static void eth_parse_llh ( const struct pk_buff *pkb, - struct ll_header *llhdr ) { +static void eth_rx ( struct pk_buff *pkb, struct net_device *netdev ) { struct ethhdr *ethhdr = pkb->data; - memcpy ( llhdr->dest_ll_addr, ethhdr->h_dest, ETH_ALEN ); - memcpy ( llhdr->source_ll_addr, ethhdr->h_source, ETH_ALEN ); - llhdr->net_proto = ethhdr->h_protocol; - - if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) { - llhdr->flags = PKT_FL_BROADCAST; - } else if ( ethhdr->h_dest[0] & 0x01 ) { - llhdr->flags = PKT_FL_MULTICAST; - } else { - llhdr->flags = 0; + /* Sanity check */ + if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) { + DBG ( "Ethernet packet too short (%d bytes)\n", + pkb_len ( pkb ) ); + return; } + + /* 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_addr_len = ETH_ALEN, .ll_broadcast = eth_broadcast, - .transmit = eth_transmit, - .parse_llh = eth_parse_llh, + .tx = eth_tx, + .rx = eth_rx, .ntoa = eth_ntoa, }; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index ae3404cc..47b8cb7f 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -7,10 +7,6 @@ #include #include #include - -#include - - #include #include #include @@ -104,7 +100,7 @@ void del_ipv4_address ( struct net_device *netdev ) { * @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 ipv4_miniroute *miniroute; struct net_device *netdev = NULL; @@ -162,7 +158,7 @@ int ipv4_uip_transmit ( struct pk_buff *pkb ) { } /* Hand off to link layer */ - return net_transmit ( pkb, netdev, &ipv4_protocol, ll_dest ); + return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest ); err: free_pkb ( pkb ); @@ -173,12 +169,15 @@ int ipv4_uip_transmit ( struct pk_buff *pkb ) { * Process incoming IP packets * * @v pkb Packet buffer + * @v netdev Network device + * @v ll_source Link-layer source address * @ret rc Return status code * * This handles IP packets by handing them off to the uIP protocol * 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, * but will do as a proof-of-concept for now. @@ -195,11 +194,32 @@ static int ipv4_rx ( struct pk_buff *pkb ) { return -ENOMEM; pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len ); - ipv4_uip_transmit ( pkb ); + ipv4_uip_tx ( pkb ); } 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 * @@ -230,18 +250,16 @@ struct net_protocol ipv4_protocol = { .name = "IP", .net_proto = htons ( ETH_P_IP ), .net_addr_len = sizeof ( struct in_addr ), - .rx_process = ipv4_rx, + .rx = ipv4_rx, .ntoa = ipv4_ntoa, }; NET_PROTOCOL ( ipv4_protocol ); -/** IPv4 address for the static single net device */ -struct net_address static_single_ipv4_address = { +/** IPv4 ARP protocol */ +struct arp_net_protocol ipv4_arp_protocol = { .net_protocol = &ipv4_protocol, - -#warning "Remove this static-IP hack" - .net_addr = { 0x0a, 0xfe, 0xfe, 0x01 }, + .check = ipv4_arp_check, }; -STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address ); +ARP_NET_PROTOCOL ( ipv4_arp_protocol ); diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 1825a55b..1197e66c 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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 */ static struct net_protocol net_protocols[0] __table_start ( net_protocols ); static struct net_protocol net_protocols_end[0] __table_end ( net_protocols ); -/** Network-layer addresses for @c static_single_netdev */ -static struct net_address static_single_netdev_addresses[0] - __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 ); +/** List of network devices */ +static LIST_HEAD ( net_devices ); #warning "Remove this static IP address hack" #include #include +/** + * 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 * @@ -89,6 +192,10 @@ int register_netdev ( struct net_device *netdev ) { return rc; } + /* Add to device list */ + list_add_tail ( &netdev->list, &net_devices ); + DBG ( "%s registered\n", netdev_name ( netdev ) ); + return 0; } @@ -100,157 +207,52 @@ int register_netdev ( struct net_device *netdev ) { * Removes the network device from the list of network devices. */ void unregister_netdev ( struct net_device *netdev ) { + struct pk_buff *pkb; #warning "Remove this static IP address hack" 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 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 ) { - DBG ( "Packet received\n" ); - pkb->ll_protocol = netdev->ll_protocol; - list_add_tail ( &pkb->list, &rx_queue ); +void free_netdev ( struct net_device *netdev ) { + free ( netdev ); } /** - * 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 * - * Searches through all network devices to find the device with the - * specified network-layer address. - * - * Note that even with a static single network device, this function - * can still return NULL. + * This returns the registered network devices in the order of + * registration. If no network devices are registered, it will return + * NULL. */ -struct net_device * -find_netdev_by_net_addr ( struct net_protocol *net_protocol, - 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; - } +struct net_device * next_netdev ( void ) { + struct net_device *netdev; - return NULL; -} - -/** - * 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; + list_for_each_entry ( netdev, &net_devices, list ) { + list_del ( &netdev->list ); + list_add_tail ( &netdev->list, &net_devices ); + return netdev; } 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 * @@ -266,15 +268,21 @@ int net_rx_process ( struct pk_buff *pkb ) { * multiple packets are processed per poll. */ static void net_step ( struct process *process ) { + struct net_device *netdev; struct pk_buff *pkb; - /* Poll for new packets */ - net_poll(); + /* Poll and process each network device */ + list_for_each_entry ( netdev, &net_devices, list ) { - /* Handle at most one received packet */ - if ( ( pkb = net_rx_dequeue () ) ) { - net_rx_process ( pkb ); - DBG ( "Processed received packet\n" ); + /* Poll for new packets */ + netdev_poll ( netdev ); + + /* 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 */ diff --git a/src/net/tcp.c b/src/net/tcp.c index 5027678b..e73708dc 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -177,7 +177,7 @@ static void tcp_periodic ( void ) { pkb_put ( pkb, uip_len ); memcpy ( pkb->data, uip_buf, uip_len ); - ipv4_uip_transmit ( pkb ); + ipv4_uip_tx ( pkb ); } } }