A packet sent or received by an application is processed by several different layers in the network stack. In real BSD-style implementations, an mbuf structure is used for passing the packet between the different layers. In projects 2 and 3, you will be using a pbuf structure for building and passing packets between network stack layers. The pbuf structure is simplified version of the BSD mbuf.
The definition of the pbuf structure is the following:
struct p_hdr { struct pbuf *ph_next; /* next buffer in chain */ struct pbuf *ph_nextpkt; /* next chain in queue/record */ caddr_t ph_data; /* location of data */ int ph_len; /* amount of data in this mbuf */ int ph_type; /* type of data in this mbuf */ int ph_flags; /* flags; see below */ }; struct pbuf { struct p_hdr p_hdr; char p_databuf[PHLEN]; }; #define p_next p_hdr.ph_next #define p_nextpkt p_hdr.ph_nextpkt #define p_data p_hdr.ph_data #define p_len p_hdr.ph_len #define p_type p_hdr.ph_type #define p_flags p_hdr.ph_flags #define p_dat p_databuf
pbuf's must be allocated and deallocated using the routines
p_get() and p_free() declared in
$PDIR/include/pbuf.h.
Since a pbuf contains less than 512 bytes of data (PHLEN is defined
as 512 minus header length), an MTU-sized packet (1500 bytes in your projects)
will consist of 4 pbuf structures linked together by the
p_next field in each pbuf -- this is called a
pbuf chain. The p_nextpkt field can be used to link multiple
packets together on a queue.
By convention, only the first pbuf in a pbuf chain should be
used to link to another pbuf chain (through p_nextpkt).
The field p_data points to the location where the packet data starts within the p_databuf[PHLEN] buffer. Why implement pbufs this way? Suppose your transport layer has built a UDP packet with 20 bytes of data and an 8-byte UDP header. Before this packet gets sent on the wire, it will have to go through netowrk and link layer processing. If you place the data at the beginning of the pbuf, the network layer will have to allocate a new pbuf in which to store the 20-byte IP header and prepend this pbuf to the packet. However, if you were clever enough to leave 20 bytes of space at the beginning of the p_databuf[] buffer, you could simply subtract 20 from the value of p_data and then copy the 20-byte IP header to the address indicated by this pointer. An example of a packet consisting of multiple pbuf structures is shown in Figure 3.
The field p_len is the length of data contained in the pbuf; it is not the total length of the packet. p_type is managed by the pbuf allocation code and p_flags is presently not used at all by the kernel.
In addition to the functions p_get() and p_free() mentioned above, there are some other functions that you may find useful for manipulating pbuf's. They are defined in $PDIR/include/pbuf.h. Some examples of these are: