]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[netdevice] Add the concept of an "Ethernet-compatible" MAC address
authorMichael Brown <mcb30@etherboot.org>
Fri, 23 Oct 2009 21:14:05 +0000 (22:14 +0100)
committerMichael Brown <mcb30@etherboot.org>
Fri, 23 Oct 2009 21:14:05 +0000 (22:14 +0100)
The iBFT is Ethernet-centric in providing only six bytes for a MAC
address.  This is most probably an indirect consequence of a similar
design flaw in the Windows NDIS stack.  (The WinOF IPoIB stack
performs all sorts of contortions in order to pretend to the NDIS
layer that it is dealing with six-byte MAC addresses.)

There is no sensible way in which to extend the iBFT without breaking
compatibility with programs that expect to parse it.  Add the notion
of an "Ethernet-compatible" MAC address to our link layer abstraction,
so that link layers can provide their own workarounds for this
limitation.

src/drivers/net/ipoib.c
src/include/gpxe/ethernet.h
src/include/gpxe/netdevice.h
src/net/80211/net80211.c
src/net/ethernet.c

index dde4ee5a304d23cba1b006e138f02efe6c066b85..260d2d0ee46a2729c4e79bb6838418796855417b 100644 (file)
@@ -296,6 +296,62 @@ static int ipoib_mc_hash ( unsigned int af __unused,
        return -ENOTSUP;
 }
 
+/**
+ * Generate Mellanox Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr          Link-layer address
+ * @v eth_addr         Ethernet-compatible address to fill in
+ */
+static int ipoib_mlx_eth_addr ( const struct ib_gid_half *guid,
+                               uint8_t *eth_addr ) {
+       eth_addr[0] = ( ( guid->u.bytes[3] == 2 ) ? 0x00 : 0x02 );
+       eth_addr[1] = guid->u.bytes[1];
+       eth_addr[2] = guid->u.bytes[2];
+       eth_addr[3] = guid->u.bytes[5];
+       eth_addr[4] = guid->u.bytes[6];
+       eth_addr[5] = guid->u.bytes[7];
+       return 0;
+}
+
+/** An IPoIB Ethernet-compatible compressed link-layer address generator */
+struct ipoib_eth_addr_handler {
+       /** GUID byte 1 */
+       uint8_t byte1;
+       /** GUID byte 2 */
+       uint8_t byte2;
+       /** Handler */
+       int ( * eth_addr ) ( const struct ib_gid_half *guid,
+                            uint8_t *eth_addr );
+};
+
+/** IPoIB Ethernet-compatible compressed link-layer address generators */
+static struct ipoib_eth_addr_handler ipoib_eth_addr_handlers[] = {
+       { 0x02, 0xc9, ipoib_mlx_eth_addr },
+};
+
+/**
+ * Generate Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr          Link-layer address
+ * @v eth_addr         Ethernet-compatible address to fill in
+ */
+static int ipoib_eth_addr ( const void *ll_addr, void *eth_addr ) {
+       const struct ipoib_mac *ipoib_addr = ll_addr;
+       const struct ib_gid_half *guid = &ipoib_addr->gid.u.half[1];
+       struct ipoib_eth_addr_handler *handler;
+       unsigned int i;
+
+       for ( i = 0 ; i < ( sizeof ( ipoib_eth_addr_handlers ) /
+                           sizeof ( ipoib_eth_addr_handlers[0] ) ) ; i++ ) {
+               handler = &ipoib_eth_addr_handlers[i];
+               if ( ( handler->byte1 == guid->u.bytes[1] ) &&
+                    ( handler->byte2 == guid->u.bytes[2] ) ) {
+                       return handler->eth_addr ( guid, eth_addr );
+               }
+       }
+       return -ENOTSUP;
+}
+
 /** IPoIB protocol */
 struct ll_protocol ipoib_protocol __ll_protocol = {
        .name           = "IPoIB",
@@ -308,6 +364,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
        .init_addr      = ipoib_init_addr,
        .ntoa           = ipoib_ntoa,
        .mc_hash        = ipoib_mc_hash,
+       .eth_addr       = ipoib_eth_addr,
 };
 
 /**
index 8cf6b1be7019c13cd03ed5b0b805dbb85a3744c8..4dfc24d3f431a32fce028fb87378cdb9945baf38 100644 (file)
@@ -15,6 +15,7 @@ extern void eth_init_addr ( const void *hw_addr, void *ll_addr );
 extern const char * eth_ntoa ( const void *ll_addr );
 extern int eth_mc_hash ( unsigned int af, const void *net_addr,
                         void *ll_addr );
+extern int eth_eth_addr ( const void *ll_addr, void *eth_addr );
 extern struct net_device * alloc_etherdev ( size_t priv_size );
 
 #endif /* _GPXE_ETHERNET_H */
