bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GNU Mach interface to packet filters


From: Richard Braun
Subject: Re: GNU Mach interface to packet filters
Date: Fri, 14 Apr 2006 16:13:05 +0200
User-agent: Mutt/1.5.9i

OK, so, after getting some feedback, here is a new patch (the change in
kern/queue.h was inappropriate, and a useful comment was added).
I'm also going to describe the changes brought to the interface to packet
filters more clearly.

The main changes to the interface are visible in include/device/net_status.h.
First, keep in mind that we support two types of packet filters which are
NETF (also called CSPF) and BPF. The interface must provide a way to
specify the type of filter sent to the kernel. Next, with this patch,
egress packets are sent to packet filters. Therefore the interface must
provide a way to specify which type of packets (egress, ingress, or both)
a filter will be applied to. Another requirement is that, once packets are
sent to userspace listeners, those listeners must be able to know if the
packet captured is an egress or ingress packet (can't be both here).
In order to achieve all this, we decided to use the first filter_t object
of any filter as a header. Common filter_t objects are split in two
parts, one for the operator (6 bits) and one for the argument (10 bits).
We decided to match this separation in the header, which in turn
contains the filter type on 6 bits and some flags on 10 bits. Four
macros were added to net_status.h, which are :
 o NETF_TYPE_MASK : mask to use on the header to get the type of the filter
                   (can also be used to get only the flags)
 o NETF_BPF : for BPF filters
 o NETF_IN : flag to apply the filter on ingress packets
 o NETF_OUT : same for egress packets

NETF filters are considered to be native filters, so there is no macro
for them (a requirement for all non-native filters is to be non-zero).

Macros were also added in include/device/bpf.h :
#define BPF_BEGIN       NETF_BPF
#define BPF_IN          NETF_IN
#define BPF_OUT         NETF_OUT

Here is the NETF filter that would be used in pfinet :
static short ether_filter[] =
{
  NETF_IN, /* header */
  NETF_PUSHLIT | NETF_NOP,
  1
};

And here is the BPF filter used in the currently developed BPF translator :
static const struct bpf_insn bpf_header =
{
  BPF_BEGIN | BPF_IN, /* BPF_OUT is OR'ed if the ``see sent'' flag is
  0,                  /* enabled - see bpf(4) on a BSD system. */
  0,
  0
};

FYI, this structure is called bpf_header because a compliant BPF implementation
doesn't have such a header. When a listener such as tcpdump sends a filter
to the BPF translator, a new filter (bpf_header + the filter received) will
be forged and sent to GNU Mach.

Finally, a new field of type boolean_t was added to struct net_rcv_msg
to tell listeners that the packet is egress or ingress. The field is
named ``sent'' to match the BIOCSEESENT ioctl(). It is also used inside
the kernel to know which list of filters (ifp->if_(rcv|snd)_port_list) is
going to be used when applying filters on a packet.

Here are the two patches we've been working on. The second one makes
Hurd's pfinet use the new interface just discussed.


18_packet_filters.patch:
2006-04-14 Richard Braun <syn@hurdfr.org>

        * device/if_hdr.h: Added a port list for egress packets and its
        lock.
        * device/net_io.c: Added and fixed a patch from
        Manuel Menal <mmenal@hurdfr.org> to improve BPF support.
        Filters can be applied to ingress packets, egress packets, or both.
        * device/subrs.c: Initialize the new port list and its lock.
        * include/device/bpf.h: Uncommented and added some macros and
        type definitions.
        * include/device/net_status.h: Added macros and changed the
        definition of struct net_rcv_msg. This changes the interface to
        packet filters.
        * linux/dev/glue/net.c: Mark ingress packets as received and
        inject egress packets into packet filters.

diff -Nurp gnumach-20060408.dfsg.1.orig/device/if_hdr.h 
gnumach-20060408.dfsg.1/device/if_hdr.h
--- gnumach-20060408.dfsg.1.orig/device/if_hdr.h        2006-04-14 
10:29:33.000000000 +0000
+++ gnumach-20060408.dfsg.1/device/if_hdr.h     2006-04-14 10:31:16.000000000 
+0000
@@ -79,8 +79,11 @@ struct ifnet {
        char    *if_address;            /* pointer to hardware address */
        struct ifqueue if_snd;          /* output queue */
        queue_head_t if_rcv_port_list;  /* input filter list */
+       queue_head_t if_snd_port_list;  /* output filter list */
        decl_simple_lock_data(,
-               if_rcv_port_list_lock)  /* lock for filter list */
+               if_rcv_port_list_lock)  /* lock for input filter list */
+       decl_simple_lock_data(,
+               if_snd_port_list_lock)  /* lock for output filter list */
 /* statistics */
        int     if_ipackets;            /* packets received */
        int     if_ierrors;             /* input errors */
diff -Nurp gnumach-20060408.dfsg.1.orig/device/net_io.c 
gnumach-20060408.dfsg.1/device/net_io.c
--- gnumach-20060408.dfsg.1.orig/device/net_io.c        2006-04-14 
10:29:32.000000000 +0000
+++ gnumach-20060408.dfsg.1/device/net_io.c     2006-04-14 13:28:04.000000000 
+0000
@@ -288,7 +288,8 @@ net_kmsg_more(void)
  * filter for a single session.
  */
 struct net_rcv_port {
-       queue_chain_t   chain;          /* list of open_descriptors */
+       queue_chain_t   input;          /* list of input open_descriptors */
+       queue_chain_t   output;         /* list of output open_descriptors */
        ipc_port_t      rcv_port;       /* port to send packet to */
        int             rcv_qlimit;     /* port's qlimit */
        int             rcv_count;      /* number of packets received */
@@ -348,15 +349,15 @@ decl_simple_lock_data(,net_hash_header_l
        } while ((elt) != (head));
 
 
-#define FILTER_ITERATE(ifp, fp, nextfp) \
-       for ((fp) = (net_rcv_port_t) queue_first(&(ifp)->if_rcv_port_list);\
-            !queue_end(&(ifp)->if_rcv_port_list, (queue_entry_t)(fp));    \
-            (fp) = (nextfp)) {                                            \
-               (nextfp) = (net_rcv_port_t) queue_next(&(fp)->chain);
+#define FILTER_ITERATE(if_port_list, fp, nextfp, chain)        \
+       for ((fp) = (net_rcv_port_t) queue_first(if_port_list); \
+            !queue_end(if_port_list, (queue_entry_t)(fp));     \
+            (fp) = (nextfp)) {                                 \
+               (nextfp) = (net_rcv_port_t) queue_next(chain);
 #define FILTER_ITERATE_END }
 
 /* entry_p must be net_rcv_port_t or net_hash_entry_t */
-#define ENQUEUE_DEAD(dead, entry_p) { \
+#define ENQUEUE_DEAD(dead, entry_p, chain) {                   \
        queue_next(&(entry_p)->chain) = (queue_entry_t) (dead); \
        (dead) = (queue_entry_t)(entry_p);                      \
 }
@@ -711,23 +712,36 @@ net_filter(kmsg, send_list)
        queue_entry_t           dead_entp = (queue_entry_t) 0;
        unsigned int            ret_count;
 
+       queue_head_t *if_port_list;
+
        int count = net_kmsg(kmsg)->net_rcv_msg_packet_count;
        ifp = (struct ifnet *) kmsg->ikm_header.msgh_remote_port;
        ipc_kmsg_queue_init(send_list);
 
+       if (net_kmsg(kmsg)->sent)
+           if_port_list = &ifp->if_snd_port_list;
+       else
+           if_port_list = &ifp->if_rcv_port_list;
+
        /*
         * Unfortunately we can't allocate or deallocate memory
-        * while holding this lock.  And we can't drop the lock
-        * while examining the filter list.
+        * while holding these locks. And we can't drop the locks
+        * while examining the filter lists.
+        * Both locks are hold in case a filter is removed from both
+        * queues.
         */
        simple_lock(&ifp->if_rcv_port_list_lock);
-       FILTER_ITERATE(ifp, infp, nextfp)
-       {
+       simple_lock(&ifp->if_snd_port_list_lock);
+       FILTER_ITERATE(if_port_list, infp, nextfp,
+                      net_kmsg(kmsg)->sent ? &infp->output : &infp->input)
+       {
            entp = (net_hash_entry_t) 0;
-           if (infp->filter[0] == NETF_BPF) {
-               ret_count = bpf_do_filter(infp, net_kmsg(kmsg)->packet, count,
-                                         net_kmsg(kmsg)->header,
-                                         &hash_headp, &entp);
+           if ((infp->filter[0] & NETF_TYPE_MASK) == NETF_BPF) {
+               ret_count = bpf_do_filter(infp, net_kmsg(kmsg)->packet
+                                         + sizeof(struct packet_header),
+                                         count, net_kmsg(kmsg)->header,
+                                         ifp->if_header_size, &hash_headp,
+                                         &entp);
                if (entp == (net_hash_entry_t) 0)
                  dest = infp->rcv_port;
                else
@@ -754,9 +768,15 @@ net_filter(kmsg, send_list)
                     */
 
                    if (entp == (net_hash_entry_t) 0) {
-                       queue_remove(&ifp->if_rcv_port_list, infp,
-                                    net_rcv_port_t, chain);
-                       ENQUEUE_DEAD(dead_infp, infp);
+                       if (infp->filter[0] & NETF_IN)
+                           queue_remove(&ifp->if_rcv_port_list, infp,
+                                        net_rcv_port_t, input);
+                       if (infp->filter[0] & NETF_OUT)
+                           queue_remove(&ifp->if_snd_port_list, infp,
+                                        net_rcv_port_t, output);
+
+                       /* Use input only for queues of dead filters. */
+                       ENQUEUE_DEAD(dead_infp, infp, input);
                        continue;
                    } else {
                        hash_ent_remove (ifp,
@@ -808,22 +828,27 @@ net_filter(kmsg, send_list)
                 * See if ordering of filters is wrong
                 */
                if (infp->priority >= NET_HI_PRI) {
-                   prevfp = (net_rcv_port_t) queue_prev(&infp->chain);
-                   /*
-                    * If infp is not the first element on the queue,
-                    * and the previous element is at equal priority
-                    * but has a lower count, then promote infp to
-                    * be in front of prevfp.
-                    */
-                   if ((queue_t)prevfp != &ifp->if_rcv_port_list &&
-                       infp->priority == prevfp->priority) {
-                       /*
-                        * Threshold difference to prevent thrashing
-                        */
-                       if (net_filter_queue_reorder
-                           && (100 + prevfp->rcv_count < rcount))
-                               reorder_queue(&prevfp->chain, &infp->chain);
+#define REORDER_PRIO(chain)                                            \
+                   prevfp = (net_rcv_port_t) queue_prev(&infp->chain); \
+                   /*                                                  \
+                    * If infp is not the first element on the queue,   \
+                    * and the previous element is at equal priority    \
+                    * but has a lower count, then promote infp to      \
+                    * be in front of prevfp.                           \
+                    */                                                 \
+                   if ((queue_t)prevfp != if_port_list &&              \
+                       infp->priority == prevfp->priority) {           \
+                       /*                                              \
+                        * Threshold difference to prevent thrashing    \
+                        */                                             \
+                       if (net_filter_queue_reorder                    \
+                           && (100 + prevfp->rcv_count < rcount))      \
+                           reorder_queue(&prevfp->chain, &infp->chain);\
                    }
+
+                   REORDER_PRIO(input);
+                   REORDER_PRIO(output);
+
                    /*
                     * High-priority filter -> no more deliveries
                     */
@@ -833,7 +858,7 @@ net_filter(kmsg, send_list)
            }
        }
        FILTER_ITERATE_END
-
+       simple_unlock(&ifp->if_snd_port_list_lock);
        simple_unlock(&ifp->if_rcv_port_list_lock);
 
        /*
@@ -872,7 +897,7 @@ net_do_filter(infp, data, data_count, he
 #define        header_word     ((unsigned short *)header)
 
        sp = &stack[NET_FILTER_STACK_DEPTH];
-       fp = &infp->filter[0];
+       fp = &infp->filter[1]; /* filter[0] used for flags */
        fpe = infp->filter_end;
 
        *sp = TRUE;
@@ -999,6 +1024,10 @@ parse_net_filter(filter, count)
        register filter_t       *fpe = &filter[count];
        register filter_t       op, arg;
 
+       /*
+        * count is at least 1, and filter[0] is used for flags.
+        */
+       filter++;
        sp = NET_FILTER_STACK_DEPTH;
 
        for (; filter < fpe; filter++) {
@@ -1099,6 +1128,7 @@ net_set_filter(ifp, rcv_port, priority, 
     int                                i;
     int                                ret, is_new_infp;
     io_return_t                        rval;
+    boolean_t                  in, out;
 
     /*
      * Check the filter syntax.
@@ -1107,13 +1137,19 @@ net_set_filter(ifp, rcv_port, priority, 
     filter_bytes = CSPF_BYTES(filter_count);
     match = (bpf_insn_t) 0;
 
-    if (filter_count > 0 && filter[0] == NETF_BPF) {
+    if (filter_count == 0) {
+       return (D_INVALID_OPERATION);
+    } else if (!((filter[0] & NETF_IN) || (filter[0] & NETF_OUT))) {
+       return (D_INVALID_OPERATION); /* NETF_IN or NETF_OUT required */
+    } else if ((filter[0] & NETF_TYPE_MASK) == NETF_BPF) {
        ret = bpf_validate((bpf_insn_t)filter, filter_bytes, &match);
        if (!ret)
            return (D_INVALID_OPERATION);
-    } else {
+    } else if ((filter[0] & NETF_TYPE_MASK) == 0) {
        if (!parse_net_filter(filter, filter_count))
            return (D_INVALID_OPERATION);
+    } else {
+       return (D_INVALID_OPERATION);
     }
 
     rval = D_SUCCESS;                  /* default return value */
@@ -1129,8 +1165,8 @@ net_set_filter(ifp, rcv_port, priority, 
        is_new_infp = TRUE;
     } else {
         /*
-        * If there is a match instruction, we assume there will
-        * multiple session with a common substructure and allocate
+        * If there is a match instruction, we assume there will be
+        * multiple sessions with a common substructure and allocate
         * a hash table to deal with them.
         */
        my_infp = 0;
@@ -1143,70 +1179,87 @@ net_set_filter(ifp, rcv_port, priority, 
      * Look for filters with dead ports (for GC).
      * Look for a filter with the same code except KEY insns.
      */
-    
-    simple_lock(&ifp->if_rcv_port_list_lock);
-    
-    FILTER_ITERATE(ifp, infp, nextfp)
+    void check_filter_list(queue_head_t *if_port_list)
     {
+       FILTER_ITERATE(if_port_list, infp, nextfp,
+                       (if_port_list == &ifp->if_rcv_port_list)
+                       ? &infp->input : &infp->output)
+       {
            if (infp->rcv_port == MACH_PORT_NULL) {
-                   if (match != 0
-                       && infp->priority == priority
-                       && my_infp == 0
-                       && (infp->filter_end - infp->filter) == filter_count
-                       && bpf_eq((bpf_insn_t)infp->filter,
-                                 filter, filter_bytes))
-                           {
-                                   my_infp = infp;
-                           }
-
-                   for (i = 0; i < NET_HASH_SIZE; i++) {
-                           head = &((net_hash_header_t) infp)->table[i];
-                           if (*head == 0)
-                                   continue;
-
-                           /*
-                            * Check each hash entry to make sure the
-                            * destination port is still valid.  Remove
-                            * any invalid entries.
-                            */
-                           entp = *head;
-                           do {
-                                   nextentp = (net_hash_entry_t) entp->he_next;
+               if (match != 0
+                   && infp->priority == priority
+                   && my_infp == 0
+                   && (infp->filter_end - infp->filter) == filter_count
+                   && bpf_eq((bpf_insn_t)infp->filter,
+                             filter, filter_bytes))
+                   my_infp = infp;
+
+               for (i = 0; i < NET_HASH_SIZE; i++) {
+                   head = &((net_hash_header_t) infp)->table[i];
+                   if (*head == 0)
+                       continue;
+
+                   /*
+                    * Check each hash entry to make sure the
+                    * destination port is still valid.  Remove
+                    * any invalid entries.
+                    */
+                   entp = *head;
+                   do {
+                       nextentp = (net_hash_entry_t) entp->he_next;
   
-                                   /* checked without 
-                                      ip_lock(entp->rcv_port) */
-                                   if (entp->rcv_port == rcv_port
-                                       || !IP_VALID(entp->rcv_port)
-                                       || !ip_active(entp->rcv_port)) {
-                               
-                                           ret = hash_ent_remove (ifp,
-                                               (net_hash_header_t)infp,
-                                               (my_infp == infp),
-                                               head,
-                                               entp,
-                                               &dead_entp);
-                                           if (ret)
-                                                   goto hash_loop_end;
-                                   }
+                       /* checked without 
+                          ip_lock(entp->rcv_port) */
+                       if (entp->rcv_port == rcv_port
+                           || !IP_VALID(entp->rcv_port)
+                           || !ip_active(entp->rcv_port)) {
+                           ret = hash_ent_remove (ifp,
+                               (net_hash_header_t)infp,
+                               (my_infp == infp),
+                               head,
+                               entp,
+                               &dead_entp);
+                           if (ret)
+                               goto hash_loop_end;
+                       }
                        
-                                   entp = nextentp;
-                           /* While test checks head since hash_ent_remove
-                              might modify it.
-                              */
-                           } while (*head != 0 && entp != *head);
-                   }
+                       entp = nextentp;
+                   /* While test checks head since hash_ent_remove
+                      might modify it.
+                    */
+                   } while (*head != 0 && entp != *head);
+               }
+
                hash_loop_end:
                    ;
-                   
            } else if (infp->rcv_port == rcv_port
                       || !IP_VALID(infp->rcv_port)
                       || !ip_active(infp->rcv_port)) {
-                   /* Remove the old filter from list */
-                   remqueue(&ifp->if_rcv_port_list, (queue_entry_t)infp);
-                   ENQUEUE_DEAD(dead_infp, infp);
+
+                   /* Remove the old filter from lists */
+                   if (infp->filter[0] & NETF_IN)
+                       queue_remove(&ifp->if_rcv_port_list, infp,
+                                    net_rcv_port_t, input);
+                   if (infp->filter[0] & NETF_OUT)
+                       queue_remove(&ifp->if_snd_port_list, infp,
+                                    net_rcv_port_t, output);
+
+                   ENQUEUE_DEAD(dead_infp, infp, input);
            }
+       }
+       FILTER_ITERATE_END
     }
-    FILTER_ITERATE_END
+
+    in = (filter[0] & NETF_IN) != 0;
+    out = (filter[0] & NETF_OUT) != 0;
+
+    simple_lock(&ifp->if_rcv_port_list_lock);
+    simple_lock(&ifp->if_snd_port_list_lock);
+
+    if (in)
+       check_filter_list(&ifp->if_rcv_port_list);
+    if (out)
+       check_filter_list(&ifp->if_snd_port_list);
 
     if (my_infp == 0) {
        /* Allocate a dummy infp */
@@ -1217,6 +1270,7 @@ net_set_filter(ifp, rcv_port, priority, 
        }
        if (i == N_NET_HASH) {
            simple_unlock(&net_hash_header_lock);
+           simple_unlock(&ifp->if_snd_port_list_lock);
            simple_unlock(&ifp->if_rcv_port_list_lock);
 
             ipc_port_release_send(rcv_port);
@@ -1257,10 +1311,21 @@ net_set_filter(ifp, rcv_port, priority, 
        }
 
        /* Insert my_infp according to priority */
-       queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, chain)
-           if (priority > infp->priority)
-               break;
-       enqueue_tail((queue_t)&infp->chain, (queue_entry_t)my_infp);
+       if (in) {
+           queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, input)
+               if (priority > infp->priority)
+                   break;
+
+           queue_enter(&ifp->if_rcv_port_list, my_infp, net_rcv_port_t, input);
+       }
+
+       if (out) {
+           queue_iterate(&ifp->if_snd_port_list, infp, net_rcv_port_t, output)
+               if (priority > infp->priority)
+                   break;
+
+           queue_enter(&ifp->if_snd_port_list, my_infp, net_rcv_port_t, 
output);
+       }
     }
     
     if (match != 0)
@@ -1284,9 +1349,9 @@ net_set_filter(ifp, rcv_port, priority, 
 
        ((net_hash_header_t)my_infp)->ref_count++;
        hash_entp->rcv_qlimit = net_add_q_info(rcv_port);
-
     }
     
+    simple_unlock(&ifp->if_snd_port_list_lock);
     simple_unlock(&ifp->if_rcv_port_list_lock);
 
 clean_and_return:
@@ -1537,11 +1602,12 @@ net_io_init()
  */
 
 int
-bpf_do_filter(infp, p, wirelen, header, hash_headpp, entpp)
+bpf_do_filter(infp, p, wirelen, header, hlen, hash_headpp, entpp)
        net_rcv_port_t  infp;
        char *          p;              /* packet data */
        unsigned int    wirelen;        /* data_count (in bytes) */
        char *          header;
+       unsigned int    hlen;           /* header len (in bytes) */
        net_hash_entry_t        **hash_headpp, *entpp;  /* out */
 {
        register bpf_insn_t pc, pc_end;
@@ -1551,8 +1617,11 @@ bpf_do_filter(infp, p, wirelen, header, 
        register int k;
        long mem[BPF_MEMWORDS];
 
+       /* Generic pointer to either HEADER or P according to the specified 
offset. */
+       char *data = NULL;
+
        pc = ((bpf_insn_t) infp->filter) + 1;
-                                       /* filter[0].code is BPF_BEGIN */
+                               /* filter[0].code is (NETF_BPF | flags) */
        pc_end = (bpf_insn_t)infp->filter_end;
        buflen = NET_RCV_MAX;
        *entpp = 0;                     /* default */
@@ -1596,58 +1665,53 @@ bpf_do_filter(infp, p, wirelen, header, 
 
                case BPF_LD|BPF_W|BPF_ABS:
                        k = pc->k;
-                       if ((u_int)k + sizeof(long) <= buflen) {
-#ifdef BPF_ALIGN
-                               if (((int)(p + k) & 3) != 0)
-                                       A = EXTRACT_LONG(&p[k]);
-                               else
-#endif
-                                       A = ntohl(*(long *)(p + k));
-                               continue;
-                       }
 
-                       k -= BPF_DLBASE;
-                       if ((u_int)k + sizeof(long) <= NET_HDW_HDR_MAX) {
+               load_word:
+                       if ((u_int)k + sizeof(long) <= hlen)
+                            data = header;
+                       else if ((u_int)k + sizeof(long) <= buflen) {
+                            k -= hlen;
+                            data = p;
+                       } else
+                            return 0;
+
 #ifdef BPF_ALIGN
-                               if (((int)(header + k) & 3) != 0)
-                                       A = EXTRACT_LONG(&header[k]);
-                               else
+                       if (((int)(data + k) & 3) != 0)
+                            A = EXTRACT_LONG(&data[k]);
+                       else
 #endif
-                                       A = ntohl(*(long *)(header + k));
-                               continue;
-                       } else {
-                               return 0;
-                       }
+                            A = ntohl(*(long *)(data + k));
+                       continue;
 
                case BPF_LD|BPF_H|BPF_ABS:
                        k = pc->k;
-                       if ((u_int)k + sizeof(short) <= buflen) {
-                               A = EXTRACT_SHORT(&p[k]);
-                               continue;
-                       }
 
-                       k -= BPF_DLBASE;
-                       if ((u_int)k + sizeof(short) <= NET_HDW_HDR_MAX) {
-                               A = EXTRACT_SHORT(&header[k]);
-                               continue;
-                       } else {
-                               return 0;
-                       }
+               load_half:
+                       if ((u_int)k + sizeof(short) <= hlen)
+                            data = header;
+                       else if ((u_int)k + sizeof(short) <= buflen) {
+                            k -= hlen;
+                            data = p;
+                       } else
+                            return 0;
+
+                       A = EXTRACT_SHORT(&data[k]);
+                       continue;
 
                case BPF_LD|BPF_B|BPF_ABS:
-                       k = pc->k;
-                       if ((u_int)k < buflen) {
-                               A = p[k];
-                               continue;
-                       }
-                       
-                       k -= BPF_DLBASE;
-                       if ((u_int)k < NET_HDW_HDR_MAX) {
-                               A = header[k];
-                               continue;
-                       } else {
-                               return 0;
-                       }
+                       k = pc->k;
+
+               load_byte:
+                       if ((u_int)k < hlen)
+                            data = header;
+                       else if ((u_int)k < buflen) {
+                            data = p;
+                            k -= hlen;
+                       } else
+                            return 0;
+
+                       A = data[k];
+                       continue;
 
                case BPF_LD|BPF_W|BPF_LEN:
                        A = wirelen;
@@ -1659,35 +1723,27 @@ bpf_do_filter(infp, p, wirelen, header, 
 
                case BPF_LD|BPF_W|BPF_IND:
                        k = X + pc->k;
-                       if (k + sizeof(long) > buflen)
-                               return 0;
-#ifdef BPF_ALIGN
-                       if (((int)(p + k) & 3) != 0)
-                               A = EXTRACT_LONG(&p[k]);
-                       else
-#endif
-                               A = ntohl(*(long *)(p + k));
-                       continue;
-
+                       goto load_word;
+                       
                case BPF_LD|BPF_H|BPF_IND:
                        k = X + pc->k;
-                       if (k + sizeof(short) > buflen)
-                               return 0;
-                       A = EXTRACT_SHORT(&p[k]);
-                       continue;
+                       goto load_half;
 
                case BPF_LD|BPF_B|BPF_IND:
                        k = X + pc->k;
-                       if (k >= buflen)
-                               return 0;
-                       A = p[k];
-                       continue;
+                       goto load_byte;
 
                case BPF_LDX|BPF_MSH|BPF_B:
                        k = pc->k;
-                       if (k >= buflen)
-                               return 0;
-                       X = (p[pc->k] & 0xf) << 2;
+                       if (k < hlen)
+                            data = header;
+                       else if (k < buflen) {
+                            data = p;
+                            k -= hlen;
+                       } else
+                            return 0;
+
+                       X = (data[k] & 0xf) << 2;
                        continue;
 
                case BPF_LD|BPF_IMM:
@@ -1855,7 +1911,11 @@ bpf_validate(f, bytes, match)
        register bpf_insn_t p;
 
        len = BPF_BYTES2LEN(bytes);
-       /* f[0].code is already checked to be BPF_BEGIN. So skip f[0]. */
+
+       /*
+        * f[0].code is already checked to be (NETF_BPF | flags).
+        * So skip f[0].
+        */
 
        for (i = 1; i < len; ++i) {
                /*
@@ -1984,7 +2044,7 @@ bpf_match (hash, n_keys, keys, hash_head
 /*
  * Removes a hash entry (ENTP) from its queue (HEAD).
  * If the reference count of filter (HP) becomes zero and not USED,
- * HP is removed from ifp->if_rcv_port_list and is freed.
+ * HP is removed from the corresponding port lists and is freed.
  */
 
 int
@@ -1998,13 +2058,18 @@ hash_ent_remove (ifp, hp, used, head, en
        hp->ref_count--;
 
        if (*head == entp) {
-
                if (queue_empty((queue_t) entp)) {
                        *head = 0;
-                       ENQUEUE_DEAD(*dead_p, entp);
+                       ENQUEUE_DEAD(*dead_p, entp, chain);
                        if (hp->ref_count == 0 && !used) {
-                               remqueue((queue_t) &ifp->if_rcv_port_list,
-                                        (queue_entry_t)hp);
+                               if (((net_rcv_port_t)hp)->filter[0] & NETF_IN)
+                                       queue_remove(&ifp->if_rcv_port_list,
+                                                    (net_rcv_port_t)hp,
+                                                    net_rcv_port_t, input);
+                               if (((net_rcv_port_t)hp)->filter[0] & NETF_OUT)
+                                       queue_remove(&ifp->if_snd_port_list,
+                                                    (net_rcv_port_t)hp,
+                                                    net_rcv_port_t, output);
                                hp->n_keys = 0;
                                return TRUE;
                        }
@@ -2015,7 +2080,7 @@ hash_ent_remove (ifp, hp, used, head, en
        }
 
        remqueue((queue_t)*head, (queue_entry_t)entp);
-       ENQUEUE_DEAD(*dead_p, entp);
+       ENQUEUE_DEAD(*dead_p, entp, chain);
        return FALSE;
 }    
 
@@ -2069,7 +2134,7 @@ net_free_dead_infp (dead_infp)
 
        for (infp = (net_rcv_port_t) dead_infp; infp != 0; infp = nextfp)
        {
-               nextfp = (net_rcv_port_t) queue_next(&infp->chain);
+               nextfp = (net_rcv_port_t) queue_next(&infp->input);
                ipc_port_release_send(infp->rcv_port);
                net_del_q_info(infp->rcv_qlimit);
                zfree(net_rcv_zone, (vm_offset_t) infp);
diff -Nurp gnumach-20060408.dfsg.1.orig/device/subrs.c 
gnumach-20060408.dfsg.1/device/subrs.c
--- gnumach-20060408.dfsg.1.orig/device/subrs.c 2006-04-14 10:29:32.000000000 
+0000
+++ gnumach-20060408.dfsg.1/device/subrs.c      2006-04-14 10:31:16.000000000 
+0000
@@ -82,7 +82,9 @@ void if_init_queues(ifp)
 {
        IFQ_INIT(&ifp->if_snd);
        queue_init(&ifp->if_rcv_port_list);
+       queue_init(&ifp->if_snd_port_list);
        simple_lock_init(&ifp->if_rcv_port_list_lock);
+       simple_lock_init(&ifp->if_snd_port_list_lock);
 }
 
 
diff -Nurp gnumach-20060408.dfsg.1.orig/include/device/bpf.h 
gnumach-20060408.dfsg.1/include/device/bpf.h
--- gnumach-20060408.dfsg.1.orig/include/device/bpf.h   2006-04-14 
10:30:37.000000000 +0000
+++ gnumach-20060408.dfsg.1/include/device/bpf.h        2006-04-14 
10:31:16.000000000 +0000
@@ -72,7 +72,8 @@
 #ifndef _DEVICE_BPF_H_
 #define _DEVICE_BPF_H_
 
-#if 0  /* not used in MK now */
+#include <sys/types.h> /* u_short */
+
 /*
  * Alignment macros.  BPF_WORDALIGN rounds up to the next 
  * even multiple of BPF_ALIGNMENT. 
@@ -115,14 +116,14 @@ struct bpf_version {
 #define DLT_PPP                9       /* Point-to-point Protocol */
 #define DLT_FDDI       10      /* FDDI */
 
-#endif /* 0 */
-
 /*
  * The instruction encondings.
  */
 
-/* Magic number for the first instruction */
-#define BPF_BEGIN NETF_BPF
+/* Magic number and flags for the first instruction */
+#define BPF_BEGIN      NETF_BPF
+#define BPF_IN         NETF_IN
+#define BPF_OUT                NETF_OUT
 
 /* instruction classes */
 #define BPF_CLASS(code) ((code) & 0x07)
diff -Nurp gnumach-20060408.dfsg.1.orig/include/device/net_status.h 
gnumach-20060408.dfsg.1/include/device/net_status.h
--- gnumach-20060408.dfsg.1.orig/include/device/net_status.h    2006-04-14 
10:30:37.000000000 +0000
+++ gnumach-20060408.dfsg.1/include/device/net_status.h 2006-04-14 
10:31:16.000000000 +0000
@@ -98,6 +98,11 @@ struct net_status {
  *  If the final value of the filter operation is true, then the packet is
  *  accepted for the filter.
  *
+ *  The first filter_t object is a header which allows to set flags for the
+ *  filter code. Main flags concern the direction of packets. This header is
+ *  split in the same way NETF words are : the 6 MSB bits indicate the type
+ *  of filter while the 10 LSB bits are the flags. For native NETF filters,
+ *  clear the 6 MSB bits (which is why there is no dedicated macro).
  */
 
 typedef        unsigned short  filter_t;
@@ -112,6 +117,14 @@ typedef filter_t   *filter_array_t;
 #define        NETF_ARG(word)  ((word) & 0x3ff)
 #define        NETF_OP(word)   (((word)>>NETF_NBPA)&0x3f)
 
+/*  filter types  */
+#define NETF_TYPE_MASK (((1 << NETF_NBPO) - 1) << NETF_NBPA)
+#define NETF_BPF       (1 << NETF_NBPA)
+
+/*  flags  */
+#define NETF_IN                0x1
+#define NETF_OUT       0x2
+
 /*  binary operators  */
 #define NETF_NOP       (0<<NETF_NBPA)
 #define NETF_EQ                (1<<NETF_NBPA)
@@ -131,7 +144,6 @@ typedef filter_t    *filter_array_t;
 #define        NETF_RSH        (15<<NETF_NBPA)
 #define        NETF_ADD        (16<<NETF_NBPA)
 #define        NETF_SUB        (17<<NETF_NBPA)
-#define NETF_BPF       (((1 << NETF_NBPO) - 1) << NETF_NBPA)
 
 
 /*  stack arguments  */
@@ -178,6 +190,7 @@ struct net_rcv_msg {
        char            header[NET_HDW_HDR_MAX];
        mach_msg_type_t packet_type;
        char            packet[NET_RCV_MAX];
+       boolean_t       sent;
 };
 typedef struct net_rcv_msg     *net_rcv_msg_t;
 #define        net_rcv_msg_packet_count packet_type.msgt_number
diff -Nurp gnumach-20060408.dfsg.1.orig/linux/dev/glue/net.c 
gnumach-20060408.dfsg.1/linux/dev/glue/net.c
--- gnumach-20060408.dfsg.1.orig/linux/dev/glue/net.c   2006-04-14 
10:29:42.000000000 +0000
+++ gnumach-20060408.dfsg.1/linux/dev/glue/net.c        2006-04-14 
10:50:43.000000000 +0000
@@ -290,6 +290,9 @@ netif_rx (struct sk_buff *skb)
   eh = (struct ether_header *) (net_kmsg (kmsg)->header);
   ph = (struct packet_header *) (net_kmsg (kmsg)->packet);
   memcpy (eh, skb->data, sizeof (struct ether_header));
+
+  /* packet is prefixed with a struct packet_header,
+     see include/device/net_status.h.  */
   memcpy (ph + 1, skb->data + sizeof (struct ether_header),
          skb->len - sizeof (struct ether_header));
   ph->type = eh->ether_type;
@@ -298,6 +301,8 @@ netif_rx (struct sk_buff *skb)
 
   dev_kfree_skb (skb, FREE_READ);
 
+  net_kmsg(kmsg)->sent = FALSE; /* Mark packet as received.  */
+
   /* Pass packet up to the microkernel.  */
   net_packet (&dev->net_data->ifnet, kmsg,
              ph->length, ethernet_priority (kmsg));
@@ -484,6 +489,34 @@ device_write (void *d, ipc_port_t reply_
     }
   splx (s);
 
+  /* Send packet to filters.  */
+  {
+    struct packet_header *packet;
+    struct ether_header *header;
+    ipc_kmsg_t kmsg;
+
+    kmsg = net_kmsg_get ();
+
+    if (kmsg != IKM_NULL)
+      {
+        /* Suitable for Ethernet only.  */
+        header = (struct ether_header *) (net_kmsg (kmsg)->header);
+        packet = (struct packet_header *) (net_kmsg (kmsg)->packet);
+        memcpy (header, skb->data, sizeof (struct ether_header));
+
+        /* packet is prefixed with a struct packet_header,
+           see include/device/net_status.h.  */
+        memcpy (packet + 1, skb->data + sizeof (struct ether_header),
+                skb->len - sizeof (struct ether_header));
+        packet->length = skb->len - sizeof (struct ether_header)
+                         + sizeof (struct packet_header);
+        packet->type = header->ether_type;
+        net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent.  */
+        net_packet (&dev->net_data->ifnet, kmsg, packet->length,
+                    ethernet_priority (kmsg));
+      }
+  }
+
   return MIG_NO_REPLY;
 }
 

pfinet_packet_filter.patch:
2006-03-06 Richard Braun <syn@hurdfr.org>

        * pfinet/ethernet.c: Update the NETF filter to include the new
        mandatory header.

diff -Nurp pfinet/ethernet.c.orig pfinet/ethernet.c
--- pfinet/ethernet.c.orig      2006-03-06 10:48:04.000000000 +0100
+++ pfinet/ethernet.c   2006-03-06 07:28:10.000000000 +0100
@@ -68,6 +68,7 @@ ethernet_set_multi (struct device *dev)
 
 static short ether_filter[] =
 {
+  NETF_IN,
   NETF_PUSHLIT | NETF_NOP,
   1
 };


-- 
Richard Braun

Attachment: signature.asc
Description: Digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]