diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c index dde4ee5a..260d2d0e 100644 --- a/src/drivers/net/ipoib.c +++ b/src/drivers/net/ipoib.c @@ -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, }; /** diff --git a/src/include/gpxe/ethernet.h b/src/include/gpxe/ethernet.h index 8cf6b1be..4dfc24d3 100644 --- a/src/include/gpxe/ethernet.h +++ b/src/include/gpxe/ethernet.h @@ -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 */ diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index fd77d893..858d8e97 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -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. diff --git a/src/net/80211/net80211.c b/src/net/80211/net80211.c index 1fc983a0..c3d9fc61 100644 --- a/src/net/80211/net80211.c +++ b/src/net/80211/net80211.c @@ -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, diff --git a/src/net/ethernet.c b/src/net/ethernet.c index e8daf9f9..79ed1dc6 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -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, }; /**