TCP/IP Networking

Introduction

As the Internet has grown to become more and more visible in our daily lives, the protocol it's based on - IP (Internet Protocol) - has become increasingly important. Even if you're not connecting to "The Internet" per se, the IP protocol and tools that go with it are ubiquitous, making IP the de facto choice for many private networks.

IP is used for everything from simple tasks (e.g. remote login) to more complicated tasks (e.g. delivering realtime stock quotes). More and more businesses are turning to the World Wide Web, which commonly rides on IP, for communication with their customers, advertising, and other business connectivity.

Given these and many other user requirements, we've designed the Neutrino Tiny TCP/IP stack (Ttcpip) to be very light on resources, while using the common BSD API. Ttcpip is under 40K of code.

The Neutrino TCP/IP suite is also modular - it provides both client and server NFS as separate modules. With this kind of modularity, together with small-sized modules, embedded systems developers can more easily build small TCP/IP-capable systems.

Structure of TCP/IP manager

Ttcpip is designed as a multithreaded resource manager. It shares in the standard resource manager structure, which allows it to gain code savings and a standard interface. Its multithreading allows it to service many clients virtually simultaneously. Due to the natural priority inheritance of QNX IPC, clients will be dealt with in priority and time order, which leads to a more natural allocation of CPU resources.

 


fig: images/tcpipdll.gif


The Ttcpip suite and dependents.

 

Most of the link-layer support is implemented outside of Ttcpip. SLIP is an exception. Given its simplicity, SLIP has been implemented inside the stack itself. PPP and the Ethernet drivers are separate processes that communicate with Ttcpip via open(), read(), write(), devctl(), and close() functions.

This separation between the network drivers and the protocol stack increases fault-tolerance. This also allows the customer to implement simple I/O managers for their custom hardware (e.g. CDMA) and use Ttcpip on top without compromising the basic stability of the OS or the TCP/IP stack.

Other components of the Ttcpip suite such as NFS are implemented outside of Ttcpip. This leads to better modularity and fault-tolerance. This also allows the network filesystems (NFS, CIFS) to share code and technology with the other Neutrino filesystems, which ultimately leads to smaller size and better performance.

Socket API

The BSD Socket API was the obvious choice for Neutrino. The Socket API is the standard API for TCP/IP programming in the Unix world. In the Windows world, the Winsock API is based on and shares a lot with the BSD Socket API. This makes conversion between the two fairly easy.

All the routines that application programmers would expect are available, including:

accept()
bind()
bindresvport()
connect()
dn_comp()
dn_expand()
endprotoent()
endservent()
gethostbyaddr()
gethostbyname()
getpeername()
getprotobyname()
getprotobynumber()
getprotoent()
getservbyname()
getservent()
getsockname()
getsockopt()
herror()
hstrerror()
htonl()
htons()
h_errlist()
h_errno()
h_nerr()
inet_addr()
inet_aton()
inet_lnaof()
inet_makeaddr()
inet_netof()
inet_network()
inet_ntoa()
ioctl()
listen()
ntohl()
ntohs()
recv()
recvfrom()
res_init()
res_mkquery()
res_query()
res_querydomain()
res_search()
res_send()
select()
send()
sendto()
setprotoent()
setservent()
setsockopt()
shutdown()
socket()

The common daemons and utilities from the Internet will easily port or just compile in this environment. This makes leveraging what already exists for your applications a snap.

Database routines

The database routines have been modified to better suit embedded systems.

/etc/resolv.conf

The information in /etc/resolv.conf can be put in the environment variable RESCONF. This lets you use a nameserver without /etc/resolv.conf. This effects gethostbyname() and other resolver routines.

/etc/protocols

The getprotobyname() and getprotobynumber() functions have been modified to contain a small number of builtin protocols, including IP, ICNP, UDP, and TCP. For many applications, this means that the /etc/protocols file doesn't need to exist.

/etc/services

The getservbyname() function has been modified to contain a small number of builtin services, including ftp, telnet, smtp, domain, nntp, netbios-ns, netbios-ssn, sunrpc, and nfsd. For many applications, this means that the /etc/services file doesn't need to exist.

Network interoperability

Ttcpip was designed and implemented with interoperability utmost in mind. The code takes into account both the RFCs and the real world. Ttcpip addresses all the functionality proposed in RFC 1122. The ARP, IP, ICMP, UDP, and TCP protocols are supported as well.


Note: In order to meet the size requirements for Ttcpip, we had to leave out certain features sometimes found in stacks meant for Unix servers. Ttcpip doesn't support more than one interface - this typically isn't an issue for embedded devices. Neither complex routing tables nor dynamic routing protocols are supported (in release 1.0).

Future directions

The performance enhancements proposed in RFC 1323 will be implemented, as will the DHCP (Dynamic Host Configuration Protocol). We expect that DHCP will be of interest to the embedded systems developer, because it allows the individual box to get its configuration information at boot time.

Instead of bloating Ttcpip with server features not normally needed in resource-constrained environments, we've decided to provide a second stack for larger server use. This stack will be a direct derivative of the BSD 4.4 stack, which is powering many of the large servers on the Internet today.

The applications you write will use one API, regardless of which stack you'll ultimately use. Without recompiling or relinking, you'll be able to change from using the tiny stack on your embedded target to using the large stack on a different target.