From fdc2ee79db376b03710f9255720ce45c79022768 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 24 Apr 2006 15:33:06 +0000 Subject: Network API now allows for multiple network devices (although the implementation allows for only one, and does so without compromising on the efficiency of static allocation). Link-layer protocols are cleanly separated from the device drivers. Network-layer protocols are cleanly separated from individual network devices. Link-layer and network-layer protocols are cleanly separated from each other. --- src/net/arp.c | 191 +++++++++++++++++++++----------------- src/net/ethernet.c | 117 ++++++++++++++---------- src/net/netdevice.c | 257 ++++++++++++++++++++++++++++++++++------------------ 3 files changed, 347 insertions(+), 218 deletions(-) (limited to 'src/net') diff --git a/src/net/arp.c b/src/net/arp.c index bee7f5773..7b8eede6b 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -39,13 +39,13 @@ /** An ARP cache entry */ struct arp_entry { /** Network-layer protocol */ - uint16_t net_proto; + struct net_protocol *net_protocol; /** Link-layer protocol */ - uint16_t ll_proto; + struct ll_protocol *ll_protocol; /** Network-layer address */ uint8_t net_addr[MAX_NET_ADDR_LEN]; /** Link-layer address */ - uint8_t ll_addr[MAX_LLH_ADDR_LEN]; + uint8_t ll_addr[MAX_LL_ADDR_LEN]; }; /** Number of entries in the ARP cache @@ -61,25 +61,28 @@ static struct arp_entry arp_table[NUM_ARP_ENTRIES]; static unsigned int next_new_arp_entry = 0; +struct net_protocol arp_protocol; + /** * Find entry in the ARP cache * - * @v ll_proto Link-layer protocol - * @v net_proto Network-layer protocol + * @v ll_protocol Link-layer protocol + * @v net_protocol Network-layer protocol * @v net_addr Network-layer address - * @v net_addr_len Network-layer address length * @ret arp ARP cache entry, or NULL if not found * */ static struct arp_entry * -arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr, - size_t net_addr_len ) { +arp_find_entry ( struct ll_protocol *ll_protocol, + struct net_protocol *net_protocol, + const void *net_addr ) { struct arp_entry *arp; for ( arp = arp_table ; arp < arp_table_end ; arp++ ) { - if ( ( arp->ll_proto == ll_proto ) && - ( arp->net_proto == net_proto ) && - ( memcmp ( arp->net_addr, net_addr, net_addr_len ) == 0 )) + if ( ( arp->ll_protocol == ll_protocol ) && + ( arp->net_protocol == net_protocol ) && + ( memcmp ( arp->net_addr, net_addr, + net_protocol->net_addr_len ) == 0 ) ) return arp; } return NULL; @@ -88,59 +91,64 @@ arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr, /** * Look up media-specific link-layer address in the ARP cache * - * @v netdev Network device - * @v pkb Packet buffer - * @ret ll_addr Pointer to link-layer address + * @v nethdr Generic network-layer header + * @ret llhdr Generic link-layer header * @ret rc Return status code * * This function will use the ARP cache to look up the link-layer - * address for the media corresponding to @c netdev and the - * network-layer address as specified in the @c pkb metadata. + * address for the link-layer protocol specified in @c llhdr and the + * network-layer protocol and address as specified in @c nethdr. If + * found, the destination link-layer address will be filled in in @c + * llhdr. * * If no address is found in the ARP cache, an ARP request will be - * transmitted, -ENOENT will be returned, and the packet buffer - * contents will be undefined. + * transmitted and -ENOENT will be returned. */ -int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb, - const void **ll_addr ) { +int arp_resolve ( const struct net_header *nethdr, struct ll_header *llhdr ) { + struct net_protocol *net_protocol = nethdr->net_protocol; + struct ll_protocol *ll_protocol = llhdr->ll_protocol; const struct arp_entry *arp; - struct net_interface *netif; + struct pk_buff *pkb; struct arphdr *arphdr; + int rc; /* Look for existing entry in ARP table */ - arp = arp_find_entry ( netdev->ll_proto, pkb->net_proto, - pkb->net_addr, pkb->net_addr_len ); + arp = arp_find_entry ( ll_protocol, net_protocol, + nethdr->dest_net_addr ); if ( arp ) { - *ll_addr = arp->ll_addr; + memcpy ( llhdr->dest_ll_addr, arp->ll_addr, + sizeof ( llhdr->dest_ll_addr ) ); return 0; } - /* Find interface for this protocol */ - netif = netdev_find_netif ( netdev, pkb->net_proto ); - if ( ! netif ) - return -EAFNOSUPPORT; + /* Allocate ARP packet */ + pkb = alloc_pkb ( sizeof ( *arphdr ) + + 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ); + if ( ! pkb ) + return -ENOMEM; + pkb->net_protocol = &arp_protocol; /* Build up ARP request */ - pkb_empty ( pkb ); arphdr = pkb_put ( pkb, sizeof ( *arphdr ) ); - arphdr->ar_hrd = netdev->ll_proto; - arphdr->ar_hln = netdev->ll_addr_len; - arphdr->ar_pro = pkb->net_proto; - arphdr->ar_pln = pkb->net_addr_len; + arphdr->ar_hrd = ll_protocol->ll_proto; + arphdr->ar_hln = ll_protocol->ll_addr_len; + arphdr->ar_pro = net_protocol->net_proto; + arphdr->ar_pln = net_protocol->net_addr_len; arphdr->ar_op = htons ( ARPOP_REQUEST ); - memcpy ( pkb_put ( pkb, netdev->ll_addr_len ), - netdev->ll_addr, netdev->ll_addr_len ); - memcpy ( pkb_put ( pkb, netif->net_addr_len ), - netif->net_addr, netif->net_addr_len ); - memset ( pkb_put ( pkb, netdev->ll_addr_len ), - 0xff, netdev->ll_addr_len ); - memcpy ( pkb_put ( pkb, netif->net_addr_len ), - pkb->net_addr, netif->net_addr_len ); - - /* Locate ARP interface and send ARP request */ - netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) ); - assert ( netif != NULL ); - netif_send ( netif, pkb ); + memcpy ( pkb_put ( pkb, ll_protocol->ll_addr_len ), + llhdr->source_ll_addr, ll_protocol->ll_addr_len ); + memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ), + nethdr->source_net_addr, net_protocol->net_addr_len ); + memset ( pkb_put ( pkb, ll_protocol->ll_addr_len ), + 0, ll_protocol->ll_addr_len ); + memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ), + nethdr->dest_net_addr, net_protocol->net_addr_len ); + + /* Transmit ARP request */ + if ( ( rc = net_transmit ( pkb ) ) != 0 ) { + free_pkb ( pkb ); + return rc; + } return -ENOENT; } @@ -148,7 +156,6 @@ int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb, /** * Process incoming ARP packets * - * @v arp_netif Network interface for ARP packets * @v pkb Packet buffer * @ret rc Return status code * @@ -158,80 +165,96 @@ int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb, * avoiding the need for extraneous ARP requests; read the RFC for * details. */ -int arp_process ( struct net_interface *arp_netif, struct pk_buff *pkb ) { +static int arp_rx ( struct pk_buff *pkb ) { struct arphdr *arphdr = pkb->data; - struct net_device *netdev = arp_netif->netdev; - struct net_interface *netif; + struct ll_protocol *ll_protocol; + struct net_protocol *net_protocol; struct arp_entry *arp; + struct net_device *netdev; int merge = 0; - /* Check for correct link-layer protocol and length */ - if ( ( arphdr->ar_hrd != netdev->ll_proto ) || - ( arphdr->ar_hln != netdev->ll_addr_len ) ) - return 0; + /* Identify link-layer and network-layer protocols */ + ll_protocol = pkb->ll_protocol; + net_protocol = net_find_protocol ( arphdr->ar_pro ); + if ( ! net_protocol ) + goto done; - /* See if we have an interface for this network-layer protocol */ - netif = netdev_find_netif ( netdev, arphdr->ar_pro ); - if ( ! netif ) - return 0; - if ( arphdr->ar_pln != netif->net_addr_len ) - return 0; + /* Sanity checks */ + if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) || + ( arphdr->ar_hln != ll_protocol->ll_addr_len ) || + ( arphdr->ar_pln != net_protocol->net_addr_len ) ) + goto done; /* See if we have an entry for this sender, and update it if so */ - arp = arp_find_entry ( arphdr->ar_hrd, arphdr->ar_pro, - arp_sender_pa ( arphdr ), arphdr->ar_pln ); + arp = arp_find_entry ( ll_protocol, net_protocol, + arp_sender_pa ( arphdr ) ); if ( arp ) { memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), arphdr->ar_hln ); merge = 1; } - /* See if we are the target protocol address */ - if ( memcmp ( arp_target_pa ( arphdr ), netif->net_addr, - arphdr->ar_pln ) != 0 ) - return 0; - + /* See if we own the target protocol address */ + netdev = net_find_address ( net_protocol, arp_target_pa ( arphdr ) ); + if ( ! netdev ) + goto done; + /* Create new ARP table entry if necessary */ if ( ! merge ) { arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES]; - arp->ll_proto = arphdr->ar_hrd; - arp->net_proto = arphdr->ar_pro; + arp->ll_protocol = ll_protocol; + arp->net_protocol = net_protocol; memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), arphdr->ar_hln ); memcpy ( arp->net_addr, arp_sender_pa ( arphdr ), - arphdr->ar_pln ); + arphdr->ar_pln); } /* If it's not a request, there's nothing more to do */ if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) - return 0; + goto done; /* Change request to a reply, and send it */ arphdr->ar_op = htons ( ARPOP_REPLY ); - memcpy ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), + memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), arphdr->ar_hln + arphdr->ar_pln ); memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); - memcpy ( arp_target_pa ( arphdr ), netif->net_addr, arphdr->ar_pln ); - netif_send ( arp_netif, pkb ); + if ( net_transmit ( pkb ) == 0 ) + pkb = NULL; + done: + free_pkb ( pkb ); return 0; } /** - * Add media-independent link-layer header + * Perform ARP network-layer routing * - * @v arp_netif Network interface for ARP packets - * @v pkb Packet buffer - * @ret rc Return status code + * @v pkb Packet buffer + * @ret source Network-layer source address + * @ret dest Network-layer destination address + * @ret rc Return status code */ -int arp_add_llh_metadata ( struct net_interface *arp_netif __unused, - struct pk_buff *pkb ) { +static int arp_route ( const struct pk_buff *pkb, + struct net_header *nethdr ) { struct arphdr *arphdr = pkb->data; - pkb->net_proto = htons ( ETH_P_ARP ); - pkb->flags = PKB_FL_RAW_NET_ADDR; - pkb->net_addr_len = arphdr->ar_hln; - pkb->net_addr = arp_target_ha ( arphdr ); + memcpy ( nethdr->source_net_addr, arp_sender_ha ( arphdr ), + arphdr->ar_hln ); + memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ), + arphdr->ar_hln ); + nethdr->dest_flags = NETADDR_FL_RAW; + if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) ) + nethdr->dest_flags |= NETADDR_FL_BROADCAST; return 0; } + +/** ARP protocol */ +struct net_protocol arp_protocol = { + .net_proto = ETH_P_ARP, + .rx = arp_rx, + .route = arp_route, +}; + +NET_PROTOCOL ( arp_protocol ); diff --git a/src/net/ethernet.c b/src/net/ethernet.c index 078719b32..59b469f17 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -20,10 +20,12 @@ #include #include #include +#include #include #include #include #include +#include /** @file * @@ -32,85 +34,104 @@ */ /** Ethernet broadcast MAC address */ -static uint8_t eth_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /** - * Build Ethernet link-layer header + * Perform Ethernet routing * - * @v netdev Network device - * @v pkb Packet buffer + * @v nethdr Generic network-layer header + * @ret llhdr Generic link-layer header * @ret rc Return status code * - * This constructs the Ethernet link-layer header (destination MAC, - * source MAC, network-layer protocol) based on the metadata found in - * @c pkb. + * Constructs the generic link-layer header based on the generic + * network-layer header, i.e. maps network-layer addresses (e.g. IPv4 + * addresses) to MAC addresses. * * If the destination MAC address cannot be determined, an ARP request - * is sent for the requested network-layer address instead. + * is sent for the requested network-layer address and -ENOENT is + * returned. */ -int eth_build_llh ( struct net_device *netdev, struct pk_buff *pkb ) { - struct ethhdr *ethhdr = pkb->data; - const void *eth_dest; +static int eth_route ( const struct net_header *nethdr, + struct ll_header *llhdr ) { int rc; - /* Do the easy bits */ - ethhdr->h_protocol = pkb->net_proto; - memcpy ( ethhdr->h_source, netdev->ll_addr, - sizeof ( ethhdr->h_source ) ); - /* Work out the destination MAC address */ - if ( pkb->flags & PKB_FL_RAW_NET_ADDR ) { - eth_dest = pkb->net_addr; - } else if ( pkb->flags & PKB_FL_BROADCAST ) { - eth_dest = eth_broadcast; - } else if ( pkb->flags & PKB_FL_MULTICAST ) { + if ( nethdr->dest_flags & NETADDR_FL_RAW ) { + memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN); + } else if ( nethdr->dest_flags & NETADDR_FL_BROADCAST ) { + memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN ); + } else if ( nethdr->dest_flags & NETADDR_FL_MULTICAST ) { /* IP multicast is a special case; there exists a * direct mapping from IP address to MAC address */ - assert ( pkb->net_proto == htons ( ETH_P_IP ) ); - ethhdr->h_dest[0] = 0x01; - ethhdr->h_dest[1] = 0x00; - ethhdr->h_dest[2] = 0x5e; - ethhdr->h_dest[3] = *( ( char * ) pkb->net_addr + 1 ) & 0x7f; - ethhdr->h_dest[4] = *( ( char * ) pkb->net_addr + 2 ); - ethhdr->h_dest[5] = *( ( char * ) pkb->net_addr + 3 ); - eth_dest = ethhdr->h_dest; + assert ( nethdr->net_protocol->net_proto == htons(ETH_P_IP) ); + llhdr->dest_ll_addr[0] = 0x01; + llhdr->dest_ll_addr[1] = 0x00; + llhdr->dest_ll_addr[2] = 0x5e; + llhdr->dest_ll_addr[3] = nethdr->dest_net_addr[1] & 0x7f; + llhdr->dest_ll_addr[4] = nethdr->dest_net_addr[2]; + llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3]; } else { /* Otherwise, look up the address using ARP */ - if ( ( rc = arp_resolve ( netdev, pkb, ð_dest ) ) != 0 ) + if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 ) return rc; } - /* Fill in destination MAC address */ - memcpy ( ethhdr->h_dest, eth_dest, sizeof ( ethhdr->h_dest ) ); - return 0; } +/** + * Fill in Ethernet link-layer header + * + * @v pkb Packet buffer + * @v llhdr Generic link-layer header + * + * Fills in the Ethernet link-layer header in the packet buffer based + * on information in the generic link-layer header. + */ +static void eth_fill_llh ( const struct ll_header *llhdr, + struct pk_buff *pkb ) { + struct ethhdr *ethhdr = pkb->data; + + memcpy ( ethhdr->h_dest, llhdr->dest_ll_addr, ETH_ALEN ); + memcpy ( ethhdr->h_source, llhdr->source_ll_addr, ETH_ALEN ); + ethhdr->h_protocol = llhdr->net_proto; +} + /** * Parse Ethernet link-layer header * - * @v netdev Network device * @v pkb Packet buffer - * @ret rc Return status code + * @v llhdr Generic link-layer header * - * This parses the Ethernet link-layer header (destination MAC, source - * MAC, network-layer protocol) and fills in the metadata in @c pkb. + * Fills in the generic link-layer header based on information in the + * Ethernet link-layer header in the packet buffer. */ -int eth_parse_llh ( struct net_device *netdev __unused, struct pk_buff *pkb ) { +static void eth_parse_llh ( const struct pk_buff *pkb, + struct ll_header *llhdr ) { struct ethhdr *ethhdr = pkb->data; - pkb->net_proto = ethhdr->h_protocol; - pkb->flags = PKB_FL_RAW_NET_ADDR; - pkb->net_addr_len = sizeof ( ethhdr->h_dest ); - pkb->net_addr = ethhdr->h_dest; + 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, - sizeof ( ethhdr->h_dest ) ) == 0 ) { - pkb->flags |= PKB_FL_BROADCAST; + if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) { + llhdr->dest_flags = NETADDR_FL_BROADCAST; } else if ( ethhdr->h_dest[0] & 0x01 ) { - pkb->flags |= PKB_FL_MULTICAST; + llhdr->dest_flags = NETADDR_FL_MULTICAST; + } else { + llhdr->dest_flags = 0; } - - return 0; } + +/** Ethernet protocol */ +struct ll_protocol ethernet_protocol = { + .ll_proto = htons ( ARPHRD_ETHER ), + .ll_addr_len = ETH_ALEN, + .ll_header_len = ETH_HLEN, + .route = eth_route, + .fill_llh = eth_fill_llh, + .parse_llh = eth_parse_llh, +}; + +LL_PROTOCOL ( ethernet_protocol ); diff --git a/src/net/netdevice.c b/src/net/netdevice.c index d7ad30808..3ff6657c3 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -18,146 +18,231 @@ #include #include +#include #include #include #include +#include #include /** @file * - * Network devices and network interfaces + * Network device management * */ -/** List of all registered network devices */ -static LIST_HEAD ( net_devices ); - /** - * Register network device + * 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. * - * @v netdev Network device - * @ret rc Return status code + * No code outside of netdevice.c should ever refer directly to @c + * static_single_netdev. * - * Adds the network device to the list of network devices. + * 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. */ -int register_netdevice ( struct net_device *netdev ) { - list_add ( &netdev->devices, &net_devices ); - return 0; -} +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 ); /** - * Unregister network device + * Identify network protocol * - * @v netdev Network device + * @v net_proto Network-layer protocol, in network-byte order + * @ret net_protocol Network-layer protocol, or NULL * - * Removes the network device from the list of network devices. + * Identify a network-layer protocol from a protocol number, which + * must be an ETH_P_XXX constant in network-byte order. */ -void unregister_netdevice ( struct net_device *netdev ) { - list_del ( &netdev->devices ); +struct net_protocol * net_find_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; } /** - * Transmit packet via network device + * Identify network device by network-layer address * - * @v netdev Network device - * @v pkb Packet buffer - * @ret rc Return status code + * @v net_protocol Network-layer protocol + * @v net_addr Network-layer address + * @ret netdev Network device, or NULL * - * Transmits the packet via the network device. The @c pkb link-layer - * metadata must already have been filled in, and space for the - * link-layer header must already be present in the packet buffer. + * 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. */ -int netdev_send ( struct net_device *netdev, struct pk_buff *pkb ) { - int rc; - - if ( pkb->net_proto != ETH_P_RAW ) { - if ( ( rc = netdev->build_llh ( netdev, pkb ) ) != 0 ) - return rc; +struct net_device * net_find_address ( 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; } - return netdev->transmit ( netdev, pkb ); + return NULL; } /** - * Poll for packet on network device + * Transmit packet * - * @v netdev Network device - * @v pkb Packet buffer - * @ret rc Return status code + * @v pkb Packet buffer + * @ret rc Return status code * - * Polls the network device for a packet. If a packet is available, - * it will be added to the packet buffer, and the link-layer metadata - * fields in @c pkb will be filled in. + * Transmits the packet via the appropriate network device. If this + * function returns success, it has taken ownership of the packet + * buffer. */ -int netdev_poll ( struct net_device *netdev, struct pk_buff *pkb ) { +int net_transmit ( struct pk_buff *pkb ) { + struct net_protocol *net_protocol; + struct net_header nethdr; + struct ll_protocol *ll_protocol; + struct ll_header llhdr; + struct net_device *netdev; int rc; - if ( ( rc = netdev->poll ( netdev, pkb ) ) != 0 ) - return rc; - return netdev->parse_llh ( netdev, pkb ); + /* Perform network-layer routing */ + net_protocol = pkb->net_protocol; + nethdr.net_protocol = net_protocol; + if ( ( rc = net_protocol->route ( pkb, &nethdr ) ) != 0 ) + goto err; + + /* Identify transmitting network device */ + netdev = net_find_address ( net_protocol, nethdr.source_net_addr ); + if ( ! netdev ) + goto err; + + /* Perform link-layer routing */ + ll_protocol = netdev->ll_protocol; + llhdr.ll_protocol = ll_protocol; + llhdr.net_proto = net_protocol->net_proto; + memcpy ( llhdr.source_ll_addr, netdev->ll_addr, + ll_protocol->ll_addr_len); + if ( ( rc = ll_protocol->route ( &nethdr, &llhdr ) ) != 0 ) + goto err; + + /* Prepend link-layer header */ + pkb_push ( pkb, ll_protocol->ll_header_len ); + ll_protocol->fill_llh ( &llhdr, pkb ); + + /* Transmit packet */ + if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 ) + goto err; + + return 0; + + err: + free_pkb ( pkb ); + return rc; } /** - * Transmit packet via network interface + * Poll for packet on all network devices * - * @v netif Network interface - * @v pkb Packet buffer - * @ret rc Return status code + * @ret True There are packets present in the receive queue + * @ret False There are no packets present in the receive queue * - * Transmits the packet via the network interface. The packet must - * start with a network-layer header (e.g. an IP header, for an IP - * interface). The packet contents are undefined on return. + * Polls all network devices for received packets. Any received + * packets will be added to the RX packet queue via netdev_rx(). */ -int netif_send ( struct net_interface *netif, struct pk_buff *pkb ) { - struct net_device *netdev = netif->netdev; - int rc; +int net_poll ( void ) { + struct net_device *netdev = &static_single_netdev; + + netdev->poll ( netdev ); - if ( ( rc = netif->add_llh_metadata ( netif, pkb ) ) != 0 ) - return rc; - pkb_push ( pkb, netdev->ll_hlen ); - return netdev_send ( netdev, pkb ); + return ( ! list_empty ( &rx_queue ) ); } /** - * Process received packet + * Add packet to receive queue * - * @v netif Network interface - * @v pkb Packet buffer - * @ret rc Return status code + * @v netdev Network device + * @v pkb Packet buffer * - * Processes a packet received via netdev_poll(). The interface - * corresponding to the network-layer protocol is identified, the - * link-layer header is stripped from the packet and the packet is - * passed to the net_interface::rx_packet() method. + * The packet is added to the RX queue. Ownership of the packet is + * transferred to the RX queue; the caller must not touch the packet + * buffer after calling netdev_rx(). */ -int netdev_rx_packet ( struct net_device *netdev, struct pk_buff *pkb ) { - struct net_interface *netif; - - netif = netdev_find_netif ( netdev, pkb->net_proto ); - if ( ! netif ) - return -EAFNOSUPPORT; - - pkb_pull ( pkb, netdev->ll_hlen ); - return netif->rx_packet ( netif, pkb ); +void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) { + pkb->ll_protocol = netdev->ll_protocol; + list_add_tail ( &pkb->list, &rx_queue ); } /** - * Poll for packet on all network devices + * Remove packet from receive queue * - * @v pkb Packet buffer - * @ret netdev Network device - * @ret rc Return status code + * @ret pkb Packet buffer, or NULL * - * Polls all network devices for a packet. If a packet is available - * on any interface, @c netdev will be filled in and the packet will - * be received as per netdev_poll(). + * Removes the first packet from the RX queue and returns it. + * Ownership of the packet is transferred to the caller. */ -int net_poll ( struct pk_buff *pkb, struct net_device **netdev ) { - int rc; +struct pk_buff * net_rx_dequeue ( void ) { + struct pk_buff *pkb; - list_for_each_entry ( (*netdev), &net_devices, devices ) { - if ( ( rc = netdev_poll ( *netdev, pkb ) ) == 0 ) - return rc; + list_for_each_entry ( pkb, &rx_queue, list ) { + list_del ( &pkb->list ); + return pkb; } + return NULL; +} - return -EAGAIN; +void net_run ( void ) { + struct pk_buff *pkb; + struct ll_protocol *ll_protocol; + struct ll_header llhdr; + struct net_protocol *net_protocol; + + while ( ( pkb = net_rx_dequeue () ) ) { + + /* Parse link-layer header */ + ll_protocol = pkb->ll_protocol; + ll_protocol->parse_llh ( pkb, &llhdr ); + + /* Identify network-layer protocol */ + net_protocol = net_find_protocol ( llhdr.net_proto ); + if ( ! net_protocol ) { + DBG ( "Unknown network-layer protocol %02x\n", + ntohs ( llhdr.net_proto ) ); + free_pkb ( pkb ); + continue; + } + + /* Strip off link-layer header */ + pkb_pull ( pkb, ll_protocol->ll_header_len ); + + /* Hand off to network layer */ + if ( net_protocol->rx ( pkb ) != 0 ) { + free_pkb ( pkb ); + continue; + } + } } + + + -- cgit v1.2.3-55-g7522