lwIP update note 02: network interface flag (a flag only does one thing)

Starting from lwIP-2.0.0, the up flag of the network interface netif is changed to an administrative flag, and the up flag no longer has the previous The IP4 address is valid meaning.

What is the network interface netif ?
Network interface belongs to the category of link layer. It aims to uniformly encapsulate specific network hardware and software, and provide unified interface services for the upper layer of the protocol stack (IP layer). The lwIP protocol stack uses a network interface structure named netif to describe the physical network card, such as interface IP address, interface status, etc., and registers the operation function for the structure in the , such as data packet input function, output function, etc. An embedded system may have multiple network interfaces, such as multiple network ports, lwIP will allocate a netif data structure for each network interface.

Now, if a network interface netif does not have the up flag set, users cannot send or receive data on this network interface! Even with DHCP, set netif to the up state before starting the DHCP client.

This is different from lwIP-1.4.1 and earlier versions, the difference between the two is:

lwIP 1.4.1 version lwIP 2.1.2 version
Set the network interface netif to up state, which can be used to handle traffic. In addition, when the network interface uses DHCP, DHCP will automatically set the interface to the up state after configuration, so this flag is also often used for the “IP4 address valid” flag. Set the network interface netif to up state, only used to handle traffic.

Both versions use the function netif_set_up() to set netif to the up state, which is usually called at the end of initializing the network:

/*Initialize the network*/
void init_ethernet(void)
{<!-- -->
    ip_addr_t ulIPAddr, ulNetMask, ulGWAddr;
    struct netif *err;
    init_ethernet_gpio();
lwip_init();
   
    IP4_ADDR( & amp;ulIPAddr, 192, 168, 1, 100); // Here is the simplest way to explain
IP4_ADDR( &ulNetMask, 255.255.255.0);
IP4_ADDR( &ulGWAddr, 192, 168, 1, 1);

/* Register network interface */
err=netif_add( &lpc_netif, &ulIPAddr, &ulNetMask, &ulGWAddr, NULL, lpc_enetif_init, ethernet_input);
    if(err==NULL) // Need to add error handling by yourself
        return;
    
netif_set_default( &lpc_netif);
netif_set_up( &lpc_netif); // <--- here
}

The code of the function netif_set_up(netif) is as follows (simplified):

void netif_set_up(struct netif *netif)
{<!-- -->
  if (!(netif->flags & NETIF_FLAG_UP)) {<!-- -->
    netif->flags |= NETIF_FLAG_UP;

    NETIF_STATUS_CALLBACK(netif);
}

You can see that setting the network interface to the up state is simply adding the NETIF_FLAG_UP flag to the flags field.

How does this flag control data flow?
Data traffic consists of two parts: sending and receiving. Let’s look at the sending part first.

1. Control data transmission
At the IP layer, the function ip_route(ip_addr_t *dest) finds the correct network interface netif according to the specified destination IP address. The function will first determine whether the network interface is in the up state. If the network interface is not up, it will not check whether the destination IP address is matched, but return NULL code>, that is, no suitable network interface was found. Without a network interface, naturally data cannot be sent.
In implementation, lwIP-1.4.1 and lwIP-2.1.3 are slightly different:

For lwIP-1.4.1:

// excerpt from lwip1.4.1
/* iterate through netifs */
for (netif = netif_list; netif != NULL; netif = netif->next) {<!-- -->
 /* network mask matches? */
 if (netif_is_up(netif)) {<!-- --> //<--here
   if (ip_addr_netcmp(dest, & amp;(netif->ip_addr), & amp;(netif->netmask))) {<!-- -->
     /* return netif on which to forward IP packet */
     return netif;
   }
  }
}

if ((netif_default == NULL) || (!netif_is_up(netif_default))) {<!-- -->//<--here
 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\
",
   ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
 return NULL;
}

For lwIP-2.1.3, not only check whether netif is in up state, but also check whether the physical layer connection is in up state:

 // excerpt from lwip 2.1.3
  for (netif = netif_list; netif != NULL; netif = netif->next) {<!-- -->
     /* is the netif up, does it have a link and a valid address? */
    if (netif_is_up(netif) & amp; & amp; netif_is_link_up(netif) & amp; & amp; !ip4_addr_isany_val(*netif_ip4_addr(netif))) {<!-- -->
      /* network mask matches? */
      if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {<!-- -->
        /* return netif on which to forward IP packet */
        return netif;
      }
    }
  }

  if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) ||
      ip4_addr_isany_val(*netif_ip4_addr(netif_default)) || ip4_addr_isloopback(dest)) {<!-- -->
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\
",
                ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
    return NULL;
  }

