Most commonly used protocols wish to operate on a data stream in three ways. These are:
Headers are usually used to ensure that data gets to the right place, or to signify that it came from a particular place. We can consider how such operations affect high performance stream I/O, particularly in respect of security. In the Internet much of the security which exists relies on secure port numbers. These are port numbers which are only available to the highest authority on a given machine, and receivers may assume that any such packet bears the full authority of the administrators of the source machine rather than an arbitrary user. It is similarly important that machines accurately report their own addresses. For this reason the transmission of arbitrary packets must be prohibited; transmission must include the correct headers as authorised by the system. This has been one reason for having such networking protocols in the kernel or, in a micro-kernel, implemented in a single ``networking daemon''. However this is not a foregone conclusion.
It is possible instead to have protocol implementations within the user process, and still retain the required security. The device driver must then perform the security control. There is a broad spectrum of the possible ways of engineering such a solution. In one extreme the device drivers actually include code (via a trusted library) which ``understands'' the protocol and checks the headers; which is close to implementing the protocol itself in each device driver.
Alternatively, the device driver could include an ``inverse'' packet filter, code which determines if the packet is valid for transmission (rather than reception). As with a packet filter for reception this process can be highly optimised.
For any implementation the volatility of the buffer memory must be taken into consideration; the driver must protect against the process corrupting the headers after they have been checked. This may entail copying the security related fields of the header before checking them. Another solution may rely on caching the secure part of the header in the device driver's private memory and updating the per-packet fields.
For many other fields such as checksums, the user process is the only one to suffer if they are not initialised correctly. Thus for UDP and TCP only the port values need to be secured. For IP all but the length and checksum fields must be secured, and for Ethernet all the fields must be secured.
One final possible concern would be with respect to flow control or congestion avoidance; conceivably a user process could have private code which disobeyed the standards on TCP congestion control. There are various answers to this. First, a malevolent user process could simply use UDP, which has no congestion control, instead if it wished. Second, since the operating system is designed with quality of service support, the system could easily limit the rate at which a process is permitted to transmit. Third, the application may in fact be able to make better use of the resources in the network due to application specific knowledge, or by using advanced experimental code.
Unlike headers, trailers do not usually contain any security information. Trailers are most easily dealt with by requiring the user process to provide enough space (or the correct padding) for the packet on both receive and transmit. If there is not enough, the packet will simply be discarded - a loss to the user processes. Providing this space is not difficult for a process once it is known how much is necessary; this value can be computed by a shared library or discovered using an IPC call.
APPLICATION DATA UNITS
Many applications have application specific basic data units which may be too large for individual network packets. For example, NFS blocks over Ethernet are usually fragmented at the IP level. Ideally a system should permit the application to specify receive buffers in such a way that the actual data of interest to the application ends up in contiguous virtual addresses.
On the other hand for some applications, the application's basic data unit (i.e. the unit over which the application considers loss of any sub part to be loss of the total) may be very small. This may be found in multimedia streams such as audio over ATM, and compressed tiled video. For such streams, the application should not have to suffer very large numbers of interactions with the device driver; it should be able to handle the data stream only when an aggregate of many small data units is available.