0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <linux/skbuff.h>
0012 #include <linux/tc_ematch/tc_em_cmp.h>
0013 #include <asm/unaligned.h>
0014 #include <net/pkt_cls.h>
0015
0016 static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
0017 {
0018 return unlikely(cmp->flags & TCF_EM_CMP_TRANS);
0019 }
0020
0021 static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
0022 struct tcf_pkt_info *info)
0023 {
0024 struct tcf_em_cmp *cmp = (struct tcf_em_cmp *) em->data;
0025 unsigned char *ptr = tcf_get_base_ptr(skb, cmp->layer) + cmp->off;
0026 u32 val = 0;
0027
0028 if (!tcf_valid_offset(skb, ptr, cmp->align))
0029 return 0;
0030
0031 switch (cmp->align) {
0032 case TCF_EM_ALIGN_U8:
0033 val = *ptr;
0034 break;
0035
0036 case TCF_EM_ALIGN_U16:
0037 val = get_unaligned_be16(ptr);
0038
0039 if (cmp_needs_transformation(cmp))
0040 val = be16_to_cpu(val);
0041 break;
0042
0043 case TCF_EM_ALIGN_U32:
0044
0045
0046
0047 val = get_unaligned_be32(ptr);
0048
0049 if (cmp_needs_transformation(cmp))
0050 val = be32_to_cpu(val);
0051 break;
0052
0053 default:
0054 return 0;
0055 }
0056
0057 if (cmp->mask)
0058 val &= cmp->mask;
0059
0060 switch (cmp->opnd) {
0061 case TCF_EM_OPND_EQ:
0062 return val == cmp->val;
0063 case TCF_EM_OPND_LT:
0064 return val < cmp->val;
0065 case TCF_EM_OPND_GT:
0066 return val > cmp->val;
0067 }
0068
0069 return 0;
0070 }
0071
0072 static struct tcf_ematch_ops em_cmp_ops = {
0073 .kind = TCF_EM_CMP,
0074 .datalen = sizeof(struct tcf_em_cmp),
0075 .match = em_cmp_match,
0076 .owner = THIS_MODULE,
0077 .link = LIST_HEAD_INIT(em_cmp_ops.link)
0078 };
0079
0080 static int __init init_em_cmp(void)
0081 {
0082 return tcf_em_register(&em_cmp_ops);
0083 }
0084
0085 static void __exit exit_em_cmp(void)
0086 {
0087 tcf_em_unregister(&em_cmp_ops);
0088 }
0089
0090 MODULE_LICENSE("GPL");
0091
0092 module_init(init_em_cmp);
0093 module_exit(exit_em_cmp);
0094
0095 MODULE_ALIAS_TCF_EMATCH(TCF_EM_CMP);