Remove the concept of the media-independent link-layer header and replace
authorMichael Brown <mcb30@etherboot.org>
Wed, 19 Apr 2006 11:32:24 +0000 (11:32 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 19 Apr 2006 11:32:24 +0000 (11:32 +0000)
it with metadata in the pkb structure.  This is required since UNDI will
want to be able to parse the link-layer header without destroying it.

src/include/gpxe/arp.h
src/include/gpxe/llh.h [deleted file]
src/include/gpxe/netdevice.h
src/include/gpxe/pkbuff.h
src/net/arp.c
src/net/ethernet.c [new file with mode: 0644]

index 64e6c27..f6ec47a 100644 (file)
@@ -12,7 +12,7 @@ struct net_interface;
 struct pk_buff;
 
 extern int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
-                        void *ll_addr );
+                        const void **ll_addr );
 
 extern int arp_process ( struct net_interface *arp_netif,
                         struct pk_buff *pkb );
diff --git a/src/include/gpxe/llh.h b/src/include/gpxe/llh.h
deleted file mode 100644 (file)
index f600781..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef _LLH_H
-#define _LLH_H
-
-/** @file
- *
- * Link-layer headers
- *
- * This file defines a media-independent link-layer header, used for
- * communication between the network and link layers of the stack.
- *
- */
-
-#include <stdint.h>
-
-/** Maximum length of a link-layer address */
-#define MAX_LLH_ADDR_LEN 6
-
-/** Maximum length of a network-layer address */
-#define MAX_NET_ADDR_LEN 4
-
-/* Network-layer address may be required to contain a raw link-layer address */
-#if MAX_NET_ADDR_LEN < MAX_LLH_ADDR_LEN
-#undef MAX_NET_ADDR_LEN
-#define MAX_NET_ADDR_LEN MAX_LLH_ADDR_LEN
-#endif
-
-/** A media-independent link-layer header
- *
- * This structure represents a generic link-layer header.  It never
- * appears on the wire, but is used to communicate between different
- * layers within the gPXE protocol stack.
- */
-struct gpxehdr {
-       /** The network-layer protocol
-        *
-        * This is the network-layer protocol expressed as an
-        * ETH_P_XXX constant, in network-byte order.
-        */
-       uint16_t net_proto;
-       /** Flags
-        *
-        * Filled in only on outgoing packets.  Value is the
-        * bitwise-OR of zero or more GPXE_FL_XXX constants.
-        */
-       uint8_t flags;
-       /** Network-layer address length 
-        *
-        * Filled in only on outgoing packets.
-        */
-       uint8_t net_addr_len;
-       /** Network-layer address
-        *
-        * Filled in only on outgoing packets.
-        */
-       uint8_t net_addr[MAX_NET_ADDR_LEN];
-} __attribute__ (( packed ));
-
-/* Media-independent link-layer header flags */
-#define GPXE_FL_BROADCAST      0x01
-#define GPXE_FL_MULTICAST      0x02
-#define GPXE_FL_RAW            0x04
-
-#endif /* _LLH_H */
index dbb6be8..7517c3e 100644 (file)
@@ -8,13 +8,18 @@
  */
 
 #include <stdint.h>
-#include <gpxe/llh.h>
 #include <gpxe/list.h>
 
 struct net_device;
 struct net_interface;
 struct pk_buff;
 
+/** Maximum length of a link-layer address */
+#define MAX_LLH_ADDR_LEN 6
+
+/** Maximum length of a network-layer address */
+#define MAX_NET_ADDR_LEN 4
+
 /**
  * A network device
  *
@@ -45,7 +50,6 @@ struct net_device {
        /** Poll for received packet
         *
         * @v netdev    Network device
-        * @v retrieve  Flag indicating whether or not to retrieve packet
         * @v pkb       Packet buffer to contain received packet
         * @ret rc      Return status code
         *
@@ -53,55 +57,42 @@ struct net_device {
         * received packet.  If no packet is available, the method
         * should return -EAGAIN (i.e. this method is *always*
         * considered to be a non-blocking read).  If a packet is
-        * available, but @c retrieve is false, the method should
-        * return zero for success.  If a packet is available and @c
-        * retrieve is true, the method should fill the packet buffer
-        * and return zero for success.
+        * available, the method should fill the packet buffer and
+        * return zero for success.
         */
-       int ( * poll ) ( struct net_device *netdev, int retrieve,
-                        struct pk_buff *pkb );
-       /** Build media-specific link-layer header
+       int ( * poll ) ( struct net_device *netdev, struct pk_buff *pkb );
+       /** Build link-layer header
         *
         * @v netdev    Network device
         * @v pkb       Packet buffer
         * @ret rc      Return status code
         *
-        * This method should convert the packet buffer's generic
-        * link-layer header (a struct gpxehdr) into a media-specific
-        * link-layer header (e.g. a struct ethhdr).  The generic
-        * header should be removed from the buffer (via pkb_pull())
-        * and the media-specific header should be prepended (via
-        * pkb_push()) in its place.
+        * This method should fill in the link-layer header based on
+        * the metadata contained in @c pkb.
         *
         * If a link-layer header cannot be constructed (e.g. because
         * of a missing ARP cache entry), then this method should
         * return an error (after transmitting an ARP request, if
         * applicable).
         */
