diff -Nru linux-2.6.10-bk4.orig/include/linux/pkt_cls.h linux-2.6.10-bk4/include/linux/pkt_cls.h --- linux-2.6.10-bk4.orig/include/linux/pkt_cls.h 2005-01-02 22:37:46.000000000 +0100 +++ linux-2.6.10-bk4/include/linux/pkt_cls.h 2005-01-02 22:37:39.000000000 +0100 @@ -346,6 +346,7 @@ enum { TCF_EM_CONTAINER, + TCF_EM_U32, __TCF_EM_MAX }; @@ -362,4 +363,28 @@ #define TCF_EM_REL_OR (1<<2) #define TCF_EM_INVERT (1<<3) +struct tcf_em_u32 +{ + __u32 val; + __u32 mask; + __u16 off; + __u8 align; + __u8 layer:4; + __u8 opnd:4; +}; + +enum +{ + TCF_EM_ALIGN_U8 = 1, + TCF_EM_ALIGN_U16 = 2, + TCF_EM_ALIGN_U32 = 4 +}; + +enum +{ + TCF_EM_OPND_EQ, + TCF_EM_OPND_GT, + TCF_EM_OPND_LT +}; + #endif diff -Nru linux-2.6.10-bk4.orig/include/net/pkt_cls.h linux-2.6.10-bk4/include/net/pkt_cls.h --- linux-2.6.10-bk4.orig/include/net/pkt_cls.h 2005-01-02 22:37:46.000000000 +0100 +++ linux-2.6.10-bk4/include/net/pkt_cls.h 2005-01-02 22:23:24.000000000 +0100 @@ -218,6 +218,36 @@ #endif /* CONFIG_NET_EMATCH */ +static inline u32 tcf_read_bucket(u8 *ptr, u8 align) +{ + switch (align) { + case TCF_EM_ALIGN_U8: + return *ptr; + case TCF_EM_ALIGN_U16: + return (*ptr << 8) | *(ptr+1); + case TCF_EM_ALIGN_U32: + return (*ptr << 24) | (*(ptr+1) << 16) | + (*(ptr+2) << 8) | *(ptr+3); + } + return 0; +} + +static inline u8 * tcf_get_base_ptr(struct sk_buff *skb, u8 layer) +{ + switch (layer) { + case 0: + return skb->data; + case 1: + return skb->nh.raw; + case 2: + return skb->h.raw; + } + return NULL; +} + +#define tcf_valid_offset(skb, ptr, off, len) \ + ((ptr + off + len) < skb->tail && (ptr + off) > skb->head) + #ifdef CONFIG_NET_CLS_IND static inline int tcf_change_indev(struct tcf_proto *tp, char *indev, struct rtattr *indev_tlv) diff -Nru linux-2.6.10-bk4.orig/net/sched/Kconfig linux-2.6.10-bk4/net/sched/Kconfig --- linux-2.6.10-bk4.orig/net/sched/Kconfig 2005-01-02 22:37:46.000000000 +0100 +++ linux-2.6.10-bk4/net/sched/Kconfig 2005-01-02 22:37:39.000000000 +0100 @@ -381,6 +381,12 @@ ---help--- TODO +config NET_EMATCH_U32 + tristate "U32" + depends on NET_EMATCH + ---help--- + TODO + config NET_CLS_ACT bool "Packet ACTION" depends on EXPERIMENTAL && NET_CLS && NET_QOS diff -Nru linux-2.6.10-bk4.orig/net/sched/Makefile linux-2.6.10-bk4/net/sched/Makefile --- linux-2.6.10-bk4.orig/net/sched/Makefile 2005-01-02 22:37:46.000000000 +0100 +++ linux-2.6.10-bk4/net/sched/Makefile 2005-01-02 22:37:39.000000000 +0100 @@ -34,3 +34,4 @@ obj-$(CONFIG_NET_CLS_TCINDEX) += cls_tcindex.o obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o obj-$(CONFIG_NET_EMATCH) += ematch.o +obj-$(CONFIG_NET_EMATCH_U32) += em_u32.o diff -Nru linux-2.6.10-bk4.orig/net/sched/em_u32.c linux-2.6.10-bk4/net/sched/em_u32.c --- linux-2.6.10-bk4.orig/net/sched/em_u32.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-bk4/net/sched/em_u32.c 2005-01-02 22:38:27.000000000 +0100 @@ -0,0 +1,98 @@ +/* + * net/sched/em_u32.c U32 ematch + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int em_u32_change(struct tcf_proto *tp, void *data, int len, + struct tcf_ematch *m) +{ + if (len != sizeof(struct tcf_em_u32)) + return -EINVAL; + + m->data = (unsigned long) kmalloc(len, GFP_KERNEL); + if (!m->data) + return -ENOBUFS; + + memcpy((void *) m->data, data, len); + return 0; +} + +static int em_u32_match(struct sk_buff *skb, struct tcf_ematch *m) +{ + struct tcf_em_u32 *u = (struct tcf_em_u32 *) m->data; + u8 *ptr = tcf_get_base_ptr(skb, u->layer); + u32 v; + + if (unlikely(!tcf_valid_offset(skb, ptr, u->off, u->align))) + return 0; + + v = tcf_read_bucket(ptr + u->off, u->align) & u->mask; + + switch (u->opnd) { + case TCF_EM_OPND_EQ: + return v == u->val; + case TCF_EM_OPND_LT: + return v < u->val; + case TCF_EM_OPND_GT: + return v > u->val; + } + + return 0; +} + +static int em_u32_destroy(struct tcf_proto *tp, struct tcf_ematch *m) +{ + kfree((void *) m->data); + return 0; +} + +static int em_u32_dump(struct sk_buff *skb, struct tcf_ematch *m) +{ + RTA_PUT_NOHDR(skb, sizeof(struct tcf_em_u32), (void *) m->data); + return 0; +rtattr_failure: + return -1; +} + +static struct tcf_ematch_ops em_u32_ops = { + .kind = TCF_EM_U32, + .change = em_u32_change, + .match = em_u32_match, + .destroy = em_u32_destroy, + .dump = em_u32_dump, + .owner = THIS_MODULE, + .link = LIST_HEAD_INIT(em_u32_ops.link) +}; + +static int __init init_em_u32(void) +{ + return tcf_em_register(&em_u32_ops); +} + +static void __exit exit_em_u32(void) +{ + tcf_em_unregister(&em_u32_ops); +} + +MODULE_LICENSE("GPL"); + +module_init(init_em_u32); +module_exit(exit_em_u32); +