diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c index 9c9bc918..47090bb2 100644 --- a/src/drivers/net/ipoib.c +++ b/src/drivers/net/ipoib.c @@ -222,6 +222,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) { return buf; } +/** + * 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 + */ +static int ipoib_mc_hash ( unsigned int af __unused, + const void *net_addr __unused, + void *ll_addr __unused ) { + + return -ENOTSUP; +} + /** IPoIB protocol */ struct ll_protocol ipoib_protocol __ll_protocol = { .name = "IPoIB", @@ -232,6 +247,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = { .push = ipoib_push, .pull = ipoib_pull, .ntoa = ipoib_ntoa, + .mc_hash = ipoib_mc_hash, }; /**************************************************************************** diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 9f39e0c9..3109db83 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -120,6 +120,16 @@ struct ll_protocol { * allocated. */ const char * ( * ntoa ) ( const void * ll_addr ); + /** + * 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 + */ + int ( * mc_hash ) ( unsigned int af, const void *net_addr, + void *ll_addr ); /** Link-layer protocol * * This is an ARPHRD_XXX constant, in network byte order. diff --git a/src/net/ethernet.c b/src/net/ethernet.c index 7b1c496f..ebb551f0 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -92,8 +93,8 @@ static int eth_pull ( struct io_buffer *iobuf, /** * Transcribe Ethernet address * - * @v ll_addr Link-layer address - * @ret string Link-layer address in human-readable format + * @v ll_addr Link-layer address + * @ret string Link-layer address in human-readable format */ const char * eth_ntoa ( const void *ll_addr ) { static char buf[18]; /* "00:00:00:00:00:00" */ @@ -105,6 +106,32 @@ const char * eth_ntoa ( const void *ll_addr ) { return buf; } +/** + * 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 + */ +static int eth_mc_hash ( unsigned int af, const void *net_addr, + void *ll_addr ) { + const uint8_t *net_addr_bytes = net_addr; + uint8_t *ll_addr_bytes = ll_addr; + + switch ( af ) { + case AF_INET: + ll_addr_bytes[0] = 0x01; + ll_addr_bytes[1] = 0x00; + ll_addr_bytes[2] = 0x5e; + ll_addr_bytes[3] = net_addr_bytes[1] & 0x7f; + ll_addr_bytes[4] = net_addr_bytes[2]; + ll_addr_bytes[5] = net_addr_bytes[3]; + default: + return -ENOTSUP; + } +} + /** Ethernet protocol */ struct ll_protocol ethernet_protocol __ll_protocol = { .name = "Ethernet", @@ -115,4 +142,5 @@ struct ll_protocol ethernet_protocol __ll_protocol = { .push = eth_push, .pull = eth_pull, .ntoa = eth_ntoa, + .mc_hash = eth_mc_hash, }; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 82a13c33..e14ed6a7 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -266,7 +266,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) { static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, struct net_device *netdev, uint8_t *ll_dest ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - uint8_t *dest_bytes = ( ( uint8_t * ) &dest ); if ( dest.s_addr == INADDR_BROADCAST ) { /* Broadcast address */ @@ -274,17 +273,7 @@ static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, ll_protocol->ll_addr_len ); return 0; } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) { - /* Special case: IPv4 multicast over Ethernet. This - * code may need to be generalised once we find out - * what happens for other link layers. - */ - ll_dest[0] = 0x01; - ll_dest[1] = 0x00; - ll_dest[2] = 0x5e; - ll_dest[3] = dest_bytes[1] & 0x7f; - ll_dest[4] = dest_bytes[2]; - ll_dest[5] = dest_bytes[3]; - return 0; + return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest ); } else { /* Unicast address: resolve via ARP */ return arp_resolve ( netdev, &ipv4_protocol, &dest,