packetfilter(4)packetfilter(4)Namepacketfilter - Ethernet packet filter
Syntax
options PACKETFILTER
pseudo-device packetfilterDescription
The packet filter pseudo-device driver provides a raw interface to Eth‐
ernets and similar network data link layers. Packets received that are
not used by the kernel (for example, to support the IP and DECnet pro‐
tocol families) are available through this mechanism. The packet fil‐
ter driver is kernel-resident code provided by the ULTRIX operating
system. The driver appears to applications as a set of character spe‐
cial files, one for each open packet filter application. (Throughout
this reference page, the word file refers to such a character special
file.)
You create the minor device files with the script using these commands:
# cd /dev
# MAKEDEV pfilt
A single call to with an argument of creates 64 character special files
in which are named where nnn is the unit number. Successive calls to
with arguments of and make additional sets of 64 sequentially numbered
packet filters to a maximum of 256. The maximum number of packet fil‐
ter special files is limited to 256, which is the maximum number of
minor device numbers allowed for each major device number. (See for
more information on making system special files.)
For opening these special files, the ULTRIX operating system provides
the library routine.
Associated with each open instance of a packet filter special file is a
user-settable packet filter ``program'' that is used to select which
incoming packets are delivered by that packet filter special file.
Whenever a packet is received from the net, the packet filter driver
successively applies the filter programs of each of the open packet
filter files to the packet, until one filter program ``accepts'' the
packet. When a filter accepts the packet, it is placed on the packet
input queue of the associated special file. If no filters accept the
packet, it is discarded. The format of a packet filter is described
later.
Reads from these files return the next packet from a queue of packets
that have matched the filter. If the read operation specifies insuffi‐
cient buffer space to store the entire packet, the packet is truncated
and the trailing contents lost. Writes to these files transmit packets
on the network, with each write operation generating exactly one
packet.
The packet filter supports a variety of different Ethernet data-link
levels:
10Mb Ethernet
Packets consist of fourteen or more bytes, with the first six
bytes specifying the destination Ethernet address, the next six
bytes the source Ethernet address, and the next two bytes speci‐
fying the packet type. (This is the Standard Ethernet.)
3Mb Ethernet
Packets consist of four or more bytes, with the first byte spec‐
ifying the source Ethernet address, the second byte specifying
the destination Ethernet address, and the next two bytes speci‐
fying the packet type. (On the network, the source and destina‐
tion addresses are in the opposite order.)
Byte-swapping 3Mb Ethernet
Packets consist of four or more bytes, with the first byte spec‐
ifying the source Ethernet address, the second byte specifying
the destination Ethernet address, and the next two bytes speci‐
fying the packet type. Each short word (pair of bytes) is
swapped from the network byte order. This device type is pro‐
vided only for backwards-compatibility.
The remaining words are interpreted according to the packet type. Note
that 16-bit and 32-bit quantities may have to be byteswapped (and pos‐
sibly short-swapped) to be intelligible on an ULTRIX system.
The packet filters treat the entire packet, including headers, as unin‐
terpreted data. The user must supply the headers for transmitted pack‐
ets (although the system makes sure that the source address is correct)
and the headers of received packets are delivered to the user. The
packet filter mechanism does not know anything about the data portion
of the packets it sends and receives.
In addition to the FIONREAD request (described in the reference page),
the application can apply several special requests to an open packet
filter file. The calls are divided into five categories: packet-filter
specifying, packet handling, device configuration, administrative, and
miscellaneous.
Packet-filter Specification ioctl Request
The is central to the operation of the packet filter interface, because
it specifies which packets the application wishes to receive. It is
used to set the packet filter ``program'' for an open packet filter
file, and is of the form:
ioctl(fildes, EIOCSETF, filter)
struct enfilter *filter
The structure is defined in as:
struct enfilter
{
u_char enf_Priority;
u_char enf_FilterLen;
u_short enf_Filter[ENMAXFILTERS];
};
A packet filter consists of a priority, the filter command list length
(in shortwords), and the filter command list itself. Each filter com‐
mand list specifies a sequence of actions that operate on an internal
stack. Each shortword of the command list specifies an action and a
binary operator.
Command List Actions
The action can be one of the following:
ENF_PUSHLIT
Pushes the next shortword of the command list on the stack.
ENF_PUSHWORD+N
Pushes shortword N of the incoming packet on the stack.
ENF_PUSHZERO
Pushes a zero. Is slightly faster than ENF_PUSHLIT with an
explicit literal.
ENF_PUSHONE
Pushes a one. Is slightly faster than ENF_PUSHLIT with an
explicit literal.
ENF_PUSHFFFF
Pushes 0xFFFF. Is slightly faster than ENF_PUSHLIT with an
explicit literal.
ENF_PUSH00FF
Pushes 0x00FF. Is slightly faster than ENF_PUSHLIT with an
explicit literal.
ENF_PUSHFF00
Pushes 0xFF00. Is slightly faster than ENF_PUSHLIT with an
explicit literal.
ENF_NOPUSH
Defined as zero.
Binary Operators
When both an action and an operator are specified in the same short‐
word, the action is performed, followed by the operation. You can com‐
bine an action with an operator using bitwise OR; for example,
((ENF_PUSHWORD+3) | ENF_EQ)
The binary operator, which can be one of the following, operates on the
top two elements of the stack and replaces them with its result:
ENF_EQ Returns true if the result is equal.
ENF_NEQ Returns true if the result is not equal.
ENF_LT Returns true if the result is less than.
ENF_LE Returns true if the result is less than or equal.
ENF_GT Returns true if the result is greater than.
ENF_GE Returns true if the result is greater than or equal.
ENF_AND Returns the result of the binary AND operation.
ENF_OR Returns the result of the binary OR operation.
ENF_XOR Returns the result of the binary XOR operation.
ENF_NOP Defined as zero.
ENF_CAND Returns false immediately if the result is false, and
continues execution of the filter otherwise. (Short-
circuit operator)
ENF_COR Returns true immediately if the result is true, and con‐
tinues execution of the filter otherwise. (Short-cir‐
cuit operator)
ENF_CNAND Returns true immediately if the result is false, and
continues execution of the filter otherwise. (Short-
circuit operator)
ENF_CNOR Returns false immediately if the result is true, and
continues execution of the filter otherwise. (Short-
circuit operator)
The short-circuit operators are so called because they terminate the
execution of the filter immediately if the condition they are checking
for is found, and continue otherwise. All the short-circuit operators
pop two elements from the stack and compare them for equality. Unlike
the other binary operators, these four operators do not leave a result
on the stack, even if they continue.
Use the short-circuit operators whenever possible, to reduce the amount
of time spent evaluating filters. When you use them, you should also
arrange the order of the tests so that the filter will succeed or fail
as soon as possible. For example, checking a word in an address field
of an Ethernet packet is more likely to indicate failure than the Eth‐
ernet type field.
The special action ENF_NOPUSH and the special operator ENF_NOP can be
used to only perform the binary operation or to only push a value on
the stack. Because both are defined to be zero, specifying only an
action actually specifies the action followed by ENF_NOP, and specify‐
ing only an operation actually specifies ENF_NOPUSH followed by the
operation.
After executing the filter command list, a nonzero value (true) left on
top of the stack (or an empty stack) causes the incoming packet to be
accepted for the corresponding packet filter file and a zero value
(false) causes the packet to be passed through the next packet filter.
If the filter exits as the result of a short-circuit operator, the top-
of-stack value is ignored. Specifying an undefined operation or action
in the command list or performing an illegal operation or action (such
as pushing a shortword offset past the end of the packet or executing a
binary operator with fewer than two shortwords on the stack) causes a
filter to reject the packet.
To resolve problems with overlapping or conflicting packet filters, the
filters for each open packet filter file are ordered by the driver
according to their priority (lowest priority is 0, highest is 255).
When processing incoming packets, filters are applied according to
their priority (from highest to lowest) and for identical priority val‐
ues according to their relative ``busyness'' (the filter that has pre‐
viously matched the most packets is checked first), until one or more
filters accept the packet or all filters reject it and it is discarded.
Normally once a packet is delivered to a filter, it is not presented to
any other filters. However, if the packet is accepted by a filter in
nonexclusive mode (ENNONEXCL set using EIOCMBIS, described in the fol‐
lowing section), the packet is passed along to lower-priority filters
and may be delivered more than once. The use of nonexclusive filters
imposes an additional cost on the system, because it increases the
average number of filters applied to each packet.
The packet filter for a packet filter file is initialized with length 0
at priority 0 by and hence, by default, accepts all packets in which no
higher-priority filter is interested.
Priorities should be assigned so that, in general, the more packets a
filter is expected to match, the higher its priority. This prevents a
lot of checking of packets against filters that are unlikely to match
them.
The filter in this example accepts incoming RARP (Reverse Address Reso‐
lution Protocol) broadcast packets.
The filter first checks the Ethernet type of the packet. If it is not
a RARP (Reverse ARP) packet, it is discarded. Then, the RARP type
field is checked for a reverse request (type 3), followed by a check
for a broadcast destination address. Note that the packet type field
is checked before the destination address, because the total number of
broadcast packets on the network is larger than the number of RARP
packets. Thus, the filter is ordered with a minimum amount of process‐
ing overhead.
struct enfilter f =
{
36, 0, /* priority and length */
ENF_PUSHWORD + 6,
ENF_PUSHLIT, 0x3580,
ENF_CAND, /* Ethernet type == 0x8035 (RARP) */
ENF_PUSHWORD + 10,
ENF_PUSHLIT, 0x0300,
ENF_CAND, /* reverse request type = 0003 */
ENF_PUSHWORD + 0,
ENF_PUSHLIT, 0xFFFF,
ENF_CAND, /* dest addr = FF-FF */
ENF_PUSHWORD + 1,
ENF_PUSHLIT, 0xFFFF,
ENF_CAND, /* dest addr = FF-FF */
ENF_PUSHWORD + 2,
ENF_PUSHLIT, 0xFFFF,
ENF_EQ /* dest addr = FF-FF */
};
Note that shortwords, such as the packet type field, are in network
byte-order. The literals you compare them to may have to be byte-
swapped on machines like the VAX.
By taking advantage of the ability to specify both an action and opera‐
tion in each word of the command list, you could abbreviate the filter
to the following:
struct enfilter f =
{
36, 0, /* priority and length */
ENF_PUSHWORD + 6,
ENF_PUSHLIT | ENF_CAND,
0x3580, /* Ethernet type == 0x8035 (RARP) */
ENF_PUSHWORD + 10,
ENF_PUSHLIT | ENF_CAND,
0x0300, /* reverse request type = 0003 */
ENF_PUSHWORD + 0,
ENF_PUSHFFFF | ENF_CAND, /* dest addr = FF-FF */
ENF_PUSHWORD + 1,
ENF_PUSHFFFF | ENF_CAND, /* dest addr = FF-FF */
ENF_PUSHWORD + 2,
ENF_PUSHFFFF | ENF_EQ /* dest addr = FF-FF */
};
Packet-Handling ioctl Requests
These requests control how the packet filter processes input packets
and returns them to the application process. The most useful of these
requests set and clear so-called ``mode bits'' for the file and are of
this form:
ioctl(fildes, code, bits)
u_short *bits;
In these calls, bits is a bitmask specifying which bits to set or
clear. The applicable codes are:
EIOCMBIS
Sets the specified mode bits.
EIOCMBIC
Clears the specified mode bits.
The bits are:
ENTSTAMP
If set, a received packet is preceded by a header structure (see
the description of following) that includes a time stamp and
other information.
ENBATCH
If clear, each system call returns at most one packet. If set,
a call might return more than one packet, each of which is pre‐
ceded by an header.
ENPROMISC
If set, this filter will be applied to promiscuously-received
packets. This puts the interface into ``promiscuous mode'' only
if this has been allowed by the superuser using the EIOCALLOW‐
PROMISC call (described later).
ENCOPYALL
If set, this filter will see packets sent and received by the
kernel-resident protocols of the local host. (Normally, these
packets are not copied to the packet filter.) This mode takes
effect only if this has been allowed by the superuser using the
EIOCALLOWCOPYALL call (described later).
ENNONEXCL
If set, packets accepted by this filter will be available to any
lower-priority filters. If clear, no lower-priority filter will
see packets accepted by this filter.
ENHOLDSIG
If clear, means that the driver should disable the effect of
EIOCENBS (described later) once it has delivered a signal. If
set (the default), the effect of EIOCENBS persists.
The structure contains useful information about the packet that immedi‐
ately follows it; in ENBATCH mode, it also allows the reader to sepa‐
rate the packets in a batch. It is defined in as:
struct enstamp {
u_short ens_stamplen;
u_short ens_flags;
u_short ens_count;
u_short ens_dropped;
u_long ens_ifoverflows;
struct timevalens_tstamp;
};
The fields are:
ens_stamplen
The length of structure in bytes. The packet data follows imme‐
diately.
ens_flags
Indicates how the packet was received. The bits are:
ENSF_PROMISC
Received promiscuously (unicast to some other host).
ENSF_BROADCAST
Received as a broadcast.
ENSF_MULTICAST
Received as a multicast.
ENSF_TRAILER
Received in a trailer encapsulation. The packet has been
rearranged into header format.
ens_count
The length of the packet in bytes (does not include the header).
ens_dropped
The number of packets accepted by this filter but dropped
because the input queue was full; this is a cumulative count
since the previous was read from this packet filter file. This
count may be completely wrong if the ENNONEXCL mode bit is set
for this filter.
ens_ifoverflows
The total number of input overflows reported by the network
interface since the system was booted.
ens_tstamp
The approximate time the packet was received.
If the buffer returned by a batched contains more than one packet, the
offset from the beginning of the buffer at which each structure begins
is an integer multiple of the word-size of the processor. For example,
on a VAX, each is aligned on a longword boundary (provided that the
buffer address passed to the system call is aligned). The alignment
(in units of bytes) is given by the constant defined in If you have an
integer x, you can use the macro ENALIGN(x) to get the least integer
that is a multiple of and not less than x. For example, this code
fragment reads and processes one batch:
char *buffer = &(BigBuffer[0]);
int buflen;
int pktlen, stamplen;
struct enstamp *stamp;
buflen = read(f, buffer, sizeof(BigBuffer));
while (buflen > 0) {
stamp = (struct enstamp *)buffer;
pktlen = stamp->ens_count;
stamplen = stamp->ens_stamplen;
ProcessPacket(&(buffer[stamplen]), pktlen); /* your code here */
if (buflen == (pktlen + stamplen))
break; /* last packet in batch */
pktlen = ENALIGN(pktlen); /* account for alignment padding */
buflen -= (pktlen + stamplen);
buffer += (pktlen + stamplen); /* move to next stamp */
}
If a buffer filled by a batched read contains more than one packet, the
final packet is never truncated. If, however, the entire buffer is not
big enough to contain a single packet, the packet will be truncated;
this is also true for unbatched reads. Therefore, the buffer passed to
the system call should always be big enough to hold the largest possi‐
ble packet plus an structure. (See the request later in this reference
page for information on how to determine the maximum packet size. See
also the request for an example that delivers only the desired number
of bytes of a packet.)
Normally, a packet filter application blocks in the system call until a
received packet is available for reading. There are several ways to
avoid blocking indefinitely: an application can use the system call, it
can set a ``timeout'' for the packet filter file, or it can request the
delivery of a signal (see when a packet matches the filter.
EIOCSETW
The packet filter interface limits the number of packets that
can be queued for delivery for a specific packet filter file.
Application programs can vary this ``backlog'', if necessary,
using the following call:
ioctl(fildes, EIOCSETW, maxwaitingp)
u_int *maxwaitingp;
The argument maxwaitingp points to an integer containing the
input queue size to be set. If this is greater than the maximum
allowable size (see EIOCMAXBACKLOG later), it is set to the max‐
imum. If it is zero, it is set to a default value.
EIOCFLUSH
After changing the packet filter program, the input queue may
contain packets that were accepted under the old filter. To
flush the queue of incoming packets, use the following:
ioctl(fildes, EIOCFLUSH, 0)
EIOCTRUNCATE
An application, such as a network load monitor, that does not
want to see the entire packet can ask the packet filter to trun‐
cate received packets at a specified length. This action may
improve performance by reducing data movement.
To specify truncation, use:
ioctl(fildes, EIOCTRUNCATE, truncationp)
u_int *truncationp;
The argument truncationp points to an integer specifying the
truncation length, in bytes. Packets shorter than this length
are passed intact.
This example, a revision of the previous example, illustrates the use
of EIOCTRUNCATE, which causes the packet filter to deliver only the
first n bytes of a packet, not the entire packet.
char *buffer = &(BigBuffer[0]);
int buflen;
int pktlen, stamplen;
struct enstamp *stamp;
int truncation = SIZE_OF_INTERESTING_PART_OF_PACKET;
if (ioctl(f, EIOCTRUNCATE, &truncation) < 0)
exit(1);
while (1) {
buflen = read(f, buffer, sizeof(BigBuffer));
while (buflen > 0) {
stamp = (struct enstamp *)buffer;
pktlen = stamp->ens_count; /* ens_count is untruncated length */
stamplen = stamp->ens_stamplen;
ProcessPacket(&(buffer[stamplen]), pktlen); /* your code here */
if (pktlen > truncation) /* truncated portion not in buffer */
pktlen = truncation;
if (buflen == (pktlen + stamplen))
break; /* last packet in batch */
pktlen = ENALIGN(pktlen); /* account for alignment padding */
buflen -= (pktlen + stamplen);
buffer += (pktlen + stamplen); /* move to next stamp */
}
}
Two calls control the timeout mechanism; they are of the following
form:
#include <net/time.h>
ioctl(fildes, code, tvp)
struct timeval *tvp;
The tvp argument is the address of a containing the timeout interval
(this is a relative value, not an absolute time). The codes are:
EIOCGRTIMEOUT
Returns the current timeout value.
EIOCSRTIMEOUT
Sets the timeout value. When the value is positive, a call
returns a 0 if no packet arrives during the period. When the
timeout value is zero, reads block indefinitely (this is the
default). When the value is negative, a call returns a 0 imme‐
diately if there are no queued packets. Note that the largest
legal timeout value is a few million seconds.
Two calls control the signal-on-reception mechanism; they are of the
following form:
ioctl(fildes, code, signp)
u_int *signp;
The argument signp is a pointer to an integer containing the number of
the signal to be sent when an input packet arrives. The applicable
codes are:
EIOCENBS
Enables the specified signal when an input packet is received
for this file. If the ENHOLDSIG flag (see EIOCMBIS later) is
not set, further signals are automatically disabled whenever a
signal is sent to prevent nesting, and hence must be explicitly
re-enabled after processing. When the signal number is 0, this
call is equivalent to EIOCINHS.
EIOCINHS
Disables signaling on packet reception. The signp argument is
ignored. This is the default when the file is first opened.
Device Configuration ioctl Requests
EIOCIFNAME
Each packet filter file is associated with a specific network
interface. To find out the name of the interface underlying the
packet filter file, use the following:
#include <net/socket.h>
#include <net/if.h>
ioctl(fildes, EIOCIFNAME, ifr)
struct ifreq *ifr;
The interface name (for example, ``de0'') is returned in
ifr->ifr_name; other fields of the struct ifreq are not set.
EIOCSETIF
To set the interface associated with a packet filter file, use
the following:
ioctl(fildes, EIOCSETIF, ifr)
struct ifreq *ifr;
The interface name should be passed ifr->ifr_name; other fields
of the struct ifreq are ignored. The name provided may be one
of the actual interface names, such as ``de0'' or ``qe1'', or it
may be a pseudo-interface name of the form ``pfn'', used to
specify the nth interface attached to the system. For example,
``pf0'' specifies the first interface. This is useful for
applications that do not know the names of specific interfaces.
Pseudo-interface names are never returned by EIOCIFNAME.
EIOCDEVP
To get device parameters of the network interface underlying the
packet filter file, use the following:
ioctl(fildes, EIOCDEVP, param)
struct endevp *param;
The structure is defined in as:
struct endevp {
u_char end_dev_type;
u_char end_addr_len;
u_short end_hdr_len;
u_short end_MTU;
u_char end_addr[EN_MAX_ADDR_LEN];
u_char end_broadaddr[EN_MAX_ADDR_LEN];
};
The fields are:
end_dev_type Specifies the device type: ENDT_3MB, ENDT_BS3MB,
or ENDT_10MB.
end_addr_len Specifies the address length in bytes (for exam‐
ple, 1 or 6).
end_hdr_len Specifies the total header length in bytes (for
example, 4 or 14).
end_MTU Specifies the maximum packet size, including
header, in bytes.
end_addr The address of this interface; aligned so that
the low order byte of the address is in
end_addr[0].
end_broadaddr The hardware destination address for broadcasts
on this network.
Administrative ioctl Requests
EIOCMAXBACKLOG
The maximum queue length that can be set using EIOCSETW depends
on whether the process is running as the superuser or not. If
so, the maximum is a kernel constant; otherwise, the maximum is
a value that can be set, by the superuser, for each interface.
To set the maximum non-superuser backlog for an interface, use
EIOCSETIF to bind to the interface, and then use the following:
ioctl(fildes, EIOCMAXBACKLOG, maxbacklogp)
int *maxbacklogp;
The argument maxbacklogp points to an integer containing the
maximum value. (If maxbacklogp points to an integer containing
a negative value, it is replaced with the current backlog value,
and no action is taken.)
EIOCALLOWPROMISC
Certain kinds of network-monitoring applications need to place
the interface in ``promiscuous mode'', where it receives all
packets on the network. Promiscuous mode can be set by the
superuser with the /etc/ifconfig command, or the superuser can
configure an interface to go into promiscuous mode automatically
if any packet filter applications have the ENPROMISC mode bit
set. To do so, use EIOCSETIF to bind to the interface, and then
use the following:
ioctl(fildes, EIOCALLOWPROMISC, allowp)
int *allowp;
The argument allowp points to an integer containing a Boolean
value (nonzero means promiscuous mode is set automatically).
(If allowp points to an integer containing a negative value, it
is replaced with the current Boolean value, and no action is
taken.)
EIOCALLOWCOPYALL
Certain promiscuous-mode network-monitoring applications need to
see unicast packets sent or received by the local host. For
reasons of efficiency, these packets are not normally provided
to the packet filter, but in ``copy all'' mode they are. The
superuser can configure an interface to go into copy-all mode
automatically if any packet filter applications have the ENCOPY‐
ALL mode bit set. To do so, use EIOCSETIF to bind to the inter‐
face, and then use the following:
ioctl(fildes, EIOCALLOWCOPYALL, allowp)
int *allowp;
The argument allowp points to an integer containing a Boolean
value (nonzero means copy-all mode is set automatically). (If
allowp points to an integer containing a negative value, it is
replaced with the current Boolean value, and no action is
taken.)
EIOCMFREE
To find out how many packet filter files remain for opening, use
this which places the number in the integer pointed to by mfree:
ioctl(fildes, EIOCMFREE, mfree)
int *mfree;
Miscellaneous ioctl Requests
Two calls are provided for backwards compatibility and should not be
used in new code. These calls are used to set and fetch parameters of
a packet filter file (not the underlying device; see EIOCDEVP). The
form for these calls is:
#include <sys/types.h>
#include <net/pfilt.h>
ioctl(fildes, code, param)
struct eniocb *param;
The structure is defined in as:
struct eniocb
{
u_char en_addr;
u_char en_maxfilters;
u_char en_maxwaiting;
u_char en_maxpriority;
long en_rtout;
};
The applicable codes are:
EIOCGETP
Fetch the parameters for this file.
EIOCSETP
Set the parameters for this file.
All the fields, which are described later, except en_rtout, are
read-only.
en_addr No longer maintained; use EIOCDEVP.
en_maxfilters The maximum length of a filter command list; see
EIOCSETF.
en_maxwaiting The maximum number of packets that can be queued
for reading on the packet filter file; use EIOC‐
MAXBACKLOG.
en_maxpriority The highest allowable filter priority; see EIOC‐
SETF.
en_rtout The number of clock ticks to wait before timing
out on a read request and returning a zero
length. If zero, reads block indefinitely until
a packet arrives. If negative, read requests
return a zero length immediately if there are no
packets in the input queue. Initialized to zero
by indicating no timeout. (Use EIOCSRTIMEOUT and
EIOCGRTIMEOUT.)
Restrictions
Because the packet filter include file was originally named some filter
applications may need to be updated.
A previous restriction against accessing data words past approximately
the first hundred bytes in a packet has been removed. However, it
becomes slightly more costly to examine words that are not near the
beginning of the packet.
Because packets are streams of bytes, yet the filters operate on short
words, and standard network byte order is usually opposite from VAX
byte order, the relational operators ENF_LT, ENF_LE, ENF_GT, and ENF_GE
are not particularly useful. If this becomes a severe problem, a byte-
swapping operator could be added.
Files
Packet filter special files
See Alsoethers(3n), pfopen(3), de(4), ln(4), ni(4), qe(4), xna(4), ifconfig(8),
MAKEDEV(8), pfconfig(8c), pfstat(8)
The Packet Filter: An Efficient Mechanism for User-Level Network Code
packetfilter(4)