We have two PC boxes running FreeBSD 2.1.6, and an UltraSparc box which acts as a router. The packets sent in the tunnel by one PC box are sent to the UltraSparc, which queues them in a FIFO queue, and then forward s them to the destination box. In the FIFO queue, the packets are timestamped , and they exit the queue after a preset delay. But a tunnel device is associated with a destination address too.
Any process can then unqueue the packet from the device, and use the raw IP packet.
Alternatively, a raw IP packet with source address 10.0.0.2, and destination address 10.0.0.1 can be written to the tunnel device by a process, and the kernel will process the packet through the IP stack, just like an incoming packet. To sum it up, a tunnel device is a pseudo-device with a source address and a destination address. Packets sent to the destination address are intercepted by the kernel and queued in the device, where they can be read by any process. Packets sent to the source address can be written to the tunnel, where the kernel will unqueue them and process them up the network stack. The idea is to have a process running on the PC box, which listens to a UDP socket and to the tunnel device.