lwip multicast

cancel
Showing results for 
Search instead for 
Did you mean: 

lwip multicast

4,458 Views
davidtietz
Contributor III

Does lwip in SDK 1.2 support multicast messages?

 

If so, does anybody know any good examples to set this up?

Labels (1)
7 Replies

321 Views
Carlos_Musich
NXP Employee
NXP Employee

Hi David,

KSDK1.2 includes the lwIP 1.4.1 source code which features IGMP (Internet Group Management Protocol) for multicast traffic management.

lwip 1.4.1 can be downloaded from this link: download.savannah.gnu.org/releases/lwip/

Regards,

Carlos

0 Kudos

321 Views
davidtietz
Contributor III

Hi Carlos,

Thanks for the link, I had already found that on Google already. I will try to hit up their forums to see what I can find. I am just wondering if this is a Kinetis specific problem.

Here is what I have done in the past few days to try to get this working. To simplify I am working inside of the example project of projects provided with KSDK 1.2:

C:\Freescale\KSDK_1.2.0\examples\twrk60d100m\demo_apps\lwip\lwip_udpecho_demo\udpecho_rtos\udpecho_mqx\kds\lwip_udpecho_demo_mqx.wsd

-imported this into a blank workspace.

-everything compiles as usual.

-I can ping the tower board and send UDP packets which are echoed as expected.

I then reconfigured this example to receive multicast messages:

-Added the following line to the udpecho_thread function in main.c:

err = netconn_join_leave_group(conn, &multicast_ip_address, &local_ip_address, NETCONN_JOIN);

-Calling this requires that LWIP_IGMP be defined as 1

-Also we must define LWIP_RAND()be defined so we added the following in main.c:

#define LWIP_RAND get_random_value

uint32_t get_random_value(void)

{

       uint32_t num;

       uint8_t seed_value = 17;

       srand(seed_value);

       num = rand();

       return num;

}

Everything seems to work fine and looking at the debug dialog and wireshark we are successful at broadcasting the multicast join message.

However, we could still not receive messages.

I temporarily enabled promiscuous mode (ENET_RCR[PROM]) and this works, messages come through as expected.

So I guess my question at this point is how to implement the function to filter MAC address to allow the multicast messages through?

I am specifically talking about the area in igmp.c, around line 500:

          /* If first use of the group, allow the group at the MAC level */

          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {

            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));

            ip_addr_debug_print(IGMP_DEBUG, groupaddr);

            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));

            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);

          }

Any ideas?

Thanks,

David

0 Kudos

321 Views
joseraffucci
Contributor IV

Just ran into this and I'm working my way through it.  You need to add the hooks for the join/leave operations.

In ethernetif_init (ethernetif.c) I added:

netif_set_igmp_mac_filter(netif, ethernetif_igmp_mac_filter);

and defined:

static err_t ethernetif_igmp_mac_filter(struct netif *netif, ip_addr_t *group, u8_t action) {

  uint32_t devNumber = 0;

  uint32_t hash;

#if LWIP_HAVE_LOOPIF

  devNumber = netif->num - 1;

#else

  devNumber = netif->num;

#endif

  switch (action) {

  case IGMP_ADD_MAC_FILTER:

  return ENET_DRV_AddMulticastGroup(devNumber, (uint8_t *) group, &hash);

  case IGMP_DEL_MAC_FILTER:

  return ENET_DRV_LeaveMulticastGroup(devNumber, (uint8_t *) group);

  default:

  return ERR_IF;

  }

}

to get the ball rolling.  I can send out multicast packets and I see the IGMP membership notifications on wireshark.  Still trying to figure out why I'm not receiving any yet.

0 Kudos

321 Views
joseraffucci
Contributor IV

Figured it out... the driver expects a multicast mac address while the hook is sending an ip address.  You also need to tell netif that that interface is igmp aware:

in ethernetif.c:

Add to low_level_init():

#if LWIP_IGMP

  netif->flags |= NETIF_FLAG_IGMP;

#endif

and the above code changes slightly to:

static err_t multicast_ip_to_mac(ip_addr_t *ip_addr, uint8_t *mac_addr) {

  if ((NULL == ip_addr) || (NULL == mac_addr)) {

  return ERR_ARG;

  }

  mac_addr[0] = 0x01;

  mac_addr[1] = 0x00;

  mac_addr[2] = 0x53;

  mac_addr[3] = ip4_addr2_16(ip_addr) & ~0x80;

  mac_addr[4] = ip4_addr3_16(ip_addr);

  mac_addr[5] = ip4_addr4_16(ip_addr);

  return ENET_OK;

}

