2006-03-15 Richard Braun * device/net_io.c: Added and fixed a patch from Manuel Menal 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 /* 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<sent = FALSE; /* Mark packet as incoming. */ + /* Pass packet up to the microkernel. */ net_packet (&dev->net_data->ifnet, kmsg, ph->length, ethernet_priority (kmsg));