Hello,

During the work on the implementation of BPF, we (Guillaume Libersat and
myself) found that the NETF packet filter only sends ingress packets to
listeners. Injecting egress packets into packet filters is easy to
implement but we decided not to do it for now because there are other
problems implied that we were not able to solve (like rearranging the
filters queues to separate ingress and egress filters, adapting the GC
processing, etc...). However, the GNU Mach interface to packet filters
should be modified to allow listeners to specify the direction of the
packets they want to capture (ingress/egress/both), and there should be
a way for listeners to know the direction of the packets they capture.

As a result, we decided to use the first filter_t object of a filter as a
header with two parts, one to specify the type of filter - NETF or BPF - and
another for flags - NETF_IN and NETF_OUT. In addition, a field was added
to struct net_rcv_msg (device/net_status.h) which tells about the direction
of the packet captured.

Here you can find patches for GNU Mach and pfinet (since pfinet uses a
catch-all filter, it was necessary to alter it). The GNU Mach patch
improves BPF support, alters the interface to packet filters and uncomment
some declarations in device/bpf.h.

There are also Debian packages available (gnumach and hurd) at
http://devel.hurdfr.org/.

-- 
Richard Braun
2006-03-15 Richard Braun <[EMAIL PROTECTED]>

        * device/net_io.c: Added and fixed a patch from
        Manuel Menal <[EMAIL PROTECTED]> to improve BPF support.
        * 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 incoming packets as incoming packets.

diff -Nurp gnumach-20050801.orig/device/net_io.c 
gnumach-20050801/device/net_io.c
--- gnumach-20050801.orig/device/net_io.c       2006-03-15 16:30:03.000000000 
+0100
+++ gnumach-20050801/device/net_io.c    2006-03-15 16:44:02.000000000 +0100
@@ -735,10 +735,12 @@ net_filter(kmsg, send_list)
        FILTER_ITERATE(ifp, infp, nextfp)
        {
            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
@@ -883,7 +885,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;
@@ -1010,6 +1012,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++) {
@@ -1118,13 +1124,17 @@ 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_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 */
@@ -1605,11 +1615,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;
@@ -1619,8 +1630,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 */
@@ -1664,58 +1678,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;
@@ -1727,35 +1736,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:
@@ -1923,7 +1924,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) {
                /*
diff -Nurp gnumach-20050801.orig/include/device/bpf.h 
gnumach-20050801/include/device/bpf.h
--- gnumach-20050801.orig/include/device/bpf.h  2006-03-15 16:31:29.000000000 
+0100
+++ gnumach-20050801/include/device/bpf.h       2006-03-15 16:32:03.000000000 
+0100
@@ -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-20050801.orig/include/device/net_status.h 
gnumach-20050801/include/device/net_status.h
--- gnumach-20050801.orig/include/device/net_status.h   2006-03-15 
16:31:29.000000000 +0100
+++ gnumach-20050801/include/device/net_status.h        2006-03-15 
16:32:03.000000000 +0100
@@ -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-20050801.orig/linux/dev/glue/net.c 
gnumach-20050801/linux/dev/glue/net.c
--- gnumach-20050801.orig/linux/dev/glue/net.c  2006-03-15 16:30:12.000000000 
+0100
+++ gnumach-20050801/linux/dev/glue/net.c       2006-03-15 16:36:19.000000000 
+0100
@@ -298,6 +298,8 @@ netif_rx (struct sk_buff *skb)
 
   dev_kfree_skb (skb, FREE_READ);
 
+  net_kmsg(kmsg)->sent = FALSE; /* Mark packet as incoming.  */
+
   /* Pass packet up to the microkernel.  */
   net_packet (&dev->net_data->ifnet, kmsg,
              ph->length, ethernet_priority (kmsg));
2006-03-06 Richard Braun <[EMAIL PROTECTED]>

        * 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
 };

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Bug-hurd mailing list
Bug-hurd@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-hurd

Reply via email to