Packet Filter interface

The pfil interface is purely in the stack and supports packet-filtering hooks.

Packet filters can register hooks that are called when packet processing is taking place; in essence, pfil is a list of callbacks for certain events. In addition to being able to register a filter for incoming and outgoing packets, pfil provides support for interface attach/detach and address change notifications.

The pfil interface is one of a number of different layers that a user-supplied application can register for, to operate within the stack process context. These modules, when compiled, are called Loadable Shared Modules (lsm) in QNX Neutrino nomenclature, or Loadable Kernel Modules (lkm) in BSD nomenclature.

There are two levels of registration required with io-pkt:

In the QNX Neutrino RTOS, shared modules are dynamically loaded into the stack. You can do this by specifying them on the command line when you start io-pkt, using the -p option, or you can add them subsequently to an existing io-pkt process by using the mount command.

The application module must include an initial module entry point defined as follows:

#include "sys/io-pkt.h"
#include "nw_datastruct.h"

int mod_entry( void *dll_hdl, struct _iopkt_self *iopkt,
               char *options)
{

}

The calling parameters to the entry function are:

void * dll_hdl
An opaque pointer that identifies the shared module within io-pkt.
struct _iopkt_self * iopkt
A structure used by the stack to reference its own internals.
char * options
The options string passed by the user to be parsed by this module.
Note: The header files aren't installed as part of the OS. If you need them, contact your sales representative.

This is followed by the registration structure that the stack will look for after calling dlopen() to load the module to retrieve the entry point:

struct _iopkt_lsm_entry IOPKT_LSM_ENTRY_SYM(mod) =
  IOPKT_LSM_ENTRY_SYM_INIT(mod_entry);

This entry point registration is used by all shared modules, regardless of which layer the remainder of the code is going to hook into. Use the following functions to register with the pfil layer:

#include <sys/param.h>
#include <sys/mbuf.h>
#include <net/if.h>
#include <net/pfil.h>

struct pfil_head *
pfil_head_get(int af, u_long dlt);

struct packet_filter_hook *
pfil_hook_get(int dir, struct pfil_head *ph);

int
pfil_add_hook(int (*func)(), void *arg, int flags,
              struct pfil_head *ph);

int
pfil_remove_hook(int (*func)(), void *arg, int flags,
                 struct pfil_head *ph);

int
(*func)(void *arg, struct mbuf **mp, struct ifnet *, int dir);

The head_get() function returns the start of the appropriate pfil hook list used for the hook functions. The af argument can be either PFIL_TYPE_AF (for an address family hook) or PFIL_TYPE_IFNET (for an interface hook) for the "standard" interfaces.

If you specify PFIL_TYPE_AF, the Data Link Type (dlt) argument is a protocol family. The current implementation has filtering points for only AF_INET (IPv4) or AF_INET6 (IPv6).

When you use the interface hook (PFIL_TYPE_IFNET), dlt is a pointer to a network interface structure. All hooks attached in this case will be in reference to the specified network interface.

Once you've selected the appropriate list head, you can use pfil_add_hook() to add a hook to the filter list. This function takes as arguments a filter hook function, an opaque pointer (which is passed into the user-supplied filter arg function), a flags value (described below), and the associated list head returned by pfil_head_get().

The flags value indicates when the hook function should be called and may be one of:

When a filter is invoked, the packet appears just as if it came off the wire. That is, all protocol fields are in network-byte order. The filter returns a nonzero value if the packet processing is to stop, or zero if the processing is to continue.

For interface hooks, the flags argument can be one of:

Here's an example of what a simple pfil hook would look like. It shows when an interface is attached or detached. Upon a detach (ifconfig iface destroy), the filter is unloaded.

#include <sys/types.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/socket.h>
#include <sys/mbuf.h>
#include <net/if.h>
#include <net/pfil.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include "sys/io-pkt.h"
#include "nw_datastruct.h"


static int in_bytes = 0;    
static int out_bytes = 0;   


static int input_hook(void *arg, struct mbuf **m,
                      struct ifnet *ifp, int dir)
{
    in_bytes += (*m)->m_len;
    return 0;
}

static int output_hook(void *arg, struct mbuf **m,
                       struct ifnet *ifp, int dir)
{
    out_bytes += (*m)->m_len;
    return 0;
}


static int deinit_module(void);
static int iface_hook(void *arg, struct mbuf **m,
                      struct ifnet *ifp, int dir)
{
    printf("Iface hook called ... ");   
    if ( (int)m == PFIL_IFNET_ATTACH) {
        printf("Interface attached\n");
        printf("%d bytes in, %d bytes out\n", in_bytes,
               out_bytes);
    } else if ((int)m == PFIL_IFNET_DETACH) {
        printf("Interface detached\n");
        printf("%d bytes in, %d bytes out\n", in_bytes,
               out_bytes);
        deinit_module();
    }
    return 0;
}

static int ifacecfg_hook(void *arg, struct mbuf **m,
                         struct ifnet *ifp, int dir)
{
        
    printf("Iface cfg hook called with 0x%08X\n", (int)(m));    

    return 0;
}

static int deinit_module(void)
{
    struct pfil_head *pfh_inet;

    pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
    if (pfh_inet == NULL) {
        return ESRCH;
    }
    pfil_remove_hook(input_hook, NULL, PFIL_IN | PFIL_WAITOK,
                     pfh_inet);
    pfil_remove_hook(output_hook, NULL, PFIL_OUT | PFIL_WAITOK,
                     pfh_inet);

    pfh_inet = pfil_head_get(PFIL_TYPE_IFNET, 0);
    if (pfh_inet == NULL) {
        return ESRCH;
    }

    pfil_remove_hook(ifacecfg_hook, NULL, PFIL_IFNET, pfh_inet);

    pfil_remove_hook(iface_hook, NULL, PFIL_IFNET | PFIL_WAITOK,
                     pfh_inet);
    printf("Unloaded pfil hook\n" );

    return 0;
}



int pfil_entry(void *dll_hdl, struct _iopkt_self *iopkt,
               char *options)
{
    struct pfil_head *pfh_inet;

    pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
    if (pfh_inet == NULL) {
        return ESRCH;
    }
    pfil_add_hook(input_hook, NULL, PFIL_IN | PFIL_WAITOK,
                  pfh_inet);
    pfil_add_hook(output_hook, NULL, PFIL_OUT | PFIL_WAITOK,
                  pfh_inet);

    pfh_inet = pfil_head_get(PFIL_TYPE_IFNET,0);
    if (pfh_inet == NULL) {
        return ESRCH;
    }

    pfil_add_hook(iface_hook, NULL, PFIL_IFNET, pfh_inet);
    pfil_add_hook(ifacecfg_hook, NULL, PFIL_IFADDR, pfh_inet);
    printf("Loaded pfil hook\n" );

    return 0;
}

struct _iopkt_lsm_entry IOPKT_LSM_ENTRY_SYM(pfil) =
  IOPKT_LSM_ENTRY_SYM_INIT(pfil_entry);