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 namednetif
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 anetif
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. .
- Both the UDP sending API functions
udp_send
andudp_sendto
will callip_route
; - TCP’s send API function
tcp_output
also callsip_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. Theup
flag no longer has its former “IP4 address valid” meaning. Now, if a network interface netif does not have theup
flag set, users cannot send or receive data on this network interface! Even with DHCP, set netif to theup
state before starting the DHCP client.
How does lwip2.1.x block DHCP?
-
In dhcp.c, remove all
netif_set_up
andnetif_set_down
functions. That is, DHCP cannot update the netif flag. -
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 (〃▽’〃)