12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * net/sched/em_cmp.c Simple packet data comparison ematch
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Authors: Thomas Graf <tgraf@suug.ch>
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/skbuff.h>
121da177e4SLinus Torvalds #include <linux/tc_ematch/tc_em_cmp.h>
13d48abfecSHarvey Harrison #include <asm/unaligned.h>
141da177e4SLinus Torvalds #include <net/pkt_cls.h>
151da177e4SLinus Torvalds
cmp_needs_transformation(struct tcf_em_cmp * cmp)161da177e4SLinus Torvalds static inline int cmp_needs_transformation(struct tcf_em_cmp *cmp)
171da177e4SLinus Torvalds {
181da177e4SLinus Torvalds return unlikely(cmp->flags & TCF_EM_CMP_TRANS);
191da177e4SLinus Torvalds }
201da177e4SLinus Torvalds
em_cmp_match(struct sk_buff * skb,struct tcf_ematch * em,struct tcf_pkt_info * info)211da177e4SLinus Torvalds static int em_cmp_match(struct sk_buff *skb, struct tcf_ematch *em,
221da177e4SLinus Torvalds struct tcf_pkt_info *info)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds struct tcf_em_cmp *cmp = (struct tcf_em_cmp *) em->data;
251da177e4SLinus Torvalds unsigned char *ptr = tcf_get_base_ptr(skb, cmp->layer) + cmp->off;
261da177e4SLinus Torvalds u32 val = 0;
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds if (!tcf_valid_offset(skb, ptr, cmp->align))
291da177e4SLinus Torvalds return 0;
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds switch (cmp->align) {
321da177e4SLinus Torvalds case TCF_EM_ALIGN_U8:
331da177e4SLinus Torvalds val = *ptr;
341da177e4SLinus Torvalds break;
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds case TCF_EM_ALIGN_U16:
37d48abfecSHarvey Harrison val = get_unaligned_be16(ptr);
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds if (cmp_needs_transformation(cmp))
401da177e4SLinus Torvalds val = be16_to_cpu(val);
411da177e4SLinus Torvalds break;
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds case TCF_EM_ALIGN_U32:
44*e5a4b17dSMenglong Dong /* Worth checking boundaries? The branching seems
45cc7ec456SEric Dumazet * to get worse. Visit again.
46cc7ec456SEric Dumazet */
47d48abfecSHarvey Harrison val = get_unaligned_be32(ptr);
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds if (cmp_needs_transformation(cmp))
501da177e4SLinus Torvalds val = be32_to_cpu(val);
511da177e4SLinus Torvalds break;
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds default:
541da177e4SLinus Torvalds return 0;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds if (cmp->mask)
581da177e4SLinus Torvalds val &= cmp->mask;
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds switch (cmp->opnd) {
611da177e4SLinus Torvalds case TCF_EM_OPND_EQ:
621da177e4SLinus Torvalds return val == cmp->val;
631da177e4SLinus Torvalds case TCF_EM_OPND_LT:
641da177e4SLinus Torvalds return val < cmp->val;
651da177e4SLinus Torvalds case TCF_EM_OPND_GT:
661da177e4SLinus Torvalds return val > cmp->val;
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds static struct tcf_ematch_ops em_cmp_ops = {
731da177e4SLinus Torvalds .kind = TCF_EM_CMP,
741da177e4SLinus Torvalds .datalen = sizeof(struct tcf_em_cmp),
751da177e4SLinus Torvalds .match = em_cmp_match,
761da177e4SLinus Torvalds .owner = THIS_MODULE,
771da177e4SLinus Torvalds .link = LIST_HEAD_INIT(em_cmp_ops.link)
781da177e4SLinus Torvalds };
791da177e4SLinus Torvalds
init_em_cmp(void)801da177e4SLinus Torvalds static int __init init_em_cmp(void)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds return tcf_em_register(&em_cmp_ops);
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds
exit_em_cmp(void)851da177e4SLinus Torvalds static void __exit exit_em_cmp(void)
861da177e4SLinus Torvalds {
871da177e4SLinus Torvalds tcf_em_unregister(&em_cmp_ops);
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds MODULE_LICENSE("GPL");
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds module_init(init_em_cmp);
931da177e4SLinus Torvalds module_exit(exit_em_cmp);
941da177e4SLinus Torvalds
95db3d99c0SPatrick McHardy MODULE_ALIAS_TCF_EMATCH(TCF_EM_CMP);
96