-       int ( * make_media_header ) ( struct net_device *netdev,
-                                     struct pk_buff *pkb );
-       /** Build media-independent link-layer header
+       int ( * build_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
+       /** Parse link-layer header
         *
         * @v netdev    Network device
         * @v pkb       Packet buffer
         * @ret rc      Return status code
         *
-        * This method should convert the packet buffer's
-        * media-specific link-layer header (e.g. a struct ethhdr)
-        * into a generic link-layer header (a struct gpxehdr).  It
-        * performs the converse function of make_media_header().
-        *
-        * Note that the gpxehdr::addr and gpxehdr::addrlen fields
-        * will not be filled in by this function, since doing so
-        * would require understanding the network-layer header.
+        * This method should parse the link-layer header and fill in
+        * the metadata in @c pkb.
         */
-       int ( * make_generic_header ) ( struct net_device *netdev,
-                                       struct pk_buff *pkb );
+       int ( * parse_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
        /** Link-layer protocol
         *
         * This is an ARPHRD_XXX constant, in network byte order.
         */
        uint16_t ll_proto;
+       /** Link-layer header length */
+       uint8_t ll_hlen;
        /** Link-layer address length */
        uint8_t ll_addr_len;
        /** Link-layer address
@@ -151,17 +142,18 @@ struct net_interface {
         */
        int ( * process ) ( struct net_interface *netif,
                            struct pk_buff *pkb );
-       /** Add media-independent link-layer header
+       /** Fill in packet metadata
         *
         * @v netif     Network interface
         * @v pkb       Packet buffer
         * @ret rc      Return status code
         *
-        * This method should prepend a generic link-layer header (a
-        * struct @c gpxehdr) to the packet buffer using pkb_push().
+        * This method should fill in the @c pkb metadata with enough
+        * information to enable net_device::build_llh to construct
+        * the link-layer header.
         */
-       int ( * add_generic_header ) ( struct net_interface *netif,
-                                      struct pk_buff *pkb );
+       int ( * add_llh_metadata ) ( struct net_interface *netif,
+                                    struct pk_buff *pkb );
 };
 
 /**
@@ -196,9 +188,7 @@ extern struct net_device static_single_netdev;
 
 extern int register_netdevice ( struct net_device *netdev );
 
-static inline void unregister_netdevice ( struct net_device *netdev __unused ){
-       /* Do nothing */
-}
+extern void unregister_netdevice ( struct net_device *netdev );
 
 static inline void free_netdevice ( struct net_device *netdev __unused ) {
        /* Do nothing */
index bcc3049..f82f508 100644 (file)
@@ -26,8 +26,40 @@ struct pk_buff {
        void *tail;
        /** End of the buffer */
         void *end;
+
+       /** The network-layer protocol
+        *
+        * This is the network-layer protocol expressed as an
+        * ETH_P_XXX constant, in network-byte order.
+        */
+       uint16_t net_proto;
+       /** Flags
+        *
+        * Filled in only on outgoing packets.  Value is the
+        * bitwise-OR of zero or more PKB_FL_XXX constants.
+        */
+       uint8_t flags;
+       /** Network-layer address length 
+        *
+        * Filled in only on outgoing packets.
+        */
+       uint8_t net_addr_len;
+       /** Network-layer address
+        *
+        * Filled in only on outgoing packets.
+        */
+       void *net_addr;
 };
 
+/** Packet is a broadcast packet */
+#define PKB_FL_BROADCAST 0x01
+
+/** Packet is a multicast packet */
+#define PKB_FL_MULTICAST 0x02
+
+/** Network-layer address is a raw hardware address */
+#define PKB_FL_RAW_NET_ADDR 0x04
+
 /**
  * Add data to start of packet buffer
  *
index f739e39..bee7f57 100644 (file)
@@ -23,7 +23,6 @@
 #include <gpxe/if_ether.h>
 #include <gpxe/if_arp.h>
 #include <gpxe/pkbuff.h>
-#include <gpxe/llh.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/arp.h>
 
@@ -91,45 +90,43 @@ arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr,
  *
  * @v netdev           Network device
  * @v pkb              Packet buffer
- * @v ll_addr          Buffer to contain link-layer address
+ * @ret ll_addr                Pointer to link-layer address
  * @ret rc             Return status code
  *
- * The packet buffer must start with a media-independent link-layer
- * header (a struct @c gpxehdr).  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 @c gpxehdr.
+ * 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.
  *
  * 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.
  */
 int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
-                 void *ll_addr ) {
-       struct gpxehdr *gpxehdr = pkb->data;
+                 const void **ll_addr ) {
        const struct arp_entry *arp;
        struct net_interface *netif;
        struct arphdr *arphdr;
 
        /* Look for existing entry in ARP table */
-       arp = arp_find_entry ( netdev->ll_proto, gpxehdr->net_proto,
-                              gpxehdr->net_addr, gpxehdr->net_addr_len );
+       arp = arp_find_entry ( netdev->ll_proto, pkb->net_proto,
+                              pkb->net_addr, pkb->net_addr_len );
        if ( arp ) {
-               memcpy ( ll_addr, arp->ll_addr, netdev->ll_addr_len );
+               *ll_addr = arp->ll_addr;
                return 0;
        }
 
        /* Find interface for this protocol */
-       netif = netdev_find_netif ( netdev, gpxehdr->net_proto );
+       netif = netdev_find_netif ( netdev, pkb->net_proto );
        if ( ! netif )
                return -EAFNOSUPPORT;
 
        /* Build up ARP request */
-       pkb_unput ( pkb, pkb_len ( pkb ) - sizeof ( *gpxehdr ) );
+       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 = gpxehdr->net_proto;
-       arphdr->ar_pln = gpxehdr->net_addr_len;
+       arphdr->ar_pro = pkb->net_proto;
+       arphdr->ar_pln = pkb->net_addr_len;
        arphdr->ar_op = htons ( ARPOP_REQUEST );
        memcpy ( pkb_put ( pkb, netdev->ll_addr_len ),
                 netdev->ll_addr, netdev->ll_addr_len );
@@ -138,8 +135,7 @@ int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
        memset ( pkb_put ( pkb, netdev->ll_addr_len ),
                 0xff, netdev->ll_addr_len );
        memcpy ( pkb_put ( pkb, netif->net_addr_len ),
-                gpxehdr->net_addr, netif->net_addr_len );
-       pkb_pull ( pkb, sizeof ( *gpxehdr ) );
+                pkb->net_addr, netif->net_addr_len );
 
        /* Locate ARP interface and send ARP request */
        netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) );
