Friday 4 December 2015

LwIP IPv6 on K64F

Couple of weeks ago I did a bring-up of IPv6 connectivity using Ethernet on Freedom K64F board. I've used FreeRTOS combined with LwIP as the main components. Generally, everything went smooth beside one thing: because IPv6 uses multicasting during Neighbor Discovery instead of broadcasting as it was in old ARP, the Ethernet Controller needs to accept specific multicast MAC address.  By default (if not in promiscuous mode) all frames with destination MAC addresses that are not in the "whitelist" will be dropped by the HW network controller. We need to do an exception for multicast MAC needed by ICMPv6 protocol. Otherwise, even pings will not work because devices cannot exchange their IPv6 addresses. The whole "hey! who has >ipv6< address?" protocol will not work without it.

As a quick solution I've fixed it on a driver layer:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
enet_status_t ENET_DRV_Init(enet_dev_if_t * enetIfPtr, const enet_user_config_t* userConfig)
 {   
     enet_status_t result;
     uint32_t  frequency; 
     ENET_Type * base;
     uint32_t statusMask = 0;
     enet_cur_status_t curStatus;
     const enet_mac_config_t* macCfgPtr = userConfig->macCfgPtr;
     const enet_buff_config_t* buffCfgPtr = userConfig->buffCfgPtr;
+    uint32_t hash = 0;
+    uint8_t ipv6_multicast[6] = {0};
+    ipv6_multicast[0] = 0x33;
+    ipv6_multicast[1] = 0x33;
+    ipv6_multicast[2] = 0xff;
+    ipv6_multicast[3] = macCfgPtr->macAddr[3];
+    ipv6_multicast[4] = macCfgPtr->macAddr[4];
+    ipv6_multicast[5] = macCfgPtr->macAddr[5];
     
     enet_bd_config bdConfig = {0};
     /* Check the input parameters*/
     if ((!enetIfPtr) || (!macCfgPtr) || (!buffCfgPtr))
     {
         return kStatus_ENET_InvalidInput;
     }
 #if !ENET_RECEIVE_ALL_INTERRUPT
     /* POLL mode needs the extended buffer for data buffer update*/
     if((!buffCfgPtr->extRxBuffQue) || (!buffCfgPtr->extRxBuffNum))
     {
         return kStatus_ENET_InvalidInput;
     }
 #endif
     base = g_enetBase[enetIfPtr->deviceNumber];
 
     /* Store the global ENET structure for ISR input parameter*/
     enetIfHandle[enetIfPtr->deviceNumber] = enetIfPtr;
 
     /* Turn on ENET module clock gate */
     CLOCK_SYS_EnableEnetClock( 0U);
     frequency = CLOCK_SYS_GetSystemClockFreq();
     bdConfig.rxBds = buffCfgPtr->rxBdPtrAlign;
     bdConfig.rxBuffer = buffCfgPtr->rxBufferAlign;
     bdConfig.rxBdNumber = buffCfgPtr->rxBdNumber;
     bdConfig.rxBuffSizeAlign = buffCfgPtr->rxBuffSizeAlign;
     bdConfig.txBds = buffCfgPtr->txBdPtrAlign;
     bdConfig.txBuffer = buffCfgPtr->txBufferAlign;
     bdConfig.txBdNumber = buffCfgPtr->txBdNumber;
     bdConfig.txBuffSizeAlign = buffCfgPtr->txBuffSizeAlign;
     /* Init ENET MAC to reset status*/
     ENET_HAL_Init(base);
     /* Configure MAC controller*/
     ENET_HAL_Config(base, macCfgPtr, frequency, &bdConfig);
+    /* Add IPv6 multicast */
+    ENET_DRV_AddMulticastGroup(enetIfPtr->deviceNumber, ipv6_multicast, &hash);
(..)

There were couple more minor fixes needed as well. You can see whole project here.

No comments:

Post a Comment