Simplify RX data path.
authorMichael Brown <mcb30@etherboot.org>
Sat, 17 Jun 2006 22:36:27 +0000 (22:36 +0000)
committerMichael Brown <mcb30@etherboot.org>
Sat, 17 Jun 2006 22:36:27 +0000 (22:36 +0000)
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.

12 files changed:
src/core/main.c
src/include/gpxe/arp.h
src/include/gpxe/ethernet.h
src/include/gpxe/ip.h
src/include/gpxe/netdevice.h
src/include/gpxe/pkbuff.h
src/net/aoe.c
src/net/arp.c
src/net/ethernet.c
src/net/ipv4.c
src/net/netdevice.c
src/net/tcp.c

index 71300a8..e2b6ae8 100644 (file)
@@ -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" );
        }
index a1f9e34..ffaf418 100644 (file)
@@ -7,9 +7,33 @@
  *
  */
 
+#include <gpxe/tables.h>
+
 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,
index e62eb09..0188ac8 100644 (file)
@@ -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 = &ethernet_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 = &ethernet_protocol;
+       }
+       return netdev;
+}
 
 #endif /* _GPXE_ETHERNET_H */
index 8eac31a..7cd2fcf 100644 (file)
@@ -7,6 +7,8 @@
  *
  */
 
+#include <ip.h>
+
 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 */
index 68226dc..b8cf9ae 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <stdint.h>
+#include <gpxe/list.h>
 #include <gpxe/tables.h>
 
 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 netdev           Network device
+ * @ret name           Network device name
  *
- * @v net_address      Network-layer address
+ * 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 */
index 6c50402..c363a50 100644 (file)
@@ -14,9 +14,6 @@
 #include <assert.h>
 #include <gpxe/list.h>
 
-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;
 };
 
 /**
index 693b360..e0954fa 100644 (file)
@@ -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 );
index 66f9bd4..6293bf9 100644 (file)
  *
  */
 
+/** 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,
 };
 
index ab7d427..13b3c2d 100644 (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.
  */
-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,
 };
 
index ae3404c..47b8cb7 100644 (file)
@@ -7,10 +7,6 @@
 #include <gpxe/list.h>
 #include <gpxe/in.h>
 #include <gpxe/arp.h>
-
-#include <ip.h>
-
-
 #include <gpxe/if_ether.h>
 #include <gpxe/pkbuff.h>
 #include <gpxe/netdevice.h>
@@ -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 );
index 1825a55..1197e66 100644 (file)
@@ -20,6 +20,7 @@
 #include <byteswap.h>
 #include <string.h>
 #include <errno.h>
+#include <malloc.h>
 #include <gpxe/if_ether.h>
 #include <gpxe/pkbuff.h>
 #include <gpxe/tables.h>
  *
  */
 
-/**
- * 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 <ip.h>
 #include <gpxe/ip.h>
 
 /**
- * Register network device
+ * Transmit raw packet via network device
  *
  * @v netdev           Network device
+ * @v pkb              Packet buffer
  * @ret rc             Return status code
  *
- * Adds the network device to the list of network devices.
+ * Transmits the packet via the specified network device.  This
+ * function takes ownership of the packet buffer.
  */
-int register_netdev ( struct net_device *netdev ) {
-       
-#warning "Remove this static IP address hack"
-       {
-               const struct in_addr static_address = { htonl ( 0x0afefe01 ) };
-               const struct in_addr static_netmask = { htonl ( 0xffffff00 ) };
-               const struct in_addr static_gateway = { INADDR_NONE };
-               int rc;
-               
-               if ( ( rc = add_ipv4_address ( netdev, static_address,
-                                              static_netmask,
-                                              static_gateway ) ) != 0 )
-                       return rc;
-       }
-
-       return 0;
+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 );
 }
 
 /**
- * Unregister network device
+ * Add packet to receive queue
  *
  * @v netdev           Network device
+ * @v pkb              Packet buffer
  *
- * Removes the network device from the list of network devices.
+ * The packet is added to the network device's RX queue.  This
+ * function takes ownership of the packet buffer.
  */
-void unregister_netdev ( struct net_device *netdev ) {
-
-#warning "Remove this static IP address hack"
-       del_ipv4_address ( netdev );
-
+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 );
 }
 
 /**
- * Add packet to receive queue
+ * Transmit network-layer packet
  *
- * @v netdev           Network device
  * @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
  *
- * The packet is added to the RX queue.  This function takes ownership
- * of the packet buffer.
+ * 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.
  */
-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 );
+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 );
 }
 
 /**
- * Identify network protocol
+ * Process received network-layer packet
  *
+ * @v pkb              Packet buffer
+ * @v netdev           Network device
  * @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.
+ * @v ll_source                Source link-layer address
  */
