NetDev_AddrMulticastAdd()

The next API function is the AddrMulticastAdd() function used to configure a device with an (IP-to-Ethernet) multicast hardware address.

Files

Every device driver’s net_dev.c

Prototype

          static void NetDev_AddrMulticastAdd (NET_IF     *pif,
                                               CPU_INT08U *paddr_hw,
                                               CPU_INT08U  addr_hw_len,
                                               NET_ERR    *perr);

Note that since every device driver’s AddrMulticastAdd() function is accessed only by function pointer via the device driver’s API structure, it doesn’t need to be globally available and should therefore be declared as ‘static’.

Arguments

pif

Pointer to the interface to add/configure a multicast address.

paddr_hw

Pointer to multicast hardware address to add.

addr_hw_len

Length of multicast hardware address.

perr

Pointer to variable that will receive the return error code from this function.

Returned Value

None.

Required Configuration

Necessary only if NET_MCAST_CFG_IPv4_RX_EN  or  NET_MCAST_CFG_IPv4_TX_EN is configured for transmit and receive multicasting.

Notes / Warnings

Since many network controllers’ documentation fail to properly indicate how to add/configure an Ethernet MAC device with a multicast address, the following methodology is recommended for determining and testing the correct multicast hash bit algorithm.

  1. Configure a packet capture program or multicast application to broadcast a multicast packet with Ethernet destination address of 01:00:5E:00:00:01. 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.
  2. 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 disconnect as many other hosts from the network as possible.
  3. 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.
  4. The following hash bit algorithm code below could be adjusted 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 exlusive 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 da0 represents the least significant bit of the first byte of the destination address received and where da47 represents the most significant bit of the last byte of the destination address received.

    Listing - Example device multicast address configuration using CRC hash code algorithm
                                                                /* ---------- 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.                          */
                      bit        =  octet & (1 << (bit_nbr % 8));  /* Check if octet's bit is set.           */
                      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);
              }
                                                                /* ---------- CALCULATE HASH CODE ---------- */
                                                                /* Calculate CRC.                            */
              crc = NetUtil_32BitCRC_Calc((CPU_INT08U *)paddr_hw,
                                          (CPU_INT32U  ) addr_hw_len,
                                          (NET_ERR    *)perr);


    Alternatively, you may be able to compute the CRC hash with a call to
    NetUtil_32BitCRC_CalcCpl() followed by an optional call to NetUtil_32BitReflect(), with four possible combinations:

    1. CRC without complement and without reflection
    2. CRC without complement and with reflection
    3. CRC with complement and without reflection
    4. CRC with complement and with reflection


      Listing - Example device multicast address configuration using CRC and reflection functions
                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 product documentation will not likely tell you which combination of complement and reflection is necessary in order to properly compute the hash value. Most likely, the documentation will simply 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 the debugger may be used 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.


Update the device driver’s AddrMulticastAdd() function to calculate and configure the correct CRC.

Test the device driver’s AddrMulticastAdd() function by ensuring that the group address 224.0.0.1, when joined from the application (see NetIGMP_HostGrpJoin), correctly configures the device to receive multicast packets destined to the 224.0.0.1 address. Then broadcast the 224.0.0.1 (see step 1) to test if the device receives the multicast packet.