index fd77d893ad64aaa4ed464159361792241ed6c92f..858d8e97db8d9e31a6b767f611e7e6b7c134be3e 100644 (file)
@@ -128,8 +128,8 @@ struct ll_protocol {
        /**
         * Transcribe link-layer address
         *
-        * @v ll_addr   Link-layer address
-        * @ret string  Human-readable transcription of address
+        * @v ll_addr           Link-layer address
+        * @ret string          Human-readable transcription of address
         *
         * This method should convert the link-layer address into a
         * human-readable format.
@@ -141,13 +141,20 @@ struct ll_protocol {
        /**
         * Hash multicast address
         *
-        * @v af        Address family
-        * @v net_addr  Network-layer address
-        * @v ll_addr   Link-layer address to fill in
-        * @ret rc      Return status code
+        * @v af                Address family
+        * @v net_addr          Network-layer address
+        * @v ll_addr           Link-layer address to fill in
+        * @ret rc              Return status code
         */
        int ( * mc_hash ) ( unsigned int af, const void *net_addr,
                            void *ll_addr );
+       /**
+        * Generate Ethernet-compatible compressed link-layer address
+        *
+        * @v ll_addr           Link-layer address
+        * @v eth_addr          Ethernet-compatible address to fill in
+        */
+       int ( * eth_addr ) ( const void *ll_addr, void *eth_addr );
        /** Link-layer protocol
         *
         * This is an ARPHRD_XXX constant, in network byte order.
index 1fc983a01c8b4180ee24aa8f387c0619fc35b46d..c3d9fc61bc5a3d8d28dc0dce3b2a05e93967cf40 100644 (file)
@@ -586,6 +586,7 @@ static struct ll_protocol net80211_ll_protocol __ll_protocol = {
        .init_addr = eth_init_addr,
        .ntoa = eth_ntoa,
        .mc_hash = eth_mc_hash,
+       .eth_addr = eth_eth_addr,
        .ll_proto = htons ( ARPHRD_ETHER ),     /* "encapsulated Ethernet" */
        .hw_addr_len = ETH_ALEN,
        .ll_addr_len = ETH_ALEN,
index e8daf9f9092723f37f308d30d9c5cc547950c666..79ed1dc60e6d7d5a88d1f8b9aa03963fa14ff2ee 100644 (file)
@@ -148,6 +148,17 @@ int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) {
        }
 }
 
+/**
+ * Generate Ethernet-compatible compressed link-layer address
+ *
+ * @v ll_addr          Link-layer address
+ * @v eth_addr         Ethernet-compatible address to fill in
+ */
+int eth_eth_addr ( const void *ll_addr, void *eth_addr ) {
+       memcpy ( eth_addr, ll_addr, ETH_ALEN );
+       return 0;
+}
+
 /** Ethernet protocol */
 struct ll_protocol ethernet_protocol __ll_protocol = {
        .name           = "Ethernet",
@@ -160,6 +171,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = {
        .init_addr      = eth_init_addr,
        .ntoa           = eth_ntoa,
        .mc_hash        = eth_mc_hash,
+       .eth_addr       = eth_eth_addr,
 };
 
 /**