static err_t ethernetif_igmp_mac_filter(struct netif *netif, ip_addr_t *group, u8_t action) {

  uint32_t devNumber = 0;

  uint32_t hash;

#if LWIP_HAVE_LOOPIF

  devNumber = netif->num - 1;

#else

  devNumber = netif->num;

#endif

  uint8_t multicastMacAddr[kEnetMacAddrLen];

  multicast_ip_to_mac(group, multicastMacAddr);

  //LWIP_DEBUGF(IGMP_DEBUG, ("mac filtering ip: %d hw: % hash: %d", );

  switch (action) {

  case IGMP_ADD_MAC_FILTER:

  return ENET_DRV_AddMulticastGroup(devNumber, (uint8_t *) multicastMacAddr, &hash);

  case IGMP_DEL_MAC_FILTER:

  return ENET_DRV_LeaveMulticastGroup(devNumber, (uint8_t *) multicastMacAddr);

  default:

  return ERR_IF;

  }

}

321 Views
wesleyhunter
Contributor II

OMG, I been struggling so much with this. Finally got it receiving but there was a slight error in your code posted above. The mac_addr[2] should equal 0x5E not 0x53. The following site explains this conversion quite well: Mapping IP Multicast to MAC-Layer Multicast

So my code looks as follows:

err_t ethernetif_init(struct netif *netif)

{

...

...

...

#if LWIP_IGMP

  netif_set_igmp_mac_filter(netif, ethernetif_igmp_mac_filter);

#endif

  return result;

}

static err_t multicast_ip_to_mac(ip_addr_t *ip_addr, uint8_t *mac_addr)

{

  if ((NULL == ip_addr) || (NULL == mac_addr)) {

  return ERR_ARG;

  }

  mac_addr[0] = 0x01;

  mac_addr[1] = 0x00;

  mac_addr[2] = 0x5E;

  mac_addr[3] = ip4_addr2_16(ip_addr) & ~0x80;

  mac_addr[4] = ip4_addr3_16(ip_addr);

  mac_addr[5] = ip4_addr4_16(ip_addr);

  return ENET_OK;

}

static err_t ethernetif_igmp_mac_filter(struct netif *netif, ip_addr_t *group, u8_t action)

{

  uint32_t devNumber = 0;

  uint32_t hash;

#if LWIP_HAVE_LOOPIF

  devNumber = netif->num - 1;

#else

  devNumber = netif->num;

#endif

  uint8_t multicastMacAddr[kEnetMacAddrLen];

  multicast_ip_to_mac(group, multicastMacAddr);

  //LWIP_DEBUGF(IGMP_DEBUG, ("mac filtering ip: %d hw: % hash: %d", );

  switch (action)

  {

   case IGMP_ADD_MAC_FILTER:

   return ENET_DRV_AddMulticastGroup(devNumber, (uint8_t *) multicastMacAddr, &hash);

   case IGMP_DEL_MAC_FILTER:

   return ENET_DRV_LeaveMulticastGroup(devNumber, (uint8_t *) multicastMacAddr);

   default:

   return ERR_IF;

  }

}

321 Views
joseraffucci
Contributor IV

Good catch.  That was a typo that I forgot to fix in my post.

FYI - you still have to make the modifications in the 2.0 KDSK with some slight changes (so far -- haven't gotten everything working just yet)

#define IPE_ADDR_MC(addr, ip)        \

  do {                               \

    (addr)[0] = 0x01;                \

    (addr)[1] = 0x00;                \

    (addr)[2] = 0x5E;                \

    (addr)[3] = ((ip) >> 8)  & 0x7F; \

    (addr)[4] = ((ip) >> 16) & 0xFF; \

    (addr)[5] = ((ip) >> 24) & 0xFF; \

  } while (0)

static err_t ethernetif_igmp_mac_filter(struct netif *netif, ip_addr_t *group, u8_t action) {

  uint8_t multicastMacAddr[kEnetMacAddrLen];

  IPE_ADDR_MC(multicastMacAddr, group->addr);

  LWIP_DEBUGF(IGMP_DEBUG, ("Filtering multicast mac:"));

  mac_addr_debug_print(IGMP_DEBUG, multicastMacAddr);

  switch (action) {

    case IGMP_ADD_MAC_FILTER:

    ENET_AddMulticastGroup(ENET, multicastMacAddr);

    return ERR_OK;

    case IGMP_DEL_MAC_FILTER:

    ENET_LeaveMulticastGroup(ENET, multicastMacAddr);

    return ERR_OK;

    default:

      return ERR_IF;

  }

}

low_level_init changes are the same.

0 Kudos

321 Views
mjbcswitzerland
Specialist V

David

It sounds as though these functions have never been used or tested before since the multicast filter configuration must be missing. This is HW dependent and so the lwip part is possibly just calling a dummy function that needs to be replaced for the platform. Since IPv6 also needs mulicast operation it is probable that IPv6 link-local operations will not function either.

I have attached the Kinetis Ethernet driver from the uTasker project so that you can take the multicast filter parts in case you don't find a quick solution from the other communities.

Just search for

external: fnModifyMulticastFilter()

static: fnDisableMulticastHash()

static: fnEnableMulticastHash()

static:fnCalculateHash()

For multicast/IGMP overview you can look at

www. utasker.com/docs/uTasker/uTasker_IGMP.pdf

Regards

Mark

0 Kudos