The Npcap API

Abstract

The Npcap Application Programming Interface (API) consists of the libpcap API and a few non-portable extensions: pcap_setbuff, pcap_setuserbuffer, pcap_setmintocopy, pcap_getevent, pcap_setmode, pcap_oid_get_request and pcap_oid_set_request, functions for batch-sending packets with pcap_send_queue, and pcap_stats_ex.

The Npcap API is exported by wpcap.dll and is the Windows port of libpcap. The API and functions are described in the pcap(1) man page.

Extensions to libpcap for Windows

There are a few extensions to libpcap that exist only on Windows. Software that uses these extensions will not be portable to non-Windows systems. The following is a brief list of these extensions and their purpose.

pcap_setbuff

Sets the size of the kernel buffer associated with an adapter.

int pcap_setbuff(pcap_t *p, int dim);

dim specifies the size of the buffer in bytes. The return value is 0 when the call succeeds, -1 otherwise. If an old buffer was already created with a previous call to pcap_setbuff(), it is deleted and its content is discarded. pcap_open_live() creates a 1 MByte buffer by default.

Portability note: libpcap provides the pcap_set_buffer_size() function for setting the kernel buffer size. This removes the need to use the non-portable pcap_setbuff() for this purpose.

pcap_setmode

Sets the working mode of the interface.

int pcap_setmode(pcap_t *p, int mode);

Valid values for mode are MODE_CAPT (default capture mode) and MODE_STAT (statistical mode). See the section called “Gathering Statistics on the network traffic” for details about statistical mode.

pcap_setmintocopy

Sets the minumum amount of data received by the kernel in a single call.

int pcap_setmintocopy(pcap_t *p, int size);

This function changes the minimum amount of data in the kernel buffer that causes a read from the application to return (unless the timeout expires). If the value of size is large, the kernel is forced to wait the arrival of several packets before copying the data to the user. This guarantees a low number of system calls, i.e. low processor usage, and is a good setting for applications like packet-sniffers and protocol analyzers. Vice versa, in presence of a small value for this variable, the kernel will copy the packets as soon as the application is ready to receive them. This is useful for real time applications that need the best responsiveness from the kernel. pcap_open_live() sets a default size value of 16000 bytes.

Portability note: libpcap provides the pcap_set_immediate_mode() function for applications that need to receive packets as soon as they arrive. This removes the need to use the non-portable pcap_setmintocopy() for this purpose.

pcap_getevent

Returns the handle of the event associated with the interface.

HANDLE pcap_getevent(pcap_t *p);

This event can be passed to functions like WaitForSingleObject() or WaitForMultipleObjects() to wait until the driver's buffer contains some data without performing a read.

Portability note: This function is the Windows alternative to pcap_get_selectable_fd(), which is only available on UNIX-like systems.

pcap_oid_get_request and pcap_oid_set_request

Send an OID request to the underlying NDIS drivers

int pcap_oid_get_request(pcap_t *, bpf_u_int32, void *, size_t *);int pcap_oid_set_request(pcap_t *, bpf_u_int32, const void *, size_t *);
Queuing sent packets with pcap_send_queue

Npcap has the ability to queue multiple raw packets for transmission on the network in a single call. This is more efficient than issuing a series of pcap_sendpacket(), because the packets are buffered in the kernel driver, so the number of context switches is reduced.

pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);void pcap_sendqueue_destroy(pcap_send_queue* queue);

Allocate a send queue as a buffer of memsize bytes. The pcap_send_queue allocated can be freed with pcap_sendqueue_destroy().

int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);

pcap_sendqueue_queue() adds a packet at the end of the send queue pointed by the queue parameter. pkt_header points to a pcap_pkthdr structure with the timestamp and the length of the packet, pkt_data points to a buffer with the data of the packet.

The pcap_pkthdr structure is the same used by Npcap and libpcap to store the packets in a file, therefore sending a capture file is straightforward. 'Raw packet' means that the sending application will have to include the protocol headers, since every packet is sent to the network 'as is'. The CRC of the packets needs not to be calculated, because it will be transparently added by the network interface.

u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync);

This function transmits the content of a queue to the wire. p is a pointer to the adapter on which the packets will be sent, queue points to a pcap_send_queue structure containing the packets to send), sync determines if the send operation must be synchronized: if it is non-zero, the packets are sent respecting the timestamps, otherwise they are sent as fast as possible.

The return value is the amount of bytes actually sent. If it is smaller than the size parameter, an error occurred during the send. The error can be caused by a driver/adapter problem or by an inconsistent/bogus send queue.

Performance note: When sync is set to TRUE, the packets are synchronized in the kernel with a high precision timestamp. This requires a non-negligible amount of CPU, but allows normally to send the packets with a precision of some microseconds (depending on the accuracy of the performance counter of the machine). Such a precision cannot be reached sending the packets with pcap_sendpacket().

pcap_stats_ex
struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size);

pcap_stats_ex() extends the pcap_stats() allowing to return more statistical parameters than the old call. One of the advantages of this new call is that the pcap_stat structure is not allocated by the user; instead, it is returned back by the system. This allow to extend the pcap_stat structure without affecting backward compatibility on older applications. These will simply check at the values of the members at the beginning of the structure, while only newest applications are able to read new statistical values, which are appended in tail.

To be sure not to read a piece of memory which has not been allocated by the system, the variable pcap_stat_size will return back the size of the structure pcap_stat allocated by the system.

p: pointer to the pcap_t currently in use. pcap_stat_size: pointer to an integer that will contain (when the function returns back) the size of the structure pcap_stat as it has been allocated by the system.

The function returns a pointer to a pcap_stat structure, that will contain the statistics related to the current device. The return value is NULL in case of errors, and the error text can be obtained with pcap_perror() or pcap_geterr().

pcap_setuserbuffer

Sets the size of the buffer that accepts packets from the kernel driver.

int pcap_setuserbuffer(pcap_t *p, int size);

The size of the packet buffer is a parameter that can sensibly influence the performance of the capture process, since this buffer will contain the packets received from the the Npcap driver. The driver is able to return several packets using a single read call, and the number of packets transferable to the application in a call is limited only by the size of this buffer. Therefore setting a larger buffer siz can noticeably decrease the number of system calls, reducing the impact of the capture process on the processor.