No edit summary |
Tag: Visual edit |
||
(5 intermediate revisions by 5 users not shown) | |||
Line 10: | Line 10: | ||
=== Manipulating addresses === |
=== 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 |
+ | 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 <code>struct ip_addr</code>, 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> |
#include <lwip/ip_addr.h> |
||
Line 50: | Line 50: | ||
struct ip_addr ip, otherip; |
struct ip_addr ip, otherip; |
||
− | ip |
+ | 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 */ |
+ | IP4_ADDR(&ip,127,0,0,1); /* GOOD: works anywhere */ |
− | ip_addr_set(otherip,ip); /* GOOD: network-order assigned to network-order */ |
+ | ip_addr_set(&otherip,&ip); /* GOOD: network-order assigned to network-order */ |
− | otherip |
+ | otherip.addr = ip.addr; /* BAD: Works, but better to use the macro (it checks for NULL) */ |
− | if (ip |
+ | if (ip.addr == 0x7f000001) { .... /* BAD: true on big-endian, false on little-endian! */ ... } |
− | if (ip |
+ | if (ip.addr == 0x0100007f) { .... /* BAD: true on little-endian, false on big-endian! */ ... } |
− | if (ntohl(ip |
+ | if (ntohl(ip.addr) == 0x7f000001) { .... /* GOOD: Works anywhere */ ... } |
− | if (ip_addr_cmp(ip,otherip)) { .... /* GOOD: Works anywhere */ ... } |
+ | if (ip_addr_cmp(&ip,&otherip)) { .... /* GOOD: Works anywhere */ ... } |
=== Assigning addresses to interfaces === |
=== Assigning addresses to interfaces === |
Revision as of 19:14, 2 July 2020
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 addressip_addr_set(dest, src)
- to copy an address from one structure to anotherip_addr_cmp(addr1, addr2)
- to compare two addresses for equalityip4_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 ordernetval = htons(hostval)
- convert 16-bits host order to network orderhostval = ntohl(netval)
- convert 32-bits network order to host orderhostval = 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 astruct ip_addr
, and its IP address is stored in network-byte order.ip_addr_cmp
macro compares two IP addresses, as contained inside astruct 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 (vianetif_add
or vianetif_set_addr
ornetif_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
- Wikipedia: Internet Protocol
- Wikipedia: IPv4
- WireShark: IPv4
- RFC 760 (obsolete) - Internet protocol
- RFC 791 (repleaces 760) - Internet protocol
- RFC 3344 - IP Mobility Support for IPv4
- http://www.networksorcery.com/enp/protocol/ip.htm - The IP header