Packet rings are a ring of pointers to user-supplied buffer space. Incoming packets for an application are copied to the next empty buffer. Each buffer in the ring is owned by either the kernel or the application, depending on the value of a flag field in the buffer struct. If this flag is zero the buffer is empty and can be filled by the kernel. Non-zero values are the length of the packet that were copied into the buffer. When a process is done with a packet it should reset the flag to zero.
See bin/icmpd/icmpd.c for a complete example.