-struct net_protocol * find_net_protocol ( uint16_t net_proto ) {
+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 )
-                       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.
- */
-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;
+               if ( net_protocol->net_proto == net_proto ) {
+                       net_protocol->rx ( pkb, netdev, ll_source );
+                       break;
+               }
        }
-
-       return NULL;
 }
 
 /**
- * Poll for packet on all network devices
+ * 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 all network devices for received packets.  Any received
+ * Polls the network device 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" );
+int netdev_poll ( struct net_device *netdev ) {
        netdev->poll ( netdev );
-
-       return ( ! list_empty ( &rx_queue ) );
+       return ( ! list_empty ( &netdev->rx_queue ) );
 }
 
 /**
- * Remove packet from receive queue
+ * Remove packet from device's receive queue
  *
+ * @v netdev           Network device
  * @ret pkb            Packet buffer, or NULL
  *
- * Removes the first packet from the RX queue and returns it.
+ * 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 * net_rx_dequeue ( void ) {
+struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev ) {
        struct pk_buff *pkb;
 
-       list_for_each_entry ( pkb, &rx_queue, list ) {
+       list_for_each_entry ( pkb, &netdev->rx_queue, list ) {
                list_del ( &pkb->list );
                return pkb;
        }
@@ -209,48 +151,108 @@ struct pk_buff * net_rx_dequeue ( void ) {
 }
 
 /**
- * Process received packet
+ * Allocate network device
  *
- * @v pkb              Packet buffer
- * @ret rc             Return status code
+ * @v priv_size                Size of private data area (net_device::priv)
+ * @ret netdev         Network device, or NULL
  *
- * 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.
+ * Allocates space for a network device and its private data area.
  */
-int net_rx_process ( struct pk_buff *pkb ) {
-       struct ll_protocol *ll_protocol;
-       struct ll_header llhdr;
-       struct net_protocol *net_protocol;
-       int rc;
+struct net_device * alloc_netdev ( size_t priv_size ) {
+       struct net_device *netdev;
 
-       /* 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;
+       netdev = calloc ( 1, sizeof ( *netdev ) + priv_size );
+       if ( netdev ) {
+               INIT_LIST_HEAD ( &netdev->rx_queue );
+               netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
        }
-       pkb->net_protocol = net_protocol;
-       
-       /* Strip off link-layer header */
-#warning "Temporary hack"
-       pkb_pull ( pkb, ETH_HLEN );
+       return netdev;
+}
+
+/**
+ * Register network device
+ *
+ * @v netdev           Network device
+ * @ret rc             Return status code
+ *
+ * Adds the network device to the list of network devices.
+ */
+int register_netdev ( struct net_device *netdev ) {
        
-       /* Hand off to network layer */
-       if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) {
-               DBG ( "Network-layer protocol dropped packet\n" );
-               return rc;
+#warning "Remove this static IP address hack"
+       {
+               const struct in_addr static_address = { htonl ( 0x0afefe01 ) };
+               const struct in_addr static_netmask = { htonl ( 0xffffff00 ) };
+               const struct in_addr static_gateway = { INADDR_NONE };
+               int rc;
+               
+               if ( ( rc = add_ipv4_address ( netdev, static_address,
+                                              static_netmask,
+                                              static_gateway ) ) != 0 )
+                       return rc;
        }
 
+       /* Add to device list */
+       list_add_tail ( &netdev->list, &net_devices );
+       DBG ( "%s registered\n", netdev_name ( netdev ) );
+
        return 0;
 }
 
+/**
+ * Unregister network device
+ *
+ * @v netdev           Network device
+ *
+ * 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 ) );
+}
+
+/**
+ * Free network device
+ *
+ * @v netdev           Network device
+ */
+void free_netdev ( struct net_device *netdev ) {
+       free ( netdev );
+}
+
+/**
+ * Iterate through network devices
+ *
+ * @ret netdev         Network device, or 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 * next_netdev ( void ) {
+       struct net_device *netdev;
+
+       list_for_each_entry ( netdev, &net_devices, list ) {
+               list_del ( &netdev->list );
+               list_add_tail ( &netdev->list, &net_devices );
+               return netdev;
+       }
+       return NULL;
+}
+
 /**
  * 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 ) {
+
+               /* Poll for new packets */
+               netdev_poll ( netdev );
 
-       /* Handle at most one received packet */
-       if ( ( pkb = net_rx_dequeue () ) ) {
-               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 */
index 5027678..e73708d 100644 (file)
@@ -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 );
                }
        }
 }