lwIP Wiki
Register
Advertisement

IPv4 (Internet Protocol version 4) is currently the most widely-used network protocol. It has the following features:

  • Best effort delivery. Network devices do their best to get the packet to its destination, however there are no guarantees of latency or reliability, only that intermediate nodes will do their "best"
  • No guarantee of delivery or retransmission. There is no way for a destination to inform the host that it received the packet.
  • Packets may arrive in different orders than sent. Once the packets go onto the network, they may be sent on completely different routes. There is no way to coordinate that packets arrive in any particular sequence.
  • Hosts may receive duplicates of packets.

IPv4 from an application perspective[]

Manipulating addresses[]

An IPv4 address ("IP address") is 32 bits long and is written in dot-decimal notation (e.g., 127.0.0.1). Internally in lwIP, IP addresses are held in a structure called struct ip_addr, which just holds an unsigned 32-bit word. Therefore, to set an IP address, the following code can be used:

    #include <lwip/ip_addr.h>
    struct ip_addr local;
    IP4_ADDR(&local,127,0,0,1); // Set local = "127.0.0.1"

A few other useful utilities and values, which work on a struct ip_addr are:

  • IP_ADDR_ANY - the "any" address; for example, if you wish to listen to a TCP port but do not wish to bind to a particular address
  • ip_addr_set(dest, src) - to copy an address from one structure to another
  • ip_addr_cmp(addr1, addr2) - to compare two addresses for equality
  • ip4_addr1(ipaddr) - the first byte of the IP address (e.g., 182 for the address 182.178.3.5)
  • ip4_addr2(ipaddr) - the second byte of the IP address (e.g., 178 for the address 182.178.3.5)
  • ip4_addr3(ipaddr) - the third byte of the IP address (e.g., 3 for the address 182.178.3.5)
  • ip4_addr4(ipaddr) - the fourth byte of the IP address (e.g., 5 for the address 182.178.3.5)

Host vs. Network byte order[]

Because of the little-endian vs. big-endian architectural differences, you must make sure that you keep straight whether values in structures are in HOST or NETWORK byte order (see Wikipedia:Endianness for explanation).

Network byte order is big-endian. Your host platform may also be big-endian, in which case your code will technically work without any further consideration. However, if you ever recompiled your code for a little-endian processor (i.e. Intels, AMDs, ARM, etc), then your code would probably fail in very mysterious ways that will be difficult to debug or detect.

Therefore, there are set of host-to-network byte translating functions that will help. These functions are:

  • netval = htonl(hostval) - convert 32-bits host order to network order
  • netval = htons(hostval) - convert 16-bits host order to network order
  • hostval = ntohl(netval) - convert 32-bits network order to host order
  • hostval = ntohs(netval) - convert 16-bits network order to host order

lwIP takes care of most of this for you for all internal internet protocol structures. You only need to know this difference if you are setting or comparing IP addresses manually, or if you are serializing structures into packets for transmission to another system. If there is a chance that your target has a different byte ordering than you, then you must agree to a standard so that your 16-bit values and his 16-bit values agree.

As a rule of thumb for IP addresses: "ip_addr->addr is in network order and u32_t someip is in host order." Examples:

  • IN_CLASSA macro checks whether an IP address is in an "A" class; this operates on 32 bit value and is therefore in host-byte order.
  • IP_ADDR_ANY macro is a struct ip_addr, and its IP address is stored in network-byte order.
  • ip_addr_cmp macro compares two IP addresses, as contained inside a struct ip_addr. Therefore, it is network-byte order.

An example of some invalid comparisons is:

struct ip_addr ip, otherip; 
        ip.addr = 0x7f000001;   /* BAD: 127.0.0.1 on big-endian, 1.0.0.127 on little-endian */ 
        IP4_ADDR(&ip,127,0,0,1);  /* GOOD: works anywhere */ 
        ip_addr_set(&otherip,&ip); /* GOOD: network-order assigned to network-order */ 
        otherip.addr = ip.addr; /* BAD: Works, but better to use the macro (it checks for NULL) */ 
        if (ip.addr == 0x7f000001) { .... /* BAD: true on big-endian, false on little-endian! */ ... } 
        if (ip.addr == 0x0100007f) { .... /* BAD: true on little-endian, false on big-endian! */ ... } 
        if (ntohl(ip.addr) == 0x7f000001) { .... /* GOOD: Works anywhere */ ... } 
        if (ip_addr_cmp(&ip,&otherip)) { .... /* GOOD: Works anywhere */ ... }

Assigning addresses to interfaces[]

A network interface can only have one IP address assigned to it. There are three methods supported by lwIP for assigning the proper IP address to an interface:

  • Static IP: the IP address for the netif can be set either at initialization (via netif_add or via netif_set_addr or netif_set_ipaddr. See Network interfaces management for more information.
  • DHCP: DHCP is an optional protocol to obtain an IP address from a DHCP server. See DHCP for more information.
  • AUTOIP: AUTOIP is an optional protocol to pick an IP address on a local subnet without needing a server to assign addresses. See AUTOIP for more information.

Fragmentation and reassembly[]

(discuss support for)

IPv4 support history in lwIP[]

HEAD Unspecified.
1.2.0 Stable.

External references[]

See also[]

Advertisement