When the application layer sends data, whether it is UDP or TCP, it will call the ip_route function, so if the network interface netif is not set to the up state, the application cannot send data. The data sent by the application layer will be ignored. .

  1. Both the UDP sending API functions udp_send and udp_sendto will call ip_route;
  2. TCP’s send API function tcp_output also calls ip_route .

2. Control data reception
After reading the data transmission, let’s look at the data reception. Still at the IP layer, the function ip_input is used to process IP packets. The function will find the correct network interface netif according to the destination IP of the received IP packet. During the search process, it will be judged whether the network interface is in the up state. If the network interface is not up , it means that the network interface cannot be found. And if the network interface is not found, and the packet is not from a DHCP server, the received data is discarded.

/* find network interface */
if ((netif_is_up(netif)) & amp; & amp; (!ip_addr_isany( & amp;(netif->ip_addr)))) {<!-- --> //<--here
    /* unicast to this interface address? */
    if (ip_addr_cmp( & amp; current_iphdr_dest, & amp; (netif->ip_addr)) ||
        /* or broadcast on this interface network address? */
        ip_addr_isbroadcast( & current_iphdr_dest, netif)) {<!-- -->
        LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\
",
                               netif->name[0], netif->name[1]));
        /* break out of for loop */
        break;
    }
}

In the application layer, no matter it is TCP or UDP receiving API function, the data is obtained from ip_input, so if a netif is not set to up state, the application layer will not receive to the data.

Therefore, the protocol stack can control the transmission and reception of the application layer through a software flag, so that the data traffic can be processed conveniently. But this is only for the application layer, because the lwip-1.4.1 protocol stack opens the back door to DHCP.

When DHCP sends data, directly call udp_sendto_if, bypassing the ip_route function, even if netif does not set up, it can still send data.

In terms of receiving, the receiving processing function specially gives the green light to DHCP, even if no suitable network interface can be found, the data can be submitted to the HDCP processing function, and it is well-known and has RFC 1542 endorsement.

This creates an inconsistency: with a static IP, the user must call the function netif_set_up to set the network interface to the up state, but with DHCP Obtain IP dynamically. After assigning IP, DHCP client sets the network interface to up state.

This behavior of the DHCP client causes many people to misuse the up flag. When the network interface is set to up state, it means that the device has been allocated to an IP address, so many people will check whether the network interface is up status to determine whether the IP address is valid. This makes this logo ambiguous: it is originally a software logo that facilitates data traffic processing, but it also assumes the meaning of IP address is valid.

So back in August 2012, lwIP developer Simon Goldschmidt asked this question:

When the network interface netif is down, DHCP and AutoIP can still send and receive data correctly on this network interface.

I don’t think this is clear enough, there should be only one way, that netif must always be in up state when sending or receiving. The initialization phase of DHCP and AutoIP should just set the IP address of netif to ‘0.0.0.0’, and the router should ignore netif using ‘0.0.0.0’ IP.

Then in March 2015, Simon Goldschmidt fixed the unclear handling of netif up/down, which is the updated content mentioned at the beginning of this section:

Change the up flag of the network interface netif to an administrative flag. The up flag no longer has its former “IP4 address valid” meaning. Now, if a network interface netif does not have the up flag set, users cannot send or receive data on this network interface! Even with DHCP, set netif to the up state before starting the DHCP client.

How does lwip2.1.x block DHCP?

  1. In dhcp.c, remove all netif_set_up and netif_set_down functions. That is, DHCP cannot update the netif flag.

  2. In the dhcp_start function of dhcp.c, add the code:

 LWIP_ERROR("netif is not up, old style port?", netif_is_up(netif), return ERR_ARG;);

If netif is not in up state, the function returns an argument error (ERR_ARG) code. That is, if netif is not in up state, DHCP cannot be started.
Therefore, when calling the dhcp_start function, judging the return value helps to quickly find problems.

Episode:

In March 2015, after Simon Goldschmidt fixed the problem that netif up/down was not clear, the comment of the function netif_set_up has not been modified, and the comment is still Shows Enable DHCP on a network interface that is in the down state, and will set the interface to the up state after DHCP completes the configuration. It was not until October 2015 that Erik Ekman modified the comment of this function, and it became what version 2.1.3 looks like now.

After reading, you will gain something and help bloggers to raise children – knowledge is hard to buy, but you can buy a lot of milk powder (〃▽’〃)
It's hard to buy knowledge, but you can buy a lot of milk powder