The uIP TCP/IP stack provides Internet communication abilities to Contiki.
Traditional TCP/IP implementations have required far too much resources both in terms of code size and memory usage to be useful in small 8 or 16-bit systems. Code size of a few hundred kilobytes and RAM requirements of several hundreds of kilobytes have made it impossible to fit the full TCP/IP stack into systems with a few tens of kilobytes of RAM and room for less than 100 kilobytes of code.
The uIP implementation is designed to have only the absolute minimal set of features needed for a full TCP/IP stack. It can only handle a single network interface and does not implement UDP, but focuses on the IP, ICMP and TCP protocols. uIP is written in the C programming language.
Many other TCP/IP implementations for small systems assume that the embedded device always will communicate with a full-scale TCP/IP implementation running on a workstation-class machine. Under this assumption, it is possible to remove certain TCP/IP mechanisms that are very rarely used in such situations. Many of those mechanisms are essential, however, if the embedded device is to communicate with another equally limited device, e.g., when running distributed peer-to-peer services and protocols. uIP is designed to be RFC compliant in order to let the embedded devices to act as first-class network citizens. The uIP TCP/IP implementation that is not tailored for any specific application.
TCP provides a reliable byte stream to the upper layer protocols. It breaks the byte stream into appropriately sized segments and each segment is sent in its own IP packet. The IP packets are sent out on the network by the network device driver. If the destination is not on the physically connected network, the IP packet is forwarded onto another network by a router that is situated between the two networks. If the maximum packet size of the other network is smaller than the size of the IP packet, the packet is fragmented into smaller packets by the router. If possible, the size of the TCP segments are chosen so that fragmentation is minimized. The final recipient of the packet will have to reassemble any fragmented IP packets before they can be passed to higher layers.
The formal requirements for the protocols in the TCP/IP stack is specified in a number of RFC documents published by the Internet Engineering Task Force, IETF. Each of the protocols in the stack is defined in one more RFC documents and RFC1122 collects all requirements and updates the previous RFCs.
The RFC1122 requirements can be divided into two categories; those that deal with the host to host communication and those that deal with communication between the application and the networking stack. An example of the first kind is "A TCP MUST be able to receive a TCP option in any segment" and an example of the second kind is "There MUST be a mechanism for reporting soft TCP error conditions to the application." A TCP/IP implementation that violates requirements of the first kind may not be able to communicate with other TCP/IP implementations and may even lead to network failures. Violation of the second kind of requirements will only affect the communication within the system and will not affect host-to-host communication.
In our implementations, we have implemented all RFC requirements that affect host-to-host communication. However, in order to reduce code size, we have removed certain mechanisms in the interface between the application and the stack, such as the soft error reporting mechanism and dynamically configurable type-of-service bits for TCP connections. Since there are only very few applications that make use of those features they can be removed without loss of generality.
The uIP stack does not use explicit dynamic memory allocation. Instead, it uses a single global buffer for holding packets and has a fixed table for holding connection state. The global packet buffer is large enough to contain one packet of maximum size. When a packet arrives from the network, the device driver places it in the global buffer and calls the TCP/IP stack. If the packet contains data, the TCP/IP stack will notify the corresponding application. Because the data in the buffer will be overwritten by the next incoming packet, the application will either have to act immediately on the data or copy the data into a secondary buffer for later processing. The packet buffer will not be overwritten by new packets before the application has processed the data. Packets that arrive when the application is processing the data must be queued, either by the network device or by the device driver. Most single-chip Ethernet controllers have on-chip buffers that are large enough to contain at least 4 maximum sized Ethernet frames. Devices that are handled by the processor, such as RS-232 ports, can copy incoming bytes to a separate buffer during application processing. If the buffers are full, the incoming packet is dropped. This will cause performance degradation, but only when multiple connections are running in parallel. This is because uIP advertises a very small receiver window, which means that only a single TCP segment will be in the network per connection.
In uIP, the same global packet buffer that is used for incoming packets is also used for the TCP/IP headers of outgoing data. If the application sends dynamic data, it may use the parts of the global packet buffer that are not used for headers as a temporary storage buffer. To send the data, the application passes a pointer to the data as well as the length of the data to the stack. The TCP/IP headers are written into the global buffer and once the headers have been produced, the device driver sends the headers and the application data out on the network. The data is not queued for retransmissions. Instead, the application will have to reproduce the data if a retransmission is necessary.
The total amount of memory usage for uIP depends heavily on the applications of the particular device in which the implementations are to be run. The memory configuration determines both the amount of traffic the system should be able to handle and the maximum amount of simultaneous connections. A device that will be sending large e-mails while at the same time running a web server with highly dynamic web pages and multiple simultaneous clients, will require more RAM than a simple Telnet server. It is possible to run the uIP implementation with as little as 200 bytes of RAM, but such a configuration will provide extremely low throughput and will only allow a small number of simultaneous connections.
Instead, uIP uses an event driven interface where the application is invoked in response to certain events. An application running on top of uIP is implemented as a C function that is called by uIP in response to certain events. uIP calls the application when data is received, when data has been successfully delivered to the other end of the connection, when a new connection has been set up, or when data has to be retransmitted. The application is also periodically polled for new data. The application program provides only one callback function; it is up to the application to deal with mapping different network services to different ports and connections. Because the application is able to act on incoming data and connection requests as soon as the TCP/IP stack receives the packet, low response times can be achieved even in low-end systems.
uIP is different from other TCP/IP stacks in that it requires help from the application when doing retransmissions. Other TCP/IP stacks buffer the transmitted data in memory until the data is known to be successfully delivered to the remote end of the connection. If the data needs to be retransmitted, the stack takes care of the retransmission without notifying the application. With this approach, the data has to be buffered in memory while waiting for an acknowledgment even if the application might be able to quickly regenerate the data if a retransmission has to be made.
In order to reduce memory usage, uIP utilizes the fact that the application may be able to regenerate sent data and lets the application take part in retransmissions. uIP does not keep track of packet contents after they have been sent by the device driver, and uIP requires that the application takes an active part in performing the retransmission. When uIP decides that a segment should be retransmitted, it calls the application with a flag set indicating that a retransmission is required. The application checks the retransmission flag and produces the same data that was previously sent. From the application's standpoint, performing a retransmission is not different from how the data originally was sent. Therefore the application can be written in such a way that the same code is used both for sending data and retransmitting data. Also, it is important to note that even though the actual retransmission operation is carried out by the application, it is the responsibility of the stack to know when the retransmission should be made. Thus the complexity of the application does not necessarily increase because it takes an active part in doing retransmissions.
The application sends data by using the uIP function uip_send(). The uip_send() function takes two arguments; a pointer to the data to be sent and the length of the data. If the application needs RAM space for producing the actual data that should be sent, the packet buffer (pointed to by the uip_appdata pointer) can be used for this purpose.
The application can send only one chunk of data at a time on a connection and it is not possible to call uip_send() more than once per application invocation; only the data from the last call will be sent.
The application must check the uip_rexmit() flag and produce the same data that was previously sent. From the application's standpoint, performing a retransmission is not different from how the data originally was sent. Therefor, the application can be written in such a way that the same code is used both for sending data and retransmitting data. Also, it is important to note that even though the actual retransmission operation is carried out by the application, it is the responsibility of the stack to know when the retransmission should be made. Thus the complexity of the application does not necessarily increase because it takes an active part in doing retransmissions.
If the connection has been closed by the remote end, the test function uip_closed() is true. The application may then do any necessary cleanups.
The polling event has two purposes. The first is to let the application periodically know that a connection is idle, which allows the application to close connections that have been idle for too long. The other purpose is to let the application send new data that has been produced. The application can only send data when invoked by uIP, and therefore the poll event is the only way to send data on an otherwise idle connection.
The application can check the lport field in the uip_conn structure to check to which port the new connection was connected.
The function uip_ipaddr() may be used to pack an IP address into the two element 16-bit array used by uIP to represent IP addresses.
Two examples of usage are shown below. The first example shows how to open a connection to TCP port 8080 of the remote end of the current connection. If there are not enough TCP connection slots to allow a new connection to be opened, the uip_connect() function returns NULL and the current connection is aborted by uip_abort().
void connect_example1_app(void) { if(uip_connect(uip_conn->ripaddr, 8080) == NULL) { uip_abort(); } }
The second example shows how to open a new connection to a specific IP address. No error checks are made in this example.
void connect_example2(void) { u16_t ipaddr[2]; uip_ipaddr(ipaddr, 192,168,0,1); uip_connect(ipaddr, 8080); }
The uip_periodic() function should be invoked periodically once per connection by the device driver, typically one per second. This function is used by uIP to drive protocol timers and retransmissions, and when it returns it may have placed an outbound packet in the uip_buf buffer.
Files | |
| file | uip.h |
| Header file for the uIP TCP/IP stack. | |
| file | uip.c |
| The uIP TCP/IP stack code. | |
Modules | |
| group | uIP configuration functions |
| group | uIP initialization functions |
| group | uIP device driver functions |
| group | uIP application functions |
| group | uIP conversion functions |
| group | uIP Address Resolution Protocol |
| group | uIP packet forwarding |
| group | uIP TCP throughput booster hack |
| group | uIP hostname resolver functions |
| group | Architecture specific uIP functions |
Data Structures | |
| struct | uip_conn |
| Representation of a uIP TCP connection. More... | |
| struct | uip_udp_conn |
| Representation of a uIP UDP connection. More... | |
| struct | uip_stats |
| The structure holding the TCP/IP statistics that are gathered if UIP_STATISTICS is set to 1. More... | |
| struct | uip_eth_addr |
| Representation of a 48-bit Ethernet address. More... | |
Defines | |
| #define | UIP_APPDATA_SIZE |
| The buffer size available for user data in the uip_buf buffer. | |
Typedefs | |
| typedef u16_t | uip_ipaddr_t [2] |
| Repressentation of an IP address. | |
Functions | |
| u16_t | uip_chksum (u16_t *buf, u16_t len) |
| Calculate the Internet checksum over a buffer. | |
| u16_t | uip_ipchksum (void) |
| Calculate the IP header checksum of the packet header in uip_buf. | |
| u16_t | uip_tcpchksum (void) |
| Calculate the TCP checksum of the packet in uip_buf and uip_appdata. | |
| void | uip_add32 (u8_t *op32, u16_t op16) |
| Carry out a 32-bit addition. | |
| void | uip_init (void) |
| uIP initialization function. | |
| uip_conn * | uip_connect (uip_ipaddr_t *ripaddr, u16_t rport) |
| Connect to a remote host using TCP. | |
| uip_udp_conn * | uip_udp_new (uip_ipaddr_t *ripaddr, u16_t rport) |
| Set up a new UDP connection. | |
| void | uip_unlisten (u16_t port) |
| Stop listening to the specified port. | |
| void | uip_listen (u16_t port) |
| Start listening to the specified port. | |
| u16_t | htons (u16_t val) |
| Convert 16-bit quantity from host byte order to network byte order. | |
| void | uip_send (const char *data, int len) |
| Send data on the current connection. | |
Variables | |
| u8_t * | uip_appdata |
| Pointer to the application data in the packet buffer. | |
| uip_stats | uip_stat |
| The uIP TCP/IP statistics. | |
| u8_t | uip_buf [UIP_BUFSIZE+2] |
| The uIP packet buffer. | |
| u8_t * | uip_appdata |
| Pointer to the application data in the packet buffer. | |
| u8_t | uip_acc32 [4] |
| 4-byte array used for the 32-bit sequence number calculations. | |
|
|
The buffer size available for user data in the uip_buf buffer. This macro holds the available size for user data in the uip_buf buffer. The macro is intended to be used for checking bounds of available user data. Example:
|
|
|
Convert 16-bit quantity from host byte order to network byte order. This function is primarily used for converting variables from host byte order to network byte order. For converting constants to network byte order, use the HTONS() macro instead. |
|
||||||||||||
|
Carry out a 32-bit addition. Because not all architectures for which uIP is intended has native 32-bit arithmetic, uIP uses an external C function for doing the required 32-bit additions in the TCP protocol processing. This function should add the two arguments and place the result in the global variable uip_acc32.
|
|
||||||||||||
|
Calculate the Internet checksum over a buffer. The Internet checksum is the one's complement of the one's complement sum of all 16-bit words in the buffer. See RFC1071.
|
|
||||||||||||
|
Connect to a remote host using TCP. This function is used to start a new connection to the specified port on the specied host. It allocates a new connection identifier, sets the connection to the SYN_SENT state and sets the retransmission timer to 0. This will cause a TCP SYN segment to be sent out the next time this connection is periodically processed, which usually is done within 0.5 seconds after the call to uip_connect().
|
|
|
uIP initialization function. This function should be called at boot up to initilize the uIP TCP/IP stack. |
|
|
Calculate the IP header checksum of the packet header in uip_buf. The IP header checksum is the Internet checksum of the 20 bytes of the IP header.
|
|
|
Start listening to the specified port.
|
|
||||||||||||
|
Send data on the current connection. This function is used to send out a single segment of TCP data. Only applications that have been invoked by uIP for event processing can send data. The amount of data that actually is sent out after a call to this funcion is determined by the maximum amount of data TCP allows. uIP will automatically crop the data so that only the appropriate amount of data is sent. The function uip_mss() can be used to query uIP for the amount of data that actually will be sent.
|
|
|
Calculate the TCP checksum of the packet in uip_buf and uip_appdata. The TCP checksum is the Internet checksum of data contents of the TCP segment, and a pseudo-header as defined in RFC793.
|
|
||||||||||||
|
Set up a new UDP connection. This function sets up a new UDP connection. The function will automatically allocate an unused local port for the new connection. However, another port can be chosen by using the uip_udp_bind() call, after the uip_udp_new() function has been called. Example:
|
|
|
Stop listening to the specified port.
|
|
|
Pointer to the application data in the packet buffer. This pointer points to the application data when the application is called. If the application wishes to send data, the application may use this space to write the data into before calling uip_send(). |
|
|
Pointer to the application data in the packet buffer. This pointer points to the application data when the application is called. If the application wishes to send data, the application may use this space to write the data into before calling uip_send(). |
|
|
The uIP packet buffer. The uip_buf array is used to hold incoming and outgoing packets. The device driver should place incoming data into this buffer. When sending data, the device driver should read the link level headers and the TCP/IP headers from this buffer. The size of the link level headers is configured by the UIP_LLH_LEN define.
|
|
|
The uIP TCP/IP statistics. This is the variable in which the uIP TCP/IP statistics are gathered. |
1.3.6