[netdevice] Allow the hardware and link-layer addresses to differ in size
authorMichael Brown <mcb30@etherboot.org>
Tue, 11 Aug 2009 22:40:27 +0000 (23:40 +0100)
committerMichael Brown <mcb30@etherboot.org>
Tue, 11 Aug 2009 23:23:38 +0000 (00:23 +0100)
IPoIB has a 20-byte link-layer address, of which only eight bytes
represent anything relating to a "hardware address".

The PXE and EFI SNP APIs expect the permanent address to be the same
size as the link-layer address, so fill in the "permanent address"
field with the initial link layer address (as generated by
register_netdev() based upon the real hardware address).

src/arch/i386/interface/pxe/pxe_undi.c
src/drivers/net/ipoib.c
src/include/gpxe/ethernet.h
src/include/gpxe/netdevice.h
src/interface/efi/efi_snp.c
src/net/80211/net80211.c
src/net/ethernet.c
src/net/netdevice.c

index 48c274b..c9b67c0 100644 (file)
@@ -412,6 +412,7 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
                                          *undi_get_information ) {
        struct device *dev = pxe_netdev->dev;
        struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+       size_t ll_addr_len = ll_protocol->ll_addr_len;
 
        DBG ( "PXENV_UNDI_GET_INFORMATION" );
 
@@ -420,13 +421,14 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
        /* Cheat: assume all cards can cope with this */
        undi_get_information->MaxTranUnit = ETH_MAX_MTU;
        undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
-       undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
+       undi_get_information->HwAddrLen = ll_addr_len;
+       assert ( ll_addr_len <=
+                sizeof ( undi_get_information->CurrentNodeAddress ) );
        memcpy ( &undi_get_information->CurrentNodeAddress,
                 pxe_netdev->ll_addr,
                 sizeof ( undi_get_information->CurrentNodeAddress ) );
-       memcpy ( &undi_get_information->PermNodeAddress,
-                pxe_netdev->hw_addr,
-                sizeof ( undi_get_information->PermNodeAddress ) );
+       ll_protocol->init_addr ( pxe_netdev->hw_addr,
+                                &undi_get_information->PermNodeAddress );
        undi_get_information->ROMAddress = 0;
                /* nic.rom_info->rom_segment; */
        /* We only provide the ability to receive or transmit a single
index c2a6d34..dde4ee5 100644 (file)
@@ -250,7 +250,21 @@ static int ipoib_pull ( struct net_device *netdev,
 }
 
 /**
- * Transcribe IPoIB address
+ * Initialise IPoIB link-layer address
+ *
+ * @v hw_addr          Hardware address
+ * @v ll_addr          Link-layer address
+ */
+static void ipoib_init_addr ( const void *hw_addr, void *ll_addr ) {
+       const struct ib_gid_half *guid = hw_addr;
+       struct ipoib_mac *mac = ll_addr;
+
+       memset ( mac, 0, sizeof ( *mac ) );
+       memcpy ( &mac->gid.u.half[1], guid, sizeof ( mac->gid.u.half[1] ) );
+}
+
+/**
+ * Transcribe IPoIB link-layer address
  *
  * @v ll_addr  Link-layer address
  * @ret string Link-layer address in human-readable format
@@ -286,10 +300,12 @@ static int ipoib_mc_hash ( unsigned int af __unused,
 struct ll_protocol ipoib_protocol __ll_protocol = {
        .name           = "IPoIB",
        .ll_proto       = htons ( ARPHRD_INFINIBAND ),
+       .hw_addr_len    = sizeof ( struct ib_gid_half ),
        .ll_addr_len    = IPOIB_ALEN,
        .ll_header_len  = IPOIB_HLEN,
        .push           = ipoib_push,
        .pull           = ipoib_pull,
+       .init_addr      = ipoib_init_addr,
        .ntoa           = ipoib_ntoa,
        .mc_hash        = ipoib_mc_hash,
 };
@@ -653,7 +669,6 @@ void ipoib_link_state_changed ( struct ib_device *ibdev ) {
 int ipoib_probe ( struct ib_device *ibdev ) {
        struct net_device *netdev;
        struct ipoib_device *ipoib;
-       struct ipoib_mac *mac;
        int rc;
 
        /* Allocate network device */
@@ -669,9 +684,8 @@ int ipoib_probe ( struct ib_device *ibdev ) {
        ipoib->ibdev = ibdev;
 
        /* Extract hardware address */
-       mac = ( ( struct ipoib_mac * ) netdev->hw_addr );
-       memcpy ( &mac->gid.u.half[1], &ibdev->gid.u.half[1],
-                sizeof ( mac->gid.u.half[1] ) );
+       memcpy ( netdev->hw_addr, &ibdev->gid.u.half[1],
+                sizeof ( ibdev->gid.u.half[1] ) );
 
        /* Set default broadcast address */
        memcpy ( &ipoib->broadcast, &ipoib_broadcast,
index 9bd3455..bb82e0a 100644 (file)
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 
+extern void eth_init_addr ( const void *hw_addr, void *ll_addr );
 extern const char * eth_ntoa ( const void *ll_addr );
 extern struct net_device * alloc_etherdev ( size_t priv_size );
 
index 5ac2f62..fd77d89 100644 (file)
@@ -21,6 +21,12 @@ struct net_protocol;
 struct ll_protocol;
 struct device;
 
+/** Maximum length of a hardware address
+ *
+ * The longest currently-supported link-layer address is for IPoIB.
+ */
+#define MAX_HW_ADDR_LEN 8
+
 /** Maximum length of a link-layer address
  *
  * The longest currently-supported link-layer address is for IPoIB.
@@ -112,6 +118,13 @@ struct ll_protocol {
        int ( * pull ) ( struct net_device *netdev, struct io_buffer *iobuf,
                         const void **ll_dest, const void **ll_source,
                         uint16_t *net_proto );
+       /**
+        * Initialise link-layer address
+        *
+        * @v hw_addr           Hardware address
+        * @v ll_addr           Link-layer address to fill in
+        */
+       void ( * init_addr ) ( const void *hw_addr, void *ll_addr );
        /**
         * Transcribe link-layer address
         *
@@ -124,7 +137,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 );
        /**
         * Hash multicast address
         *
@@ -140,6 +153,8 @@ struct ll_protocol {
         * This is an ARPHRD_XXX constant, in network byte order.
         */
        uint16_t ll_proto;
+       /** Hardware address length */
+       uint8_t hw_addr_len;
        /** Link-layer address length */
        uint8_t ll_addr_len;
        /** Link-layer header length */
@@ -258,8 +273,11 @@ struct net_device {
         *
         * This is an address which is an intrinsic property of the
         * hardware, e.g. an address held in EEPROM.
+        *
+        * Note that the hardware address may not be the same length
+        * as the link-layer address.
         */
-       uint8_t hw_addr[MAX_LL_ADDR_LEN];
+       uint8_t hw_addr[MAX_HW_ADDR_LEN];
        /** Link-layer address
         *
         * This is the current link-layer address assigned to the
index 0083034..b5241e5 100644 (file)
@@ -119,10 +119,11 @@ static EFI_GUID efi_pci_io_protocol_guid
 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
        struct net_device *netdev = snpdev->netdev;
        EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
-       unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len;
+       struct ll_protocol *ll_protocol = netdev->ll_protocol;
+       unsigned int ll_addr_len = ll_protocol->ll_addr_len;
 
        mode->HwAddressSize = ll_addr_len;
-       mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len;
+       mode->MediaHeaderSize = ll_protocol->ll_header_len;
        mode->MaxPacketSize = netdev->max_pkt_len;
        mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
                                    EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
@@ -130,8 +131,8 @@ static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
        assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
        memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
        memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
-       memcpy ( &mode->PermanentAddress, netdev->hw_addr, ll_addr_len );
-       mode->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+       ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
+       mode->IfType = ntohs ( ll_protocol->ll_proto );
        mode->MacAddressChangeable = TRUE;
        mode->MediaPresentSupported = TRUE;
        mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
index f361285..a07e2fa 100644 (file)
@@ -602,9 +602,11 @@ static struct ll_protocol net80211_ll_protocol __ll_protocol = {
        .name = "802.11",
        .push = net80211_ll_push,
        .pull = net80211_ll_pull,
+       .init_addr = eth_init_addr,
        .ntoa = eth_ntoa,
        .mc_hash = net80211_ll_mc_hash,
        .ll_proto = htons ( ARPHRD_ETHER ),     /* "encapsulated Ethernet" */
+       .hw_addr_len = ETH_ALEN,
        .ll_addr_len = ETH_ALEN,
        .ll_header_len = IEEE80211_TYP_FRAME_HEADER_LEN +
                                IEEE80211_LLC_HEADER_LEN,
index 5e2793f..dfeba7c 100644 (file)
@@ -96,6 +96,16 @@ static int eth_pull ( struct net_device *netdev __unused,
        return 0;
 }
 
+/**
+ * Initialise Ethernet address
+ *
+ * @v hw_addr          Hardware address
+ * @v ll_addr          Link-layer address
+ */
+void eth_init_addr ( const void *hw_addr, void *ll_addr ) {
+       memcpy ( ll_addr, hw_addr, ETH_ALEN );
+}
+
 /**
  * Transcribe Ethernet address
  *
@@ -143,10 +153,12 @@ static int eth_mc_hash ( unsigned int af, const void *net_addr,
 struct ll_protocol ethernet_protocol __ll_protocol = {
        .name           = "Ethernet",
        .ll_proto       = htons ( ARPHRD_ETHER ),
+       .hw_addr_len    = ETH_ALEN,
        .ll_addr_len    = ETH_ALEN,
        .ll_header_len  = ETH_HLEN,
        .push           = eth_push,
        .pull           = eth_pull,
+       .init_addr      = eth_init_addr,
        .ntoa           = eth_ntoa,
        .mc_hash        = eth_mc_hash,
 };
index f43ca8a..ee0d0b7 100644 (file)
@@ -358,8 +358,7 @@ int register_netdev ( struct net_device *netdev ) {
                   ifindex++ );
 
        /* Set initial link-layer address */
-       memcpy ( netdev->ll_addr, netdev->hw_addr,
-                netdev->ll_protocol->ll_addr_len );
+       netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
 
        /* Register per-netdev configuration settings */
        if ( ( rc = register_settings ( netdev_settings ( netdev ),