From bdc8190c8dea79b0d72f5b80654269836964e5b8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 19 Apr 2006 11:32:24 +0000 Subject: [PATCH] Remove the concept of the media-independent link-layer header and replace 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 | 2 +- src/include/gpxe/llh.h | 63 ------------------- src/include/gpxe/netdevice.h | 62 ++++++++----------- src/include/gpxe/pkbuff.h | 32 ++++++++++ src/net/arp.c | 45 ++++++-------- src/net/ethernet.c | 116 +++++++++++++++++++++++++++++++++++ 6 files changed, 194 insertions(+), 126 deletions(-) delete mode 100644 src/include/gpxe/llh.h create mode 100644 src/net/ethernet.c diff --git a/src/include/gpxe/arp.h b/src/include/gpxe/arp.h index 64e6c272..f6ec47af 100644 --- a/src/include/gpxe/arp.h +++ b/src/include/gpxe/arp.h @@ -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 index f6007814..00000000 --- a/src/include/gpxe/llh.h +++ /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 - -/** 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 */ diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index dbb6be84..7517c3e7 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -8,13 +8,18 @@ */ #include -#include #include 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 */ diff --git a/src/include/gpxe/pkbuff.h b/src/include/gpxe/pkbuff.h index bcc30497..f82f508a 100644 --- a/src/include/gpxe/pkbuff.h +++ b/src/include/gpxe/pkbuff.h @@ -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 * diff --git a/src/net/arp.c b/src/net/arp.c index f739e392..bee7f577 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -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 index 00000000..078719b3 --- /dev/null +++ b/src/net/ethernet.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/** @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, ð_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; +}