9.  Protocol/network-interface interface

      The lowest layer in the set of protocols which comprise a protocol family must interface itself to one or more network interfaces in order to transmit and receive packets. It is assumed that any routing decisions have been made before handing a packet to a network interface, in fact this is absolutely necessary in order to locate any interface at all (unless, of course, one uses a single ``hardwired'' interface). There are two cases with which to be concerned, transmission of a packet and receipt of a packet; each will be considered separately.

9.1.  Packet transmission

      Assuming a protocol has a handle on an interface, ifp, a (struct ifnet *), it transmits a fully formatted packet with the following call,

error = (*ifp->if_output)(ifp, m, dst)
int error; struct ifnet *ifp; struct mbuf *m; struct sockaddr *dst;
The output routine for the network interface transmits the packet m to the dst address, or returns an error indication (a UNIX error number). In reality transmission may not be immediate or successful; normally the output routine simply queues the packet on its send queue and primes an interrupt driven routine to actually transmit the packet. For unreliable media, such as the Ethernet, ``successful'' transmission simply means that the packet has been placed on the cable without a collision. On the other hand, an 1822 interface guarantees proper delivery or an error indication for each message transmitted. The model employed in the networking system attaches no promises of delivery to the packets handed to a network interface, and thus corresponds more closely to the Ethernet. Errors returned by the output routine are only those that can be detected immediately, and are normally trivial in nature (no buffer space, address format not handled, etc.). No indication is received if errors are detected after the call has returned.

9.2.  Packet reception

      Each protocol family must have one or more ``lowest level'' protocols. These protocols deal with internetwork addressing and are responsible for the delivery of incoming packets to the proper protocol processing modules. In the PUP model [Boggs78] these protocols are termed Level 1 protocols, in the ISO model, network layer protocols. In this system each such protocol module has an input packet queue assigned to it. Incoming packets received by a network interface are queued for the protocol module, and a VAX software interrupt is posted to initiate processing.

      Three macros are available for queuing and dequeuing packets:

IF_ENQUEUE(ifq, m)

This places the packet m at the tail of the queue ifq.
IF_DEQUEUE(ifq, m)

This places a pointer to the packet at the head of queue ifq in m and removes the packet from the queue. A zero value will be returned in m if the queue is empty.
IF_DEQUEUEIF(ifq, m, ifp)

Like IF_DEQUEUE, this removes the next packet from the head of a queue and returns it in m. A pointer to the interface on which the packet was received is placed in ifp, a (struct ifnet *).
IF_PREPEND(ifq, m)

This places the packet m at the head of the queue ifq.

      Each queue has a maximum length associated with it as a simple form of congestion control. The macro IF_QFULL(ifq) returns 1 if the queue is filled, in which case the macro IF_DROP(ifq) should be used to increment the count of the number of packets dropped, and the offending packet is dropped. For example, the following code fragment is commonly found in a network interface's input routine,

if (IF_QFULL(inq)) {
	IF_DROP(inq);
	m_freem(m);
} else
	IF_ENQUEUE(inq, m);