@@ -228,17 +224,14 @@ int arp_process ( struct net_interface *arp_netif, struct pk_buff *pkb ) {
  * @v pkb              Packet buffer
  * @ret rc             Return status code
  */
-int arp_add_generic_header ( struct net_interface *arp_netif __unused,
-                            struct pk_buff *pkb ) {
+int arp_add_llh_metadata ( struct net_interface *arp_netif __unused,
+                          struct pk_buff *pkb ) {
        struct arphdr *arphdr = pkb->data;
-       struct gpxehdr *gpxehdr;
-
-       /* We're ARP; we always know the raw link-layer address we want */
-       gpxehdr = pkb_push ( pkb, sizeof ( *gpxehdr ) );
-       gpxehdr->net_proto = htons ( ETH_P_ARP );
-       gpxehdr->flags = GPXE_FL_RAW;
-       gpxehdr->net_addr_len = arphdr->ar_hln;
-       memcpy ( gpxehdr->net_addr, arp_target_ha ( arphdr ), arphdr->ar_hln );
+
+       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 );
        
        return 0;
 }
diff --git a/src/net/ethernet.c b/src/net/ethernet.c
new file mode 100644 (file)
index 0000000..078719b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/pkbuff.h>
+#include <gpxe/arp.h>
+
+/** @file
+ *
+ * Ethernet protocol
+ *
+ */
+
+/** Ethernet broadcast MAC address */
+static uint8_t eth_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/**
+ * Build Ethernet link-layer header
+ *
+ * @v netdev   Network device
+ * @v pkb      Packet buffer
+ * @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.
+ *
+ * If the destination MAC address cannot be determined, an ARP request
+ * is sent for the requested network-layer address instead.
+ */
+int eth_build_llh ( struct net_device *netdev, struct pk_buff *pkb ) {
+       struct ethhdr *ethhdr = pkb->data;
+       const void *eth_dest;
+       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 ) {
+               /* 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;
+       } else {
+               /* Otherwise, look up the address using ARP */
+               if ( ( rc = arp_resolve ( netdev, pkb, &eth_dest ) ) != 0 )
+                       return rc;
+       }
+
+       /* Fill in destination MAC address */
+       memcpy ( ethhdr->h_dest, eth_dest, sizeof ( ethhdr->h_dest ) );
+
+       return 0;
+}
+
+/**
+ * Parse Ethernet link-layer header
+ *
+ * @v netdev   Network device
+ * @v pkb      Packet buffer
+ * @ret rc     Return status code
+ *
+ * This parses the Ethernet link-layer header (destination MAC, source
+ * MAC, network-layer protocol) and fills in the metadata in @c pkb.
+ */
+int eth_parse_llh ( struct net_device *netdev __unused, struct pk_buff *pkb ) {
+       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;
+
+       if ( memcmp ( ethhdr->h_dest, eth_broadcast,
+                     sizeof ( ethhdr->h_dest ) ) == 0 ) {
+               pkb->flags |= PKB_FL_BROADCAST;
+       } else if ( ethhdr->h_dest[0] & 0x01 ) {
+               pkb->flags |= PKB_FL_MULTICAST;
+       }
+
+       return 0;
+}