Adding an Address to the Multicast Address Filter of a Network Device
NetDev_AddrMulticastAdd() is used to configure a device with an (IP-to-Ethernet) multicast hardware address.
Since many network controllers’ documentation fails to properly indicate how to add/configure an Ethernet MAC device with a multicast address, the following method is recommended for determining and testing the correct multicast hash bit algorithm.
Configure a packet capture program or multicast application to broadcast a multicast packet with Ethernet destination address of 01:00:5E:00:00:01 (which is an IPv4 Ethernet multicast address). This MAC address corresponds to the multicast group IP address of 224.0.0.1 which will be converted to a MAC address by higher layers and passed to this function.
Set a break point in the receive ISR handler, and transmit one Send packet to the target. The break point should not be reached as the result of the transmitted packet. Use caution to ensure that other network traffic is not the source of the interrupt when the button is pressed. Sometimes asynchronous network events happen very close in time and the end result can be deceiving. Ideally, these tests should be performed on an isolated network, but if that is not an option, disconnect as many other hosts from the network as possible.
Use the debugger to stop the application and program the MAC multicast hash register low bits to 0xFFFFFFFF. Go to step 2. Repeat for the hash bit high register if necessary. The goal is to bracket off which bit in either the high or low hash bit register causes the device to be interrupted when the broadcast frame is received by the target. Once the correct bit is known, the hash algorithm can be easily written and tested.
Update the device driver’s
NetDev_AddrMulticastAdd()function to calculate and configure the correct CRC. The sample code in Listing 7-4 can be adjusted as per the network controller’s documentation in order to get the hash from the correct subset of CRC bits. Most of the code is similar between various devices and is thus reusable. The hash algorithm is the exclusive OR of every 6th bit of the destination address:hash[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]hash[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]hash[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]hash[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]hash[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]hash[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]Where da[0] represents the least significant bit of the first byte of the Ethernet destination address (da) received and where da[47] represents the most significant bit of the last byte of the Ethernet destination address received.
Test the device driver’s
NetDev_AddrMulticastAdd()function by ensuring that the group address 224.0.0.1, when joined from the application correctly configures the device to receive multicast packets destined to the 224.0.0.1 address. Then broadcast to 224.0.0.1 to test if the device receives the multicast packet.Listing - Explicit multicast hash code
/* ---------- CALCULATE HASH CODE ---------- */ hash = 0; for (i = 0; i < 6; i++) { /* For each row in the bit hash table: */ bit_val = 0; /* Clear initial xor value for each row. */ for (j = 0; j < 8; j++) { /* For each bit in each octet: */ bit_nbr = (j * 6) + i; /* Determine which bit in stream, 0-47. */ octet_nbr = bit_nbr / 8; /* Determine which octet bit belongs to. */ octet = paddr_hw[octet_nbr]; /* Get octet value. */ /* Check if octet's bit is set. */ bit = octet & (1 << (bit_nbr % 8)); bit_val ^= (bit > 0) ? 1 : 0; /* Calculate table row's XOR hash value. */ } hash |= (bit_val << i); /* Add row's XOR hash value to final hash. */ } /* ---- ADD MULTICAST ADDRESS TO DEVICE ---- */ reg_sel = (hash >> 5) & 0x01; /* Determine hash register to configure. */ reg_bit = (hash >> 0) & 0x1F; /* Determine hash register bit to configure. */ /* (Substitute '0x01'/'0x1F' with device's ..*/ /* .. actual hash register bit masks/shifts.)*/ paddr_hash_ctrs = &pdev_data->MulticastAddrHashBitCtr[hash]; (*paddr_hash_ctrs)++; /* Increment hash bit reference counter. */ if (reg_sel == 0) { /* Set multicast hash register bit. */ pdev->MCAST_REG_LO |= (1 << reg_bit); /* (Substitute 'MCAST_REG_LO/HI' with .. */ } else { /* .. device's actual multicast registers.) */ pdev->MCAST_REG_HI |= (1 << reg_bit); }
Alternate Hash Code
Alternatively, Figure 7-7 shows how the CRC hash can be computed with a call to NetUtil_32BitCRC_CalcCpl() followed by an optional call to NetUtil_32BitReflect(), with four possible combinations:
CRC without complement, without reflection
CRC without complement, with reflection
CRC with complement, without reflection
CRC with complement, with reflection
Listing - CRC Multicast Hash Code
/* ---------- CALCULATE HASH CODE ---------- */
/* Calculate CRC. */
crc = NetUtil_32BitCRC_Calc((CPU_INT08U *)paddr_hw,
(CPU_INT32U ) addr_hw_len,
(NET_ERR *)perr);
if (*perr != NET_UTIL_ERR_NONE) {
return;
}
/* ---- ADD MULTICAST ADDRESS TO DEVICE ---- */
crc = NetUtil_32BitReflect(crc); /* Optionally, complement CRC. */
hash = (crc >> 23u) & 0x3F; /* Determine hash register to configure. */
reg_bit = (hash % 32u); /* Determine hash register bit to configure. */
/* (Substitute '23u'/'0x3F' with device's .. */
/* .. actual hash register bit masks/shifts.)*/
paddr_hash_ctrs = &pdev_data->MulticastAddrHashBitCtr[hash];
(*paddr_hash_ctrs)++; /* Increment hash bit reference counter. */
if (hash <= 31u) { /* Set multicast hash register bit. */
pdev->MCAST_REG_LO |= (1 << reg_bit); /* (Substitute 'MCAST_REG_LO/HI' with .. */
} else { /* .. device's actual multicast registers.) */
pdev->MCAST_REG_HI |= (1 << reg_bit);
}
Unfortunately, the network controller's documentation will likely not tell you which combination of complement and reflection is needed to properly compute the hash value. The documentation will likely state ‘Standard Ethernet CRC’, which when compared to other documents, means any of the four combinations above; different than the actual frame CRC.
Fortunately, if the code is written to perform both the complement and reflection, then you can use the debugger to repeat the code block over and over, skipping either the line that performs the complement or the function call to the reflection, until the output hash bit is computed correctly.